massive move and cleanup
This commit is contained in:
512
python/imgAnalysis/findxtal.py
Executable file
512
python/imgAnalysis/findxtal.py
Executable file
@@ -0,0 +1,512 @@
|
||||
#!/usr/bin/env python
|
||||
#*-----------------------------------------------------------------------*
|
||||
#| |
|
||||
#| Copyright (c) 2018 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||
#| |
|
||||
#| Author Thierry Zamofing (thierry.zamofing@psi.ch) |
|
||||
#*-----------------------------------------------------------------------*
|
||||
'''
|
||||
implements an image alalyser for ESB MX
|
||||
'''
|
||||
import os
|
||||
from scipy import fftpack, ndimage
|
||||
import scipy.ndimage as ndi
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib as mpl
|
||||
import numpy as np
|
||||
import imgStack
|
||||
|
||||
def findGrid(image,numPeak=2,minFrq=2,maxFrq=None,debug=0):
|
||||
d2r=np.pi/180.
|
||||
s=image.shape
|
||||
w1=np.hamming(s[0]).reshape((-1,1))
|
||||
w2=np.hamming(s[1]).reshape((1,-1))
|
||||
wnd=w1*w2
|
||||
#plt.figure(num='hamming window')
|
||||
#plt.imshow(wnd, interpolation="nearest")
|
||||
image=wnd*image
|
||||
if debug&1:
|
||||
plt.figure(num='hamming window*img')
|
||||
plt.imshow(image, interpolation="nearest")
|
||||
|
||||
fft2 = np.fft.fft2(image)
|
||||
fft2=np.fft.fftshift(fft2)
|
||||
fa =abs(fft2)
|
||||
if debug&1:
|
||||
plt.figure(num='log of fft: hamming wnd*image')
|
||||
hi=plt.imshow(fa, interpolation="nearest",norm=mpl.colors.LogNorm(vmin=.1, vmax=fa.max()))
|
||||
#plt.xlim(s[1]/2-50, s[1]/2+50);plt.ylim(s[0]/2-50, s[0]/2+50)
|
||||
|
||||
ctr=np.array(image.shape,dtype=np.int16)/2
|
||||
fa[ctr[0]-minFrq+1:ctr[0]+minFrq, ctr[1]-minFrq+1:ctr[1]+minFrq]=0 # set dc to 0
|
||||
# limit to maximal frequency
|
||||
if maxFrq is not None:
|
||||
fa[:ctr[0]-maxFrq,:]=0;fa[ctr[0]+maxFrq:,:]=0
|
||||
fa[:,:ctr[1]-maxFrq]=0;fa[:,ctr[1]+maxFrq:]=0
|
||||
x=np.arange(s[1])/float(s[1])*2.*np.pi
|
||||
y=np.arange(s[0])/float(s[0])*2.*np.pi
|
||||
if debug&1:
|
||||
hi.set_data(fa)
|
||||
gen = np.zeros(fft2.shape)
|
||||
#x=np.linspace(0,2*np.pi,s[1],endpoint=False)
|
||||
#y=np.linspace(0,2*np.pi,s[0],endpoint=False)
|
||||
xx, yy = np.meshgrid(x, y)
|
||||
|
||||
my=int(s[0]/2)
|
||||
mx=int(s[1]/2)
|
||||
|
||||
res=[] #list of tuples (freq_x,freq_y, phase)
|
||||
for i in range(numPeak):
|
||||
maxAmpIdx=fa.argmax()
|
||||
maxAmpPos=np.array(divmod(maxAmpIdx,fa.shape[1]),dtype=np.int16)
|
||||
peakPos=maxAmpPos-ctr
|
||||
peak=fft2[maxAmpPos[0] - 1:maxAmpPos[0] + 2, maxAmpPos[1] - 1:maxAmpPos[1] + 2]
|
||||
if debug&2:
|
||||
print(peakPos)
|
||||
print(abs(peak))
|
||||
(vn, v0, vp)=np.log(fa[maxAmpPos[0], maxAmpPos[1] - 1:maxAmpPos[1] + 2]) #using log for interpolation is more precise
|
||||
freq_x=peakPos[1]+(vn-vp)/(2.*(vp+vn-2*v0))
|
||||
(vn, v0, vp)=np.log(fa[maxAmpPos[0]-1:maxAmpPos[0]+2,maxAmpPos[1]])
|
||||
freq_y=peakPos[0]+(vn-vp)/(2.*(vp+vn-2*v0))
|
||||
#calculate phase
|
||||
sumCos=0.
|
||||
sumSin=0.
|
||||
sumAmp=0.
|
||||
n=np.prod(s)
|
||||
for iy in (-1,0,1):#(0,):
|
||||
for ix in (-1,0,1):
|
||||
v=peak[iy+1,ix+1]
|
||||
fx=peakPos[1]+ix
|
||||
fy=peakPos[0]+iy
|
||||
amp=np.abs(v)/n; ang=np.angle(v)
|
||||
sumAmp+=amp
|
||||
sumCos+=amp*np.cos(fx*x[mx+ix] + fy*y[my+iy] + ang)
|
||||
sumSin+=amp*np.sin(fx*x[mx+ix] + fy*y[my+iy] + ang)
|
||||
if debug&1:
|
||||
gen+=amp*np.cos(fx*xx + fy*yy + ang)
|
||||
sumAmp*=2. #double because of conjugate part
|
||||
sumCos*=2.
|
||||
sumSin*=2.
|
||||
#sumAmp=np.abs(peak).sum()/n*2 #double because of conjugate part
|
||||
w=np.arccos(sumCos/sumAmp)
|
||||
if sumSin<0: w=-w
|
||||
phi_= freq_x*x[mx]+freq_y*y[my]-w
|
||||
phi_%=(np.pi*2)
|
||||
#have main frequency positive and phase positive (for convinient)
|
||||
if (freq_x<0 and abs(freq_x)> abs(freq_y)) or \
|
||||
(freq_y<0 and abs(freq_y)> abs(freq_x)):
|
||||
freq_x = -freq_x; freq_y = -freq_y; phi_=-phi_
|
||||
if phi_<0: phi_+=2*np.pi
|
||||
|
||||
res.append((freq_x,freq_y,phi_))
|
||||
fa[maxAmpPos[0]-1:maxAmpPos[0]+2,maxAmpPos[1]-1:maxAmpPos[1]+2]=0 # clear peak
|
||||
maxAmpPos_=2*ctr-maxAmpPos
|
||||
fa[maxAmpPos_[0]-1:maxAmpPos_[0]+2,maxAmpPos_[1]-1:maxAmpPos_[1]+2]=0 # clear conjugated peak
|
||||
if debug&1:
|
||||
hi.set_data(fa)
|
||||
|
||||
if debug&1:
|
||||
gen*=2. # double because of conjugate part
|
||||
if debug&2:
|
||||
for fx,fy,phase in res:
|
||||
print('fx: %g fy: %g phase: %g deg'%(fx,fy,phase/d2r))
|
||||
|
||||
if debug&1:
|
||||
plt.xlim(s[1]/2-50, s[1]/2+50)
|
||||
plt.ylim(s[0]/2-50, s[0]/2+50)
|
||||
plt.figure('image*wnd')
|
||||
plt.imshow(image,interpolation="nearest")
|
||||
plt.figure('reconstruct')
|
||||
plt.imshow(gen,interpolation="nearest")
|
||||
|
||||
plt.figure()
|
||||
x=range(s[1])
|
||||
y=int(s[0]/2)-1
|
||||
plt.plot(x,image[y,:],'r')
|
||||
plt.plot(x,gen[y,:],'g')
|
||||
return res
|
||||
|
||||
def plotGrid(grid,shape):
|
||||
#x=np.linspace(0,2*np.pi,shape[1],endpoint=False)
|
||||
#y=np.linspace(0,2*np.pi,shape[0],endpoint=False)
|
||||
#for (freq_x, freq_y, phase) in grid:
|
||||
#find points were: np.cos(freq_x*xx + freq_y*yy - phase) is max
|
||||
#freq_x*xx + freq_y*yy - phase = 0 2pi, 4pi
|
||||
# grid should have 2 entries
|
||||
# -> 2 equations to solve
|
||||
# points for:
|
||||
# entry1 entry2 = (0 0), (0, 2*pi), (2*pi 0)
|
||||
(fx0,fy0,p0)=grid[0]
|
||||
(fx1,fy1,p1)=grid[1]
|
||||
A=np.array([[fx0,fy0],[fx1,fy1]])
|
||||
A*=np.array([2*np.pi/shape[1],2*np.pi/shape[0]])
|
||||
Ai=np.asmatrix(A).I
|
||||
|
||||
|
||||
na=int(max(abs(fx0),abs(fy0)))+1
|
||||
nb=int(max(abs(fx1),abs(fy1)))+1
|
||||
p=np.ndarray((na*nb,2))
|
||||
#p=np.ndarray((3,2))
|
||||
#i=0
|
||||
#for x,y in ((0,0),(1,0),(0,1)):
|
||||
# v = np.array([p0+x*2.*np.pi, p1+y*2.*np.pi]).reshape(-1, 1)
|
||||
# p[i,:]=(Ai*v).reshape(-1)
|
||||
# i+=1
|
||||
|
||||
i=0
|
||||
for b in range(nb):
|
||||
for a in range(na):
|
||||
v = np.array([p0+a*2.*np.pi, p1+b*2.*np.pi]).reshape(-1, 1)
|
||||
p[i,:]=(Ai*v).reshape(-1)
|
||||
i+=1
|
||||
|
||||
|
||||
|
||||
|
||||
#plt.plot([400,500],[400,500],'r+',markeredgewidth=2, markersize=10)
|
||||
plt.plot(p[:,0],p[:,1],'r+',markeredgewidth=2, markersize=10)
|
||||
plt.axis('image')
|
||||
pass
|
||||
|
||||
def ShowImage(img,title=None,cmap='gray',vmin=None, vmax=None):
|
||||
plt.figure(title)
|
||||
plt.imshow(img, interpolation="nearest", cmap=cmap,vmin=vmin,vmax=vmax) # ,vmin=m-3*s, vmax=m+3*s)
|
||||
plt.colorbar()
|
||||
|
||||
def imgEqualize(img,num_bins=256):
|
||||
# get image histogram
|
||||
hist, bins = np.histogram(img.flatten(), num_bins, normed=True)
|
||||
cdf = hist.cumsum() # cumulative distribution function
|
||||
cdf = 255 * cdf / cdf[-1] # normalize
|
||||
|
||||
# use linear interpolation of cdf to find new pixel values
|
||||
imgEqu=np.interp(img.flatten(), bins[:-1], cdf)
|
||||
imgEqu=np.uint8(imgEqu.reshape(img.shape))
|
||||
|
||||
plt.figure();plt.plot(hist)
|
||||
h2,b2=np.histogram(imgEqu.flatten(), num_bins, normed=True)
|
||||
plt.figure();plt.plot(h2)
|
||||
return imgEqu.reshape(img.shape)#, cdf
|
||||
|
||||
|
||||
def findObj(image,objSize=150,tol=0,debug=0):
|
||||
|
||||
#objSiz is the rough diameter of the searched features in pixels
|
||||
#tol = tolerance in object size (not yet implemented)
|
||||
#tolShape = roudness tolerance in object roundness (not yet implemented)
|
||||
|
||||
from scipy.signal import convolve2d
|
||||
plt.ion()
|
||||
image=image[500:2500,1000:2500]
|
||||
s=image.shape
|
||||
f=np.array([0.9595264, 0.9600567, 0.9608751, 0.9620137, 0.9634765, 0.9652363, 0.9672352, 0.9693891, 0.9715959, 0.9737464, 0.9757344, 0.9774676, 0.9788761, 0.9799176, 0.9805792, 0.9808776, 0.9808528, 0.9805624, 0.9800734, 0.9794550])
|
||||
f=f*1000
|
||||
f=f-f.mean()
|
||||
|
||||
m=image.mean();s=image.std()
|
||||
ShowImage(image,vmin=-.85,vmax=-.99)
|
||||
ShowImage(image,vmin=m-3*s,vmax=m+3*s)
|
||||
ieq=imgEqualize(image)
|
||||
ShowImage(ieq)
|
||||
m=image.mean();s=image.std()
|
||||
i2=(image-m)*(256./(3*s))+128.
|
||||
i2[i2>255.]=255.
|
||||
i2[i2<0.]=0.
|
||||
i2=np.uint8(i2)
|
||||
ShowImage(i2)
|
||||
image=ndi.filters.gaussian_filter1d(image,sigma=5./3,truncate=3.,axis=0)
|
||||
image=ndi.filters.gaussian_filter1d(image,sigma=5./3,truncate=3.,axis=1)
|
||||
ShowImage(image,vmin=-.85,vmax=-.99)
|
||||
|
||||
img2=ndi.filters.convolve1d(image,f,0)
|
||||
ShowImage(img2,vmin=-3,vmax=3)
|
||||
|
||||
img3=ndi.filters.convolve1d(image,f,1)
|
||||
ShowImage(img3,vmin=-3,vmax=3)
|
||||
img4=np.maximum(abs(img2),abs(img3))
|
||||
ShowImage(img4,vmin=0,vmax=3)
|
||||
|
||||
m=image.mean();s=image.std()
|
||||
img5=np.zeros(image.shape)
|
||||
w=np.where(img4>1.5)
|
||||
img5[w]=1
|
||||
ShowImage(img5)
|
||||
#imgStack.Run([image, img2,img3,img4,img5])
|
||||
#w=np.where(img2>image*1.01)
|
||||
#img2[:]=0
|
||||
#img2[w]=1
|
||||
l=int(objSize/30);l=5
|
||||
img6=ndi.binary_fill_holes(img5, structure=np.ones((l,l)))
|
||||
|
||||
#img6 = ndi.binary_dilation(img5, iterations=2)
|
||||
#img6 = ndi.binary_erosion(img5, iterations=2)
|
||||
ShowImage(img6)
|
||||
|
||||
l=int(objSize/5)#=int(objSize/10)
|
||||
if l>=3:
|
||||
#img5=ndi.binary_opening(img4, structure=np.ones((l,l)))
|
||||
#img5=ndi.binary_erosion(img4, structure=np.ones((l,l)))
|
||||
img5=ndi.binary_erosion(img4, iterations=l)
|
||||
if debug&4:
|
||||
plt.figure()
|
||||
plt.imshow(img5, interpolation="nearest", cmap='gray')
|
||||
#plt.show()
|
||||
else:
|
||||
img5=img4
|
||||
|
||||
import cv2
|
||||
#cvi1=np.zeros(shape=img5.shape+(3,), dtype=np.uint8)
|
||||
#cvi1[:,:,0]=image
|
||||
#image*np.array([1,1,1]).reshape(-1,1,1)
|
||||
s=image.shape+(1,)
|
||||
cvi1=image.reshape(s)*np.ones((1,1,3),dtype=np.uint8)
|
||||
#cvi1=np.ones((3,1,1),dtype=np.uint8)image
|
||||
contours, hierarchy=cv2.findContours(np.uint8(img5),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
|
||||
#contours,hierarchy=cv2.findContours(np.uint8(img5),1,2)
|
||||
cv2.drawContours(cvi1, contours, -1, (0,255,0), 3)
|
||||
plt.figure()
|
||||
plt.imshow(cvi1 , interpolation="nearest", cmap='gray')
|
||||
m=cv2.moments(contours[0])
|
||||
|
||||
lbl = ndi.label(img5)
|
||||
if debug&2:
|
||||
plt.figure()
|
||||
plt.imshow(lbl[0], interpolation="nearest")
|
||||
#plt.show()
|
||||
ctr=ndi.measurements.center_of_mass(image, lbl[0],range(lbl[1]))
|
||||
ctr=np.array(ctr)
|
||||
ctr2=np.ndarray(shape=(len(contours),2),dtype=np.uint16)
|
||||
i=0
|
||||
for c in contours:
|
||||
m=cv2.moments(c)
|
||||
try:
|
||||
m00=m['m00']
|
||||
m10=m['m10']
|
||||
m01=m['m01']
|
||||
#print m00
|
||||
if m00>1000 and m00<7000:
|
||||
ctr2[i,:]=(m10/m00,m01/m00)
|
||||
i+=1
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
#ctr2[i, :]=c[0,0]
|
||||
|
||||
if debug&1:
|
||||
plt.figure()
|
||||
plt.imshow(image, interpolation="nearest", cmap='gray')
|
||||
plt.plot(ctr[:,1],ctr[:,0],'or',markeredgewidth=2, markersize=10)
|
||||
plt.plot(ctr2[:i,0],ctr2[:i,1],'+y',markeredgewidth=2, markersize=10)
|
||||
plt.show()
|
||||
return ctr
|
||||
|
||||
def genImg(shape,*args):
|
||||
'''args is a list of tuples (freq_x,freq_y, phase) multiple args can be added'''
|
||||
image=np.ndarray(shape)#,dtype=np.uint8)
|
||||
x=np.linspace(0,2*np.pi,shape[1],endpoint=False)
|
||||
y=np.linspace(0,2*np.pi,shape[0],endpoint=False)
|
||||
#xx, yy = np.meshgrid(x, y, sparse=True)
|
||||
xx, yy = np.meshgrid(x, y)
|
||||
dc=0
|
||||
for i,f in enumerate(args):
|
||||
(freq_x, freq_y, phase)=f
|
||||
if i==0:
|
||||
image = dc+np.cos(freq_x*xx + freq_y*yy - phase)
|
||||
else:
|
||||
image += np.cos(freq_x * xx + freq_y * yy - phase)
|
||||
return image
|
||||
|
||||
def phase_retrieval_intensity_tranport(image, mu, delta, I_in, M, pixel_size, R2):
|
||||
'''calculates the projected thickness as in eq. 12 of Paganin et al, 2002, J. Microscopy,
|
||||
from an image, the absoption coefficient mu (um-1), the real part of the deviation of the refractive index
|
||||
from unity delta, the uniform intensity of the incident radiation I_in (ph/s/um2), the magnification of the
|
||||
image from the point source illumination M, the pixel size (um), the propagation distance R2 (um).'''
|
||||
F = np.fft.rfft2(image)
|
||||
k_x = 1/(pixel_size*image.shape[0]) # is there a 2pi factor?
|
||||
k_y = 1/(pixel_size*image.shape[1]) # is there a 2pi factor?
|
||||
#print k_x,k_y
|
||||
k_array = np.zeros((F.shape[0],F.shape[1]))
|
||||
A = np.zeros((F.shape[0],F.shape[1]), dtype=np.complex128)
|
||||
for i_k in range(k_array.shape[0]):
|
||||
for j_k in range(k_array.shape[1]):
|
||||
k_array[i_k,j_k] = np.sqrt((i_k * k_x)**2 + (j_k * k_y)**2)
|
||||
A[i_k,j_k] = mu * F[i_k,j_k] / (I_in * (R2 * delta * k_array[i_k,j_k]**2 / M + mu))
|
||||
Fm1 = np.fft.irfft2(A)
|
||||
T = np.multiply(-1/mu, np.log(Fm1))
|
||||
return T
|
||||
|
||||
if __name__ == '__main__':
|
||||
def testfftLoop():
|
||||
plt.ioff()
|
||||
for phi in np.arange(0.,180.,10.):
|
||||
testfft(phi=phi)
|
||||
plt.show()
|
||||
pass
|
||||
|
||||
def testfft(phi=45.,frq=4.2,amp=1.,n=256.):
|
||||
#find the main frequency and phase in 1-D
|
||||
plt.figure(1)
|
||||
d2r=np.pi/180.
|
||||
x=np.arange(n)
|
||||
phi=phi*d2r
|
||||
y=amp*np.cos(frq*x/n*2.*np.pi-phi)
|
||||
plt.plot(x,y,'y')
|
||||
#y[np.where(y<-.5)]=0
|
||||
#y*=np.hamming(n)
|
||||
w=np.hanning(n)
|
||||
plt.plot(x,w,'y')
|
||||
y*=w
|
||||
#y*=1.-np.cos(x/(n-1.)*2.*np.pi)
|
||||
|
||||
#y=[1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1]
|
||||
plt.stem(x,y)
|
||||
|
||||
fy=np.fft.fft(y)
|
||||
fya=np.abs(fy)
|
||||
plt.figure(2)
|
||||
plt.subplot(211)
|
||||
plt.stem(x,fya)
|
||||
plt.subplot(212)
|
||||
plt.stem(x,np.angle(fy)/d2r)
|
||||
print(np.angle(fy[frq])/d2r)
|
||||
|
||||
fya[0]=0
|
||||
i=(fya.reshape(2,-1)[0,:]).argmax()
|
||||
(vn,v0,vp)=fya[i-1:i+2]
|
||||
frq_=i+(vn-vp)/(2.*(vp+vn-2*v0))
|
||||
print('freq: %g phase %g %g %g'%((frq_,)+tuple(np.angle(fy[i-1:i+2])/d2r)))
|
||||
|
||||
#PHASE CALCULATION
|
||||
plt.figure(1)
|
||||
y=np.zeros(x.shape)
|
||||
z=np.zeros(x.shape)
|
||||
for ii in (i,i-1,i+1):
|
||||
y+=np.abs(fy[ii])/n*np.cos(ii*x/n*2.*np.pi+np.angle(fy[ii]))
|
||||
z+=np.abs(fy[ii])/n*np.sin(ii*x/n*2.*np.pi+np.angle(fy[ii]))
|
||||
y*=2 #double because of conjugate part
|
||||
z*=2 #double because of conjugate part
|
||||
plt.plot(x,y,'r')
|
||||
amp_=fya[i-1:i+2].sum()/n*2.
|
||||
t=int(n/2)-1
|
||||
#->phase: find maximum or where the sin is 0
|
||||
w=np.arccos(y[t]/amp_)
|
||||
if(z[t]<0): w=-w
|
||||
print('amplitude %g, value at middle (%d) cos->%g sin->%g -> acos %g deg'%(amp_,t,y[t],z[t],w/d2r))
|
||||
#rot angle at middle x=127 =frq_*t/n*2.*np.pi-phi_=w '%(amp_,t,y[t],phi_/d2r))
|
||||
phi_=frq_*t/n*2.*np.pi-w
|
||||
y=amp_*np.cos(frq_*x/n*2.*np.pi-phi_)
|
||||
print('y[%d] %g'%(t,y[t]))
|
||||
|
||||
plt.plot(x,y,'g')
|
||||
pass
|
||||
|
||||
def testFindGrid():
|
||||
plt.ioff()
|
||||
imggrid=(
|
||||
('grid_20180409_115332_45deg.png', 2,None),
|
||||
('grid_20180409_115332.png', 2,None),
|
||||
('honeycomb.png', 2,25),
|
||||
('MS01_20180411_110544.png', 10,None),
|
||||
('MS02_20180411_120354.png', 10,None),
|
||||
('MS03_20180411_135524.png', 10,None),
|
||||
('MS04_20180411_143045.png', 10,None),
|
||||
('MS04_20180411_144239.png', 10,None),
|
||||
)
|
||||
for (file,minFrq,maxFrq) in imggrid:
|
||||
image = ndimage.imread(os.path.join(basePath,file))
|
||||
image=-image
|
||||
grid=findGrid(image,minFrq=minFrq,maxFrq=maxFrq,numPeak=2)
|
||||
plt.figure('grid');plt.imshow(image, interpolation="nearest", cmap='gray')
|
||||
plotGrid(grid, image.shape)
|
||||
plt.show()
|
||||
|
||||
def testFindObj():
|
||||
plt.ioff()
|
||||
imggrid=(
|
||||
('grid_20180409_115332_45deg.png', 2,None),
|
||||
)
|
||||
for (file,p0,p1) in imggrid:
|
||||
image = ndimage.imread(os.path.join(basePath,file))
|
||||
image=-image
|
||||
objPos=findObj(image,debug=0)
|
||||
plt.figure('findObj');plt.imshow(image, interpolation="nearest", cmap='gray')
|
||||
plt.plot(objPos[:,1],objPos[:,0],'r+',markeredgewidth=2, markersize=10)
|
||||
plt.axis('image')
|
||||
plt.show()
|
||||
|
||||
def testPhaseEnhance():
|
||||
|
||||
mu=0.001 # um-1, optimal value found is 0.001
|
||||
phase_shift=-0.4 # rad/um, optimal value found is -1
|
||||
E=18 # keV
|
||||
wavelength=12.4/E/10000 # um
|
||||
delta=-wavelength/(2*np.pi)*phase_shift
|
||||
delta=4.38560287631e-06
|
||||
M=1
|
||||
R2=19*1e4 # um
|
||||
pixel_size=0.325 # um
|
||||
flux=1e12 # ph/s
|
||||
for fn in ('lyso1_scan_18keV_190mm_MosaicJ_noblend_crop.tif',
|
||||
'PepT2_scan_18keV_190mm_MosaicJ_noblend_crop_FFT40.tif',
|
||||
'SiN_lysoS1_scan_18keV_190mm_MosaicJ_noblend_crop_FFT40.tif',
|
||||
'SiN_PepT2_scan_18keV_190mm_MosaicJ_noblend_crop.tif',):
|
||||
img = ndimage.imread(os.path.join(basePath,fn))
|
||||
FOV_pix = img.shape
|
||||
FOV_um = (FOV_pix[0] * pixel_size, FOV_pix[1] * pixel_size)
|
||||
I_in = flux / (FOV_um[0] * FOV_um[1]) # ph/s/um2
|
||||
phase_image = phase_retrieval_intensity_tranport(img, mu, delta, I_in, M, pixel_size, R2)
|
||||
phase_image_flipped = phase_retrieval_intensity_tranport(np.fliplr(img), mu, delta, I_in, M, pixel_size, R2)
|
||||
added_image = np.add(phase_image,np.fliplr(phase_image_flipped))
|
||||
|
||||
|
||||
m=img.mean();s=img.std()
|
||||
ShowImage(img, title=fn+' raw', vmin=m-3*s, vmax=m+3*s)
|
||||
m=added_image.mean();s=added_image.std()
|
||||
ShowImage(added_image, title=fn+' phase retrival', vmin=m-3*s, vmax=m+3*s)
|
||||
plt.show()
|
||||
|
||||
basePath='/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/images/'
|
||||
#testfftLoop()
|
||||
#testFindGrid()
|
||||
testFindObj()
|
||||
#testPhaseEnhance()
|
||||
exit(0)
|
||||
|
||||
plt.ion()
|
||||
#image = ndimage.imread(os.path.join(basePath, 'lyso1_scan_18keV_190mm_MosaicJ_noblend_crop.tif'))
|
||||
image = ndimage.imread(os.path.join(basePath, 'lyso1_scan_18keV_190mm_MosaicJ_noblend_crop.tif'))
|
||||
#image = ndimage.imread(os.path.join(basePath, 'grid_20180409_115332.png'))
|
||||
image = -image
|
||||
#plt.figure('input');
|
||||
#plt.imshow(image, interpolation="nearest", cmap='gray')
|
||||
#sbl=ndi.sobel(image)
|
||||
#plt.figure('sobel');
|
||||
#plt.imshow(sbl, interpolation="nearest", cmap='gray')
|
||||
objPos = findObj(image, objSize=50,debug=255)
|
||||
plt.figure('findObj');
|
||||
plt.imshow(image, interpolation="nearest", cmap='gray')
|
||||
plt.plot(objPos[:, 1], objPos[:, 0], 'r+', markeredgewidth=2, markersize=10)
|
||||
plt.axis('image')
|
||||
plt.show()
|
||||
|
||||
#d2r=np.pi/180.
|
||||
#image=genImg((600,800),(4.,1.0,10.*d2r))
|
||||
#image=genImg((600,800),(4.5,-3.2,70.*d2r))
|
||||
#image=genImg((600,800),(-4.5,3.2,290.*d2r)) #same image
|
||||
#findGrid(image,numPeak=1)
|
||||
#findGrid(image,numPeak=1,debug=2)
|
||||
|
||||
#for v in np.arange(0,2,.3):
|
||||
# image=genImg((600,800),(8,.2+v,40.*d2r),(.4,5.2,30.*d2r))
|
||||
# #image = genImg((600, 800), (.4,5.2,30.))
|
||||
# plt.figure(10);plt.cla()
|
||||
# plt.imshow(image)
|
||||
# grid=findGrid(image,numPeak=2,debug=255)
|
||||
# plt.figure(1);plt.cla()
|
||||
# plt.imshow(image, interpolation="nearest", cmap='gray')
|
||||
# plotGrid(grid,image.shape)
|
||||
# plt.show()
|
||||
#image=genImg((600,800),(9.5,.2,0),(.4,5.2,0),(4,8,0))
|
||||
#findObj(image,viz=1)
|
||||
#findObj(image,viz=255)
|
||||
#print(findObj(image))
|
||||
|
||||
551
python/imgAnalysis/imgStack.py
Normal file
551
python/imgAnalysis/imgStack.py
Normal file
@@ -0,0 +1,551 @@
|
||||
#!/usr/bin/env python
|
||||
#*-----------------------------------------------------------------------*
|
||||
#| |
|
||||
#| Copyright (c) 2013 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||
#| |
|
||||
#| Author Thierry Zamofing (thierry.zamofing@psi.ch) |
|
||||
#*-----------------------------------------------------------------------*
|
||||
'''
|
||||
implements an image view to show a colored image of a hdf5 dataset.
|
||||
'''
|
||||
|
||||
if __name__ == '__main__':
|
||||
#Used to guarantee to use at least Wx2.8
|
||||
import wxversion
|
||||
wxversion.ensureMinimal('2.8')
|
||||
import wx
|
||||
import matplotlib as mpl
|
||||
if __name__ == '__main__':
|
||||
mpl.use('WXAgg')
|
||||
#or mpl.use('WX')
|
||||
#matplotlib.get_backend()
|
||||
|
||||
import os
|
||||
import numpy as np
|
||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
|
||||
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
|
||||
import pylab as plt #used for the colormaps
|
||||
|
||||
|
||||
class SliderGroup():
|
||||
def __init__(self, parent, label, range=(0,100),val=0):
|
||||
self.sliderLabel = wx.StaticText(parent, label=label)
|
||||
self.sliderText = wx.TextCtrl(parent, -1, style=wx.TE_PROCESS_ENTER)
|
||||
self.slider = wx.Slider(parent, -1)
|
||||
self.slider.SetRange(range[0],range[1])
|
||||
sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizer.Add(self.sliderLabel, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=2)
|
||||
sizer.Add(self.sliderText, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=2)
|
||||
sizer.Add(self.slider, 1, wx.EXPAND)
|
||||
self.sizer = sizer
|
||||
self.slider.Bind(wx.EVT_SLIDER, self.sliderHandler)
|
||||
self.sliderText.Bind(wx.EVT_TEXT_ENTER, self.sliderTextHandler)
|
||||
self.SetValue(val)
|
||||
|
||||
def SetValue(self, value):
|
||||
self.value = value
|
||||
self.slider.SetValue(value)
|
||||
self.sliderText.SetValue(str(value))
|
||||
|
||||
def SetCallback(self,funcCB,usrData):
|
||||
self.cbFuncData=(funcCB,usrData)
|
||||
|
||||
def Callback(self,value,msg):
|
||||
try:
|
||||
(funcCB,usrData)=self.cbFuncData
|
||||
except BaseException as e:
|
||||
pass
|
||||
else:
|
||||
funcCB(usrData,value,msg)
|
||||
|
||||
def sliderHandler(self, evt):
|
||||
value = evt.GetInt()
|
||||
self.sliderText.SetValue(str(value))
|
||||
self.value=value
|
||||
self.Callback(value,0)
|
||||
|
||||
def sliderTextHandler(self, evt):
|
||||
value = int(self.sliderText.GetValue())
|
||||
self.slider.SetValue(value)
|
||||
value = self.slider.Value
|
||||
self.sliderText.SetValue(str(value))
|
||||
self.value=value
|
||||
self.Callback(value,0)
|
||||
|
||||
|
||||
def AddToolbar(parent,sizer):
|
||||
toolbar = NavigationToolbar(parent)
|
||||
toolbar.Realize()
|
||||
if wx.Platform == '__WXMAC__':
|
||||
# Mac platform (OSX 10.3, MacPython) does not seem to cope with
|
||||
# having a toolbar in a sizer. This work-around gets the buttons
|
||||
# back, but at the expense of having the toolbar at the top
|
||||
parent.SetToolBar(toolbar)
|
||||
else:
|
||||
# On Windows platform, default window size is incorrect, so set
|
||||
# toolbar width to figure width.
|
||||
tw, th = toolbar.GetSizeTuple()
|
||||
fw, fh = parent.GetSizeTuple()
|
||||
# By adding toolbar in sizer, we are able to put it at the bottom
|
||||
# of the frame - so appearance is closer to GTK version.
|
||||
# As noted above, doesn't work for Mac.
|
||||
toolbar.SetSize(wx.Size(fw, th))
|
||||
sizer.Add(toolbar, 0, wx.LEFT | wx.EXPAND)
|
||||
# update the axes menu on the toolbar
|
||||
toolbar.update()
|
||||
return toolbar
|
||||
|
||||
|
||||
#class ShiftedLogNorm(mpl.colors.Normalize):
|
||||
class ShiftedLogNorm(mpl.colors.LogNorm):
|
||||
#copied and modified from LogNorm
|
||||
def __call__(self, value, clip=None):
|
||||
#print value.shape,self.vmin,self.vmax,self.clip,clip
|
||||
if clip is None:
|
||||
clip = self.clip
|
||||
ofs0=1-self.vmin
|
||||
ofs1=1./(np.log(self.vmax+1-self.vmin))
|
||||
result=np.log(value+ofs0)*ofs1
|
||||
result = np.ma.masked_less_equal(result, 0, copy=False)
|
||||
return result
|
||||
def inverse(self, value):
|
||||
if not self.scaled():
|
||||
raise ValueError("Not invertible until scaled")
|
||||
vmin, vmax = self.vmin, self.vmax
|
||||
ofs0=1-vmin
|
||||
if mpl.cbook.iterable(value):
|
||||
val = np.ma.asarray(value)
|
||||
return vmin * np.ma.power((vmax/vmin), val)-ofs0
|
||||
else:
|
||||
return vmin * pow((vmax/vmin), value)-ofs0
|
||||
def autoscale_None(self, A):
|
||||
if self.vmin is None:
|
||||
self.vmin = np.ma.min(A)
|
||||
if self.vmax is None:
|
||||
self.vmax = np.ma.max(A)
|
||||
pass
|
||||
def autoscale(self, A):
|
||||
pass
|
||||
|
||||
class MPLCanvasImg(FigureCanvas):
|
||||
def __init__(self,parent,SetStatusCB=None):
|
||||
if SetStatusCB:
|
||||
self.SetStatusCB=SetStatusCB
|
||||
fig = mpl.figure.Figure()
|
||||
ax = fig.add_axes([0.075,0.1,0.75,0.85])
|
||||
FigureCanvas.__init__(self,parent, -1, fig)
|
||||
self.mpl_connect('motion_notify_event', self.OnMotion)
|
||||
self.mpl_connect('button_press_event', self.OnBtnPress)
|
||||
self.mpl_connect('button_release_event', self.OnBtnRelease)
|
||||
self.mpl_connect('scroll_event', self.OnBtnScroll)
|
||||
self.mpl_connect('key_press_event',self.OnKeyPress)
|
||||
self.fig=fig
|
||||
self.ax=ax
|
||||
|
||||
def InitChild(self,data):
|
||||
if data.dtype==np.complex128:
|
||||
self.dataRaw=data
|
||||
#data=np.angle(data)
|
||||
data=np.absolute(data)
|
||||
|
||||
fig=self.fig
|
||||
ax=self.ax
|
||||
|
||||
msk=~np.isnan(data);msk=data[msk]
|
||||
avg=np.average(msk); std=np.std(msk)
|
||||
vmin=np.min(msk);vmax=np.max(msk)
|
||||
vmin=max(vmin,avg-3*std);vmax=min(vmax,avg+3*std)
|
||||
if vmin==0:vmin=1
|
||||
if vmax<=vmin:
|
||||
vmax=vmin+1
|
||||
|
||||
#norm=ShiftedLogNorm()
|
||||
norm=mpl.colors.Normalize()
|
||||
#img = ax.imshow(data,interpolation='nearest',cmap=mpl.cm.jet, norm=ShiftedLogNorm(vmin=vmin, vmax=vmax))
|
||||
|
||||
img = ax.imshow(data,interpolation='nearest',cmap=mpl.cm.jet, vmin=vmin, vmax=vmax)
|
||||
colBar=fig.colorbar(img,orientation='vertical',norm=norm)
|
||||
#colBar.norm=ShiftedLogNorm(vmin=vmin, vmax=vmax)
|
||||
colBar.norm=mpl.colors.Normalize(vmin=vmin, vmax=vmax)
|
||||
img.set_norm(colBar.norm)
|
||||
img.cmap._init();bg=img.cmap._lut[0].copy();bg[:-1]/=4
|
||||
ax.set_axis_bgcolor(bg)
|
||||
|
||||
|
||||
self.colBar=colBar
|
||||
self.colCycle = sorted([i for i in dir(plt.cm) if hasattr(getattr(plt.cm,i),'N')])
|
||||
self.colIndex = self.colCycle.index(colBar.get_cmap().name)
|
||||
self.img=img
|
||||
|
||||
def OnMotion(self,event):
|
||||
#print event,event.x,event.y,event.inaxes,event.xdata,event.ydata
|
||||
if event.inaxes==self.ax:
|
||||
x=int(round(event.xdata))
|
||||
y=int(round(event.ydata))
|
||||
try:
|
||||
v=self.img.get_array()[y,x]
|
||||
except IndexError as e:
|
||||
pass
|
||||
else:
|
||||
#print x,y,v
|
||||
self.SetStatusCB(self.Parent,0,(x,y,v))
|
||||
elif event.inaxes==self.colBar.ax:
|
||||
colBar=self.colBar
|
||||
pt=colBar.ax.bbox.get_points()[:,1]
|
||||
nrm=colBar.norm
|
||||
vmin,vmax,p0,p1,pS = (nrm.vmin,nrm.vmax,pt[0],pt[1],event.y)
|
||||
if isinstance(colBar.norm,mpl.colors.LogNorm):#type(colBar.norm)==mpl.colors.LogNorm does not work...
|
||||
vS=0
|
||||
else:#scale around point
|
||||
vS=vmin+(vmax-vmin)/(p1-p0)*(pS-p0)
|
||||
self.SetStatusCB(self.Parent,1,vS)
|
||||
try:
|
||||
vmin,vmax,p0,p1,pS=self.colBarPressed
|
||||
except AttributeError:
|
||||
return
|
||||
#if event.inaxes != self.cbar.ax: return
|
||||
colBar=self.colBar
|
||||
#print vmin,vmax,p0,p1,pS,type(colBar.norm)
|
||||
#print 'x0=%f, xpress=%f, event.xdata=%f, dx=%f, x0+dx=%f'%(x0, xpress, event.xdata, dx, x0+dx)
|
||||
|
||||
if isinstance(colBar.norm,mpl.colors.LogNorm):#type(colBar.norm)==mpl.colors.LogNorm does not work...
|
||||
if event.button==1:
|
||||
#colBar.norm.vmin=.1
|
||||
colBar.norm.vmax=vmax*np.exp((pS-event.y)/100)
|
||||
#scale= np.exp((event.y-pS)/100)
|
||||
elif event.button==1:#move top,bottom,both
|
||||
pD = event.y - pS
|
||||
vD=(vmax-vmin)/(p1-p0)*(pS-event.y)
|
||||
colBar.norm.vmin = vmin+vD
|
||||
colBar.norm.vmax = vmax+vD
|
||||
elif event.button==3:#scale around point
|
||||
scale= np.exp((pS-event.y)/100)
|
||||
vS=vmin+(vmax-vmin)/(p1-p0)*(pS-p0)
|
||||
#print scale,vS
|
||||
colBar.norm.vmin = vS-scale*(vS-vmin)
|
||||
colBar.norm.vmax = vS-scale*(vS-vmax)
|
||||
self.img.set_norm(colBar.norm)#force image to redraw
|
||||
colBar.patch.figure.canvas.draw()
|
||||
|
||||
def OnBtnPress(self, event):
|
||||
"""on button press we will see if the mouse is over us and store some data"""
|
||||
#print dir(event.guiEvent)
|
||||
if event.inaxes == self.colBar.ax:
|
||||
#if event.guiEvent.LeftDClick()==True:
|
||||
# print dlg
|
||||
pt=self.colBar.ax.bbox.get_points()[:,1]
|
||||
nrm=self.colBar.norm
|
||||
self.colBarPressed = (nrm.vmin,nrm.vmax,pt[0],pt[1],event.y)
|
||||
#self.colBarPressed = event.x, event.y
|
||||
#print self.colBarPressed
|
||||
#self.OnMouse(event)
|
||||
pass
|
||||
|
||||
def OnBtnRelease(self, event):
|
||||
"""on release we reset the press data"""
|
||||
#self.OnMouse(event)
|
||||
try: del self.colBarPressed
|
||||
except AttributeError: pass
|
||||
|
||||
def OnBtnScroll(self, event):
|
||||
#self.OnMouse(event)
|
||||
colBar=self.colBar
|
||||
if event.inaxes==colBar.ax:
|
||||
pt=colBar.ax.bbox.get_points()[:,1]
|
||||
nrm=colBar.norm
|
||||
vmin,vmax,p0,p1,pS = (nrm.vmin,nrm.vmax,pt[0],pt[1],event.y)
|
||||
if isinstance(colBar.norm,mpl.colors.LogNorm):#type(colBar.norm)==mpl.colors.LogNorm does not work...
|
||||
scale= np.exp((-event.step)/10)
|
||||
colBar.norm.vmax=vmax*scale
|
||||
else:#scale around point
|
||||
scale= np.exp((-event.step)/10)
|
||||
vS=vmin+(vmax-vmin)/(p1-p0)*(pS-p0)
|
||||
#print scale,vS
|
||||
colBar.norm.vmin = vS-scale*(vS-vmin)
|
||||
colBar.norm.vmax = vS-scale*(vS-vmax)
|
||||
self.img.set_norm(colBar.norm)#force image to redraw
|
||||
colBar.patch.figure.canvas.draw()
|
||||
|
||||
def OnKeyPress(self, event):
|
||||
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):
|
||||
for k in dir(event):
|
||||
if k[0]!='_':
|
||||
print k,getattr(event,k)
|
||||
|
||||
|
||||
class DlgColBarSetup(wx.Dialog):
|
||||
def __init__(self,parent):
|
||||
wx.Dialog.__init__(self,parent,-1,'Colormap Setup')
|
||||
colBar=parent.canvas.colBar
|
||||
cmap=colBar.cmap
|
||||
nrm=colBar.norm
|
||||
|
||||
txtVMin=wx.StaticText(self,-1,'vmin')
|
||||
txtVMax=wx.StaticText(self,-1,'vmax')
|
||||
txtColMap=wx.StaticText(self,-1,'colormap')
|
||||
self.edVMin=edVMin=wx.TextCtrl(self,-1,'%g'%nrm.vmin,style=wx.TE_PROCESS_ENTER)
|
||||
self.edVMax=edVMax=wx.TextCtrl(self,-1,'%g'%nrm.vmax,style=wx.TE_PROCESS_ENTER)
|
||||
|
||||
txtTxrFunc=wx.StaticText(self,-1,'function')
|
||||
self.cbtxrFunc=cbtxrFunc=wx.ComboBox(self, -1, choices=('linear','logarithmic'), style=wx.CB_READONLY)
|
||||
cbtxrFunc.SetSelection(0 if nrm.__class__==mpl.colors.Normalize else 1)
|
||||
|
||||
#colMapLst=('Accent', 'Blues', 'BrBG', 'BuGn', 'BuPu', 'Dark2', 'GnBu', 'Greens', 'Greys', 'OrRd', 'Oranges', 'PRGn', 'Paired',
|
||||
#'Pastel1', 'Pastel2', 'PiYG', 'PuBu', 'PuBuGn', 'PuOr', 'PuRd', 'Purples', 'RdBu', 'RdGy', 'RdPu', 'RdYlBu', 'RdYlGn', 'Reds',
|
||||
#'Set1', 'Set2', 'Set3', 'Spectral', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd', 'afmhot', 'autumn', 'binary', 'bone', 'brg', 'bwr',
|
||||
#'cool', 'coolwarm', 'copper', 'cubehelix', 'flag', 'gist_earth', 'gist_gray', 'gist_heat', 'gist_ncar', 'gist_rainbow', 'gist_stern',
|
||||
#'gist_yarg', 'gnuplot', 'gnuplot2', 'gray', 'hot', 'hsv', 'jet', 'ocean', 'pink', 'prism', 'rainbow', 'seismic', 'spectral',
|
||||
#'spring', 'summer', 'terrain', 'winter')
|
||||
|
||||
colMapLst=('hot','spectral','jet','gray','RdYlBu','hsv','gist_stern','gist_ncar','BrBG','RdYlBu','brg','gnuplot2',
|
||||
'prism','rainbow',)
|
||||
|
||||
self.cbColMap=cbColMap=wx.ComboBox(self, -1, choices=colMapLst, style=wx.CB_READONLY)
|
||||
cbColMap.Value=cmap.name
|
||||
|
||||
sizer=wx.BoxSizer(wx.VERTICAL)
|
||||
fgs=wx.FlexGridSizer(4,2,5,5)
|
||||
fgs.Add(txtVMin,0,wx.ALIGN_RIGHT)
|
||||
fgs.Add(edVMin,0,wx.EXPAND)
|
||||
fgs.Add(txtVMax,0,wx.ALIGN_RIGHT)
|
||||
fgs.Add(edVMax,0,wx.EXPAND)
|
||||
fgs.Add(txtTxrFunc,0,wx.ALIGN_RIGHT)
|
||||
fgs.Add(cbtxrFunc,0,wx.EXPAND)
|
||||
fgs.Add(txtColMap,0,wx.ALIGN_RIGHT)
|
||||
fgs.Add(cbColMap,0,wx.EXPAND)
|
||||
sizer.Add(fgs,0,wx.EXPAND|wx.ALL,5)
|
||||
|
||||
edVMin.SetFocus()
|
||||
|
||||
btns = self.CreateButtonSizer(wx.OK|wx.CANCEL)
|
||||
btnApply=wx.Button(self, -1, 'Apply')
|
||||
btns.Add(btnApply, 0, wx.ALL, 5)
|
||||
sizer.Add(btns,0,wx.EXPAND|wx.ALL,5)
|
||||
self.Bind(wx.EVT_BUTTON, self.OnModify, id=wx.ID_OK)
|
||||
self.Bind(wx.EVT_BUTTON, self.OnModify, btnApply)
|
||||
#self.Bind(wx.EVT_TEXT_ENTER, self.OnModify, edVMin)
|
||||
#self.Bind(wx.EVT_TEXT_ENTER, self.OnModify, edVMax)
|
||||
self.Bind(wx.EVT_TEXT, self.OnModify, edVMin)
|
||||
self.Bind(wx.EVT_TEXT, self.OnModify, edVMax)
|
||||
self.Bind(wx.EVT_COMBOBOX, self.OnModify, cbtxrFunc)
|
||||
self.Bind(wx.EVT_COMBOBOX, self.OnModify, cbColMap)
|
||||
|
||||
self.SetSizer(sizer)
|
||||
sizer.Fit(self)
|
||||
|
||||
def OnModify(self, event):
|
||||
#print 'OnModify'
|
||||
parent=self.GetParent()
|
||||
canvas=parent.canvas
|
||||
colBar=canvas.colBar
|
||||
cmap=colBar.cmap
|
||||
nrm=colBar.norm
|
||||
img=canvas.img
|
||||
ax=img.get_axes()
|
||||
data=img.get_array()
|
||||
|
||||
v=self.cbColMap.Value
|
||||
if v!=cmap.name:
|
||||
cmap=getattr(mpl.cm,v)
|
||||
colBar.set_cmap(cmap)
|
||||
colBar.draw_all()
|
||||
img.set_cmap(cmap)
|
||||
ax.set_title(cmap.name)
|
||||
colBar.patch.figure.canvas.draw()
|
||||
|
||||
vmin,vmax=(float(self.edVMin.Value),float(self.edVMax.Value))
|
||||
nrm.vmin=vmin; nrm.vmax=vmax
|
||||
v=self.cbtxrFunc.GetCurrentSelection()
|
||||
func=(mpl.colors.Normalize,ShiftedLogNorm)
|
||||
if nrm.__class__!=func[v]:
|
||||
if v==0: #linear mapping
|
||||
colBar.norm = mpl.colors.Normalize(vmin, vmax)
|
||||
elif v==1: #log mapping
|
||||
img.cmap._init();bg=img.cmap._lut[0].copy();bg[:-1]/=4
|
||||
ax.set_axis_bgcolor(bg)
|
||||
vmin=1
|
||||
colBar.norm = mpl.colors.LogNorm(vmin,vmax)
|
||||
img.set_norm(colBar.norm)
|
||||
colBar.patch.figure.canvas.draw()
|
||||
parent.Refresh(False)
|
||||
if event.GetId()==wx.ID_OK:
|
||||
event.Skip()#do not consume (use event to close the window and sent return code)
|
||||
|
||||
class HdfImageFrame(wx.Frame):
|
||||
def __init__(self, parent,lbl,ims):
|
||||
wx.Frame.__init__(self, parent, title=lbl, size=wx.Size(850, 650))
|
||||
|
||||
canvas = MPLCanvasImg(self,self.SetStatusCB)
|
||||
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
sizer.Add(canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
|
||||
self.SetSizer(sizer)
|
||||
|
||||
toolbar=AddToolbar(canvas,sizer)
|
||||
|
||||
l=len(ims)
|
||||
wxAxCtrl=SliderGroup(self, label='Axis:%d'%0,range=(0,l-1))
|
||||
sizer.Add(wxAxCtrl.sizer, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=5)
|
||||
wxAxCtrl.SetCallback(HdfImageFrame.OnSetView,wxAxCtrl)
|
||||
|
||||
idx=wxAxCtrl.value
|
||||
data=ims[idx]
|
||||
canvas.InitChild(data)
|
||||
|
||||
#self.Fit()
|
||||
self.Centre()
|
||||
|
||||
self.BuildMenu(data.dtype)
|
||||
self.canvas=canvas
|
||||
self.sizer=sizer
|
||||
self.toolbar=toolbar
|
||||
self.ims=ims
|
||||
self.wxAxCtrl=wxAxCtrl
|
||||
|
||||
def BuildMenu(self,dtype):
|
||||
mnBar = wx.MenuBar()
|
||||
|
||||
#-------- Edit Menu --------
|
||||
mn = wx.Menu()
|
||||
mnItem=mn.Append(wx.ID_ANY, 'Setup Colormap', 'Setup the color mapping ');self.Bind(wx.EVT_MENU, self.OnColmapSetup, mnItem)
|
||||
mnItem=mn.Append(wx.ID_ANY, 'Invert X-Axis', kind=wx.ITEM_CHECK);self.Bind(wx.EVT_MENU, self.OnInvertAxis, mnItem)
|
||||
self.mnIDxAxis=mnItem.GetId()
|
||||
mnItem=mn.Append(wx.ID_ANY, 'Invert Y-Axis', kind=wx.ITEM_CHECK);self.Bind(wx.EVT_MENU, self.OnInvertAxis, mnItem)
|
||||
mnItem=mn.Append(wx.ID_ANY, 'Tomo Normalize', 'Multiplies each pixel with a normalization factor. Assumes there exist an array exchange/data_white', kind=wx.ITEM_CHECK);self.Bind(wx.EVT_MENU, self.OnTomoNormalize, mnItem)
|
||||
self.mnItemTomoNormalize=mnItem
|
||||
|
||||
if dtype==np.complex128:
|
||||
mnItem=mn.Append(wx.ID_ANY, 'Complex: Phase', kind=wx.ITEM_CHECK);self.Bind(wx.EVT_MENU, self.OnSetComplexData, mnItem)
|
||||
|
||||
|
||||
mnBar.Append(mn, '&Edit')
|
||||
mn = wx.Menu()
|
||||
mnItem=mn.Append(wx.ID_ANY, 'Help', 'How to use the image viewer');self.Bind(wx.EVT_MENU, self.OnHelp, mnItem)
|
||||
mnBar.Append(mn, '&Help')
|
||||
|
||||
self.SetMenuBar(mnBar)
|
||||
self.CreateStatusBar()
|
||||
|
||||
def SetIdxXY(self,x,y):
|
||||
self.idxXY=(x,y)
|
||||
|
||||
@staticmethod
|
||||
def SetStatusCB(obj,mode,v):
|
||||
if mode==0:
|
||||
obj.SetStatusText( "x= %d y=%d val=%g"%v,0)
|
||||
elif mode==1:
|
||||
obj.SetStatusText( "Colormap Value %d (drag to scale)"%v,0)
|
||||
else:
|
||||
raise KeyError('wrong mode')
|
||||
|
||||
@staticmethod
|
||||
def OnSetView(usrData,value,msg):
|
||||
'called when a slice is selected with the slider controls'
|
||||
imgFrm=usrData.slider.Parent
|
||||
#imgFrm.img.set_array(imgFrm.data[usrData.value,...])
|
||||
idx=imgFrm.wxAxCtrl.value
|
||||
data=imgFrm.ims[idx]
|
||||
try:
|
||||
tomoNorm=imgFrm.tomoNorm
|
||||
except AttributeError:
|
||||
imgFrm.canvas.img.set_array(data)
|
||||
else:
|
||||
data=data*tomoNorm
|
||||
imgFrm.canvas.img.set_array(data)
|
||||
|
||||
imgFrm.canvas.draw()
|
||||
pass
|
||||
|
||||
|
||||
def OnTomoNormalize(self,event):
|
||||
if event.IsChecked():
|
||||
#try to find white image
|
||||
#calculate average
|
||||
#show white normalize factors
|
||||
white=self.data.parent['data_white']
|
||||
tomoNorm=white[1,:,:]
|
||||
#tomoNorm=white[:,:,:].mean(axis=0)
|
||||
#np.iinfo(tomoNorm.dtype).max
|
||||
#tomoNorm=float(np.iinfo(tomoNorm.dtype).max/2)/tomoNorm
|
||||
tomoNorm=tomoNorm.mean()/tomoNorm
|
||||
#tomoNorm=tomoNorm/float(np.iinfo(tomoNorm.dtype).max)
|
||||
data=self.canvas.img.get_array()
|
||||
data*=tomoNorm
|
||||
#data/=tomoNorm
|
||||
self.tomoNorm=tomoNorm
|
||||
self.canvas.img.set_array(data)
|
||||
else:
|
||||
tomoNorm=self.tomoNorm
|
||||
data=self.canvas.img.get_array()
|
||||
data/=tomoNorm
|
||||
self.canvas.img.set_array(data)
|
||||
del self.tomoNorm
|
||||
self.canvas.draw()
|
||||
|
||||
def OnSetComplexData(self, event):
|
||||
if event.IsChecked():
|
||||
data=np.angle(self.canvas.dataRaw)
|
||||
else:
|
||||
data=np.absolute(self.canvas.dataRaw)
|
||||
self.canvas.img.set_array(data)
|
||||
self.canvas.draw()
|
||||
|
||||
def OnHelp(self,event):
|
||||
msg='''to change the image selection:
|
||||
use the toolbar at the bottom to pan and zoom the image
|
||||
use the scrollbars at the bottom (if present) to select an other slice
|
||||
|
||||
to change the colorscale:
|
||||
drag with left mouse button to move the colorbar up and down
|
||||
drag with right mouse button to zoom in/out the colorbar at a given point
|
||||
use mouse weel to zoom in/out the colorbar at a given point
|
||||
double click left mouse button to set maximum and minimun colorbar values
|
||||
use cursor up and down to use a different colormap'''
|
||||
dlg = wx.MessageDialog(self, msg, 'Help', wx.OK|wx.ICON_INFORMATION)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
|
||||
def OnColmapSetup(self,event):
|
||||
dlg=DlgColBarSetup(self)
|
||||
if dlg.ShowModal()==wx.ID_OK:
|
||||
pass
|
||||
dlg.Destroy()
|
||||
|
||||
def OnInvertAxis(self,event):
|
||||
ax=self.canvas.ax
|
||||
#event.Checked()
|
||||
if self.mnIDxAxis==event.GetId():
|
||||
ax.invert_xaxis()
|
||||
else:
|
||||
ax.invert_yaxis()
|
||||
self.canvas.draw()
|
||||
pass
|
||||
|
||||
class ImgStackApp(wx.App):
|
||||
def OnInit(self):
|
||||
#parser=GetParser(False) # debug with exampleCmd
|
||||
return True
|
||||
|
||||
def OnExit(self):
|
||||
pass
|
||||
|
||||
def Run(ims):
|
||||
app=ImgStackApp()
|
||||
frame=HdfImageFrame(None, 'Title', ims)
|
||||
frame.Show()
|
||||
app.SetTopWindow(frame)
|
||||
app.MainLoop()
|
||||
Reference in New Issue
Block a user