From cbae02c59764d4fd64877c6ec5466824337343e1 Mon Sep 17 00:00:00 2001 From: Thierry Zamofing Date: Tue, 6 Sep 2022 10:07:11 +0200 Subject: [PATCH] rework graphic opbect and coordinate transformation --- app_config.py | 18 +++++++++-- geometry.py | 57 +++++++++++++++++++---------------- pyqtUsrObj.py | 82 ++++++++++++++++++++++++++++++--------------------- swissmx.py | 41 ++++++++++++++++---------- 4 files changed, 121 insertions(+), 77 deletions(-) diff --git a/app_config.py b/app_config.py index e57abe7..b18638e 100644 --- a/app_config.py +++ b/app_config.py @@ -42,6 +42,7 @@ class AppCfg(QSettings): GEO_BEAM_POS="geometry/beam_pos" GEO_CAM_PARAM="geometry/cam_param" + GEO_CAM_TRF="geometry/cam_trf" WINDOW_GEOMETRY="window/geometry" WINDOW_SPLITTER="window/splitter" @@ -129,6 +130,11 @@ class AppCfg(QSettings): opt_ctr=np.array([603.28688025, 520.01112846]) self.setValue(AppCfg.GEO_OPT_CTR, opt_ctr) + if AppCfg.GEO_CAM_TRF not in keys: + _log.warning(f'{AppCfg.GEO_CAM_TRF} not defined. use default') + trf=np.array(((-1,0,0),(0,-1,0),(0,0,1))) + self.setValue(AppCfg.GEO_CAM_TRF, trf) + if AppCfg.DT_HOST not in keys: _log.warning(f'{AppCfg.DT_HOST} not defined. use default') self.setValue(AppCfg.DT_HOST,'SAR-CPPM-EXPMX1') @@ -155,12 +161,12 @@ class AppCfg(QSettings): def setValue(self, key: str, val): #overload to debug # only simple lists, str, int, float can not be serialized nicely t=type(val) - if key in (AppCfg.GEO_PIX2POS,): + if key in (AppCfg.GEO_PIX2POS,AppCfg.GEO_CAM_TRF): val=json.dumps(val, cls=MyJsonEncoder) elif key in (AppCfg.GEO_CAM_PARAM,AppCfg.DFT_POS_DET,AppCfg.DFT_POS_PST,AppCfg.DFT_POS_COL,AppCfg.DFT_POS_BKLGT,): val=json.dumps(val, cls=MyJsonEncoder) val=val.replace('"',"'") - elif key in (AppCfg.GEO_OPT_CTR,AppCfg.GEO_BEAM_SZ,AppCfg.GEO_BEAM_POS,): + elif key in (AppCfg.GEO_OPT_CTR,AppCfg.GEO_BEAM_SZ,AppCfg.GEO_BEAM_POS): if type(val)==np.ndarray: val=val.tolist() elif type(val)==tuple: @@ -172,6 +178,9 @@ class AppCfg(QSettings): if key in (AppCfg.GEO_PIX2POS,): val=json.loads(val)#, object_hook=MyJsonDecoder) val=(np.array(val[0]),np.array(val[1])) + elif key in (AppCfg.GEO_CAM_TRF,): + val=json.loads(val)#, object_hook=MyJsonDecoder) + val=np.array(val) elif key in (AppCfg.GEO_CAM_PARAM,AppCfg.DFT_POS_DET,AppCfg.DFT_POS_PST,AppCfg.DFT_POS_COL,AppCfg.DFT_POS_BKLGT,): if val is not None: val=val.replace("'",'"') @@ -275,6 +284,11 @@ class WndParameter(QMainWindow): {'name':AppCfg.DT_SHOW_PLOTS,'title':'show plots after collection' ,'value':dt_show_plots,'type':'bool' ,'tip':"This is a checkbox"}, {'name':AppCfg.DT_VEL_SCL ,'title':'velocity_scale' ,'value':dt_vel_scl ,'type':'float','limits':(0,1),'step':0.1,'tip':"This is a checkbox"}, ]}, + {'name':'Misc', 'type':'group', 'children':[ + {'name':AppCfg.GEO_CAM_TRF, 'value':cfg.value(AppCfg.GEO_CAM_TRF), 'type':'str'}, + ]}, + + {'name':'Save/Restore functionality', 'type':'group', 'children':[ {'name':'Save State', 'type':'action'}, {'name':'Restore State', 'type':'action', 'children':[ diff --git a/geometry.py b/geometry.py index 9273328..c9f2136 100755 --- a/geometry.py +++ b/geometry.py @@ -219,7 +219,6 @@ class geometry: return AA=np.ndarray((len(meas), 2, 2), np.float) K=np.array(tuple(meas.keys()), np.float) - self._lut_pix2pos=(K, AA) for i, (k, v) in enumerate(meas.items()): m=np.array(v) # measurements if m.shape[0]<3: @@ -238,6 +237,14 @@ class geometry: AA[i]=aa.reshape(2, -1) # bx_coefs = np.polyfit(nbx[0], nbx[1], 3) # np.poly1d(bx_coefs) + + if np.diff(K).min()<0: #zoom need to be from lowest to highest ordered + _log.debug('resorting') + s=K.argsort() + K=K[s] + AA=AA[s] #resort A if needed + self._lut_pix2pos=(K, AA) + _log.debug('least square data:\nK:{}\nAA:{}'.format(K, AA)) def autofocus(self): @@ -410,30 +417,30 @@ if __name__=="__main__": (-3.2, -6.8, 675.10991143017, 790.3040145281), (-3.2, -6.72, 638.98580653116, 59.3803912957)]} measure=\ -{1: [(6.4190000000000005, 6.907, 696.2976073449591, 227.76776138682274), - (5.719, 6.807, 410.67447894055806, 284.44919082240665), - (5.719, 5.207, 434.78681995014756, 938.5631353309454), - (6.619, 5.207, 808.7345059175318, 927.4590367789931)], - 200: [(6.619, 6.607, 940.264899030901, 187.39774454408854), - (5.519, 6.607, 272.1925062601967, 219.8977706369289), - (5.519, 5.407, 298.31361407848783, 941.97432810785), - (6.619, 5.407, 969.4645435773624, 920.3295993015843)], - 400: [(6.719, 6.707, 1099.5956451604673, 46.46696479882394), - (5.719, 6.707, 91.88845211350781, 99.00912182475837), - (5.719, 5.807, 122.49326406274122, 998.8073593766618), - (6.719, 5.807, 1137.5074440945523, 963.4302060882611)], - 600: [(6.619, 6.807, 1068.8592966662907, 106.9592377596037), - (6.019, 6.807, 75.47928488084321, 151.1144445833613), - (6.019, 6.307, 103.13064811335389, 977.5525209662414), - (6.619, 6.307, 1104.9406638931132, 939.9675773457886)], - 800: [(6.619, 6.307, 1160.5691045813528, 202.93697492698996), - (6.219, 6.307, 65.05964829488164, 253.28864950246646), - (6.219, 6.107, 88.00366601279788, 797.1538427010806), - (6.619, 6.107, 1180.6517090746024, 753.0303703110591)], - 1000: [(6.519, 6.267, 1087.8134573150567, 183.90222416155348), - (6.319, 6.267, 160.59872007696185, 229.55456266733404), - (6.319, 6.107, 190.50887289109403, 963.1404158981525), - (6.519, 6.107, 1116.3595117455784, 925.6445737503763)]} +{1000: [(-0.7310599999999997, 0.643119999999999, 1068.294887300626, 37.80427622442167), + (-0.8105999999999997, 0.6437299218749977, 325.69398272322496, 66.36584947739863), + (-0.8073999999999999, 0.548, 394.71778475125257, 954.1547514240993), + (-0.7257699218749997, 0.5511799999999984, 1155.1696726117643, 900.6018015747674)], + 800: [(-0.7087599999999997, 0.6409199999999983, 1056.3942317785522, 65.17578392519127), + (-0.8374999999999998, 0.6427399999999998, 354.2555559762018, 79.45657055167973), + (-0.8393599999999997, 0.4836299999999992, 378.0568670203493, 955.3448169763066), + (-0.6977599999999998, 0.487619999999999, 1159.9299348205936, 906.5521293358044)], + 600: [(-0.6560399999999997, 0.6448999999999997, 1112.3273127322987, 61.60558726856914), + (-0.8914799999999998, 0.6495299218750006, 324.5039171710175, 67.55591502960601), + (-0.8760799999999997, 0.3893999999999978, 407.80850582553353, 930.3534403799518), + (-0.6621199999999997, 0.39789999999999964, 1128.988230463202, 873.2302938739978)], + 400: [(-0.6044999999999998, 0.6441200000000008, 1074.2452150616627, 63.98571837298388), + (-0.9739299218749998, 0.6475599999999995, 310.2231305445289, 73.50624279064286), + (-0.9546199999999997, 0.22334999999999855, 398.28798140787467, 926.7832437233297), + (-0.5859199999999999, 0.23333999999999833, 1144.4590826418978, 880.3706871872422)], + 200: [(-0.4556199999999997, 0.6560399999999991, 1119.4677060455429, 44.9446695376659), + (-1.0542399999999998, 0.6175399999999991, 381.6270636769714, 108.01814380465672), + (-1.0568399999999998, -0.05702000000000044, 413.7588335865705, 932.7335714843665), + (-0.47519999999999984, -0.03876000000000022, 1136.1286237764461, 881.5607527394494)], + 1: [(-0.3154599999999996, 0.6150199999999987, 1112.3273127322987, 78.26650499947237), + (-1.1583899218749996, 0.5868999999999996, 425.65948910864427, 129.43932374438944), + (-1.2067399218749997, -0.3514000000000015, 400.6681125122893, 905.3620637835969), + (-0.3347399999999998, -0.36506000000000133, 1136.1286237764461, 880.3706871872422)]} obj.update_pix2pos(measure) diff --git a/pyqtUsrObj.py b/pyqtUsrObj.py index 0d67640..c358970 100644 --- a/pyqtUsrObj.py +++ b/pyqtUsrObj.py @@ -95,54 +95,56 @@ class Marker(pg.ROI): 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)) - 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) + + ofx,ofy=Marker.txtTrf(p) f=p.font() f.setPixelSize(10) p.setFont(f) - p.drawText(24, -80, 'beam marker') + p.drawText(ofx+24, ofy+20, 'beam marker') ctr=tuple(self.pos()+self.size()/2) sz=tuple(self.size()) - p.drawText(5, -55, '{:.1f}x{:.1f}'.format(*sz)) + p.drawText(ofx+5, ofy+45, '{:.1f}x{:.1f}'.format(*sz)) #p.drawText(5, -35, '{:.1f}'.format(ctr[0])) - p.drawText(5, -45,42,30,Qt.AlignRight, '{:.1f}'.format(ctr[0])) - p.drawText(55, -35, '{:.1f}'.format(ctr[1])) + p.drawText(ofx+5, ofy+55,42,30,Qt.AlignRight, '{:.1f}'.format(ctr[0])) + p.drawText(ofx+55, ofy+65, '{:.1f}'.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)) - 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) + 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(5, -90, 'optical') - p.drawText(55,-90, 'center') - #p.drawText(5, -10, '{:.1f}/{:.1f}'.format(*px)) - p.drawText(5, -10, '{:.1f}'.format(px[0])) - p.drawText(55, -10, '{:.1f}'.format(px[1])) - #p.drawText(0, 0, 'Thierry') + 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 - # w, h = self.getState()["size"] - # v1, v2 = -(h * 0.8) / 2, (h * 0.8) / 2 - # h1, h2 = -(w * 0.8) / 2, (w * 0.8) / 2 - # p.setRenderHint(QtGui.QPainter.Antialiasing) - # p.setPen(pg.mkPen(width=3, color=[200, 100, 100])) - # p.drawLine(pg.Point(0, v1), pg.Point(0, v2)) - # p.drawLine(pg.Point(h1, 0), pg.Point(h2, 0)) - # p.setPen(self.currentPen) - # #p.setPen(pg.mkPen(width=3, color=[200, 200, 100])) - # p.drawRect(-w / 2, -h / 2, w, h) - # # p.drawText(-w, -h, '{:.0f}x{:.0f}'.format(*self._size)) class Fiducial(pg.ROI): def __init__(self, pos, size, z:float, **kargs): @@ -602,7 +604,8 @@ if __name__=='__main__': 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()) + 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: @@ -645,26 +648,37 @@ if __name__=='__main__': vb.addItem(viImg) # Custom ROI for selecting an image region #viRoi=pg.ROI([20, -50], [60, 40]) - viRoi=TxtROI([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) + #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) + #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) diff --git a/swissmx.py b/swissmx.py index ccc9ca6..301519b 100755 --- a/swissmx.py +++ b/swissmx.py @@ -394,14 +394,29 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): tr=QtGui.QTransform() # prepare ImageItem transformation: opt_ctr=app._geometry._opt_ctr + #--- image group --- + # uses image transformation + # contains image and opticalcenter + self._goImgGrp=grp=pg.ItemGroup() + self.vb.addItem(grp) + trf=cfg.value(AppCfg.GEO_CAM_TRF) + # be aware: setTransform is transposed! + # Qt uses: p'=(p.T*A.T).T , but I am used: p'=A*p, with p=[x,y,1].T + tr.setMatrix(trf[0,0],trf[1,0],trf[2,0], #(-1, 0, 0, + trf[0,1],trf[1,1],trf[2,1], # 0,-1, 0, + trf[0,2],trf[1,2],trf[2,2]) # 0, 0, 1) + grp.setTransform(tr) # assign transform + #--- image --- self._goImg=img=pg.ImageItem() - tr.setMatrix(-1, 0, 0, - 0,-1, 0, - 0, 0, 1) - # opt_ctr[0], opt_ctr[1], 1) - img.setTransform(tr) # assign transform - vb.addItem(img) + grp.addItem(img) + + #--- opctical center ---- + oc_sz=np.array((50,50)) + #self._goOptCtr=obj=UsrGO.Marker(-opt_ctr+oc_sz/2, oc_sz,mode=1) + self._goOptCtr=obj=UsrGO.Marker(opt_ctr-oc_sz/2, oc_sz,mode=1) + obj.sigRegionChangeFinished.connect(self.cb_marker_moved) + grp.addItem(obj) #--- grid --- try: @@ -412,16 +427,10 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): self._goGrid=grid=pg.GridItem() # green grid and labels grid.opts['pen']=QPen(QColor(0, 255, 0)) grid.opts['textPen']=QPen(QColor(0, 255, 0)) - tr.reset() + #tr.reset() #grid.setTransform(tr) # assign transform vb.addItem(grid) - #--- opctical center ---- - oc_sz=np.array((50,50)) - self._goOptCtr=obj=UsrGO.Marker(-opt_ctr-oc_sz/2, oc_sz,mode=1) - obj.sigRegionChangeFinished.connect(self.cb_marker_moved) - #obj.setTransform(tr) # assign transform - vb.addItem(obj) #--- beam marker --- bm_sz=np.array((50, 40)) # it is immidiatly repositioned in cb_zoom_changed @@ -658,9 +667,9 @@ class WndSwissMx(QMainWindow, Ui_MainWindow): cam=app._camera cfg=app._cfg param=cam.get_param() - try: - paramSv=cfg.value(AppCfg.GEO_CAM_PARAM) - except AttributeError as e: + + paramSv=cfg.value(AppCfg.GEO_CAM_PARAM) + if paramSv is None: cfg.setValue(AppCfg.GEO_CAM_PARAM, param) else: for k,v in param.items():