Files
SwissMX/pyqtUsrObj.py

801 lines
33 KiB
Python

#!/usr/bin/env python
# *-----------------------------------------------------------------------*
# | |
# | Copyright (c) 2022 by Paul Scherrer Institute (http://www.psi.ch) |
# | Based on Zac great first implementation |
# | Author Thierry Zamofing (thierry.zamofing@psi.ch) |
# *-----------------------------------------------------------------------*
'''
User pyqtgraph objects and functions.
TODO: Dimension of pyqtgraph is in um not pixel (as now)
'''
#import initExample ## Add path to library (just for examples; you do not need this)
import logging
_log=logging.getLogger(__name__)
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
from PyQt5.QtGui import QPolygon,QPolygonF
from PyQt5.QtCore import Qt,QPointF,QLineF
from PyQt5.QtWidgets import QMenu
def itr2str(itr):
return '('+', '.join(tuple(map(lambda x:f'{x:.6g}', itr)))+')'
def obj_tree(obj,p=''):
obj_info(obj,p)
for o in obj.childItems():
obj_tree(o,p+'.')
def obj_info(obj,p=''):
print(f"{p}obj_info:{obj}")
try:
pos=obj.pos()
print(f"{p}pos:({pos.x():.6g},{pos.y():.6g})") # in coordinate value on the scene (no change by zooming)
except AttributeError:
pass
try:
sz=obj.size()
print(f"{p}size:({sz.x():.6g},{sz.y():.6g})") # in coordinate value on the scene (no change by zooming)
except AttributeError:
pass
try:
for k, v in (('Viewport', obj.viewport()), ('Window', obj.window())):
print(
f"{p}{k} (x,y)(w,h):({v.x():.6g},{v.y():.6g})({v.width():.6g},{v.height():.6g})") # in coordinate value on the scene (no change by zooming)
except AttributeError:
pass
try:
scnPos=obj.scenePos()
print(f"{p}scenePos:({scnPos.x():.6g},{scnPos.y():.6g})") # in pixel on the scene (changes by zooming)
except AttributeError:
pass
try:
if type(obj)==QtGui.QTransform:
t=obj
else:
t=obj.transform()
print(f"{p}QTransform:{t.m11():8.5g} {t.m12():8.5g} {t.m13():8.5g}")
print(f"{p} {t.m21():8.5g} {t.m22():8.5g} {t.m23():8.5g}")
print(f"{p} {t.m31():8.5g} {t.m32():8.5g} {t.m33():8.5g}")
except AttributeError:
pass
class Marker(pg.ROI):
"""A crosshair ROI whose position is at the center of the crosshairs. By default, it is scalable, rotatable and translatable."""
def __init__(self, pos, size, mode, **kargs):
pg.ROI.__init__(self, pos, size, **kargs)
self._mode=mode
#widget.signal.connect(slot_function)
#self.sigRegionChangeFinished.connect(self.OnRgnChanged)
#def OnRgnChanged(self, event):
# print(event)
# obj_info(self)
def paint(self, p, *args):
#pg.ROI.paint(self, p, *args)
r=QtCore.QRectF(0, 0, self.state['size'][0], self.state['size'][1]).normalized()
p.setRenderHint(QtGui.QPainter.Antialiasing)
p.setPen(self.currentPen)
p.translate(r.left(), r.top())
#p.scale(r.width(), r.height()) # -> values x,y 0 to 1
#f=p.font();
#f.setPixelSize(50)
#p.setFont(f)
# p.drawText(0, 0, '{:.0f}x{:.0f}'.format(*tuple(self.size())))
#p.drawText(0, 0, 'Thierry')
p.scale(.01*r.width(), .01*r.height()) # -> values x,y 0 to 100
m=self._mode
if m==0:
p.drawEllipse(0, 0, 100, 100)
p.drawRect(0, 0, 100, 100)
p.drawRect(0, 0, 5, 5)
p.setPen(pg.mkPen(width=3, color=[200, 100, 100]))
p.drawLine(pg.Point(50, 0), pg.Point(50, 100))
p.drawLine(pg.Point( 0,50), pg.Point(100, 50))
ofx,ofy=Marker.txtTrf(p)
f=p.font()
f.setPixelSize(10)
p.setFont(f)
p.drawText(ofx+24, ofy+20, 'beam marker')
ctr=tuple((self.pos()+self.size()/2)*1000)
sz=tuple(self.size()*1000)
p.drawText(ofx+5, ofy+45, '{:.1f}x{:.1f} um'.format(*sz))
#p.drawText(5, -35, '{:.1f}'.format(ctr[0]))
p.drawText(ofx+5, ofy+55,42,30,Qt.AlignRight, '{:.1f}'.format(ctr[0]))
p.drawText(ofx+55, ofy+65, '{:.1f} um'.format(ctr[1]))
elif m==1:
p.drawEllipse(20,20,60,60)
p.drawRect(0, 0, 5, 5)
p.drawRect(0, 0, 100, 100)
p.setPen(pg.mkPen(width=2, color=[10, 255, 0]))
p.drawLine(pg.Point(50, 0), pg.Point( 50,100))
p.drawLine(pg.Point( 0,50), pg.Point(100, 50))
ofx,ofy=Marker.txtTrf(p)
f=p.font();
f.setPixelSize(10)
p.setFont(f)
#p.drawText(ofx+0, ofy+0, 'FFF')
#p.drawText(ofx+100, ofy+100, 'GGG')
px=tuple(self.pos()+self.size()/2)
p.drawText(ofx+18, ofy+10, 'optical center')
p.drawText(ofx+5, ofy+80,42,30,Qt.AlignRight, '{:.1f}'.format(px[0]))
p.drawText(ofx+55,ofy+90, '{:.1f}'.format(px[1]))
@staticmethod
def txtTrf(p):
tr=p.transform()
assert (p.transform()==p.worldTransform())
m11, m12, m13, m21, m22, m23, m31, m32, m33=tr.m11(), tr.m12(), tr.m13(), tr.m21(), tr.m22(), tr.m23(), tr.m31(), tr.m32(), tr.m33()
ofx=ofy=0
if m11<0:
m11=-m11; m12=-m12; ofx-=100
if m22<0:
m22=-m22; m21=-m21; ofy=-100
tr.setMatrix(m11, m12, m13, m21, m22, m23, m31, m32, m33)
p.setTransform(tr)
return ofx,ofy
class UsrROI(pg.ROI):
def __init__(self, pos, size, **kargs):
pg.ROI.__init__(self, pos, size, **kargs)
def cb_toggle_movable(self):
self.translatable=not self.translatable
def contextMenuEvent(self, event):
#pg.ROI.contextMenuEvent(self,event)
_log.debug('ContextMenu')
menu = QMenu("ctx")
act=menu.addAction('locked')
act.setCheckable(True)
act.setChecked(not self.translatable)
act.triggered.connect(self.cb_toggle_movable)
#menu.addAction('center in view')
#menu.addAction('delete')
menu.exec(event.screenPos())
class Fiducial(UsrROI):
def __init__(self, pos, size, z:float, **kargs):
UsrROI.__init__(self, pos, size, **kargs)
self._z=z
def paint(self, p, *args):
#pg.ROI.paint(self, p, *args)
r=QtCore.QRectF(0, 0, self.state['size'][0], self.state['size'][1]).normalized()
p.setRenderHint(QtGui.QPainter.Antialiasing)
p.setPen(self.currentPen)
p.translate(r.left(), r.top())
p.scale(.01*r.width(), .01*r.height()) # -> values x,y 0 to 100
p.drawRect(0, 0, 100, 100)
p.drawEllipse(45, 45, 10, 10)
p.setPen(pg.mkPen(width=1, color=[255, 0, 0]))
p.drawLine(pg.Point(50,10), pg.Point(50, 90))
p.drawLine(pg.Point(10,50), pg.Point(90, 50))
#tr=p.transform()
#tr.setMatrix(tr.m11(), tr.m12(), tr.m13(), tr.m21(), -tr.m22(), tr.m23(), tr.m31(), tr.m32(), tr.m33())
#p.setTransform(tr)
f=p.font()
f.setPixelSize(10)
p.setFont(f)
#p.drawText(24, 20, 'beam marker')
ctr=tuple(self.pos()+self.size()/2)
sz=tuple(self.size())
#print((*ctr,self._z))
#p.drawText(5, 25, 'x{:.4g}\ny{:.4g}\nz{:.4g}'.format(*ctr,self._z))
p.drawText(52, 10,40,40,Qt.TextWordWrap, 'x{:.5g}\ny{:.5g}\nz{:.5g}'.format(*ctr,self._z))
def ctr(self):
ctr=tuple(self.pos()+self.size()/2)+(self._z,)
return ctr
def __repr__(self):
ctr=self.ctr()
s=f'{self.__class__.__name__}:(ctr:{itr2str(ctr)}, size:{itr2str(self.size())}}}'
return s
def obj2json(self,encoder):
jsn= {
'__class__':self.__class__.__name__,
'pos':tuple(self.pos()),
'size':tuple(self.size()),
'z':self._z,
}
return jsn
class Grid(UsrROI):
'''a grid'''
def __init__( self, pos=(0,0), size=(30,20), cnt=(6,4), fiducialSize=.2, **kargs):
pg.ROI.__init__(self, pos, size, **kargs)
self._cnt=cnt
self._fidSz=fiducialSize
self.addScaleHandle([1, 1], [0, 0])
self.addScaleHandle([0, 0], [1, 1])
self.addScaleRotateHandle([1, 0], [0, 0])
def paint(self, p, *args):
#pg.ROI.paint(self, p, *args)
sz=self.state['size']
nx, ny=self._cnt
px, py=sz[0]/(nx-1), sz[1]/(ny-1)
r=QtCore.QRectF(0, 0, sz[0], sz[1]).normalized()
p.setRenderHint(QtGui.QPainter.Antialiasing)
p.setPen(self.currentPen)
for i in range(nx):
x=i*px
p.drawLine(pg.Point(x, 0), pg.Point(x, sz[1]))
for i in range(ny):
y=i*py
p.drawLine(pg.Point(0, y), pg.Point(sz[0] ,y ))
fidSz=self._fidSz
rx=ry=fidSz/2
p.setPen(pg.mkPen(width=1, color=(255, 0, 0)))
for j in range(ny):
y=j*py
for i in range(nx):
x=i*px
p.drawEllipse(QPointF(x,y), rx, ry)
#p.translate(r.left(), r.top())
#p.scale(r.width(), r.height())
#p.drawEllipse(0, 0, 1, 1)
#p.drawRect(0, 0, 1, 1)
def __repr__(self):
s=f'{self.__class__.__name__}:(pos:{itr2str(self.pos())}, size:{itr2str(self.size())}, cnt:{self._cnt}, fidSize:{self._fidSz}}}'
return s
def obj2json(self,encoder):
jsn= {
'__class__':self.__class__.__name__,
'pos':tuple(self.pos()),
'size':tuple(self.size()),
'cnt':self._cnt,
'fiducialSize':self._fidSz
}
return jsn
def get_scan_param(self,mode=0x2):
'returns scan parameters for scanning with deltatau. the format is as used for shapepath'
#pos=np.array(self.pos())
cnt=np.array(self._cnt,np.int32)
sz=np.array(self.size())
pitch=sz/cnt
xx, yy=np.meshgrid(range(cnt[0]), range(cnt[1]))
if mode&0x01: #modify x scaning forward backward each line
for i in range(1,cnt[1],2):
xx[i]=xx[i][::-1]
if mode&0x02: # modify y scaning forward backward each line
xx=xx.T
yy=yy.T
for i in range(1, cnt[0], 2):
yy[i]=yy[i][::-1]
pts=np.array([xx.reshape(-1), yy.reshape(-1)], dtype=np.float).transpose()*pitch
#pts+=pos
return pts
class Path(UsrROI):
'''
a path object with fiducials
path=np.array(n,2) of path points
ficucialScale=size for fiducials in dimensions of path
fiducial = np.array(n,2) of fiducial points
a circle is plot at the path positions
a cross is plot at the fiducial positions
'''
def __init__( self, pos=(0,0), path=np.array(((6,4),(16,24),(-5,7),(3,12))), fiducial=None, ficucialScale=5, **kargs):
if fiducial is None:
all=path
else:
all=np.vstack((fiducial,path))
mn=all.min(0)
mx=all.max(0)
sz=mx-mn
pg.ROI.__init__(self, pos, sz, **kargs)
self._fiducial=fiducial
self._path=path
self._fidScl=ficucialScale
self._rect=r=QtCore.QRectF(mn[0], mn[1], sz[0], sz[1])
self._qpath=qPth=QPolygonF()
for pt in path:
qPth.append(QPointF(*pt))
self.addFreeHandle([.1, .1])
self.addScaleHandle([1, 1], [0, 0])
self.addScaleHandle([0, 0], [1, 1])
self.addScaleRotateHandle([1, 0], [0, 0])
def paint(self, p, *args):
#pg.ROI.paint(self, p, *args)
pos=self.state['pos']
sz=self.state['size']
r=self._rect
p.setRenderHint(QtGui.QPainter.Antialiasing)
p.setPen(self.currentPen)
#p.drawEllipse(0, 0, int(sz[0]), int(sz[1]))
p.drawRect(0, 0, int(sz[0]), int(sz[1]))
#obj_info(p)
p.scale(sz[0]/r.width(), sz[1]/r.height())
p.translate(-r.left(), -r.top())
qpath=self._qpath
p.drawPolyline(qpath)
fidScl=self._fidScl
rx=fidScl*r.width()/sz[0]
ry=fidScl*r.height()/sz[1]
p.setPen(pg.mkPen(width=1, color=(255, 0, 0)))
for ctr in qpath:
p.drawEllipse(ctr, rx, ry)
fid=self._fiducial
for i in range(fid.shape[0]):
x,y=fid[i,:] #;print(x,y)
lh=QLineF(x-5*rx,y,x+5*rx,y)
lv=QLineF(x, y-5*ry, x, y+5*ry)
p.drawLines(lh,lv)
def __repr__(self):
s=f'{self.__class__.__name__}:(pos:{itr2str(self.pos())}, size:{itr2str(self.size())}, numFid:{self._fiducial.shape[0]}, numPts:{self._path.shape[0]}, ficucialScale:{self._fidScl}}}'
return s
def obj2json(self,encoder):
jsn= {
'__class__':self.__class__.__name__,
'pos':tuple(self.pos()),
'fiducial': repr(self._fiducial),
'path': repr(self._path),
'ficucialScale':self._fidScl
}
return jsn
class FixTargetFrame(UsrROI):
'''fixed target frame'''
tpl={
'test':{
'size':(120*15, 120*11),
'fiducial':{
'type':0,
'pos':((120*2, 120*2), (120*13, 120*2), (120*2, 120*9), (120*13, 120*9))
},
'grid':{
'pos':(120*4, 120*3),
'pitch':(120, 120),
'count':(8, 6)
}
},
'12.5x12.5':{
'size':(12500+120*4, 12500+120*4),
'fiducial':{
'type':0,
'pos':((240, 240), (240+12500, 240), (240, 240+12500), (240+12500, 240+12500))
},
'grid':{
# 240+(12500-78*120)/2=1810
'pos':(1810, 1810),
'pitch':(120, 120),
'count':(78, 78) #(84,84)... but sone covered
}
},
'23.0x23.0':{
'size':(23000+120*4, 23000+120*4),
'fiducial':{
'type':0,
'pos':((240, 240), (240+23000, 240), (240, 240+23000), (240+23000, 240+23000))
},
'grid':{
# 240+(23000-162*120)/2+60?=2020+60?
'pos':(2080, 2080),
'pitch':(120, 120),
'count':(162, 162) #(172,172)... but sone covered
}
}
}
def __init__( self, pos=(0,0), size=(100,100), tpl='test', dscr=None, **kwargs):
trf=kwargs.pop('trf',None)
pg.ROI.__init__(self, pos, size, **kwargs)
if trf is not None:
t=self.transform()
t.setMatrix(trf[0][0], trf[0][1], 0,
trf[1][0], trf[1][1], 0,
0, 0, 1)
self.setTransform(t)
#fiducial type 0: 5 squares with pitch 120 um
if dscr is not None:
self._dscr=dscr
else:
self._dscr=FixTargetFrame.tpl[tpl]
self.addScaleHandle([1, 1], [0, 0])
self.addScaleHandle([0, 0], [1, 1])
self.addScaleRotateHandle([1, 0], [0, 0])
#self.sigHoverEvent.connect(self.hover)
# def hover(self):
# _log.debug(f'hover {self}')
def paint(self, p, *args):
#pg.ROI.paint(self, p, *args)
sz=self.state['size']
#nx, ny=self._cnt
#px, py=sz[0]/(nx-1), sz[1]/(ny-1)
r=QtCore.QRectF(0, 0, sz[0], sz[1]).normalized()
p.setRenderHint(QtGui.QPainter.Antialiasing)
p.setPen(self.currentPen)
#p.drawRect(0, 0, int(sz[0]), int(sz[1]))
p.drawRect(r)
dscr=self._dscr
objSz=dscr['size']
p.translate(r.left(), r.top())
p.scale(r.width()/objSz[0], r.height()/objSz[1]) # -> values x,y 0 to 13000
dscr=self._dscr
g=dscr['grid']
ox,oy=g['pos']
px,py=g['pitch']
nx,ny=g['count']
#x0=ox; x1=ox+(ny-1)*py
#y0=oy; y1=oy+(nx-1)*px
x0=ox-.5*px; x1=ox+(nx-.5)*px
y0=oy-.5*py; y1=oy+(ny-.5)*py
for i in range(nx):
x=ox+i*px
p.drawLine(pg.Point(x, y0), pg.Point(x, y1))
for i in range(ny):
y=oy+i*py
p.drawLine(pg.Point(x0, y), pg.Point(x1 ,y ))
f=dscr['fiducial']
rx=50
ry=50
p.setPen(pg.mkPen(width=1, color=(255, 0, 0)))
if f['type']==0:
for p0 in f['pos']:
p0=np.array(p0)
for p1 in ((-120,-120),(120,-120),(0,0),(-120,120),(120,120),):
p1=np.array(p1)
x, y=p0+p1 #;print(x,y)
lh=QLineF(x-rx, y, x+rx, y)
lv=QLineF(x, y-ry, x, y+ry)
p.drawLines(lh, lv)
#plot center of all feducials
ctr=np.array(f['pos']).mean(axis=0)
x, y=ctr # ;print(x,y)
lh=QLineF(x-rx, y, x+rx, y)
lv=QLineF(x, y-ry, x, y+ry)
p.drawLines(lh, lv)
p.drawEllipse(x-rx/2, y-ry/2, rx, ry)
else:
assert('unknown feducial type')
def __repr__(self):
s=f'{self.__class__.__name__}:(pos:{itr2str(self.pos())}, size:{itr2str(self.size())}, dscr:{self._dscr}}}'
return s
def obj2json(self,encoder):
jsn= {
'__class__':self.__class__.__name__,
'pos':tuple(self.pos()),
'size':tuple(self.size()),
'dscr': self._dscr
}
trf=self.transform()
if not trf.isIdentity():
#obj_info(trf)
trf=((trf.m11(),trf.m12()),(trf.m21(),trf.m22()))
jsn['trf']=trf
return jsn
def get_scan_param(self,mode=0x2):
'returns scan parameters for scanning with deltatau. the format is as used for shapepath'
grid=self._dscr['grid']
self._dscr['size']
#pos=np.array(self.pos())
cnt =np.array(grid['count'],np.int32)
#pos =np.array(grid['pos'],np.float)
#pitch=np.array(grid['pitch'],np.float)
xx, yy=np.meshgrid(range(cnt[0]), range(cnt[1]))
if mode&0x01: #modify x scaning forward backward each line
for i in range(1,cnt[1],2):
xx[i]=xx[i][::-1]
if mode&0x02: # modify y scaning forward backward each line
xx=xx.T
yy=yy.T
for i in range(1, cnt[0], 2):
yy[i]=yy[i][::-1]
pts=np.array([xx.reshape(-1), yy.reshape(-1)], dtype=np.float).transpose() #*pitch
param={'grid':grid, 'points':pts}
t=self.transform()
p=np.array(self.pos())
s=self.size()/self._dscr['size']
trf=np.array(((t.m11(),t.m12()),(t.m21(),t.m22()),(0,0)))
trf[2,:]=p # shift origin
#trf[:2, 0]*=s[0];trf[:2, 1]*=s[1] #scaling (before rotation shear)
trf[:2,:]=(trf[:2,:].T*s).T # same as np.asmatrix(np.diag(s))*trf[:2,:], trf[:2,:]*=s not working, scale before rot / shear
# trf*'gridpos in um' -> motor pos in mm
param['trf']=trf
return param
## Start Qt event loop unless running in interactive mode or using pyside.
if __name__=='__main__':
def set_fiducial(pic):
# fiducial test
f=np.array(((0, 0, 0, 0, 0),
(0, 1, 1, 1, 0),
(0, 1, 0, 0, 0),
(0, 1, 1, 0, 0),
(0, 1, 0, 0, 0),
(0, 0, 0, 0, 0),), pic.dtype)
pic[0:6, 0:5]=f*pic.max()
# TODO: pg.ItemGroup does not support bounding box and therefore vb.autoRange() does not work
class ItemGroup(pg.ItemGroup):
# own item group that supports bounding rect
def __init__(self, *args, **kargs):
pg.ItemGroup.__init__(self, *args, **kargs)
def boundingRect(self):
# tr=self.transform()
boRects=[]
for item in self.childItems():
boRects.append(item.boundingRect())
if boRects:
# r=QtCore.QRectF(tr.map(boRects[0].bottomRight()),tr.map(boRects[0].topLeft()))
return boRects[0]
else:
return pg.ItemGroup.boundingRect(self)
def addItem(self, *args, **kargs):
self.setFlag(self.ItemHasNoContents, False)
pg.ItemGroup.addItem(self, *args, **kargs)
class TxtROI(pg.ROI):
def __init__(self, pos, size, **kargs):
pg.ROI.__init__(self, pos, size, **kargs)
def paint(self, p, *args):
# pg.ROI.paint(self, p, *args)
r=QtCore.QRectF(0, 0, self.state['size'][0], self.state['size'][1]).normalized()
p.setRenderHint(QtGui.QPainter.Antialiasing)
p.setPen(self.currentPen)
# p.translate(r.left(), r.top())
# p.scale(r.width(), r.height())
# p.drawRect(0, 0, 1, 1)
p.drawRect(r)
tr=p.worldTransform()
obj_info(tr)
tr.setMatrix(tr.m11(), tr.m12(), tr.m13(), tr.m21(), -tr.m22(), tr.m23(), tr.m31(), tr.m32(), tr.m33())
p.setWorldTransform(tr)
obj_info(tr)
obj_info(p.transform())
obj_info(p.worldTransform())
f=p.font();
f.setPixelSize(15)
p.setFont(f)
p.drawText(0, 5, 'Thierry')
import sys
import argparse
#(h, t)=os.path.split(sys.argv[0]);cmd='\n '+(t if len(h)>20 else sys.argv[0])+' '
#exampleCmd=('', '-m0xf -v0')
epilog=__doc__ #+'\nExamples:'+''.join(map(lambda s:cmd+s, exampleCmd))+'\n'
parser=argparse.ArgumentParser(epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("--mode", "-m", type=lambda x: int(x,0), help="mode default=0x%(default)x", default=0)
args = parser.parse_args()
pg.setConfigOptions(imageAxisOrder='row-major')
def pt2str(p):
return (f'({p.x():.5g},{p.y():.5g})')
def childTree(obj, lvl=0):
print('+'*lvl+str(obj))
for child in obj.childItems():
childTree(child, lvl+1)
def gen_swissmx_points(flipx=False,flipy=False,ofs=(-200,0),width=1000):
'generathe a path that writes swissfel'
#string from inkscape path of the drawing
d="m 524.7061,637.31536 3.54883,0 3.54882,0 3.54883,0 0,-4.20801 0,-4.20801 0,-4.208 0,-4.20801 4.22949,0 4.22949,0 4.2295,0 4.22949,0 0,-3.55957 0,-3.55957 0,-3.55957 0,-3.55957 -4.22949,0 -4.2295,0 -4.22949,0 -4.22949,0 0,-4.22949 0,-4.2295 0,-4.22949 0,-4.22949 -3.54883,0 -3.54882,0 -3.54883,0 -3.54883,0 0,4.22949 0,4.22949 0,4.2295 0,4.22949 -4.20752,0 -4.20752,0 -4.20752,0 -4.20752,0 0,3.55957 0,3.55957 0,3.55957 0,3.55957 4.20752,0 4.20752,0 4.20752,0 4.20752,0 0,4.20801 0,4.208 0,4.20801 0,4.20801 -11.87126,0.36152 -12.12171,-0.13934 -2.52941,3.93977 -2.57238,3.94369 -2.50854,3.88614 -2.50731,3.91767 -2.49035,3.88268 -2.50987,3.91244 -2.50453,3.88732 -2.51897,3.9189 -6.39782,5.72802 -6.63782,6.70894 -3.21517,5.11464 -3.3404,5.32333 -3.08995,5.11464 -3.17343,5.15637 -16.69223,0.0698 5.55908,0 5.55909,0 5.55908,0 3.18604,-5.17432 3.18603,-5.17431 3.18604,-5.17432 3.18603,-5.17431 3.17481,5.17431 3.1748,5.17432 3.17481,5.17431 3.1748,5.17432 5.59229,0 5.59228,0 5.59229,0 5.59228,0 -2.74121,-4.15283 -2.74121,-4.15283 -2.74121,-4.15283 -2.74121,-4.15284 -2.74122,-4.15283 -2.74121,-4.15283 -2.74121,-4.15283 -2.74121,-4.15283 2.50488,-3.90015 2.50489,-3.90015 2.50488,-3.90014 2.50488,-3.90015 2.50488,-3.90015 2.50489,-3.90015 2.50488,-3.90014 2.50488,-3.90015 -5.42724,0 -5.42725,0 -5.42724,0 -5.42725,0 -2.76855,4.95508 -2.76856,4.95508 -2.76855,4.95508 -2.76856,4.95508 -2.85644,-4.95508 -2.85645,-4.95508 -2.85644,-4.95508 -2.85645,-4.95508 -5.48193,0 -5.48194,0 -5.48194,0 -5.48193,0 2.52686,3.8562 2.52685,3.8562 2.52686,3.8562 2.52686,3.85621 2.52685,3.8562 2.52686,3.8562 2.52685,3.8562 2.52686,3.8562 -2.77954,4.19678 -2.77954,4.19678 -2.77954,4.19677 -2.77955,4.19678 -2.77954,4.19678 -2.77954,4.19678 -2.77954,4.19677 -2.77954,4.19678 -4.91638,0 -4.91638,0 -4.91639,0 -4.91638,0 -4.91638,0 -4.91638,0 -4.91638,0 -4.91638,0 -4.91639,0 -4.91638,0 -4.91638,0 -4.91638,0 -4.91638,0 -4.91639,0 -4.91638,0 -4.91638,0 4.07568,0 4.07568,0 4.07569,0 4.07568,0 0,-6.14136 0,-6.14135 0,-6.14136 0,-6.14136 0,-6.14136 0,-6.14135 0,-6.14136 0,-6.14136 1.57105,6.14136 1.57104,6.14136 1.57104,6.14135 1.57105,6.14136 1.57105,6.14136 1.57104,6.14136 1.57104,6.14135 1.57105,6.14136 3.68066,0 3.68067,0 3.68067,0 3.68066,0 1.57642,-6.14136 1.57641,-6.14135 1.57642,-6.14136 1.57641,-6.14136 1.57642,-6.14136 1.57642,-6.14135 1.57641,-6.14136 1.57642,-6.14136 0,6.14136 0,6.14136 0,6.14135 0,6.14136 0,6.14136 0,6.14136 0,6.14135 0,6.14136 4.06494,0 4.06494,0 4.06494,0 4.06494,0 0,-8.05298 0,-8.05298 0,-8.05298 0,-8.05297 0,-8.05298 0,-8.05298 0,-8.05298 0,-8.05298 -6.52588,0 -6.52588,0 -6.52587,0 -6.52588,0 -1.25781,4.8999 -1.25782,4.89991 -1.25781,4.8999 -1.25781,4.8999 -1.25781,4.8999 -1.25782,4.89991 -1.25781,4.8999 -1.25781,4.8999 -1.26343,-4.8999 -1.26343,-4.8999 -1.26343,-4.89991 -1.26343,-4.8999 -1.26342,-4.8999 -1.26343,-4.8999 -1.26343,-4.89991 -1.26343,-4.8999 -6.54785,0 -6.54785,0 -6.54785,0 -6.54785,0 0,8.05298 0,8.05298 0,8.05298 0,8.05298 0,8.05297 0,8.05298 0,8.05298 -4.25755,8.13646 -8.40743,0.19687 -8.40743,0.19687 -8.40743,0.19687 -8.40743,0.19687 5.93521,0.22812 8.09742,-0.56079 6.18579,-1.6814 4.55883,-2.66919 3.13062,-3.43823 1.84571,-3.87866 0.61523,-3.98853 -0.58179,-3.83373 -1.74634,-3.50416 -2.802,-2.95581 -3.83472,-2.18676 -5.49316,-1.60401 -7.77832,-1.20849 -7.64649,-1.58204 -1.75781,-2.59179 1.36328,-2.59375 4.4375,-1.09766 5.09766,1.40625 2.19727,3.29492 4.24072,-0.41748 4.24073,-0.41748 4.24072,-0.41748 4.24072,-0.41748 -1.98804,-4.09741 -2.44946,-3.15259 -2.97778,-2.3291 -3.65894,-1.62598 -5.05371,-0.95629 -7.25098,-0.3191 -7.10766,0.41748 -5.50367,1.25244 -4.19677,2.05494 -3.18604,2.91186 -2.01099,3.65796 -0.67065,4.29517 0.61523,3.98852 1.84571,3.5271 2.78002,2.823 3.32935,1.87817 5.06421,1.42822 7.89868,1.56006 7.69141,1.84571 2.02148,2.98828 -1.53906,2.85742 -5.58008,1.53711 -5.27344,-1.36133 -3.07617,-4.52734 -4.43847,0.41748 -4.43848,0.41748 -4.43848,0.41748 -4.43847,0.41748 2.50488,5.95459 4.43848,4.4165 3.18313,1.59592 4.10031,1.14017 -3.65979,0.0939 -5.9713,6e-5 -5.97131,5e-5 -5.9713,6e-5 -5.9713,6e-5 -5.9713,5e-5 -5.97131,6e-5 -5.9713,5e-5 -5.9713,6e-5 5.34491,0.81842 8.09742,-0.56079 6.18579,-1.6814 4.55883,-2.66919 3.13062,-3.43823 1.84571,-3.87866 0.61523,-3.98853 -0.58179,-3.83373 -1.74634,-3.50416 -2.802,-2.95581 -3.83472,-2.18676 -5.49316,-1.60401 -7.77832,-1.20849 -7.64649,-1.58204 -1.75781,-2.59179 1.36328,-2.59375 4.4375,-1.09766 5.09766,1.40625 2.19727,3.29492 4.24072,-0.41748 4.24073,-0.41748 4.24072,-0.41748 4.24072,-0.41748 -1.98804,-4.09741 -2.44946,-3.15259 -2.97778,-2.3291 -3.65894,-1.62598 -5.05371,-0.95629 -7.25098,-0.3191 -7.10766,0.41748 -5.50367,1.25244 -4.19677,2.05494 -3.18604,2.91186 -2.01099,3.65796 -0.67065,4.29517 0.61523,3.98852 1.84571,3.5271 2.78002,2.823 3.32935,1.87817 5.06421,1.42822 7.89868,1.56006 7.69141,1.84571 2.02148,2.98828 -1.53906,2.85742 -5.58008,1.53711 -5.27344,-1.36133 -3.07617,-4.52734 -4.43847,0.41748 -4.43848,0.41748 -4.43848,0.41748 -4.43847,0.41748 2.50488,5.95459 4.43848,4.4165 3.18313,1.59592 4.10031,1.14017 -3.06953,-0.0416 -3.06952,-0.0416 -8.58102,-0.0261 -10.12782,-0.0261 -7.03422,-0.0261 -8.58102,-0.0261 4.47168,0 6.6151,0 2.32826,0 4.47168,0 0,-5.83374 0,-5.83374 0,-5.83374 0,-5.83374 0,-5.83374 0,-5.83374 0,-5.83374 0,-5.83374 -4.47168,0 -4.47168,0 -4.47168,0 0,-5.5796 4.47168,0 4.47168,0 4.47168,0 0,-6.08691 0,-6.08692 -4.47168,0 -4.47168,0 -4.47168,0 -4.47168,0 0,6.08692 0,6.08691 0,5.5796 0,5.83374 0,5.83374 0,5.83374 0,5.83374 0,5.83374 0,5.83374 0,5.83374 -3.67318,5.83374 -8.7308,0 -10.73079,0 -6.7308,0 -9.10563,0 -2.25201,0.007 -8.72971,0.0266 -7.53755,-0.0442 -9.68477,0.0107 -6.3443,0 3.99902,0 3.99902,0 3.99903,0 3.99902,0 2.28516,-7.02002 2.28516,-7.02002 2.28516,-7.02002 2.28516,-7.02002 2.36181,7.02002 2.36182,7.02002 2.36181,7.02002 2.36182,7.02002 3.97705,0 3.97705,0 3.97705,0 3.97705,0 2.14795,-5.83374 2.14795,-5.83374 2.14795,-5.83374 2.14795,-5.83374 2.14795,-5.83374 2.14795,-5.83374 2.14795,-5.83374 2.14795,-5.83374 -4.2959,0 -4.2959,0 -4.2959,0 -4.2959,0 -0.93921,3.67505 -0.93921,3.67505 -0.93921,3.67505 -0.93921,3.67505 -0.9392,3.67504 -0.93921,3.67505 -0.93921,3.67505 -0.93921,3.67505 -1.23047,-3.67505 -1.23047,-3.67505 -1.23047,-3.67505 -1.23047,-3.67504 -1.23046,-3.67505 -1.23047,-3.67505 -1.23047,-3.67505 -1.23047,-3.67505 -4.03223,0 -4.03222,0 -4.03223,0 -4.03223,0 -1.18652,3.67505 -1.18653,3.67505 -1.18652,3.67505 -1.18653,3.67505 -1.18652,3.67504 -1.18652,3.67505 -1.18653,3.67505 -1.18652,3.67505 -0.93921,-3.67505 -0.93921,-3.67505 -0.93921,-3.67505 -0.93921,-3.67504 -0.9392,-3.67505 -0.93921,-3.67505 -0.93921,-3.67505 -0.93921,-3.67505 -4.32862,0 -4.32861,0 -4.32862,0 -4.32861,0 2.16431,5.83374 2.1643,5.83374 2.16431,5.83374 2.16431,5.83374 2.16431,5.83374 2.1643,5.83374 2.16431,5.83374 -3.84635,5.83374 -5.60781,0.003 -5.6078,0.003 -5.60781,0.003 -5.6078,0.003 -5.4839,-1.59358 0,0 5.47119,-3.35034 4.10888,-4.60278 2.5708,-5.4712 0.85694,-5.95459 -0.64868,-5.02123 -1.94507,-4.51587 -3.32837,-3.91114 -4.88843,-3.20801 -7.482173,-2.87842 -5.1337,-1.42273 -6.06186,-1.41174 -6.67969,-2.37304 -1.44922,-2.76758 1.75782,-3.56055 5.22851,-1.49414 6.5918,1.97852 1.99951,2.5708 1.16455,3.75732 4.69141,-0.2749 4.691403,-0.2749 4.6914,-0.27491 4.69141,-0.2749 -0.94483,-4.66918 -1.604,-3.98804 -2.26318,-3.30688 -2.92236,-2.62574 -3.59802,-2.01858 -4.334103,-1.44162 -5.0702,-0.86484 -5.80627,-0.28824 -4.76547,0.1593 -4.23282,0.47791 -6.86695,1.91162 -5.04223,2.98828 -3.61401,3.95507 -2.14283,4.53687 -0.7146,4.82251 1.40625,6.88892 4.21875,5.54858 3.26035,2.31812 4.19986,2.07641 5.13919,1.83472 6.07834,1.59302 6.54785,1.81226 3.64746,1.92211 2.19727,4.48242 -2.33008,4.65821 -6.54688,1.97851 -5.05371,-0.97827 -3.73535,-2.93384 -1.57153,-2.9663 -0.93433,-4.06495 -4.73486,0.29688 -4.73487,0.29687 -4.73486,0.29688 -4.73486,0.29687 0.76065,4.6637 1.44711,4.23523 2.13376,3.80676 2.82059,3.3783 3.79577,2.76855 5.0592,1.97754 6.32264,1.18652 7.58606,0.39551 9.481626,-0.95145 -7.224723,-0.043 -7.224724,-0.043 -7.224723,-0.043 -7.224723,-0.043 -7.224723,-0.043 -7.224723,-0.043 -7.224724,-0.043 -7.224723,-0.043"
d=d.split()
pts=np.ndarray((len(d)-1,2),dtype=np.float)
for i in range(pts.shape[0]):
pts[i,:]=tuple(map(float,d[i+1].split(',')))
pts[0,:]=(0,0)
pts=pts.cumsum(0)
pts=pts[::-1,:]
pts=pts-pts[0]
pts*=width/pts[:,0].max()
if flipx: pts[:,0]=-pts[:,0]
if not flipy: pts[:,1]=-pts[:,1]
pts+=ofs
return pts
def mouse_click_event(event):
#event.pos(): return Point(self.currentItem.mapFromScene(self._scenePos))
pos=event.pos()
scn=event.scenePos() # there is a small black border, that makes the difference
print(f'mouse-> scene pos:{pt2str(scn)} currentItem pos:{pt2str(pos)}')
#img=viImg.mapFromScene(scn)
#roi=viUsrRoi.mapFromScene(scn)
#print(f'mouse-> img:{pt2str(img)} roi:{pt2str(roi)}')
#childTree(vb)
#obj_info(viImg)
m=int(event.modifiers())
o=event.currentItem
if m&Qt.ShiftModifier:
o.setPos((100,200))
o.setSize((200,100))
o.rotate(10)
pass
elif m&Qt.ControlModifier:
tr=o.transform()
obj_info(tr)
#tr.setMatrix(tr.m11(),tr.m12(),tr.m13()+100,tr.m21(),tr.m22(),tr.m23(),tr.m31(),tr.m32(),tr.m33())
#tr.setMatrix(tr.m11(),tr.m12(),tr.m13(),tr.m21(),tr.m22(),tr.m23(),tr.m31(),tr.m32()+20,tr.m33())
#tr.setMatrix(tr.m11(),tr.m12(),tr.m13(),tr.m21(),-tr.m22(),tr.m23(),tr.m31(),tr.m32(),tr.m33())
tr.setMatrix(-tr.m11(),tr.m12(),tr.m13(),tr.m21(),-tr.m22(),tr.m23(),tr.m31(),tr.m32(),tr.m33())
obj_info(tr)
o.setTransform(tr)
elif m&Qt.AltModifier:
import matplotlib.pyplot as plt
import numpy as np
x=np.linspace(0.1, 2*np.pi, 41)
y=np.exp(np.sin(x))
plt.stem(x, y)
plt.show()
pass
else:
obj_info(o)
#print(o.state)
## Create image to display
arr=np.ones((100, 100), dtype=float)
arr[45:55, 45:55]=0
arr[25, :]=5
arr[:, 25]=5
arr[75, :]=5
arr[:, 75]=5
arr[50, :]=10
arr[:, 50]=10
arr+=np.sin(np.linspace(0, 20, 100)).reshape(1, 100)
arr+=np.random.normal(size=(100, 100))
set_fiducial(arr)
# add an arrow for asymmetry
arr[10, :50]=10
arr[9:12, 44:48]=10
arr[8:13, 44:46]=10
## create GUI
app=QtGui.QApplication([])
w=pg.GraphicsLayoutWidget(show=True, size=(1000, 800), border=True)
w.setWindowTitle('pyqtgraph example: ROI Examples')
vb=w.addViewBox(row=1, col=0, lockAspect=True,invertY=False,enableMenu=False)
vb.enableAutoRange(enable=False)
try:
g=pg.GridItem(pen=(0, 255, 0), textPen=(0, 255, 0)) # green grid and labels
except:
g=pg.GridItem()
vb.addItem(g)
viImg=pg.ImageItem(arr, border='y')
vb.addItem(viImg)
# Custom ROI for selecting an image region
#viRoi=pg.ROI([20, -50], [60, 40])
#viRoi=TxtROI([20, -50], [60, 40])
#viRoi.addScaleHandle([1, 1], [0, 0])
#viRoi.addScaleHandle([.7, .5], [0, 0])
#vb.addItem(viRoi)
viUsrRoi=Marker([50, 120], [30, 20],mode=0)
vb.addItem(viUsrRoi)
#obj=Marker([250, 220], [30, 20],mode=1)
#vb.addItem(obj)
vi=Grid( (120,-100), (200,150), (30,20),2)
tr=QtGui.QTransform() # prepare ImageItem transformation:
tr.setMatrix(1, -.1, 0,
.2, 1, 0,
10, 10, 1)
vi.setTransform(tr) # assign transform
#vi=Grid( (50,10), (200,150), (6,4))
vb.addItem(vi) #vi= visual item
grp=pg.ItemGroup()
vb.addItem(grp)
tr.setMatrix(-1, -.1, 0,
.2, -1, 0,
10, 10, 1)
grp.setTransform(tr) # assign transform
obj=Marker([20, 40], [30, 20],mode=1)
grp.addItem(obj)
obj=Marker([20, 40], [30, 20],mode=1)
vb.addItem(obj)
fidScl=.5
fiducial=np.array(((18, 7), (25, 16), (70, 20)))
path=gen_swissmx_points(ofs=(10, 5), width=200)
vi=Path((120,100),path,fiducial,fidScl)
#tr=QtGui.QTransform() # prepare ImageItem transformation:
#tr.setMatrix(1, 0, 0,
# 0, 1, 0,
# 10, 10, 1)
#vi.setTransform(tr) # assign transform
vb.addItem(vi)
vi=FixTargetFrame((100,300),(100,100),tpl='test')
vb.addItem(vi)
vi=FixTargetFrame((400,-200),(400,400),tpl='12.5x12.5')
vb.addItem(vi)
vi=Fiducial((0,200),(40,40),3,movable=False,removable=True)
vb.addItem(vi)
vi=pg.PolyLineROI([(22, -19), (40, -30), (23, -10), (22, -19)], closed=True)
vb.addItem(vi)
viRoi=pg.ROI([-200, -200], [100, 80],movable=True, rotatable=True, resizable=True)
viRoi.addFreeHandle(pos=[.7, .5], axes=None, item=None, name=None, index=None) # rechteck , frei beweglich ??? verschwinden anch bewegung
#viRoi.addRotateFreeHandle([.7, .5], [0, 0], axes=None, item=None, name=None, index=None) # kreis ??? verschwinden anch erstem gebrauch
#viRoi.addRotateHandle([.7, .5], [0, 0], item=None, name=None, index=None) # kreis, nur rot
#viRoi.addScaleHandle([.7, .5], [0, 0], axes=None, item=None, name=None, lockAspect=False, index=None) # raute scale x,y
#viRoi.addScaleRotateHandle([0, .5], [1, .5], item=None, name=None, index=None) # kreis
#viRoi.addTranslateHandle([.7, .5], axes=None, item=None, name=None, index=None) #quadrat
vb.addItem(viRoi)
#autorange not working, as all rois are in ItemGroup
vb.setRange(QtCore.QRectF(-300, -400, 900+300, 500+400))
childTree(vb)
w.scene().sigMouseClicked.connect(mouse_click_event)
#viImg.sigImageChanged
#print(vb.pos())
#vb.setPos(50,50)
if (sys.flags.interactive!=1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()