transform image

This commit is contained in:
2018-12-12 17:24:16 +01:00
parent 69b31e4474
commit 36c8d3b373
2 changed files with 208 additions and 33 deletions

View File

@@ -30,6 +30,26 @@ import pylab as plt #used for the colormaps
#The source of the DraggableColorbar is from: #The source of the DraggableColorbar is from:
#http://www.ster.kuleuven.be/~pieterd/python/html/plotting/interactive_colorbar.html #http://www.ster.kuleuven.be/~pieterd/python/html/plotting/interactive_colorbar.html
class MouseData: #data structure for mouse events on image
usageStr='unknown mode. available m:move t: transform'
def __init__(self):
self.mode=None
def addTrfPt(self,p1):
try:
p0=self.btnPress
del self.btnPress
except AttributeError: return
try:
trf=self.trfPts
except AttributeError:
trf=self.trfPts=[]
p=p0+p1
print('add trf: {}'.format(p))
trf.append(p)
class MPLCanvasImg(FigureCanvas): class MPLCanvasImg(FigureCanvas):
def __init__(self,parent,SetStatusCB=None): def __init__(self,parent,SetStatusCB=None):
if SetStatusCB: if SetStatusCB:
@@ -44,12 +64,12 @@ class MPLCanvasImg(FigureCanvas):
self.mpl_connect('scroll_event', self.OnBtnScroll) self.mpl_connect('scroll_event', self.OnBtnScroll)
self.mpl_connect('key_press_event',self.OnKeyPress) self.mpl_connect('key_press_event',self.OnKeyPress)
#self.mpl_connect('pick_event',self.OnPick) #works but locks the screed if debugging #self.mpl_connect('pick_event',self.OnPick) #works but locks the screed if debugging
self.fig=fig
self.ax=ax self.ax=ax
self.mouseData=MouseData()
def InitChild(self,doc): def InitChild(self,doc):
fig=self.fig fig=self.figure
ax=self.ax ax=self.ax
pts=doc.fh['pts'] pts=doc.fh['pts']
rec=doc.fh['rec'] rec=doc.fh['rec']
@@ -80,6 +100,33 @@ class MPLCanvasImg(FigureCanvas):
hl+=ax.plot(rec[idxTrigger,1],rec[idxTrigger,0],'rx',label='trig',markeredgewidth=1.,markersize=6.) hl+=ax.plot(rec[idxTrigger,1],rec[idxTrigger,0],'rx',label='trig',markeredgewidth=1.,markersize=6.)
#hl+=ax.plot(recPts[:,1],recPts[:,0],'g.',label='recDot') #hl+=ax.plot(recPts[:,1],recPts[:,0],'g.',label='recDot')
fn=doc.fh.fid.name[:-4]+'.jpg'
try:
img=mpl.image.imread(fn)
try:
self.imgTrf=trf=doc.fh['imgTrf']
except KeyError:
mn=pts.min(0)
mx=pts.max(0)
ext=(mn[0], mx[0], mn[1], mx[1])
skew=None
else:
xmin=trf[0, 2]
ymin=trf[1, 2]
xmax=trf[0, :].sum()
ymax=trf[1, :].sum()
xskew=trf[0, 2]+trf[0, 0]
yskew=trf[1, 2]+trf[1, 0]
ext=(xmin, xmax, ymin, ymax)
skew=(xskew, yskew)
#interpolation must be none to allow skew image
himg=ax.imshow(img,extent=ext,interpolation='none')
himg._image_skew_coordinate=skew
pass
except IOError as e:
print(e)
ax.xaxis.set_label_text('x-pos um') ax.xaxis.set_label_text('x-pos um')
ax.yaxis.set_label_text('y-pos um') ax.yaxis.set_label_text('y-pos um')
ax.axis('equal') ax.axis('equal')
@@ -99,8 +146,26 @@ class MPLCanvasImg(FigureCanvas):
def OnMotion(self,event): def OnMotion(self,event):
#print event,event.x,event.y,event.inaxes,event.xdata,event.ydata #print event,event.x,event.y,event.inaxes,event.xdata,event.ydata
if event.inaxes==self.ax: if event.inaxes==self.ax:
md=self.mouseData
if md.mode==2 and event.button==1 and self.toolbar.mode=='': # move
try:
himg=self.ax.get_images()[0]
except IndexError:
print('no image to transform')
return
trf=self.imgTrf
xOfs=event.xdata-md.btnPress[0]
yOfs=event.ydata-md.btnPress[1]
xmin=trf[0, 2]+xOfs
ymin=trf[1, 2]+yOfs
xmax=trf[0, :].sum()+xOfs
ymax=trf[1, :].sum()+yOfs
xskew=trf[0, 2]+trf[0, 0]+xOfs
yskew=trf[1, 2]+trf[1, 0]+yOfs
himg.set_extent((xmin, xmax, ymin, ymax))
himg._image_skew_coordinate=(xskew, yskew)
self.figure.canvas.draw()
x=int(round(event.xdata)) x=int(round(event.xdata))
y=int(round(event.ydata)) y=int(round(event.ydata))
@@ -108,8 +173,8 @@ class MPLCanvasImg(FigureCanvas):
for h in self.ax.get_lines(): # to get also the ellipses: self.ax.get_children() for h in self.ax.get_lines(): # to get also the ellipses: self.ax.get_children()
c=h.contains(event) c=h.contains(event)
if c[0]: if c[0]:
#s = str(h)+str(c[1]) s = str(h)+str(c[1])
#print "over %s" % s #print("over %s" % s)
if type(h)==mpl.lines.Line2D: if type(h)==mpl.lines.Line2D:
lbl=h.get_label() lbl=h.get_label()
arr=h.get_data() arr=h.get_data()
@@ -117,9 +182,7 @@ class MPLCanvasImg(FigureCanvas):
s += '%s[%d] = [%.2f, %.2f]'%(lbl,idx,arr[0][idx],arr[1][idx]) s += '%s[%d] = [%.2f, %.2f]'%(lbl,idx,arr[0][idx],arr[1][idx])
else: else:
s += str(h)+str(c[1]) s += str(h)+str(c[1])
self.SetStatusCB(self.Parent, 0, (x, y, s)) self.SetStatusCB(self.Parent, 0, (x, y, s))
#try: #try:
# #v=self.img.get_array()[y,x] # #v=self.img.get_array()[y,x]
# v=0; # v=0;
@@ -142,14 +205,32 @@ class MPLCanvasImg(FigureCanvas):
def OnBtnPress(self, event): def OnBtnPress(self, event):
"""on button press we will see if the mouse is over us and store some data""" """on button press we will see if the mouse is over us and store some data"""
#print(dir(event.guiEvent)) if self.toolbar.mode!='':
return print(self.toolbar.mode)
if event.inaxes == self.colBar.ax: return
if event.inaxes==self.ax:
md=self.mouseData
md.mode
if md.mode==1:#transform
if event.guiEvent.RightDown()==True:
self.doTransform()
if event.guiEvent.LeftDown()==True:
p=(event.xdata,event.ydata)
md.btnPress=p
elif md.mode==2:#move
if event.guiEvent.LeftDown()==True:
p=(event.xdata,event.ydata)
md.btnPress=p
else:
print(md.usageStr)
#print('self.btnPress1', p)
#if event.inaxes == self.colBar.ax:
#if event.guiEvent.LeftDClick()==True: #if event.guiEvent.LeftDClick()==True:
# print dlg # print dlg
pt=self.colBar.ax.bbox.get_points()[:,1] #pt=self.colBar.ax.bbox.get_points()[:,1]
nrm=self.colBar.norm #nrm=self.colBar.norm
self.colBarPressed = (nrm.vmin,nrm.vmax,pt[0],pt[1],event.y) #self.colBarPressed = (nrm.vmin,nrm.vmax,pt[0],pt[1],event.y)
#self.colBarPressed = event.x, event.y #self.colBarPressed = event.x, event.y
#print self.colBarPressed #print self.colBarPressed
#self.OnMouse(event) #self.OnMouse(event)
@@ -157,10 +238,19 @@ class MPLCanvasImg(FigureCanvas):
def OnBtnRelease(self, event): def OnBtnRelease(self, event):
"""on release we reset the press data""" """on release we reset the press data"""
#self.OnMouse(event) print('OnBtnRelease')
md=self.mouseData
if md.mode==1: #transform
p1=(event.xdata, event.ydata)
md.addTrfPt(p1)
elif md.mode==2:#move
trf=self.imgTrf
xOfs=event.xdata-md.btnPress[0]
yOfs=event.ydata-md.btnPress[1]
#trf[0,2]+=xOfs
#trf[1,2]+=yOfs
#trf[1,2]+=yOfs
return return
try: del self.colBarPressed
except AttributeError: pass
def OnBtnScroll(self, event): def OnBtnScroll(self, event):
return return
@@ -183,20 +273,27 @@ class MPLCanvasImg(FigureCanvas):
colBar.patch.figure.canvas.draw() colBar.patch.figure.canvas.draw()
def OnKeyPress(self, event): def OnKeyPress(self, event):
#self.trfPts=[(-1831.2063808574276, 1349.6011964107677, -1966.6001994017945, 1433.3499501495512), (-1830.4810087443084, 917.64916303133487, -1958.3629895701151, 870.93212944552363), (-1561.5041487047886, 917.17727380319548, -1445.8912878106089, 873.29157558622114)]
#self.trfPts=[(-1960., 872., -1960., 872.), (-1450., 872, -1450., 872), (-1960., 1432.,-1960., 1432.)]
#self.trfPts=[(-1960., 872., -1760., 872.), (-1450., 872, -1250., 872), (-1960., 1432.,-1760., 1432.)]
#self.doTransform()
md=self.mouseData
if event.key=='t':
md.mode=1;print('transform image mode (drag drop to add point, right mopuse to execute)')
elif event.key=='x':
self.doTransform()
elif event.key=='m':
md.mode=2;print('move image mode')
elif event.key=='s':
self.saveTransform()
else:
try:
print('unknown mode. available m:move t: transform')
md.mode=None
except AttributeError:
pass
return return
colCycle=self.colCycle
colBar=self.colBar
if event.key=='down':
self.colIndex += 1
elif event.key=='up':
self.colIndex -= 1
self.colIndex%=len(colCycle)
cmap = colCycle[self.colIndex]
colBar.set_cmap(cmap)
colBar.draw_all()
self.img.set_cmap(cmap)
self.img.get_axes().set_title(cmap)
colBar.patch.figure.canvas.draw()
def OnMouse(self, event): def OnMouse(self, event):
return return
@@ -204,6 +301,84 @@ class MPLCanvasImg(FigureCanvas):
if k[0]!='_': if k[0]!='_':
print(k,getattr(event,k)) print(k,getattr(event,k))
def doTransform(self):
#print('doTransform')
try:
trfPts=self.mouseData.trfPts
del self.mouseData.trfPts
except AttributeError:
print('no transformation points')
return
print(trfPts)
trfPts=np.array(trfPts)
try:
himg=self.ax.get_images()[0]
except IndexError:
print('no image to transform')
return
xmin,xmax,ymin,ymax=himg.get_extent()
#himg.set_extent((xmin,xmax+10,ymin,ymax))
skew=himg._image_skew_coordinate
if skew is None:
xskew=xmax
yskew=ymin
else:
(xskew, yskew)=skew
trf0=np.array([[xskew-xmin,xmax-xskew,xmin],
[yskew-ymin,ymax-yskew,ymin],
[0,0,1]])
#calculate least square transformation matrix of the transformation points
n=trfPts.shape[0]
if n<3:
print('tot enough points (needs at least 3)')
return
M=np.mat(trf0).I
trfPtsImgI=M*np.vstack((trfPts[:,(0,1)].T,np.ones((1,n))))
trfPtsImgO=M*np.vstack((trfPts[:,(02,3)].T,np.ones((1,n))))
trfPtsImg=np.hstack((trfPtsImgI[0:2,:].T,trfPtsImgO[0:2,:].T))
A=np.zeros((n*2, 6))
A[0:n, (0, 1)]=trfPtsImg[:,(0,1)]
A[0:n, 2]=1
A[n:n*2, (3, 4)]=trfPtsImg[:,(0,1)]
A[n:n*2, 5]=1
A=np.mat(A)
B=trfPtsImg[:,(2,3)].T.reshape(-1, 1)
# (A'*A)^-1*A'*B
r=(A.T*A).I*A.T*B
trf1=np.hstack((r.T, [[0, 0, 1]])).reshape(3, -1)
trf=np.mat(trf0)*trf1
xmin=trf[0, 2]
ymin=trf[1, 2]
xmax=trf[0, :].sum()
ymax=trf[1, :].sum()
xskew=trf[0, 2]+trf[0, 0]
yskew=trf[1, 2]+trf[1, 0]
self.imgTrf=trf
print(trf)
himg.set_extent((xmin,xmax,ymin,ymax))
himg._image_skew_coordinate=(xskew, yskew)
self.figure.canvas.draw()
def saveTransform(self):
fhr=self.Parent.doc.fh
fn_npz=fhr.fid.name
fn_npzOrig=fn_npz+'.orig'
d=dict(fhr.items())
fhr.close()
if not os.path.exists(fn_npzOrig):
os.rename(fn_npz, fn_npzOrig)
d['imgTrf']=self.imgTrf
np.savez_compressed(fn_npz,**d)
self.Parent.doc.fh=np.load(fn_npz)
class MAxyPlotFrame(wx.Frame): class MAxyPlotFrame(wx.Frame):
def __del__(self): def __del__(self):
self.doc.view.remove(self) self.doc.view.remove(self)

View File

@@ -374,10 +374,10 @@ if __name__ == '__main__':
f1 = MAxyPlotFrame(frame, doc) f1 = MAxyPlotFrame(frame, doc)
f1.Show(True) f1.Show(True)
f2= MAErrorFrame(frame, doc) #f2= MAErrorFrame(frame, doc)
f2.Show(True) #f2.Show(True)
f3= MAVelocityFrame(frame, doc) #f3= MAVelocityFrame(frame, doc)
f3.Show(True) #f3.Show(True)
self.SetTopWindow(frame) self.SetTopWindow(frame)
return True return True