From 19d05eb6b15e06acb08c357337148234b4b92086 Mon Sep 17 00:00:00 2001 From: Madison Brod Date: Thu, 7 Mar 2019 16:42:11 -0500 Subject: [PATCH 01/14] initial commit of Maddie's ringfinding python modules --- xpdtools/calib2.py | 209 +++++++++++++++++++++++++++++++++++++++++++++ xpdtools/calib3.py | 171 +++++++++++++++++++++++++++++++++++++ 2 files changed, 380 insertions(+) create mode 100644 xpdtools/calib2.py create mode 100644 xpdtools/calib3.py diff --git a/xpdtools/calib2.py b/xpdtools/calib2.py new file mode 100644 index 0000000..39dccfc --- /dev/null +++ b/xpdtools/calib2.py @@ -0,0 +1,209 @@ + +import numpy as np + +import tifffile as tf +import matplotlib as mpl + +mpl.use('TkAgg') +import matplotlib.pyplot as plt + + +filename = 'Ni_pin_20181101-075909_973de2_0001.tiff' + +imarray=tf.imread(filename) +print(imarray) + +class Slyce(): + def __init__(self,direction,index,imarray): + self.direction=direction + self.index=index + self.pixels=[] + if direction=='v': + self.data=list(imarray[:,index]) + if direction=='h': + self.data=list(imarray[index,:]) + +def findringcenter(image,thres=.20,d=20): + + def findcenter(image): + s=image.shape + # number of rows divided by 2 + r=s[0]/2 + # number of columns divided by 2 + c=s[1]/2 + return r,c + + r,c=findcenter(image) + + slyce1=Slyce('v',c-d,image) + slyce2=Slyce('v',c+d,image) + slyce3=Slyce('v',c,image) + slyce4=Slyce('v',c-d/2,image) + slyce5=Slyce('v',c+d/2,image) + + slyce6=Slyce('h',r-d,image) + slyce7=Slyce('h',r+d,image) + slyce8=Slyce('h',r,image) + slyce9=Slyce('h',r+d/2,image) + slyce10=Slyce('h',r-d/2,image) + slyces=[slyce1, slyce2, slyce3, slyce4, slyce5, slyce6, slyce7, slyce8, slyce9, slyce10] + + def findthreshold(image,thres): + return thres*np.max(image) + + thresh=findthreshold(image,thres) + + def clickpoints(slyce,thresh): + p1=np.argmax(slyce.data) + p2=np.argmax(slyce.data[:p1]+slyce.data[p1+1:]) + + if slyce.data[p2]>=thresh: + slyce.pixels.append(p1) + slyce.pixels.append(p2) + + elif slyce.data[p1]>=thresh: + + slyce.pixels.append(p1) + + points2click=[] + for slyce in slyces: + clickpoints(slyce,thresh) + if slyce.direction=='v': + for pixel in slyce.pixels: + points2click.append([pixel,slyce.index]) + if slyce.direction=='h': + for pixel in slyce.pixels: + points2click.append([slyce.index,pixel]) + + highlight=np.mean(image)*.9 + image_new=image + + def finddistance(a,b): + dif1=a[1]-b[1] + dif2=a[0]-b[0] + d_sq=np.abs(dif1**2+dif2**2) + return np.sqrt(d_sq) + + + #f, ax = plt.subplots(1) + #ax.imshow(image) + ring_mask=np.ones_like(image,dtype=bool) + + + for point in points2click: + #ax.scatter(point[0],point[1]) + ring_mask[point[0],point[1]]=False + image_new[point[0],point[1]]=0 + + coords=[] + spread=[] + for row in range (int(r-3*d),int(r+3*d)): + for col in range (int(c-3*d),int(c+3*d)): + pointdist=[] + for point in points2click: + pointdist.append(finddistance([row,col],point)) + spread.append(max(pointdist)-min(pointdist)) + coords.append([row,col]) + + center=coords[spread.index(min(spread))] + return center + print(center) + + + +#take a horizontal cut out from the center of the ring to the end of the image +#row is constant and column index goes from col index of center to end + +def findrings(image): + center=findringcenter(image) + cs1=Slyce('h',center[0]-2,image) + cs2=Slyce('h',center[0]-1,image) + cs3=Slyce('h',center[0],image) + cs4=Slyce('h',center[0]+1,image) + cs5=Slyce('h',center[0]+2,image) + + cs=[cs1,cs2,cs3,cs4,cs5] + + value1=cs1.data + value2=cs2.data + value3=cs3.data + value4=cs4.data + value5=cs5.data + value_cs=np.zeros(np.shape(value1)[0]) + for i, blank in enumerate(value_cs): + value_cs[i]=np.median([value1[i],value2[i],value3[i],value4[i],value5[i]]) + + + halfcs=list(value_cs[(center[1]):]) + + #find derivative of values on the slyce + dx=1 + deriv=list(np.gradient(halfcs,dx)) + + #creates a function that finds the indices of a list where the derivative changes sign + def zerocross(lines): + z=[] + for i in range(1,len(lines)-1): + if (np.sign(lines[i]) == -1) and (np.sign(lines[i-1]) in [0,1]): + if np.abs(lines[i]-lines[i-1])>np.max(lines)/80.0: + z.append(i) + return z + + + center=findringcenter(image) + rings=zerocross(deriv) + clickpts=[] + firstpoint=[center[0],rings[0]+center[1]] + + if (halfcs[rings[0]]>0.7*np.max(halfcs)) or (halfcs[rings[0]-1]>0.7*np.max(halfcs)) or (halfcs[rings[0]+1]>0.7*np.max(halfcs)): + clickpts.append(rings[0]) + clickpts.append(rings[1]) + clickpts.append(rings[2]) + clickpts.append(rings[5]) + else: + clickpts.append(rings[1]) + clickpts.append(rings[2]) + clickpts.append(rings[3]) + clickpts.append(rings[6]) + + + + points_image=[] + for clickpt in clickpts: + points_image.append([center[0],clickpt+center[1]]) + + print(points_image) + + plt.plot(range(0,len(halfcs)), halfcs) + plt.scatter(range(0,len(deriv)),deriv) + plt.plot(deriv) + plt.plot(np.zeros(len(deriv))) + for clickpt in clickpts: + plt.scatter(clickpt,0,color='r') + plt.show() + + + new_img = np.empty((image.shape[0],image.shape[1],4)) + max_img = np.amax(image) + min_img = np.amin(image) + for i, row in enumerate(new_img): + for j, elem in enumerate(row): + old_val = image[i][j] + scaled = (old_val-min_img)/(max_img-min_img) + new_img[i][j] = np.array([1.0-scaled, 1.0-scaled, 1.0-scaled, 1.0]) + + for point_image in points_image: + for i in range(-2,2): + for j in range(-2,2): + new_img[point_image[0]+i][point_image[1]+j]=np.array([1.0, 0.0, 0.0, 1.0]) + + + + plt.imshow(new_img) + plt.show() + return points_image + + +findrings(imarray) + + diff --git a/xpdtools/calib3.py b/xpdtools/calib3.py new file mode 100644 index 0000000..7135637 --- /dev/null +++ b/xpdtools/calib3.py @@ -0,0 +1,171 @@ + +import numpy as np + +import tifffile as tf +import matplotlib as mpl + +mpl.use('TkAgg') +import matplotlib.pyplot as plt + + +filename = 'Ni_pin_20181101-075909_973de2_0001.tiff' + + + + +#take a horizontal cut out from the center of the ring to the end of the image +#row is constant and column index goes from col index of center to end + +def findrings(file_name): + + image=tf.imread(file_name) + class Slyce(): + def __init__(self,direction,index,image): + self.direction=direction + self.index=index + self.pixels=[] + if direction=='v': + self.data=list(image[:,index]) + if direction=='h': + self.data=list(image[index,:]) + + def findringcenter(image,thres=0.2,d=20): + + def findcenter(image): + s=image.shape + # number of rows divided by 2 + r=s[0]/2 + # number of columns divided by 2 + c=s[1]/2 + return r,c + + r,c=findcenter(image) + + slyce1=Slyce('v',c-d,image) + slyce2=Slyce('v',c+d,image) + slyce3=Slyce('v',c,image) + slyce4=Slyce('v',c-d/2,image) + slyce5=Slyce('v',c+d/2,image) + + slyce6=Slyce('h',r-d,image) + slyce7=Slyce('h',r+d,image) + slyce8=Slyce('h',r,image) + slyce9=Slyce('h',r+d/2,image) + slyce10=Slyce('h',r-d/2,image) + slyces=[slyce1, slyce2, slyce3, slyce4, slyce5, slyce6, slyce7, slyce8, slyce9, slyce10] + + def findthreshold(image,thres): + return thres*np.max(image) + + thresh=findthreshold(image,thres) + + def clickpoints(slyce,thresh): + p1=np.argmax(slyce.data) + p2=np.argmax(slyce.data[:p1]+slyce.data[p1+1:]) + + if slyce.data[p2]>=thresh: + slyce.pixels.append(p1) + slyce.pixels.append(p2) + + elif slyce.data[p1]>=thresh: + + slyce.pixels.append(p1) + + points2click=[] + for slyce in slyces: + clickpoints(slyce,thresh) + if slyce.direction=='v': + for pixel in slyce.pixels: + points2click.append([pixel,slyce.index]) + if slyce.direction=='h': + for pixel in slyce.pixels: + points2click.append([slyce.index,pixel]) + + + def finddistance(a,b): + dif1=a[1]-b[1] + dif2=a[0]-b[0] + d_sq=np.abs(dif1**2+dif2**2) + return np.sqrt(d_sq) + + + coords=[] + spread=[] + for row in range (int(r-3*d),int(r+3*d)): + for col in range (int(c-3*d),int(c+3*d)): + pointdist=[] + for point in points2click: + pointdist.append(finddistance([row,col],point)) + spread.append(max(pointdist)-min(pointdist)) + coords.append([row,col]) + + center=coords[spread.index(min(spread))] + return center + + + center_pt=findringcenter(image) + cs1=Slyce('h',center_pt[0]-2,image) + cs2=Slyce('h',center_pt[0]-1,image) + cs3=Slyce('h',center_pt[0],image) + cs4=Slyce('h',center_pt[0]+1,image) + cs5=Slyce('h',center_pt[0]+2,image) + + cs=[cs1,cs2,cs3,cs4,cs5] + + value1=cs1.data + value2=cs2.data + value3=cs3.data + value4=cs4.data + value5=cs5.data + value_cs=np.zeros(np.shape(value1)[0]) + for i, blank in enumerate(value_cs): + value_cs[i]=np.median([value1[i],value2[i],value3[i],value4[i],value5[i]]) + + + halfcs=list(value_cs[(center_pt[1]):]) + + #find derivative of values on the slyce + dx=1 + deriv=list(np.gradient(halfcs,dx)) + + #creates a function that finds the indices of a list where the derivative changes sign + def zerocross(lines): + z=[] + for i in range(1,len(lines)-1): + if (np.sign(lines[i]) == -1) and (np.sign(lines[i-1]) in [0,1]): + if np.abs(lines[i]-lines[i-1])>np.max(lines)/80.0: + z.append(i) + return z + + + + rings=zerocross(deriv) + clickpts=[] + firstpoint=[center_pt[0],rings[0]+center_pt[1]] + + if (halfcs[rings[0]]>0.7*np.max(halfcs)) or (halfcs[rings[0]-1]>0.7*np.max(halfcs)) or (halfcs[rings[0]+1]>0.7*np.max(halfcs)): + clickpts.append(rings[0]) + clickpts.append(rings[1]) + clickpts.append(rings[2]) + clickpts.append(rings[5]) + else: + clickpts.append(rings[1]) + clickpts.append(rings[2]) + clickpts.append(rings[3]) + clickpts.append(rings[6]) + + + + points_image=[] + for clickpt in clickpts: + points_image.append([center_pt[0],clickpt+center_pt[1]]) + + print(points_image) + print(center_pt) + + + + return points_image + + +findrings(filename) \ No newline at end of file From dd2ff3fc9600736602cbec8e2c158f4bb795b909 Mon Sep 17 00:00:00 2001 From: Maddison Brod Date: Tue, 12 Mar 2019 21:18:13 -0400 Subject: [PATCH 02/14] added comments describing what the code is doing --- xpdtools/calib3.py | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/xpdtools/calib3.py b/xpdtools/calib3.py index 7135637..ae2ab4c 100644 --- a/xpdtools/calib3.py +++ b/xpdtools/calib3.py @@ -16,9 +16,16 @@ #take a horizontal cut out from the center of the ring to the end of the image #row is constant and column index goes from col index of center to end +#findrings() takes a tiff file as an input and returns the image indices of the center points and points on rings 0,1,2,5 def findrings(file_name): + #convert tiff file to numpy array image=tf.imread(file_name) + + #define a class that creates a 1D array of data from the image from either a vertical or horizontal slice (slyce) through + # the image. v=vertical slice, h=horizontal slice + #for v slice, index gives the col index in tiff image + #for h slice, index hives row index in tiff image class Slyce(): def __init__(self,direction,index,image): self.direction=direction @@ -29,8 +36,14 @@ def __init__(self,direction,index,image): if direction=='h': self.data=list(image[index,:]) + #findringcenter() takes the image (as numpy array), a threshold, and d as inputs and returns the indices of the center of + #the inner ring + #thres is used to define a threshold that determines if a point that is identified as a maximum is significant enough to be on the center ring + #d defines a distance around the center of the image that determines where slices are taken in the image to find the center ring + #the larger d is, the farther away from the center of the image the slices will be taken def findringcenter(image,thres=0.2,d=20): + #findcenter() takes image numpy array as an input and finds the indices of the center of the image (not of the rings) def findcenter(image): s=image.shape # number of rows divided by 2 @@ -41,6 +54,7 @@ def findcenter(image): r,c=findcenter(image) + #take 10 slices within a range of 'd' away from the cetner of the image and put them into a list slyce1=Slyce('v',c-d,image) slyce2=Slyce('v',c+d,image) slyce3=Slyce('v',c,image) @@ -54,15 +68,19 @@ def findcenter(image): slyce10=Slyce('h',r-d/2,image) slyces=[slyce1, slyce2, slyce3, slyce4, slyce5, slyce6, slyce7, slyce8, slyce9, slyce10] + #find threshold takes thres and determines a threshold value from the maximum pixel value in the tiff image def findthreshold(image,thres): return thres*np.max(image) thresh=findthreshold(image,thres) + # clickpoints takes a slyce and the calculated threshold as inputs and returns the index (in a 1-d array) of 1 or two points + #that are on the INNER ring def clickpoints(slyce,thresh): p1=np.argmax(slyce.data) p2=np.argmax(slyce.data[:p1]+slyce.data[p1+1:]) + #if statement to determine if max points are large enough to actually be on center ring if slyce.data[p2]>=thresh: slyce.pixels.append(p1) slyce.pixels.append(p2) @@ -81,16 +99,21 @@ def clickpoints(slyce,thresh): for pixel in slyce.pixels: points2click.append([slyce.index,pixel]) - + #finds distance between two points def finddistance(a,b): dif1=a[1]-b[1] dif2=a[0]-b[0] d_sq=np.abs(dif1**2+dif2**2) return np.sqrt(d_sq) - + #coords keeps track of the coordinates that are tested to find the center of the inner ring coords=[] + #spread keeps track of the range of point distances from the tested point to the points that have been identified on the + #center ring spread=[] + #the center of the ring is determined by testing a range of points around the center of the image and calculating the distances + #between that point and the points that have been identified on the inner ring through the clickpoints() function + #the point that has the smallest range of distances is identified as the center for row in range (int(r-3*d),int(r+3*d)): for col in range (int(c-3*d),int(c+3*d)): pointdist=[] @@ -104,6 +127,8 @@ def finddistance(a,b): center_pt=findringcenter(image) + + #create horizontal slyces from the center of the inner ring (but use 5 and find the median value to avoid issues with hot pixels) cs1=Slyce('h',center_pt[0]-2,image) cs2=Slyce('h',center_pt[0]-1,image) cs3=Slyce('h',center_pt[0],image) @@ -118,17 +143,19 @@ def finddistance(a,b): value4=cs4.data value5=cs5.data value_cs=np.zeros(np.shape(value1)[0]) + + #create list of median values in horizontal center slyce to avoid hot pixel values for i, blank in enumerate(value_cs): value_cs[i]=np.median([value1[i],value2[i],value3[i],value4[i],value5[i]]) - + #take half of center slyce from the center of the inner ring out halfcs=list(value_cs[(center_pt[1]):]) #find derivative of values on the slyce dx=1 deriv=list(np.gradient(halfcs,dx)) - #creates a function that finds the indices of a list where the derivative changes sign + #creates a function that finds the indices of a list where the derivative changes sign (these are points where peaks could occur) def zerocross(lines): z=[] for i in range(1,len(lines)-1): @@ -143,6 +170,8 @@ def zerocross(lines): clickpts=[] firstpoint=[center_pt[0],rings[0]+center_pt[1]] + #tests a series of conditions to determine if there is a peak at a certain index in 1D array + #tests to make sure that peak is real and not noise/small fluctuation if (halfcs[rings[0]]>0.7*np.max(halfcs)) or (halfcs[rings[0]-1]>0.7*np.max(halfcs)) or (halfcs[rings[0]+1]>0.7*np.max(halfcs)): clickpts.append(rings[0]) clickpts.append(rings[1]) @@ -155,7 +184,7 @@ def zerocross(lines): clickpts.append(rings[6]) - + #find indices of points that shoudl be "clicked" in tiff image array points_image=[] for clickpt in clickpts: points_image.append([center_pt[0],clickpt+center_pt[1]]) From 624703c40857d491fbfded402a789fa1985003e7 Mon Sep 17 00:00:00 2001 From: Maddison Brod Date: Wed, 20 Mar 2019 15:16:17 -0400 Subject: [PATCH 03/14] added docstrings to functions and modified findrings() to take in a numpy array as an input instead of a str --- xpdtools/calib3.py | 149 +++++++++++++++++++++++++++++++-------------- 1 file changed, 104 insertions(+), 45 deletions(-) diff --git a/xpdtools/calib3.py b/xpdtools/calib3.py index ae2ab4c..9a1e72f 100644 --- a/xpdtools/calib3.py +++ b/xpdtools/calib3.py @@ -2,30 +2,29 @@ import numpy as np import tifffile as tf -import matplotlib as mpl -mpl.use('TkAgg') -import matplotlib.pyplot as plt filename = 'Ni_pin_20181101-075909_973de2_0001.tiff' +imarray=tf.imread(filename) + -#take a horizontal cut out from the center of the ring to the end of the image -#row is constant and column index goes from col index of center to end +def findrings(image): + + """ + Takes a numpy array representing a tiff image and returns the pixel indices of the center point and points on rings 0,1,2,5 + + Parameters: + image: numpy array of tiff image + Returns: + pixel index of point on center ring and pixel indices of points on rings 0,1,2,5 + + """ + -#findrings() takes a tiff file as an input and returns the image indices of the center points and points on rings 0,1,2,5 -def findrings(file_name): - - #convert tiff file to numpy array - image=tf.imread(file_name) - - #define a class that creates a 1D array of data from the image from either a vertical or horizontal slice (slyce) through - # the image. v=vertical slice, h=horizontal slice - #for v slice, index gives the col index in tiff image - #for h slice, index hives row index in tiff image class Slyce(): def __init__(self,direction,index,image): self.direction=direction @@ -35,16 +34,34 @@ def __init__(self,direction,index,image): self.data=list(image[:,index]) if direction=='h': self.data=list(image[index,:]) - - #findringcenter() takes the image (as numpy array), a threshold, and d as inputs and returns the indices of the center of - #the inner ring - #thres is used to define a threshold that determines if a point that is identified as a maximum is significant enough to be on the center ring - #d defines a distance around the center of the image that determines where slices are taken in the image to find the center ring - #the larger d is, the farther away from the center of the image the slices will be taken + + def findringcenter(image,thres=0.2,d=20): - - #findcenter() takes image numpy array as an input and finds the indices of the center of the image (not of the rings) + """ + Takes a numpy array corresponding to a tiff image and finds the pixel index of the center of the inner ring + + Parameters: + image: numpy array of tiff image + thres: float representing percentage of image maximum that could be considered a value of data on inner ring + d: integer corresponding distance around image center (distinct from inner ring center) + Returns: + Pixel indices of an estimate of center point of inner ring. + + """ + def findcenter(image): + """ + Takes numpy array corresponding to a tiff image and finds the pixel indices corresponding to the center of the image (not the center of the rings) + + Parameters: numpy array of tiff image + image: numpy array of tiff image + + Returns: + r: integer row index of image center + c: integer column index of image center + + """ + s=image.shape # number of rows divided by 2 r=s[0]/2 @@ -54,7 +71,7 @@ def findcenter(image): r,c=findcenter(image) - #take 10 slices within a range of 'd' away from the cetner of the image and put them into a list + #take 10 slices within a range of 'd' away from the cetner of the image and puts them into a list slyce1=Slyce('v',c-d,image) slyce2=Slyce('v',c+d,image) slyce3=Slyce('v',c,image) @@ -68,27 +85,46 @@ def findcenter(image): slyce10=Slyce('h',r-d/2,image) slyces=[slyce1, slyce2, slyce3, slyce4, slyce5, slyce6, slyce7, slyce8, slyce9, slyce10] - #find threshold takes thres and determines a threshold value from the maximum pixel value in the tiff image def findthreshold(image,thres): + """ + Takes in a numpy array corresponding to tiff image and a percentage of the maximum pixel value and returns the maximum pixel value. + + Parameters: + image: numpy array of tiff image + thres: float representing percentage of image maximum that could be considered a value of data on inner ring + + Returns: + float corresponding to a percentage of the maximum value in image numpy array + + """ + return thres*np.max(image) thresh=findthreshold(image,thres) - + # clickpoints takes a slyce and the calculated threshold as inputs and returns the index (in a 1-d array) of 1 or two points #that are on the INNER ring def clickpoints(slyce,thresh): + """ + Takes a slyce and threshold value and adds to the "pixels" attribute of Slyce class the indices of 1 or 2 points (in the 1-D slyce array) that correspond to points on the inner ring. + + Parameters: + slyce: 1-D numpy array of image data corresponding to a vertical or horizontal slice through the tiff image + thresh: np.float64 corresponding to a percentage of the maximum value in image numpy array + + """ p1=np.argmax(slyce.data) p2=np.argmax(slyce.data[:p1]+slyce.data[p1+1:]) - #if statement to determine if max points are large enough to actually be on center ring + #if statement to determine if max points are large enough to actually be on center ring. If so, the pixel attribute of Slyce is modified to include these indices if slyce.data[p2]>=thresh: slyce.pixels.append(p1) slyce.pixels.append(p2) - + elif slyce.data[p1]>=thresh: slyce.pixels.append(p1) - + points2click=[] for slyce in slyces: clickpoints(slyce,thresh) @@ -101,21 +137,34 @@ def clickpoints(slyce,thresh): #finds distance between two points def finddistance(a,b): - dif1=a[1]-b[1] - dif2=a[0]-b[0] - d_sq=np.abs(dif1**2+dif2**2) - return np.sqrt(d_sq) - + """ + Finds distance between two points. + + Parameters: + a: numpy array, list, or tuple containing a coordinates, where a[0] contains a row index and a[1] contains col index + b: numpy array, list, or tuple containing a coordinates, where a[0] contains a row index and a[1] contains col index + + Returns: + np.float64 corresponding to distance between two points + """ + + dif1=a[1]-b[1] + dif2=a[0]-b[0] + d_sq=np.abs(dif1**2+dif2**2) + + return np.sqrt(d_sq) + #coords keeps track of the coordinates that are tested to find the center of the inner ring coords=[] #spread keeps track of the range of point distances from the tested point to the points that have been identified on the #center ring spread=[] + #the center of the ring is determined by testing a range of points around the center of the image and calculating the distances #between that point and the points that have been identified on the inner ring through the clickpoints() function #the point that has the smallest range of distances is identified as the center for row in range (int(r-3*d),int(r+3*d)): - for col in range (int(c-3*d),int(c+3*d)): + for col in range (int(c-3*d),int(c+3*d)): pointdist=[] for point in points2click: pointdist.append(finddistance([row,col],point)) @@ -123,8 +172,9 @@ def finddistance(a,b): coords.append([row,col]) center=coords[spread.index(min(spread))] + return center - + center_pt=findringcenter(image) @@ -136,36 +186,45 @@ def finddistance(a,b): cs5=Slyce('h',center_pt[0]+2,image) cs=[cs1,cs2,cs3,cs4,cs5] - + value1=cs1.data value2=cs2.data value3=cs3.data value4=cs4.data value5=cs5.data value_cs=np.zeros(np.shape(value1)[0]) - + #create list of median values in horizontal center slyce to avoid hot pixel values for i, blank in enumerate(value_cs): value_cs[i]=np.median([value1[i],value2[i],value3[i],value4[i],value5[i]]) - + #take half of center slyce from the center of the inner ring out halfcs=list(value_cs[(center_pt[1]):]) #find derivative of values on the slyce dx=1 deriv=list(np.gradient(halfcs,dx)) + - #creates a function that finds the indices of a list where the derivative changes sign (these are points where peaks could occur) def zerocross(lines): + """ + Takes in 1-D numpy array and determines array indices corresponding to points where an adjacent value has a different sign and where the difference between the two values before and after zero-crossing exceeds a certain threshold + + Parameters: + lines: 1-D numpy array + Returns: + z: list of indices in lines that correspond to both a change in sign of adjacent values and significant difference in these values + + """ z=[] for i in range(1,len(lines)-1): - if (np.sign(lines[i]) == -1) and (np.sign(lines[i-1]) in [0,1]): + if (np.sign(lines[i]) == -1) and (np.sign(lines[i-1]) in [0,1]): if np.abs(lines[i]-lines[i-1])>np.max(lines)/80.0: z.append(i) return z - - + + rings=zerocross(deriv) clickpts=[] firstpoint=[center_pt[0],rings[0]+center_pt[1]] @@ -193,8 +252,8 @@ def zerocross(lines): print(center_pt) - + return points_image -findrings(filename) \ No newline at end of file +findrings(imarray) \ No newline at end of file From 9fdcc5cbed1d0b73fa4aebf302e46f3163ecb27f Mon Sep 17 00:00:00 2001 From: Maddison Brod Date: Wed, 20 Mar 2019 19:43:07 -0400 Subject: [PATCH 04/14] calib4.py and calib5.py have the Slyce class and functions outside of the main findrings function. calib4.py includes a visualization of the center point and points on rings, while calib5.py just returns the pixel indices of these points. --- xpdtools/calib4.py | 262 +++++++++++++++++++++++++++++++++++++++++++++ xpdtools/calib5.py | 232 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 494 insertions(+) create mode 100644 xpdtools/calib4.py create mode 100644 xpdtools/calib5.py diff --git a/xpdtools/calib4.py b/xpdtools/calib4.py new file mode 100644 index 0000000..9a23052 --- /dev/null +++ b/xpdtools/calib4.py @@ -0,0 +1,262 @@ +import numpy as np + +import tifffile as tf + +import matplotlib as mpl + +mpl.use('TkAgg') +import matplotlib.pyplot as plt + +filename = 'Ni_pin_20181101-075909_973de2_0001.tiff' + + +imarray=tf.imread(filename) + + +class Slyce(): + def __init__(self,direction,index,image): + self.direction=direction + self.index=index + self.pixels=[] + if direction=='v': + self.data=list(image[:,index]) + if direction=='h': + self.data=list(image[index,:]) + +def findcenter(image): + """ + Takes numpy array corresponding to a tiff image and finds the pixel indices corresponding to the center of the image (not the center of the rings) + + Parameters: numpy array of tiff image + image: numpy array of tiff image + + Returns: + r: integer row index of image center + c: integer column index of image center + + """ + + s=image.shape + # number of rows divided by 2 + r=s[0]/2 + # number of columns divided by 2 + c=s[1]/2 + return r,c + + +def clickpoints(slyce,thresh): + """ + Takes a slyce and threshold value and adds to the "pixels" attribute of Slyce class the indices of 1 or 2 points (in the 1-D slyce array) that correspond to points on the inner ring. + + Parameters: + slyce: 1-D numpy array of image data corresponding to a vertical or horizontal slice through the tiff image + thresh: np.float64 corresponding to a percentage of the maximum value in image numpy array + + """ + p1=np.argmax(slyce.data) + p2=np.argmax(slyce.data[:p1]+slyce.data[p1+1:]) + + #if statement to determine if max points are large enough to actually be on center ring. If so, the pixel attribute of Slyce is modified to include these indices + if slyce.data[p2]>=thresh: + slyce.pixels.append(p1) + slyce.pixels.append(p2) + + elif slyce.data[p1]>=thresh: + + + slyce.pixels.append(p1) + +def finddistance(a,b): + """ + Finds distance between two points. + + Parameters: + a: numpy array, list, or tuple containing a coordinates, where a[0] contains a row index and a[1] contains col index + b: numpy array, list, or tuple containing a coordinates, where a[0] contains a row index and a[1] contains col index + + Returns: + np.float64 corresponding to distance between two points + """ + + dif1=a[1]-b[1] + dif2=a[0]-b[0] + d_sq=np.abs(dif1**2+dif2**2) + + return np.sqrt(d_sq) + +def findringcenter(image,thres=0.2,d=20): + """ + Takes a numpy array corresponding to a tiff image and finds the pixel index of the center of the inner ring. + + Parameters: + image: numpy array of tiff image + d: integer corresponding distance around image center (distinct from inner ring center) + Returns: + Pixel indices of an estimate of center point of inner ring. + + + """ + thresh=thres*np.max(image) + r,c=findcenter(image) + + #take 10 slices within a range of 'd' away from the cetner of the image and puts them into a list + slyce1=Slyce('v',c-d,image) + slyce2=Slyce('v',c+d,image) + slyce3=Slyce('v',c,image) + slyce4=Slyce('v',c-d/2,image) + slyce5=Slyce('v',c+d/2,image) + + slyce6=Slyce('h',r-d,image) + slyce7=Slyce('h',r+d,image) + slyce8=Slyce('h',r,image) + slyce9=Slyce('h',r+d/2,image) + slyce10=Slyce('h',r-d/2,image) + slyces=[slyce1, slyce2, slyce3, slyce4, slyce5, slyce6, slyce7, slyce8, slyce9, slyce10] + + + + points2click=[] + for slyce in slyces: + clickpoints(slyce,thresh) + if slyce.direction=='v': + for pixel in slyce.pixels: + points2click.append([pixel,slyce.index]) + if slyce.direction=='h': + for pixel in slyce.pixels: + points2click.append([slyce.index,pixel]) + + #coords keeps track of the coordinates that are tested to find the center of the inner ring + coords=[] + #spread keeps track of the range of point distances from the tested point to the points that have been identified on the center ring + spread=[] + + #the center of the ring is determined by testing a range of points around the center of the image and calculating the distances + #between that point and the points that have been identified on the inner ring through the clickpoints() function + #the point that has the smallest range of distances is identified as the center + for row in range (int(r-3*d),int(r+3*d)): + for col in range (int(c-3*d),int(c+3*d)): + pointdist=[] + for point in points2click: + pointdist.append(finddistance([row,col],point)) + spread.append(max(pointdist)-min(pointdist)) + coords.append([row,col]) + + center=coords[spread.index(min(spread))] + + return center + + +def zerocross(lines): + """ + Takes in 1-D numpy array and determines array indices corresponding to points where an adjacent value has a different sign and where the difference between the two values before and after zero-crossing exceeds a certain threshold + + Parameters: + lines: 1-D numpy array + Returns: + z: list of indices in lines that correspond to both a change in sign of adjacent values and significant difference in these values + + """ + z=[] + for i in range(1,len(lines)-1): + if (np.sign(lines[i]) == -1) and (np.sign(lines[i-1]) in [0,1]): + if np.abs(lines[i]-lines[i-1])>np.max(lines)/80.0: + z.append(i) + return z + +def findrings(image): + + """ + Takes a numpy array representing a tiff image and returns the pixel indices of the center point and points on rings 0,1,2,5 + + Parameters: + image: numpy array of tiff image + Returns: + pixel index of point on center ring and pixel indices of points on rings 0,1,2,5 + + """ + center_pt=findringcenter(image) + print(center_pt) + + #create horizontal slyces from the center of the inner ring (but use 5 and find the median value to avoid issues with hot pixels) + cs1=Slyce('h',center_pt[0]-2,image) + cs2=Slyce('h',center_pt[0]-1,image) + cs3=Slyce('h',center_pt[0],image) + cs4=Slyce('h',center_pt[0]+1,image) + cs5=Slyce('h',center_pt[0]+2,image) + + cs=[cs1,cs2,cs3,cs4,cs5] + + value1=cs1.data + value2=cs2.data + value3=cs3.data + value4=cs4.data + value5=cs5.data + value_cs=np.zeros(np.shape(value1)[0]) + + #create list of median values in horizontal center slyce to avoid hot pixel values + for i, blank in enumerate(value_cs): + value_cs[i]=np.median([value1[i],value2[i],value3[i],value4[i],value5[i]]) + + #take half of center slyce from the center of the inner ring out + halfcs=list(value_cs[(center_pt[1]):]) + + #find derivative of values on the slyce + dx=1 + deriv=list(np.gradient(halfcs,dx)) + + + rings=zerocross(deriv) + clickpts=[] + firstpoint=[center_pt[0],rings[0]+center_pt[1]] + + #tests a series of conditions to determine if there is a peak at a certain index in 1D array + #tests to make sure that peak is real and not noise/small fluctuation + if (halfcs[rings[0]]>0.7*np.max(halfcs)) or (halfcs[rings[0]-1]>0.7*np.max(halfcs)) or (halfcs[rings[0]+1]>0.7*np.max(halfcs)): + clickpts.append(rings[0]) + clickpts.append(rings[1]) + clickpts.append(rings[2]) + clickpts.append(rings[5]) + else: + clickpts.append(rings[1]) + clickpts.append(rings[2]) + clickpts.append(rings[3]) + clickpts.append(rings[6]) + + + #find indices of points that shoudl be "clicked" in tiff image array + points_image=[] + for clickpt in clickpts: + points_image.append([center_pt[0],clickpt+center_pt[1]]) + + print(points_image) + print(center_pt) + + + + return points_image, center_pt + +points_image,center_pt=findrings(imarray) + + +new_img = np.empty((imarray.shape[0],imarray.shape[1],4)) +max_img = np.amax(imarray) +min_img = np.amin(imarray) +for i, row in enumerate(new_img): + for j, elem in enumerate(row): + old_val = imarray[i][j] + scaled = (old_val-min_img)/(max_img-min_img) + new_img[i][j] = np.array([1.0-scaled, 1.0-scaled, 1.0-scaled, 1.0]) + +for point_image in points_image: + for i in range(-2,2): + for j in range(-2,2): + new_img[point_image[0]+i][point_image[1]+j]=np.array([1.0, 0.0, 0.0, 1.0]) + +for i in range(-2,2): + for j in range(-2,2): + new_img[center_pt[0]+i][center_pt+j]=np.array([1.0, 0.0, 0.0, 1.0]) + + + +plt.imshow(new_img) +plt.show() diff --git a/xpdtools/calib5.py b/xpdtools/calib5.py new file mode 100644 index 0000000..8d14ee8 --- /dev/null +++ b/xpdtools/calib5.py @@ -0,0 +1,232 @@ +import numpy as np + +import tifffile as tf + + +filename = 'Ni_pin_20181101-075909_973de2_0001.tiff' + + +imarray=tf.imread(filename) + + +class Slyce(): + def __init__(self,direction,index,image): + self.direction=direction + self.index=index + self.pixels=[] + if direction=='v': + self.data=list(image[:,index]) + if direction=='h': + self.data=list(image[index,:]) + +def findcenter(image): + """ + Takes numpy array corresponding to a tiff image and finds the pixel indices corresponding to the center of the image (not the center of the rings) + + Parameters: numpy array of tiff image + image: numpy array of tiff image + + Returns: + r: integer row index of image center + c: integer column index of image center + + """ + + s=image.shape + # number of rows divided by 2 + r=s[0]/2 + # number of columns divided by 2 + c=s[1]/2 + return r,c + + +def clickpoints(slyce,thresh): + """ + Takes a slyce and threshold value and adds to the "pixels" attribute of Slyce class the indices of 1 or 2 points (in the 1-D slyce array) that correspond to points on the inner ring. + + Parameters: + slyce: 1-D numpy array of image data corresponding to a vertical or horizontal slice through the tiff image + thresh: np.float64 corresponding to a percentage of the maximum value in image numpy array + + """ + p1=np.argmax(slyce.data) + p2=np.argmax(slyce.data[:p1]+slyce.data[p1+1:]) + + #if statement to determine if max points are large enough to actually be on center ring. If so, the pixel attribute of Slyce is modified to include these indices + if slyce.data[p2]>=thresh: + slyce.pixels.append(p1) + slyce.pixels.append(p2) + + elif slyce.data[p1]>=thresh: + + + slyce.pixels.append(p1) + +def finddistance(a,b): + """ + Finds distance between two points. + + Parameters: + a: numpy array, list, or tuple containing a coordinates, where a[0] contains a row index and a[1] contains col index + b: numpy array, list, or tuple containing a coordinates, where a[0] contains a row index and a[1] contains col index + + Returns: + np.float64 corresponding to distance between two points + """ + + dif1=a[1]-b[1] + dif2=a[0]-b[0] + d_sq=np.abs(dif1**2+dif2**2) + + return np.sqrt(d_sq) + +def findringcenter(image,thres=0.2,d=20): + """ + Takes a numpy array corresponding to a tiff image and finds the pixel index of the center of the inner ring. + + Parameters: + image: numpy array of tiff image + d: integer corresponding distance around image center (distinct from inner ring center) + Returns: + Pixel indices of an estimate of center point of inner ring. + + + """ + thresh=thres*np.max(image) + r,c=findcenter(image) + + #take 10 slices within a range of 'd' away from the cetner of the image and puts them into a list + slyce1=Slyce('v',c-d,image) + slyce2=Slyce('v',c+d,image) + slyce3=Slyce('v',c,image) + slyce4=Slyce('v',c-d/2,image) + slyce5=Slyce('v',c+d/2,image) + + slyce6=Slyce('h',r-d,image) + slyce7=Slyce('h',r+d,image) + slyce8=Slyce('h',r,image) + slyce9=Slyce('h',r+d/2,image) + slyce10=Slyce('h',r-d/2,image) + slyces=[slyce1, slyce2, slyce3, slyce4, slyce5, slyce6, slyce7, slyce8, slyce9, slyce10] + + + + points2click=[] + for slyce in slyces: + clickpoints(slyce,thresh) + if slyce.direction=='v': + for pixel in slyce.pixels: + points2click.append([pixel,slyce.index]) + if slyce.direction=='h': + for pixel in slyce.pixels: + points2click.append([slyce.index,pixel]) + + #coords keeps track of the coordinates that are tested to find the center of the inner ring + coords=[] + #spread keeps track of the range of point distances from the tested point to the points that have been identified on the center ring + spread=[] + + #the center of the ring is determined by testing a range of points around the center of the image and calculating the distances + #between that point and the points that have been identified on the inner ring through the clickpoints() function + #the point that has the smallest range of distances is identified as the center + for row in range (int(r-3*d),int(r+3*d)): + for col in range (int(c-3*d),int(c+3*d)): + pointdist=[] + for point in points2click: + pointdist.append(finddistance([row,col],point)) + spread.append(max(pointdist)-min(pointdist)) + coords.append([row,col]) + + center=coords[spread.index(min(spread))] + + return center + + +def zerocross(lines): + """ + Takes in 1-D numpy array and determines array indices corresponding to points where an adjacent value has a different sign and where the difference between the two values before and after zero-crossing exceeds a certain threshold + + Parameters: + lines: 1-D numpy array + Returns: + z: list of indices in lines that correspond to both a change in sign of adjacent values and significant difference in these values + + """ + z=[] + for i in range(1,len(lines)-1): + if (np.sign(lines[i]) == -1) and (np.sign(lines[i-1]) in [0,1]): + if np.abs(lines[i]-lines[i-1])>np.max(lines)/80.0: + z.append(i) + return z + +def findrings(image): + + """ + Takes a numpy array representing a tiff image and returns the pixel indices of the center point and points on rings 0,1,2,5 + + Parameters: + image: numpy array of tiff image + Returns: + pixel index of point on center ring and pixel indices of points on rings 0,1,2,5 + + """ + center_pt=findringcenter(image) + + + #create horizontal slyces from the center of the inner ring (but use 5 and find the median value to avoid issues with hot pixels) + cs1=Slyce('h',center_pt[0]-2,image) + cs2=Slyce('h',center_pt[0]-1,image) + cs3=Slyce('h',center_pt[0],image) + cs4=Slyce('h',center_pt[0]+1,image) + cs5=Slyce('h',center_pt[0]+2,image) + + cs=[cs1,cs2,cs3,cs4,cs5] + + value1=cs1.data + value2=cs2.data + value3=cs3.data + value4=cs4.data + value5=cs5.data + value_cs=np.zeros(np.shape(value1)[0]) + + #create list of median values in horizontal center slyce to avoid hot pixel values + for i, blank in enumerate(value_cs): + value_cs[i]=np.median([value1[i],value2[i],value3[i],value4[i],value5[i]]) + + #take half of center slyce from the center of the inner ring out + halfcs=list(value_cs[(center_pt[1]):]) + + #find derivative of values on the slyce + dx=1 + deriv=list(np.gradient(halfcs,dx)) + + + rings=zerocross(deriv) + clickpts=[] + firstpoint=[center_pt[0],rings[0]+center_pt[1]] + + #tests a series of conditions to determine if there is a peak at a certain index in 1D array + #tests to make sure that peak is real and not noise/small fluctuation + if (halfcs[rings[0]]>0.7*np.max(halfcs)) or (halfcs[rings[0]-1]>0.7*np.max(halfcs)) or (halfcs[rings[0]+1]>0.7*np.max(halfcs)): + clickpts.append(rings[0]) + clickpts.append(rings[1]) + clickpts.append(rings[2]) + clickpts.append(rings[5]) + else: + clickpts.append(rings[1]) + clickpts.append(rings[2]) + clickpts.append(rings[3]) + clickpts.append(rings[6]) + + + #find indices of points that shoudl be "clicked" in tiff image array + points_image=[] + for clickpt in clickpts: + points_image.append([center_pt[0],clickpt+center_pt[1]]) + + print(points_image) + print(center_pt) + + return points_image, center_pt + +findrings(imarray) From 4d41990e10347ebccd77e3e29f933dcd5090c948 Mon Sep 17 00:00:00 2001 From: Maddison Brod Date: Thu, 21 Mar 2019 14:13:21 -0400 Subject: [PATCH 05/14] combined calib4.py and calib5.py into one file calib4.py, and made visualization portion conditional --- xpdtools/calib4.py | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/xpdtools/calib4.py b/xpdtools/calib4.py index 9a23052..672bb9c 100644 --- a/xpdtools/calib4.py +++ b/xpdtools/calib4.py @@ -175,7 +175,6 @@ def findrings(image): """ center_pt=findringcenter(image) - print(center_pt) #create horizontal slyces from the center of the inner ring (but use 5 and find the median value to avoid issues with hot pixels) cs1=Slyce('h',center_pt[0]-2,image) @@ -231,32 +230,34 @@ def findrings(image): print(points_image) print(center_pt) - - return points_image, center_pt points_image,center_pt=findrings(imarray) +#vis=True +vis=False -new_img = np.empty((imarray.shape[0],imarray.shape[1],4)) -max_img = np.amax(imarray) -min_img = np.amin(imarray) -for i, row in enumerate(new_img): - for j, elem in enumerate(row): - old_val = imarray[i][j] - scaled = (old_val-min_img)/(max_img-min_img) - new_img[i][j] = np.array([1.0-scaled, 1.0-scaled, 1.0-scaled, 1.0]) +if vis: + + new_img = np.empty((imarray.shape[0],imarray.shape[1],4)) + max_img = np.amax(imarray) + min_img = np.amin(imarray) + for i, row in enumerate(new_img): + for j, elem in enumerate(row): + old_val = imarray[i][j] + scaled = (old_val-min_img)/(max_img-min_img) + new_img[i][j] = np.array([1.0-scaled, 1.0-scaled, 1.0-scaled, 1.0]) + + for point_image in points_image: + for i in range(-2,2): + for j in range(-2,2): + new_img[point_image[0]+i][point_image[1]+j]=np.array([1.0, 0.0, 0.0, 1.0]) -for point_image in points_image: for i in range(-2,2): for j in range(-2,2): - new_img[point_image[0]+i][point_image[1]+j]=np.array([1.0, 0.0, 0.0, 1.0]) - -for i in range(-2,2): - for j in range(-2,2): - new_img[center_pt[0]+i][center_pt+j]=np.array([1.0, 0.0, 0.0, 1.0]) + new_img[center_pt[0]+i][center_pt[1]+j]=np.array([1.0, 0.0, 0.0, 1.0]) -plt.imshow(new_img) -plt.show() + plt.imshow(new_img) + plt.show() From 3447f37195280f044dc452c5d6c0820e25f3f067 Mon Sep 17 00:00:00 2001 From: Maddison Brod Date: Fri, 22 Mar 2019 16:06:50 -0400 Subject: [PATCH 06/14] removed filename from calib4.py and created test function in test_ringfinding.py --- xpdtools/calib4.py | 23 +++++++++-------------- xpdtools/tests/test_ringfinding.py | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 xpdtools/tests/test_ringfinding.py diff --git a/xpdtools/calib4.py b/xpdtools/calib4.py index 672bb9c..0d8bb5c 100644 --- a/xpdtools/calib4.py +++ b/xpdtools/calib4.py @@ -7,21 +7,17 @@ mpl.use('TkAgg') import matplotlib.pyplot as plt -filename = 'Ni_pin_20181101-075909_973de2_0001.tiff' - - -imarray=tf.imread(filename) class Slyce(): def __init__(self,direction,index,image): self.direction=direction - self.index=index + self.index=int(index) self.pixels=[] if direction=='v': - self.data=list(image[:,index]) + self.data=list(image[:, self.index]) if direction=='h': - self.data=list(image[index,:]) + self.data=list(image[self.index,:]) def findcenter(image): """ @@ -78,11 +74,11 @@ def finddistance(a,b): np.float64 corresponding to distance between two points """ - dif1=a[1]-b[1] - dif2=a[0]-b[0] - d_sq=np.abs(dif1**2+dif2**2) + dif1=a[1]-b[1] + dif2=a[0]-b[0] + d_sq=np.abs(dif1**2+dif2**2) - return np.sqrt(d_sq) + return np.sqrt(d_sq) def findringcenter(image,thres=0.2,d=20): """ @@ -134,7 +130,7 @@ def findringcenter(image,thres=0.2,d=20): #between that point and the points that have been identified on the inner ring through the clickpoints() function #the point that has the smallest range of distances is identified as the center for row in range (int(r-3*d),int(r+3*d)): - for col in range (int(c-3*d),int(c+3*d)): + for col in range (int(c-3*d),int(c+3*d)): pointdist=[] for point in points2click: pointdist.append(finddistance([row,col],point)) @@ -158,7 +154,7 @@ def zerocross(lines): """ z=[] for i in range(1,len(lines)-1): - if (np.sign(lines[i]) == -1) and (np.sign(lines[i-1]) in [0,1]): + if (np.sign(lines[i]) == -1) and (np.sign(lines[i-1]) in [0,1]): if np.abs(lines[i]-lines[i-1])>np.max(lines)/80.0: z.append(i) return z @@ -232,7 +228,6 @@ def findrings(image): return points_image, center_pt -points_image,center_pt=findrings(imarray) #vis=True vis=False diff --git a/xpdtools/tests/test_ringfinding.py b/xpdtools/tests/test_ringfinding.py new file mode 100644 index 0000000..b42a9a9 --- /dev/null +++ b/xpdtools/tests/test_ringfinding.py @@ -0,0 +1,19 @@ +from xpdtools.calib4 import findrings + +import tifffile as tf + +from pkg_resources import resource_filename as rs_fn + +import os + +DATA_DIR=rs_fn("xpdtools", "data/") + +filename="Ni_pin_20181101-075909_973de2_0001.tiff" + +impath=os.path.join(DATA_DIR, filename) + +imarray=tf.imread(impath) + +def test_ringfinding(): + center_pt, pointsimage=findrings(imarray) + #assert center_pt==right_center \ No newline at end of file From b8dc4bf749b37b95013a8a4af4ab314668409692 Mon Sep 17 00:00:00 2001 From: Maddison Brod Date: Tue, 9 Apr 2019 10:29:42 -0400 Subject: [PATCH 07/14] modified test_ringfinding with decorator so that it tests the findrings() function on 5 Ni tiff images. This version of the test function tests whether or not the x and y pixel coordinates of the center point given by findrings() are within 10 pixels of that given by paiFAI --- xpdtools/tests/test_ringfinding.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/xpdtools/tests/test_ringfinding.py b/xpdtools/tests/test_ringfinding.py index b42a9a9..449c789 100644 --- a/xpdtools/tests/test_ringfinding.py +++ b/xpdtools/tests/test_ringfinding.py @@ -2,18 +2,28 @@ import tifffile as tf +import pyFAI + from pkg_resources import resource_filename as rs_fn import os +import pytest DATA_DIR=rs_fn("xpdtools", "data/") -filename="Ni_pin_20181101-075909_973de2_0001.tiff" - -impath=os.path.join(DATA_DIR, filename) - -imarray=tf.imread(impath) - -def test_ringfinding(): - center_pt, pointsimage=findrings(imarray) - #assert center_pt==right_center \ No newline at end of file +filename=["Ni_onTape_forSlimes_andWahsers_20180812-234250_fe70b9_0001.tiff", 'Ni_calib_20180811-191034_63e554_0001.tiff', 'Ni_pin_20181101-075909_973de2_0001.tiff', 'Ni_calib_20180920-230956_0eedc4_0001.tiff','Ni_calib_20180923-133223_c2a848_0001.tiff'] + + +@pytest.mark.parametrize("filename,poni", [(filename[0], os.path.splitext(filename[0])[0]+'.edf'), + (filename[1], os.path.splitext(filename[1])[0]+'.edf'), + (filename[2], os.path.splitext(filename[2])[0]+'.edf'), + (filename[3], os.path.splitext(filename[3])[0]+'.edf'), + (filename[4], os.path.splitext(filename[4])[0]+'.edf') ]) +def test_ringfinding(filename, poni): + impath=os.path.join(DATA_DIR, filename) + imarray = tf.imread(impath) + pointsimage, center_pt=findrings(imarray) + d=pyFAI.load(poni) + centerx=d.getFit2D()['centerX'] + centery=d.getFit2D()['centerY'] + assert abs(center_pt[1]-centerx)<=10 and abs(center_pt[0]-centery)<=10 \ No newline at end of file From d07e4fbc1eba7ee217cd558503f7bb0db3155b01 Mon Sep 17 00:00:00 2001 From: Maddison Brod Date: Fri, 12 Apr 2019 21:15:43 -0400 Subject: [PATCH 08/14] modified test_ringfinding.py by adding two test functions: one that tests if findrings() raises IndexError if input is 1D numpy array and one that determines if it raises an attributeError if given an input that is not a numpy array --- xpdtools/tests/test_ringfinding.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/xpdtools/tests/test_ringfinding.py b/xpdtools/tests/test_ringfinding.py index 449c789..0aa8ad9 100644 --- a/xpdtools/tests/test_ringfinding.py +++ b/xpdtools/tests/test_ringfinding.py @@ -1,4 +1,5 @@ from xpdtools.calib4 import findrings +import numpy as np import tifffile as tf @@ -11,14 +12,14 @@ DATA_DIR=rs_fn("xpdtools", "data/") -filename=["Ni_onTape_forSlimes_andWahsers_20180812-234250_fe70b9_0001.tiff", 'Ni_calib_20180811-191034_63e554_0001.tiff', 'Ni_pin_20181101-075909_973de2_0001.tiff', 'Ni_calib_20180920-230956_0eedc4_0001.tiff','Ni_calib_20180923-133223_c2a848_0001.tiff'] +filename=["Ni_onTape_forSlimes_andWahsers_20180812-234250_fe70b9_0001.tiff", 'Ni_calib_20180811-191034_63e554_0001.tiff', 'Ni_pin_20181101-075909_973de2_0001.tiff', 'Ni_calib_20180920-230956_0eedc4_0001.tiff','Ni_calib_20180923-133223_c2a848_0001.tiff', 'Ni_20180922-001850_2a1c3b_0001.tiff'] @pytest.mark.parametrize("filename,poni", [(filename[0], os.path.splitext(filename[0])[0]+'.edf'), (filename[1], os.path.splitext(filename[1])[0]+'.edf'), (filename[2], os.path.splitext(filename[2])[0]+'.edf'), (filename[3], os.path.splitext(filename[3])[0]+'.edf'), - (filename[4], os.path.splitext(filename[4])[0]+'.edf') ]) + (filename[4], os.path.splitext(filename[4])[0]+'.edf'),(filename[5], os.path.splitext(filename[5])[0]+'.edf') ]) def test_ringfinding(filename, poni): impath=os.path.join(DATA_DIR, filename) imarray = tf.imread(impath) @@ -26,4 +27,13 @@ def test_ringfinding(filename, poni): d=pyFAI.load(poni) centerx=d.getFit2D()['centerX'] centery=d.getFit2D()['centerY'] - assert abs(center_pt[1]-centerx)<=10 and abs(center_pt[0]-centery)<=10 \ No newline at end of file + assert abs(center_pt[1]-centerx)<=8 and abs(center_pt[0]-centery)<=8 + +def test_2Darray(): + with pytest.raises(IndexError): + findrings(np.random.rand(2048)) + +def test_inputtype(): + with pytest.raises(AttributeError): + findrings([1,2,3]) + From c24d4ebbf43154c72a05e98d0ffbe05fd6c44fb4 Mon Sep 17 00:00:00 2001 From: Maddison Brod Date: Tue, 16 Apr 2019 16:27:21 -0400 Subject: [PATCH 09/14] modified findrings in calib4.py so that is raises a RuntimeError if input is not ndarray and modified test_ringfinding by adding a test function to test whether or not runtime error is raised when input is not ndarray --- xpdtools/calib4.py | 4 ++++ xpdtools/tests/test_ringfinding.py | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/xpdtools/calib4.py b/xpdtools/calib4.py index 0d8bb5c..2fc9e0a 100644 --- a/xpdtools/calib4.py +++ b/xpdtools/calib4.py @@ -170,6 +170,10 @@ def findrings(image): pixel index of point on center ring and pixel indices of points on rings 0,1,2,5 """ + + if not isinstance(image,np.ndarray): + raise RuntimeError('input type must be ndarray') + center_pt=findringcenter(image) #create horizontal slyces from the center of the inner ring (but use 5 and find the median value to avoid issues with hot pixels) diff --git a/xpdtools/tests/test_ringfinding.py b/xpdtools/tests/test_ringfinding.py index 0aa8ad9..eac0b63 100644 --- a/xpdtools/tests/test_ringfinding.py +++ b/xpdtools/tests/test_ringfinding.py @@ -33,7 +33,8 @@ def test_2Darray(): with pytest.raises(IndexError): findrings(np.random.rand(2048)) -def test_inputtype(): - with pytest.raises(AttributeError): - findrings([1,2,3]) +@pytest.mark.parametrize("wrong_input",[[1,2,3],3,2.7,(2,3),'banana']) +def test_inputtype(wrong_input): + with pytest.raises(RuntimeError): + findrings(wrong_input) From 684e1dffaee3834e3220eb9e8a6dd4afa1a0817e Mon Sep 17 00:00:00 2001 From: "Christopher J. Wright" Date: Fri, 3 May 2019 10:02:23 -0400 Subject: [PATCH 10/14] cleaning --- setup.py | 2 +- xpdtools/__init__.py | 2 +- xpdtools/calib2.py | 209 ---------------- xpdtools/calib3.py | 259 -------------------- xpdtools/calib4.py | 377 +++++++++++++++-------------- xpdtools/calib5.py | 232 ------------------ xpdtools/tests/test_pipelines.py | 5 +- xpdtools/tests/test_ringfinding.py | 62 +++-- 8 files changed, 242 insertions(+), 906 deletions(-) delete mode 100644 xpdtools/calib2.py delete mode 100644 xpdtools/calib3.py delete mode 100644 xpdtools/calib5.py diff --git a/setup.py b/setup.py index 4591226..54e85d1 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="xpdtools", - version='0.6.0', + version='0.8.0', packages=find_packages(), description="data processing module", zip_safe=False, diff --git a/xpdtools/__init__.py b/xpdtools/__init__.py index ef7eb44..906d362 100644 --- a/xpdtools/__init__.py +++ b/xpdtools/__init__.py @@ -1 +1 @@ -__version__ = '0.6.0' +__version__ = "0.6.0" diff --git a/xpdtools/calib2.py b/xpdtools/calib2.py deleted file mode 100644 index 39dccfc..0000000 --- a/xpdtools/calib2.py +++ /dev/null @@ -1,209 +0,0 @@ - -import numpy as np - -import tifffile as tf -import matplotlib as mpl - -mpl.use('TkAgg') -import matplotlib.pyplot as plt - - -filename = 'Ni_pin_20181101-075909_973de2_0001.tiff' - -imarray=tf.imread(filename) -print(imarray) - -class Slyce(): - def __init__(self,direction,index,imarray): - self.direction=direction - self.index=index - self.pixels=[] - if direction=='v': - self.data=list(imarray[:,index]) - if direction=='h': - self.data=list(imarray[index,:]) - -def findringcenter(image,thres=.20,d=20): - - def findcenter(image): - s=image.shape - # number of rows divided by 2 - r=s[0]/2 - # number of columns divided by 2 - c=s[1]/2 - return r,c - - r,c=findcenter(image) - - slyce1=Slyce('v',c-d,image) - slyce2=Slyce('v',c+d,image) - slyce3=Slyce('v',c,image) - slyce4=Slyce('v',c-d/2,image) - slyce5=Slyce('v',c+d/2,image) - - slyce6=Slyce('h',r-d,image) - slyce7=Slyce('h',r+d,image) - slyce8=Slyce('h',r,image) - slyce9=Slyce('h',r+d/2,image) - slyce10=Slyce('h',r-d/2,image) - slyces=[slyce1, slyce2, slyce3, slyce4, slyce5, slyce6, slyce7, slyce8, slyce9, slyce10] - - def findthreshold(image,thres): - return thres*np.max(image) - - thresh=findthreshold(image,thres) - - def clickpoints(slyce,thresh): - p1=np.argmax(slyce.data) - p2=np.argmax(slyce.data[:p1]+slyce.data[p1+1:]) - - if slyce.data[p2]>=thresh: - slyce.pixels.append(p1) - slyce.pixels.append(p2) - - elif slyce.data[p1]>=thresh: - - slyce.pixels.append(p1) - - points2click=[] - for slyce in slyces: - clickpoints(slyce,thresh) - if slyce.direction=='v': - for pixel in slyce.pixels: - points2click.append([pixel,slyce.index]) - if slyce.direction=='h': - for pixel in slyce.pixels: - points2click.append([slyce.index,pixel]) - - highlight=np.mean(image)*.9 - image_new=image - - def finddistance(a,b): - dif1=a[1]-b[1] - dif2=a[0]-b[0] - d_sq=np.abs(dif1**2+dif2**2) - return np.sqrt(d_sq) - - - #f, ax = plt.subplots(1) - #ax.imshow(image) - ring_mask=np.ones_like(image,dtype=bool) - - - for point in points2click: - #ax.scatter(point[0],point[1]) - ring_mask[point[0],point[1]]=False - image_new[point[0],point[1]]=0 - - coords=[] - spread=[] - for row in range (int(r-3*d),int(r+3*d)): - for col in range (int(c-3*d),int(c+3*d)): - pointdist=[] - for point in points2click: - pointdist.append(finddistance([row,col],point)) - spread.append(max(pointdist)-min(pointdist)) - coords.append([row,col]) - - center=coords[spread.index(min(spread))] - return center - print(center) - - - -#take a horizontal cut out from the center of the ring to the end of the image -#row is constant and column index goes from col index of center to end - -def findrings(image): - center=findringcenter(image) - cs1=Slyce('h',center[0]-2,image) - cs2=Slyce('h',center[0]-1,image) - cs3=Slyce('h',center[0],image) - cs4=Slyce('h',center[0]+1,image) - cs5=Slyce('h',center[0]+2,image) - - cs=[cs1,cs2,cs3,cs4,cs5] - - value1=cs1.data - value2=cs2.data - value3=cs3.data - value4=cs4.data - value5=cs5.data - value_cs=np.zeros(np.shape(value1)[0]) - for i, blank in enumerate(value_cs): - value_cs[i]=np.median([value1[i],value2[i],value3[i],value4[i],value5[i]]) - - - halfcs=list(value_cs[(center[1]):]) - - #find derivative of values on the slyce - dx=1 - deriv=list(np.gradient(halfcs,dx)) - - #creates a function that finds the indices of a list where the derivative changes sign - def zerocross(lines): - z=[] - for i in range(1,len(lines)-1): - if (np.sign(lines[i]) == -1) and (np.sign(lines[i-1]) in [0,1]): - if np.abs(lines[i]-lines[i-1])>np.max(lines)/80.0: - z.append(i) - return z - - - center=findringcenter(image) - rings=zerocross(deriv) - clickpts=[] - firstpoint=[center[0],rings[0]+center[1]] - - if (halfcs[rings[0]]>0.7*np.max(halfcs)) or (halfcs[rings[0]-1]>0.7*np.max(halfcs)) or (halfcs[rings[0]+1]>0.7*np.max(halfcs)): - clickpts.append(rings[0]) - clickpts.append(rings[1]) - clickpts.append(rings[2]) - clickpts.append(rings[5]) - else: - clickpts.append(rings[1]) - clickpts.append(rings[2]) - clickpts.append(rings[3]) - clickpts.append(rings[6]) - - - - points_image=[] - for clickpt in clickpts: - points_image.append([center[0],clickpt+center[1]]) - - print(points_image) - - plt.plot(range(0,len(halfcs)), halfcs) - plt.scatter(range(0,len(deriv)),deriv) - plt.plot(deriv) - plt.plot(np.zeros(len(deriv))) - for clickpt in clickpts: - plt.scatter(clickpt,0,color='r') - plt.show() - - - new_img = np.empty((image.shape[0],image.shape[1],4)) - max_img = np.amax(image) - min_img = np.amin(image) - for i, row in enumerate(new_img): - for j, elem in enumerate(row): - old_val = image[i][j] - scaled = (old_val-min_img)/(max_img-min_img) - new_img[i][j] = np.array([1.0-scaled, 1.0-scaled, 1.0-scaled, 1.0]) - - for point_image in points_image: - for i in range(-2,2): - for j in range(-2,2): - new_img[point_image[0]+i][point_image[1]+j]=np.array([1.0, 0.0, 0.0, 1.0]) - - - - plt.imshow(new_img) - plt.show() - return points_image - - -findrings(imarray) - - diff --git a/xpdtools/calib3.py b/xpdtools/calib3.py deleted file mode 100644 index 9a1e72f..0000000 --- a/xpdtools/calib3.py +++ /dev/null @@ -1,259 +0,0 @@ - -import numpy as np - -import tifffile as tf - - - -filename = 'Ni_pin_20181101-075909_973de2_0001.tiff' - - -imarray=tf.imread(filename) - - - -def findrings(image): - - """ - Takes a numpy array representing a tiff image and returns the pixel indices of the center point and points on rings 0,1,2,5 - - Parameters: - image: numpy array of tiff image - Returns: - pixel index of point on center ring and pixel indices of points on rings 0,1,2,5 - - """ - - - class Slyce(): - def __init__(self,direction,index,image): - self.direction=direction - self.index=index - self.pixels=[] - if direction=='v': - self.data=list(image[:,index]) - if direction=='h': - self.data=list(image[index,:]) - - - def findringcenter(image,thres=0.2,d=20): - """ - Takes a numpy array corresponding to a tiff image and finds the pixel index of the center of the inner ring - - Parameters: - image: numpy array of tiff image - thres: float representing percentage of image maximum that could be considered a value of data on inner ring - d: integer corresponding distance around image center (distinct from inner ring center) - Returns: - Pixel indices of an estimate of center point of inner ring. - - """ - - def findcenter(image): - """ - Takes numpy array corresponding to a tiff image and finds the pixel indices corresponding to the center of the image (not the center of the rings) - - Parameters: numpy array of tiff image - image: numpy array of tiff image - - Returns: - r: integer row index of image center - c: integer column index of image center - - """ - - s=image.shape - # number of rows divided by 2 - r=s[0]/2 - # number of columns divided by 2 - c=s[1]/2 - return r,c - - r,c=findcenter(image) - - #take 10 slices within a range of 'd' away from the cetner of the image and puts them into a list - slyce1=Slyce('v',c-d,image) - slyce2=Slyce('v',c+d,image) - slyce3=Slyce('v',c,image) - slyce4=Slyce('v',c-d/2,image) - slyce5=Slyce('v',c+d/2,image) - - slyce6=Slyce('h',r-d,image) - slyce7=Slyce('h',r+d,image) - slyce8=Slyce('h',r,image) - slyce9=Slyce('h',r+d/2,image) - slyce10=Slyce('h',r-d/2,image) - slyces=[slyce1, slyce2, slyce3, slyce4, slyce5, slyce6, slyce7, slyce8, slyce9, slyce10] - - def findthreshold(image,thres): - """ - Takes in a numpy array corresponding to tiff image and a percentage of the maximum pixel value and returns the maximum pixel value. - - Parameters: - image: numpy array of tiff image - thres: float representing percentage of image maximum that could be considered a value of data on inner ring - - Returns: - float corresponding to a percentage of the maximum value in image numpy array - - """ - - return thres*np.max(image) - - thresh=findthreshold(image,thres) - - # clickpoints takes a slyce and the calculated threshold as inputs and returns the index (in a 1-d array) of 1 or two points - #that are on the INNER ring - def clickpoints(slyce,thresh): - """ - Takes a slyce and threshold value and adds to the "pixels" attribute of Slyce class the indices of 1 or 2 points (in the 1-D slyce array) that correspond to points on the inner ring. - - Parameters: - slyce: 1-D numpy array of image data corresponding to a vertical or horizontal slice through the tiff image - thresh: np.float64 corresponding to a percentage of the maximum value in image numpy array - - """ - p1=np.argmax(slyce.data) - p2=np.argmax(slyce.data[:p1]+slyce.data[p1+1:]) - - #if statement to determine if max points are large enough to actually be on center ring. If so, the pixel attribute of Slyce is modified to include these indices - if slyce.data[p2]>=thresh: - slyce.pixels.append(p1) - slyce.pixels.append(p2) - - elif slyce.data[p1]>=thresh: - - slyce.pixels.append(p1) - - points2click=[] - for slyce in slyces: - clickpoints(slyce,thresh) - if slyce.direction=='v': - for pixel in slyce.pixels: - points2click.append([pixel,slyce.index]) - if slyce.direction=='h': - for pixel in slyce.pixels: - points2click.append([slyce.index,pixel]) - - #finds distance between two points - def finddistance(a,b): - """ - Finds distance between two points. - - Parameters: - a: numpy array, list, or tuple containing a coordinates, where a[0] contains a row index and a[1] contains col index - b: numpy array, list, or tuple containing a coordinates, where a[0] contains a row index and a[1] contains col index - - Returns: - np.float64 corresponding to distance between two points - """ - - dif1=a[1]-b[1] - dif2=a[0]-b[0] - d_sq=np.abs(dif1**2+dif2**2) - - return np.sqrt(d_sq) - - #coords keeps track of the coordinates that are tested to find the center of the inner ring - coords=[] - #spread keeps track of the range of point distances from the tested point to the points that have been identified on the - #center ring - spread=[] - - #the center of the ring is determined by testing a range of points around the center of the image and calculating the distances - #between that point and the points that have been identified on the inner ring through the clickpoints() function - #the point that has the smallest range of distances is identified as the center - for row in range (int(r-3*d),int(r+3*d)): - for col in range (int(c-3*d),int(c+3*d)): - pointdist=[] - for point in points2click: - pointdist.append(finddistance([row,col],point)) - spread.append(max(pointdist)-min(pointdist)) - coords.append([row,col]) - - center=coords[spread.index(min(spread))] - - return center - - - center_pt=findringcenter(image) - - #create horizontal slyces from the center of the inner ring (but use 5 and find the median value to avoid issues with hot pixels) - cs1=Slyce('h',center_pt[0]-2,image) - cs2=Slyce('h',center_pt[0]-1,image) - cs3=Slyce('h',center_pt[0],image) - cs4=Slyce('h',center_pt[0]+1,image) - cs5=Slyce('h',center_pt[0]+2,image) - - cs=[cs1,cs2,cs3,cs4,cs5] - - value1=cs1.data - value2=cs2.data - value3=cs3.data - value4=cs4.data - value5=cs5.data - value_cs=np.zeros(np.shape(value1)[0]) - - #create list of median values in horizontal center slyce to avoid hot pixel values - for i, blank in enumerate(value_cs): - value_cs[i]=np.median([value1[i],value2[i],value3[i],value4[i],value5[i]]) - - #take half of center slyce from the center of the inner ring out - halfcs=list(value_cs[(center_pt[1]):]) - - #find derivative of values on the slyce - dx=1 - deriv=list(np.gradient(halfcs,dx)) - - - def zerocross(lines): - """ - Takes in 1-D numpy array and determines array indices corresponding to points where an adjacent value has a different sign and where the difference between the two values before and after zero-crossing exceeds a certain threshold - - Parameters: - lines: 1-D numpy array - Returns: - z: list of indices in lines that correspond to both a change in sign of adjacent values and significant difference in these values - - """ - z=[] - for i in range(1,len(lines)-1): - if (np.sign(lines[i]) == -1) and (np.sign(lines[i-1]) in [0,1]): - if np.abs(lines[i]-lines[i-1])>np.max(lines)/80.0: - z.append(i) - return z - - - - rings=zerocross(deriv) - clickpts=[] - firstpoint=[center_pt[0],rings[0]+center_pt[1]] - - #tests a series of conditions to determine if there is a peak at a certain index in 1D array - #tests to make sure that peak is real and not noise/small fluctuation - if (halfcs[rings[0]]>0.7*np.max(halfcs)) or (halfcs[rings[0]-1]>0.7*np.max(halfcs)) or (halfcs[rings[0]+1]>0.7*np.max(halfcs)): - clickpts.append(rings[0]) - clickpts.append(rings[1]) - clickpts.append(rings[2]) - clickpts.append(rings[5]) - else: - clickpts.append(rings[1]) - clickpts.append(rings[2]) - clickpts.append(rings[3]) - clickpts.append(rings[6]) - - - #find indices of points that shoudl be "clicked" in tiff image array - points_image=[] - for clickpt in clickpts: - points_image.append([center_pt[0],clickpt+center_pt[1]]) - - print(points_image) - print(center_pt) - - - - return points_image - - -findrings(imarray) \ No newline at end of file diff --git a/xpdtools/calib4.py b/xpdtools/calib4.py index 2fc9e0a..9ab9d12 100644 --- a/xpdtools/calib4.py +++ b/xpdtools/calib4.py @@ -4,23 +4,23 @@ import matplotlib as mpl -mpl.use('TkAgg') +mpl.use("TkAgg") import matplotlib.pyplot as plt +class Slyce: + def __init__(self, direction, index, image): + self.direction = direction + self.index = int(index) + self.pixels = [] + if direction == "v": + self.data = list(image[:, self.index]) + if direction == "h": + self.data = list(image[self.index, :]) -class Slyce(): - def __init__(self,direction,index,image): - self.direction=direction - self.index=int(index) - self.pixels=[] - if direction=='v': - self.data=list(image[:, self.index]) - if direction=='h': - self.data=list(image[self.index,:]) def findcenter(image): - """ + """ Takes numpy array corresponding to a tiff image and finds the pixel indices corresponding to the center of the image (not the center of the rings) Parameters: numpy array of tiff image @@ -32,16 +32,16 @@ def findcenter(image): """ - s=image.shape - # number of rows divided by 2 - r=s[0]/2 - # number of columns divided by 2 - c=s[1]/2 - return r,c + s = image.shape + # number of rows divided by 2 + r = s[0] / 2 + # number of columns divided by 2 + c = s[1] / 2 + return r, c -def clickpoints(slyce,thresh): - """ +def clickpoints(slyce, thresh): + """ Takes a slyce and threshold value and adds to the "pixels" attribute of Slyce class the indices of 1 or 2 points (in the 1-D slyce array) that correspond to points on the inner ring. Parameters: @@ -49,21 +49,21 @@ def clickpoints(slyce,thresh): thresh: np.float64 corresponding to a percentage of the maximum value in image numpy array """ - p1=np.argmax(slyce.data) - p2=np.argmax(slyce.data[:p1]+slyce.data[p1+1:]) + p1 = np.argmax(slyce.data) + p2 = np.argmax(slyce.data[:p1] + slyce.data[p1 + 1 :]) - #if statement to determine if max points are large enough to actually be on center ring. If so, the pixel attribute of Slyce is modified to include these indices - if slyce.data[p2]>=thresh: - slyce.pixels.append(p1) - slyce.pixels.append(p2) + # if statement to determine if max points are large enough to actually be on center ring. If so, the pixel attribute of Slyce is modified to include these indices + if slyce.data[p2] >= thresh: + slyce.pixels.append(p1) + slyce.pixels.append(p2) - elif slyce.data[p1]>=thresh: + elif slyce.data[p1] >= thresh: + slyce.pixels.append(p1) - slyce.pixels.append(p1) -def finddistance(a,b): - """ +def finddistance(a, b): + """ Finds distance between two points. Parameters: @@ -74,14 +74,15 @@ def finddistance(a,b): np.float64 corresponding to distance between two points """ - dif1=a[1]-b[1] - dif2=a[0]-b[0] - d_sq=np.abs(dif1**2+dif2**2) - - return np.sqrt(d_sq) + dif1 = a[1] - b[1] + dif2 = a[0] - b[0] + d_sq = np.abs(dif1 ** 2 + dif2 ** 2) -def findringcenter(image,thres=0.2,d=20): - """ + return np.sqrt(d_sq) + + +def findringcenter(image, thres=0.2, d=20): + """ Takes a numpy array corresponding to a tiff image and finds the pixel index of the center of the inner ring. Parameters: @@ -92,58 +93,67 @@ def findringcenter(image,thres=0.2,d=20): """ - thresh=thres*np.max(image) - r,c=findcenter(image) - - #take 10 slices within a range of 'd' away from the cetner of the image and puts them into a list - slyce1=Slyce('v',c-d,image) - slyce2=Slyce('v',c+d,image) - slyce3=Slyce('v',c,image) - slyce4=Slyce('v',c-d/2,image) - slyce5=Slyce('v',c+d/2,image) - - slyce6=Slyce('h',r-d,image) - slyce7=Slyce('h',r+d,image) - slyce8=Slyce('h',r,image) - slyce9=Slyce('h',r+d/2,image) - slyce10=Slyce('h',r-d/2,image) - slyces=[slyce1, slyce2, slyce3, slyce4, slyce5, slyce6, slyce7, slyce8, slyce9, slyce10] - - - - points2click=[] - for slyce in slyces: - clickpoints(slyce,thresh) - if slyce.direction=='v': - for pixel in slyce.pixels: - points2click.append([pixel,slyce.index]) - if slyce.direction=='h': - for pixel in slyce.pixels: - points2click.append([slyce.index,pixel]) - - #coords keeps track of the coordinates that are tested to find the center of the inner ring - coords=[] - #spread keeps track of the range of point distances from the tested point to the points that have been identified on the center ring - spread=[] - - #the center of the ring is determined by testing a range of points around the center of the image and calculating the distances - #between that point and the points that have been identified on the inner ring through the clickpoints() function - #the point that has the smallest range of distances is identified as the center - for row in range (int(r-3*d),int(r+3*d)): - for col in range (int(c-3*d),int(c+3*d)): - pointdist=[] - for point in points2click: - pointdist.append(finddistance([row,col],point)) - spread.append(max(pointdist)-min(pointdist)) - coords.append([row,col]) - - center=coords[spread.index(min(spread))] - - return center + thresh = thres * np.max(image) + r, c = findcenter(image) + + # take 10 slices within a range of 'd' away from the cetner of the image and puts them into a list + slyce1 = Slyce("v", c - d, image) + slyce2 = Slyce("v", c + d, image) + slyce3 = Slyce("v", c, image) + slyce4 = Slyce("v", c - d / 2, image) + slyce5 = Slyce("v", c + d / 2, image) + + slyce6 = Slyce("h", r - d, image) + slyce7 = Slyce("h", r + d, image) + slyce8 = Slyce("h", r, image) + slyce9 = Slyce("h", r + d / 2, image) + slyce10 = Slyce("h", r - d / 2, image) + slyces = [ + slyce1, + slyce2, + slyce3, + slyce4, + slyce5, + slyce6, + slyce7, + slyce8, + slyce9, + slyce10, + ] + + points2click = [] + for slyce in slyces: + clickpoints(slyce, thresh) + if slyce.direction == "v": + for pixel in slyce.pixels: + points2click.append([pixel, slyce.index]) + if slyce.direction == "h": + for pixel in slyce.pixels: + points2click.append([slyce.index, pixel]) + + # coords keeps track of the coordinates that are tested to find the center of the inner ring + coords = [] + # spread keeps track of the range of point distances from the tested point to the points that have been identified on the center ring + spread = [] + + # the center of the ring is determined by testing a range of points around the center of the image and calculating the distances + # between that point and the points that have been identified on the inner ring through the clickpoints() function + # the point that has the smallest range of distances is identified as the center + for row in range(int(r - 3 * d), int(r + 3 * d)): + for col in range(int(c - 3 * d), int(c + 3 * d)): + pointdist = [] + for point in points2click: + pointdist.append(finddistance([row, col], point)) + spread.append(max(pointdist) - min(pointdist)) + coords.append([row, col]) + + center = coords[spread.index(min(spread))] + + return center def zerocross(lines): - """ + """ Takes in 1-D numpy array and determines array indices corresponding to points where an adjacent value has a different sign and where the difference between the two values before and after zero-crossing exceeds a certain threshold Parameters: @@ -152,16 +162,17 @@ def zerocross(lines): z: list of indices in lines that correspond to both a change in sign of adjacent values and significant difference in these values """ - z=[] - for i in range(1,len(lines)-1): - if (np.sign(lines[i]) == -1) and (np.sign(lines[i-1]) in [0,1]): - if np.abs(lines[i]-lines[i-1])>np.max(lines)/80.0: - z.append(i) - return z + z = [] + for i in range(1, len(lines) - 1): + if (np.sign(lines[i]) == -1) and (np.sign(lines[i - 1]) in [0, 1]): + if np.abs(lines[i] - lines[i - 1]) > np.max(lines) / 80.0: + z.append(i) + return z + def findrings(image): - """ + """ Takes a numpy array representing a tiff image and returns the pixel indices of the center point and points on rings 0,1,2,5 Parameters: @@ -169,94 +180,102 @@ def findrings(image): Returns: pixel index of point on center ring and pixel indices of points on rings 0,1,2,5 - """ - - if not isinstance(image,np.ndarray): - raise RuntimeError('input type must be ndarray') - - center_pt=findringcenter(image) - - #create horizontal slyces from the center of the inner ring (but use 5 and find the median value to avoid issues with hot pixels) - cs1=Slyce('h',center_pt[0]-2,image) - cs2=Slyce('h',center_pt[0]-1,image) - cs3=Slyce('h',center_pt[0],image) - cs4=Slyce('h',center_pt[0]+1,image) - cs5=Slyce('h',center_pt[0]+2,image) - - cs=[cs1,cs2,cs3,cs4,cs5] - - value1=cs1.data - value2=cs2.data - value3=cs3.data - value4=cs4.data - value5=cs5.data - value_cs=np.zeros(np.shape(value1)[0]) - - #create list of median values in horizontal center slyce to avoid hot pixel values - for i, blank in enumerate(value_cs): - value_cs[i]=np.median([value1[i],value2[i],value3[i],value4[i],value5[i]]) - - #take half of center slyce from the center of the inner ring out - halfcs=list(value_cs[(center_pt[1]):]) - - #find derivative of values on the slyce - dx=1 - deriv=list(np.gradient(halfcs,dx)) - - - rings=zerocross(deriv) - clickpts=[] - firstpoint=[center_pt[0],rings[0]+center_pt[1]] - - #tests a series of conditions to determine if there is a peak at a certain index in 1D array - #tests to make sure that peak is real and not noise/small fluctuation - if (halfcs[rings[0]]>0.7*np.max(halfcs)) or (halfcs[rings[0]-1]>0.7*np.max(halfcs)) or (halfcs[rings[0]+1]>0.7*np.max(halfcs)): - clickpts.append(rings[0]) - clickpts.append(rings[1]) - clickpts.append(rings[2]) - clickpts.append(rings[5]) - else: - clickpts.append(rings[1]) - clickpts.append(rings[2]) - clickpts.append(rings[3]) - clickpts.append(rings[6]) - - - #find indices of points that shoudl be "clicked" in tiff image array - points_image=[] - for clickpt in clickpts: - points_image.append([center_pt[0],clickpt+center_pt[1]]) - - print(points_image) - print(center_pt) - - return points_image, center_pt - + """ -#vis=True -vis=False + if not isinstance(image, np.ndarray): + raise RuntimeError("input type must be ndarray") + + center_pt = findringcenter(image) + + # create horizontal slyces from the center of the inner ring (but use 5 and find the median value to avoid issues with hot pixels) + cs1 = Slyce("h", center_pt[0] - 2, image) + cs2 = Slyce("h", center_pt[0] - 1, image) + cs3 = Slyce("h", center_pt[0], image) + cs4 = Slyce("h", center_pt[0] + 1, image) + cs5 = Slyce("h", center_pt[0] + 2, image) + + cs = [cs1, cs2, cs3, cs4, cs5] + + value1 = cs1.data + value2 = cs2.data + value3 = cs3.data + value4 = cs4.data + value5 = cs5.data + value_cs = np.zeros(np.shape(value1)[0]) + + # create list of median values in horizontal center slyce to avoid hot pixel values + for i, blank in enumerate(value_cs): + value_cs[i] = np.median( + [value1[i], value2[i], value3[i], value4[i], value5[i]] + ) + + # take half of center slyce from the center of the inner ring out + halfcs = list(value_cs[(center_pt[1]) :]) + + # find derivative of values on the slyce + dx = 1 + deriv = list(np.gradient(halfcs, dx)) + + rings = zerocross(deriv) + clickpts = [] + firstpoint = [center_pt[0], rings[0] + center_pt[1]] + + # tests a series of conditions to determine if there is a peak at a certain index in 1D array + # tests to make sure that peak is real and not noise/small fluctuation + if ( + (halfcs[rings[0]] > 0.7 * np.max(halfcs)) + or (halfcs[rings[0] - 1] > 0.7 * np.max(halfcs)) + or (halfcs[rings[0] + 1] > 0.7 * np.max(halfcs)) + ): + clickpts.append(rings[0]) + clickpts.append(rings[1]) + clickpts.append(rings[2]) + clickpts.append(rings[5]) + else: + clickpts.append(rings[1]) + clickpts.append(rings[2]) + clickpts.append(rings[3]) + clickpts.append(rings[6]) + + # find indices of points that shoudl be "clicked" in tiff image array + points_image = [] + for clickpt in clickpts: + points_image.append([center_pt[0], clickpt + center_pt[1]]) + + print(points_image) + print(center_pt) + + return points_image, center_pt + + +# vis=True +vis = False if vis: - new_img = np.empty((imarray.shape[0],imarray.shape[1],4)) - max_img = np.amax(imarray) - min_img = np.amin(imarray) - for i, row in enumerate(new_img): - for j, elem in enumerate(row): - old_val = imarray[i][j] - scaled = (old_val-min_img)/(max_img-min_img) - new_img[i][j] = np.array([1.0-scaled, 1.0-scaled, 1.0-scaled, 1.0]) - - for point_image in points_image: - for i in range(-2,2): - for j in range(-2,2): - new_img[point_image[0]+i][point_image[1]+j]=np.array([1.0, 0.0, 0.0, 1.0]) - - for i in range(-2,2): - for j in range(-2,2): - new_img[center_pt[0]+i][center_pt[1]+j]=np.array([1.0, 0.0, 0.0, 1.0]) - - - - plt.imshow(new_img) - plt.show() + new_img = np.empty((imarray.shape[0], imarray.shape[1], 4)) + max_img = np.amax(imarray) + min_img = np.amin(imarray) + for i, row in enumerate(new_img): + for j, elem in enumerate(row): + old_val = imarray[i][j] + scaled = (old_val - min_img) / (max_img - min_img) + new_img[i][j] = np.array( + [1.0 - scaled, 1.0 - scaled, 1.0 - scaled, 1.0] + ) + + for point_image in points_image: + for i in range(-2, 2): + for j in range(-2, 2): + new_img[point_image[0] + i][point_image[1] + j] = np.array( + [1.0, 0.0, 0.0, 1.0] + ) + + for i in range(-2, 2): + for j in range(-2, 2): + new_img[center_pt[0] + i][center_pt[1] + j] = np.array( + [1.0, 0.0, 0.0, 1.0] + ) + + plt.imshow(new_img) + plt.show() diff --git a/xpdtools/calib5.py b/xpdtools/calib5.py deleted file mode 100644 index 8d14ee8..0000000 --- a/xpdtools/calib5.py +++ /dev/null @@ -1,232 +0,0 @@ -import numpy as np - -import tifffile as tf - - -filename = 'Ni_pin_20181101-075909_973de2_0001.tiff' - - -imarray=tf.imread(filename) - - -class Slyce(): - def __init__(self,direction,index,image): - self.direction=direction - self.index=index - self.pixels=[] - if direction=='v': - self.data=list(image[:,index]) - if direction=='h': - self.data=list(image[index,:]) - -def findcenter(image): - """ - Takes numpy array corresponding to a tiff image and finds the pixel indices corresponding to the center of the image (not the center of the rings) - - Parameters: numpy array of tiff image - image: numpy array of tiff image - - Returns: - r: integer row index of image center - c: integer column index of image center - - """ - - s=image.shape - # number of rows divided by 2 - r=s[0]/2 - # number of columns divided by 2 - c=s[1]/2 - return r,c - - -def clickpoints(slyce,thresh): - """ - Takes a slyce and threshold value and adds to the "pixels" attribute of Slyce class the indices of 1 or 2 points (in the 1-D slyce array) that correspond to points on the inner ring. - - Parameters: - slyce: 1-D numpy array of image data corresponding to a vertical or horizontal slice through the tiff image - thresh: np.float64 corresponding to a percentage of the maximum value in image numpy array - - """ - p1=np.argmax(slyce.data) - p2=np.argmax(slyce.data[:p1]+slyce.data[p1+1:]) - - #if statement to determine if max points are large enough to actually be on center ring. If so, the pixel attribute of Slyce is modified to include these indices - if slyce.data[p2]>=thresh: - slyce.pixels.append(p1) - slyce.pixels.append(p2) - - elif slyce.data[p1]>=thresh: - - - slyce.pixels.append(p1) - -def finddistance(a,b): - """ - Finds distance between two points. - - Parameters: - a: numpy array, list, or tuple containing a coordinates, where a[0] contains a row index and a[1] contains col index - b: numpy array, list, or tuple containing a coordinates, where a[0] contains a row index and a[1] contains col index - - Returns: - np.float64 corresponding to distance between two points - """ - - dif1=a[1]-b[1] - dif2=a[0]-b[0] - d_sq=np.abs(dif1**2+dif2**2) - - return np.sqrt(d_sq) - -def findringcenter(image,thres=0.2,d=20): - """ - Takes a numpy array corresponding to a tiff image and finds the pixel index of the center of the inner ring. - - Parameters: - image: numpy array of tiff image - d: integer corresponding distance around image center (distinct from inner ring center) - Returns: - Pixel indices of an estimate of center point of inner ring. - - - """ - thresh=thres*np.max(image) - r,c=findcenter(image) - - #take 10 slices within a range of 'd' away from the cetner of the image and puts them into a list - slyce1=Slyce('v',c-d,image) - slyce2=Slyce('v',c+d,image) - slyce3=Slyce('v',c,image) - slyce4=Slyce('v',c-d/2,image) - slyce5=Slyce('v',c+d/2,image) - - slyce6=Slyce('h',r-d,image) - slyce7=Slyce('h',r+d,image) - slyce8=Slyce('h',r,image) - slyce9=Slyce('h',r+d/2,image) - slyce10=Slyce('h',r-d/2,image) - slyces=[slyce1, slyce2, slyce3, slyce4, slyce5, slyce6, slyce7, slyce8, slyce9, slyce10] - - - - points2click=[] - for slyce in slyces: - clickpoints(slyce,thresh) - if slyce.direction=='v': - for pixel in slyce.pixels: - points2click.append([pixel,slyce.index]) - if slyce.direction=='h': - for pixel in slyce.pixels: - points2click.append([slyce.index,pixel]) - - #coords keeps track of the coordinates that are tested to find the center of the inner ring - coords=[] - #spread keeps track of the range of point distances from the tested point to the points that have been identified on the center ring - spread=[] - - #the center of the ring is determined by testing a range of points around the center of the image and calculating the distances - #between that point and the points that have been identified on the inner ring through the clickpoints() function - #the point that has the smallest range of distances is identified as the center - for row in range (int(r-3*d),int(r+3*d)): - for col in range (int(c-3*d),int(c+3*d)): - pointdist=[] - for point in points2click: - pointdist.append(finddistance([row,col],point)) - spread.append(max(pointdist)-min(pointdist)) - coords.append([row,col]) - - center=coords[spread.index(min(spread))] - - return center - - -def zerocross(lines): - """ - Takes in 1-D numpy array and determines array indices corresponding to points where an adjacent value has a different sign and where the difference between the two values before and after zero-crossing exceeds a certain threshold - - Parameters: - lines: 1-D numpy array - Returns: - z: list of indices in lines that correspond to both a change in sign of adjacent values and significant difference in these values - - """ - z=[] - for i in range(1,len(lines)-1): - if (np.sign(lines[i]) == -1) and (np.sign(lines[i-1]) in [0,1]): - if np.abs(lines[i]-lines[i-1])>np.max(lines)/80.0: - z.append(i) - return z - -def findrings(image): - - """ - Takes a numpy array representing a tiff image and returns the pixel indices of the center point and points on rings 0,1,2,5 - - Parameters: - image: numpy array of tiff image - Returns: - pixel index of point on center ring and pixel indices of points on rings 0,1,2,5 - - """ - center_pt=findringcenter(image) - - - #create horizontal slyces from the center of the inner ring (but use 5 and find the median value to avoid issues with hot pixels) - cs1=Slyce('h',center_pt[0]-2,image) - cs2=Slyce('h',center_pt[0]-1,image) - cs3=Slyce('h',center_pt[0],image) - cs4=Slyce('h',center_pt[0]+1,image) - cs5=Slyce('h',center_pt[0]+2,image) - - cs=[cs1,cs2,cs3,cs4,cs5] - - value1=cs1.data - value2=cs2.data - value3=cs3.data - value4=cs4.data - value5=cs5.data - value_cs=np.zeros(np.shape(value1)[0]) - - #create list of median values in horizontal center slyce to avoid hot pixel values - for i, blank in enumerate(value_cs): - value_cs[i]=np.median([value1[i],value2[i],value3[i],value4[i],value5[i]]) - - #take half of center slyce from the center of the inner ring out - halfcs=list(value_cs[(center_pt[1]):]) - - #find derivative of values on the slyce - dx=1 - deriv=list(np.gradient(halfcs,dx)) - - - rings=zerocross(deriv) - clickpts=[] - firstpoint=[center_pt[0],rings[0]+center_pt[1]] - - #tests a series of conditions to determine if there is a peak at a certain index in 1D array - #tests to make sure that peak is real and not noise/small fluctuation - if (halfcs[rings[0]]>0.7*np.max(halfcs)) or (halfcs[rings[0]-1]>0.7*np.max(halfcs)) or (halfcs[rings[0]+1]>0.7*np.max(halfcs)): - clickpts.append(rings[0]) - clickpts.append(rings[1]) - clickpts.append(rings[2]) - clickpts.append(rings[5]) - else: - clickpts.append(rings[1]) - clickpts.append(rings[2]) - clickpts.append(rings[3]) - clickpts.append(rings[6]) - - - #find indices of points that shoudl be "clicked" in tiff image array - points_image=[] - for clickpt in clickpts: - points_image.append([center_pt[0],clickpt+center_pt[1]]) - - print(points_image) - print(center_pt) - - return points_image, center_pt - -findrings(imarray) diff --git a/xpdtools/tests/test_pipelines.py b/xpdtools/tests/test_pipelines.py index 9cc7e68..d07b5d4 100644 --- a/xpdtools/tests/test_pipelines.py +++ b/xpdtools/tests/test_pipelines.py @@ -8,7 +8,8 @@ max_intensity_mean, max_gr_mean, pca_pipeline, - amorphsivity_pipeline) + amorphsivity_pipeline, +) from xpdtools.pipelines.raw_pipeline import ( pipeline_order, namespace as g_namespace, @@ -199,7 +200,7 @@ def test_pca_pipeline(): def test_amorphous_pipeline(): pdf = Stream() ns = amorphsivity_pipeline(pdf) - L = ns['amorphsivity'].sink_to_list() + L = ns["amorphsivity"].sink_to_list() a = np.ones(10) pdf.emit(a) assert L[0] == np.sum(a[6:]) diff --git a/xpdtools/tests/test_ringfinding.py b/xpdtools/tests/test_ringfinding.py index eac0b63..e831567 100644 --- a/xpdtools/tests/test_ringfinding.py +++ b/xpdtools/tests/test_ringfinding.py @@ -10,31 +10,47 @@ import os import pytest -DATA_DIR=rs_fn("xpdtools", "data/") - -filename=["Ni_onTape_forSlimes_andWahsers_20180812-234250_fe70b9_0001.tiff", 'Ni_calib_20180811-191034_63e554_0001.tiff', 'Ni_pin_20181101-075909_973de2_0001.tiff', 'Ni_calib_20180920-230956_0eedc4_0001.tiff','Ni_calib_20180923-133223_c2a848_0001.tiff', 'Ni_20180922-001850_2a1c3b_0001.tiff'] - - -@pytest.mark.parametrize("filename,poni", [(filename[0], os.path.splitext(filename[0])[0]+'.edf'), - (filename[1], os.path.splitext(filename[1])[0]+'.edf'), - (filename[2], os.path.splitext(filename[2])[0]+'.edf'), - (filename[3], os.path.splitext(filename[3])[0]+'.edf'), - (filename[4], os.path.splitext(filename[4])[0]+'.edf'),(filename[5], os.path.splitext(filename[5])[0]+'.edf') ]) +DATA_DIR = rs_fn("xpdtools", "data/") + +filename = [ + "Ni_onTape_forSlimes_andWahsers_20180812-234250_fe70b9_0001.tiff", + "Ni_calib_20180811-191034_63e554_0001.tiff", + "Ni_pin_20181101-075909_973de2_0001.tiff", + "Ni_calib_20180920-230956_0eedc4_0001.tiff", + "Ni_calib_20180923-133223_c2a848_0001.tiff", + "Ni_20180922-001850_2a1c3b_0001.tiff", +] + + +@pytest.mark.parametrize( + "filename,poni", + [ + (filename[0], os.path.splitext(filename[0])[0] + ".edf"), + (filename[1], os.path.splitext(filename[1])[0] + ".edf"), + (filename[2], os.path.splitext(filename[2])[0] + ".edf"), + (filename[3], os.path.splitext(filename[3])[0] + ".edf"), + (filename[4], os.path.splitext(filename[4])[0] + ".edf"), + (filename[5], os.path.splitext(filename[5])[0] + ".edf"), + ], +) def test_ringfinding(filename, poni): - impath=os.path.join(DATA_DIR, filename) - imarray = tf.imread(impath) - pointsimage, center_pt=findrings(imarray) - d=pyFAI.load(poni) - centerx=d.getFit2D()['centerX'] - centery=d.getFit2D()['centerY'] - assert abs(center_pt[1]-centerx)<=8 and abs(center_pt[0]-centery)<=8 + impath = os.path.join(DATA_DIR, filename) + imarray = tf.imread(impath) + pointsimage, center_pt = findrings(imarray) + d = pyFAI.load(poni) + centerx = d.getFit2D()["centerX"] + centery = d.getFit2D()["centerY"] + assert ( + abs(center_pt[1] - centerx) <= 8 and abs(center_pt[0] - centery) <= 8 + ) + def test_2Darray(): - with pytest.raises(IndexError): - findrings(np.random.rand(2048)) + with pytest.raises(IndexError): + findrings(np.random.rand(2048)) -@pytest.mark.parametrize("wrong_input",[[1,2,3],3,2.7,(2,3),'banana']) -def test_inputtype(wrong_input): - with pytest.raises(RuntimeError): - findrings(wrong_input) +@pytest.mark.parametrize("wrong_input", [[1, 2, 3], 3, 2.7, (2, 3), "banana"]) +def test_inputtype(wrong_input): + with pytest.raises(RuntimeError): + findrings(wrong_input) From 90a0f2cd0f271381b819b65dda090dfe120974d1 Mon Sep 17 00:00:00 2001 From: Maddison Brod Date: Fri, 3 May 2019 10:54:35 -0400 Subject: [PATCH 11/14] added extra test files in test_ringfinding.py --- xpdtools/calib3.py | 1 - xpdtools/tests/test_ringfinding.py | 11 +++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/xpdtools/calib3.py b/xpdtools/calib3.py index 9a1e72f..0585bec 100644 --- a/xpdtools/calib3.py +++ b/xpdtools/calib3.py @@ -4,7 +4,6 @@ import tifffile as tf - filename = 'Ni_pin_20181101-075909_973de2_0001.tiff' diff --git a/xpdtools/tests/test_ringfinding.py b/xpdtools/tests/test_ringfinding.py index eac0b63..8b74f66 100644 --- a/xpdtools/tests/test_ringfinding.py +++ b/xpdtools/tests/test_ringfinding.py @@ -12,14 +12,21 @@ DATA_DIR=rs_fn("xpdtools", "data/") -filename=["Ni_onTape_forSlimes_andWahsers_20180812-234250_fe70b9_0001.tiff", 'Ni_calib_20180811-191034_63e554_0001.tiff', 'Ni_pin_20181101-075909_973de2_0001.tiff', 'Ni_calib_20180920-230956_0eedc4_0001.tiff','Ni_calib_20180923-133223_c2a848_0001.tiff', 'Ni_20180922-001850_2a1c3b_0001.tiff'] +filename=["Ni_onTape_forSlimes_andWahsers_20180812-234250_fe70b9_0001.tiff", +'Ni_calib_20180811-191034_63e554_0001.tiff', 'Ni_pin_20181101-075909_973de2_0001.tiff', +'Ni_calib_20180920-230956_0eedc4_0001.tiff','Ni_calib_20180923-133223_c2a848_0001.tiff', +'Ni_20180922-001850_2a1c3b_0001.tiff', 'Ni_cryostream_bracket_20190402-220917_229125_0001_dark_corrected_img.tiff', +'sub_20170802-212828_Ni_LongSoham_start_ct_30_3bda69_0001.tiff'] @pytest.mark.parametrize("filename,poni", [(filename[0], os.path.splitext(filename[0])[0]+'.edf'), (filename[1], os.path.splitext(filename[1])[0]+'.edf'), (filename[2], os.path.splitext(filename[2])[0]+'.edf'), (filename[3], os.path.splitext(filename[3])[0]+'.edf'), - (filename[4], os.path.splitext(filename[4])[0]+'.edf'),(filename[5], os.path.splitext(filename[5])[0]+'.edf') ]) + (filename[4], os.path.splitext(filename[4])[0]+'.edf'), + (filename[5], os.path.splitext(filename[5])[0]+'.edf'), + (filename[6], os.path.splitext(filename[6])[0]+'.edf'), + (filename[7], os.path.splitext(filename[7])[0]+'.edf') ]) def test_ringfinding(filename, poni): impath=os.path.join(DATA_DIR, filename) imarray = tf.imread(impath) From 8c596454e6eb323d78444c72a5adf95138ed7f0a Mon Sep 17 00:00:00 2001 From: Maddison Brod Date: Mon, 6 May 2019 23:27:24 -0400 Subject: [PATCH 12/14] replaced Slyce class with dictionaries, made sure r and c are always intergers, got rid of the function that finds the center of the image and incorporated that part of the code directly into the findringcenter() function --- xpdtools/calib4.py | 257 ++++++++++++++++----------------------------- 1 file changed, 88 insertions(+), 169 deletions(-) diff --git a/xpdtools/calib4.py b/xpdtools/calib4.py index 9ab9d12..5a0d18d 100644 --- a/xpdtools/calib4.py +++ b/xpdtools/calib4.py @@ -2,77 +2,41 @@ import tifffile as tf -import matplotlib as mpl - -mpl.use("TkAgg") -import matplotlib.pyplot as plt - - -class Slyce: - def __init__(self, direction, index, image): - self.direction = direction - self.index = int(index) - self.pixels = [] - if direction == "v": - self.data = list(image[:, self.index]) - if direction == "h": - self.data = list(image[self.index, :]) - - -def findcenter(image): - """ - Takes numpy array corresponding to a tiff image and finds the pixel indices corresponding to the center of the image (not the center of the rings) - - Parameters: numpy array of tiff image - image: numpy array of tiff image - - Returns: - r: integer row index of image center - c: integer column index of image center - - """ - - s = image.shape - # number of rows divided by 2 - r = s[0] / 2 - # number of columns divided by 2 - c = s[1] / 2 - return r, c - +###move this to findringcenter function def clickpoints(slyce, thresh): """ - Takes a slyce and threshold value and adds to the "pixels" attribute of Slyce class the indices of 1 or 2 points (in the 1-D slyce array) that correspond to points on the inner ring. + Takes a slyce and threshold value and adds to the "pixels" attribute of Slyce class the indices of 1 or 2 points (in the 1-D slyce array) that correspond to points on the inner ring. - Parameters: - slyce: 1-D numpy array of image data corresponding to a vertical or horizontal slice through the tiff image - thresh: np.float64 corresponding to a percentage of the maximum value in image numpy array + Parameters: + slyce: 1-D numpy array of image data corresponding to a vertical or horizontal slice through the tiff image + thresh: np.float64 corresponding to a percentage of the maximum value in image numpy array - """ - p1 = np.argmax(slyce.data) - p2 = np.argmax(slyce.data[:p1] + slyce.data[p1 + 1 :]) + """ + p1 = np.argmax(slyce['data']) + p2 = np.argmax(slyce['data'][:p1] + slyce['data'][p1 + 1 :]) # if statement to determine if max points are large enough to actually be on center ring. If so, the pixel attribute of Slyce is modified to include these indices - if slyce.data[p2] >= thresh: - slyce.pixels.append(p1) - slyce.pixels.append(p2) + if slyce['data'][p2] >= thresh: + slyce['pixels'].append(p1) + slyce['pixels'].append(p2) - elif slyce.data[p1] >= thresh: + elif slyce['data'][p1] >= thresh: - slyce.pixels.append(p1) + slyce['pixels'].append(p1) def finddistance(a, b): """ - Finds distance between two points. + Finds distance between two points. - Parameters: - a: numpy array, list, or tuple containing a coordinates, where a[0] contains a row index and a[1] contains col index - b: numpy array, list, or tuple containing a coordinates, where a[0] contains a row index and a[1] contains col index + Parameters: + a: numpy array, list, or tuple containing a coordinates, where a[0] contains a row index and a[1] contains col index + b: numpy array, list, or tuple containing a coordinates, where a[0] contains a row index and a[1] contains col index - Returns: - np.float64 corresponding to distance between two points - """ + Returns: + np.float64 corresponding to distance between two points + """ dif1 = a[1] - b[1] dif2 = a[0] - b[0] @@ -83,69 +47,65 @@ def finddistance(a, b): def findringcenter(image, thres=0.2, d=20): """ - Takes a numpy array corresponding to a tiff image and finds the pixel index of the center of the inner ring. + Takes a numpy array corresponding to a tiff image and finds the pixel index of the center of the inner ring. - Parameters: - image: numpy array of tiff image - d: integer corresponding distance around image center (distinct from inner ring center) - Returns: - Pixel indices of an estimate of center point of inner ring. + Parameters: + image: numpy array of tiff image + d: integer corresponding distance around image center (distinct from inner ring center) + Returns: + Pixel indices of an estimate of center point of inner ring. - - """ + + """ thresh = thres * np.max(image) - r, c = findcenter(image) + + s = image.shape + # number of rows divided by 2 + r = s[0] // 2 + # number of columns divided by 2 + c = s[1] // 2 # take 10 slices within a range of 'd' away from the cetner of the image and puts them into a list - slyce1 = Slyce("v", c - d, image) - slyce2 = Slyce("v", c + d, image) - slyce3 = Slyce("v", c, image) - slyce4 = Slyce("v", c - d / 2, image) - slyce5 = Slyce("v", c + d / 2, image) - - slyce6 = Slyce("h", r - d, image) - slyce7 = Slyce("h", r + d, image) - slyce8 = Slyce("h", r, image) - slyce9 = Slyce("h", r + d / 2, image) - slyce10 = Slyce("h", r - d / 2, image) - slyces = [ - slyce1, - slyce2, - slyce3, - slyce4, - slyce5, - slyce6, - slyce7, - slyce8, - slyce9, - slyce10, - ] + + slyces=[] + for dd in [0, -d, d, -d/2, d/2]: + for k in ['v', 'h']: + if k=='v': + slyces.append({'direction': 'v','index': int(c+dd), 'data': list(image[:, int(c+dd)]), 'pixels':[]}) + else: + slyces.append({'direction': 'h', 'index': int(r+dd), 'data': list(image[int(r+dd),:]), 'pixels':[]}) + + + + + points2click = [] for slyce in slyces: - clickpoints(slyce, thresh) - if slyce.direction == "v": - for pixel in slyce.pixels: - points2click.append([pixel, slyce.index]) - if slyce.direction == "h": - for pixel in slyce.pixels: - points2click.append([slyce.index, pixel]) + clickpoints(slyce,thresh) + + if slyce['direction'] == "v": + for pixel in slyce['pixels']: + points2click.append([pixel, slyce['index']]) + if slyce['direction'] == "h": + for pixel in slyce['pixels']: + points2click.append([slyce['index'], pixel]) # coords keeps track of the coordinates that are tested to find the center of the inner ring - coords = [] - # spread keeps track of the range of point distances from the tested point to the points that have been identified on the center ring - spread = [] - - # the center of the ring is determined by testing a range of points around the center of the image and calculating the distances - # between that point and the points that have been identified on the inner ring through the clickpoints() function - # the point that has the smallest range of distances is identified as the center - for row in range(int(r - 3 * d), int(r + 3 * d)): - for col in range(int(c - 3 * d), int(c + 3 * d)): - pointdist = [] - for point in points2click: - pointdist.append(finddistance([row, col], point)) - spread.append(max(pointdist) - min(pointdist)) - coords.append([row, col]) + coords = [] + # spread keeps track of the range of point distances from the tested point to the points that have been identified on the center ring + spread = [] + + # the center of the ring is determined by testing a range of points around the center of the image and calculating the distances + # between that point and the points that have been identified on the inner ring through the clickpoints() function + # the point that has the smallest range of distances is identified as the center + for row in range(int(r - 3 * d), int(r + 3 * d)): + for col in range(int(c - 3 * d), int(c + 3 * d)): + pointdist = [] + for point in points2click: + pointdist.append(finddistance([row, col], point)) + spread.append(max(pointdist) - min(pointdist)) + coords.append([row, col]) center = coords[spread.index(min(spread))] @@ -154,14 +114,14 @@ def findringcenter(image, thres=0.2, d=20): def zerocross(lines): """ - Takes in 1-D numpy array and determines array indices corresponding to points where an adjacent value has a different sign and where the difference between the two values before and after zero-crossing exceeds a certain threshold + Takes in 1-D numpy array and determines array indices corresponding to points where an adjacent value has a different sign and where the difference between the two values before and after zero-crossing exceeds a certain threshold - Parameters: - lines: 1-D numpy array - Returns: - z: list of indices in lines that correspond to both a change in sign of adjacent values and significant difference in these values + Parameters: + lines: 1-D numpy array + Returns: + z: list of indices in lines that correspond to both a change in sign of adjacent values and significant difference in these values - """ + """ z = [] for i in range(1, len(lines) - 1): if (np.sign(lines[i]) == -1) and (np.sign(lines[i - 1]) in [0, 1]): @@ -173,41 +133,31 @@ def zerocross(lines): def findrings(image): """ - Takes a numpy array representing a tiff image and returns the pixel indices of the center point and points on rings 0,1,2,5 - - Parameters: - image: numpy array of tiff image - Returns: - pixel index of point on center ring and pixel indices of points on rings 0,1,2,5 + Takes a numpy array representing a tiff image and returns the pixel indices of the center point and points on rings 0,1,2,5 + *Function only works when rings are relatively centered on image* + Parameters: + image: numpy array of tiff image + Returns: + pixel index of point on center ring and pixel indices of points on rings 0,1,2,5 - """ + """ if not isinstance(image, np.ndarray): raise RuntimeError("input type must be ndarray") center_pt = findringcenter(image) - # create horizontal slyces from the center of the inner ring (but use 5 and find the median value to avoid issues with hot pixels) - cs1 = Slyce("h", center_pt[0] - 2, image) - cs2 = Slyce("h", center_pt[0] - 1, image) - cs3 = Slyce("h", center_pt[0], image) - cs4 = Slyce("h", center_pt[0] + 1, image) - cs5 = Slyce("h", center_pt[0] + 2, image) + values=[] + for i in [-2,-1,0,1,2]: + values.append(list(image[center_pt[0]+i, :])) - cs = [cs1, cs2, cs3, cs4, cs5] + value_cs = np.zeros(np.shape(values[0])) - value1 = cs1.data - value2 = cs2.data - value3 = cs3.data - value4 = cs4.data - value5 = cs5.data - value_cs = np.zeros(np.shape(value1)[0]) # create list of median values in horizontal center slyce to avoid hot pixel values for i, blank in enumerate(value_cs): - value_cs[i] = np.median( - [value1[i], value2[i], value3[i], value4[i], value5[i]] - ) + value_cs[i] = np.median(np.array([values[0][i], values[1][i], values[2][i], values[3][i], values[4][i]])) + # take half of center slyce from the center of the inner ring out halfcs = list(value_cs[(center_pt[1]) :]) @@ -248,34 +198,3 @@ def findrings(image): return points_image, center_pt -# vis=True -vis = False - -if vis: - - new_img = np.empty((imarray.shape[0], imarray.shape[1], 4)) - max_img = np.amax(imarray) - min_img = np.amin(imarray) - for i, row in enumerate(new_img): - for j, elem in enumerate(row): - old_val = imarray[i][j] - scaled = (old_val - min_img) / (max_img - min_img) - new_img[i][j] = np.array( - [1.0 - scaled, 1.0 - scaled, 1.0 - scaled, 1.0] - ) - - for point_image in points_image: - for i in range(-2, 2): - for j in range(-2, 2): - new_img[point_image[0] + i][point_image[1] + j] = np.array( - [1.0, 0.0, 0.0, 1.0] - ) - - for i in range(-2, 2): - for j in range(-2, 2): - new_img[center_pt[0] + i][center_pt[1] + j] = np.array( - [1.0, 0.0, 0.0, 1.0] - ) - - plt.imshow(new_img) - plt.show() From ba601c97da33baa546c3a9493e26370603d49bd6 Mon Sep 17 00:00:00 2001 From: Maddison Brod Date: Tue, 7 May 2019 10:35:33 -0400 Subject: [PATCH 13/14] moved block of code that plots selected points to a new file vis_calib.py --- xpdtools/vis_calib.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 xpdtools/vis_calib.py diff --git a/xpdtools/vis_calib.py b/xpdtools/vis_calib.py new file mode 100644 index 0000000..25ad446 --- /dev/null +++ b/xpdtools/vis_calib.py @@ -0,0 +1,34 @@ +from xpdtools.calib4 import findrings +import matplotlib as mpl +mpl.use("TkAgg") +import matplotlib.pyplot as plt + + +points_image, center_pt=findrings(imarray) + +new_img = np.empty((imarray.shape[0], imarray.shape[1], 4)) + max_img = np.amax(imarray) + min_img = np.amin(imarray) + for i, row in enumerate(new_img): + for j, elem in enumerate(row): + old_val = imarray[i][j] + scaled = (old_val - min_img) / (max_img - min_img) + new_img[i][j] = np.array( + [1.0 - scaled, 1.0 - scaled, 1.0 - scaled, 1.0] + ) + + for point_image in points_image: + for i in range(-2, 2): + for j in range(-2, 2): + new_img[point_image[0] + i][point_image[1] + j] = np.array( + [1.0, 0.0, 0.0, 1.0] + ) + + for i in range(-2, 2): + for j in range(-2, 2): + new_img[center_pt[0] + i][center_pt[1] + j] = np.array( + [1.0, 0.0, 0.0, 1.0] + ) + + plt.imshow(new_img) + plt.show() From a1733cb46b7fa40147afeb5ef432cb2c1c5ad451 Mon Sep 17 00:00:00 2001 From: Maddison Brod Date: Fri, 17 May 2019 14:15:02 -0400 Subject: [PATCH 14/14] modified vis_calib.py file so that it can take in a filename and plot the points on the tiff image where the findrings() function identifies the center point and a point onrings 0,1,2,5 --- xpdtools/vis_calib.py | 45 +++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/xpdtools/vis_calib.py b/xpdtools/vis_calib.py index 25ad446..ea8990d 100644 --- a/xpdtools/vis_calib.py +++ b/xpdtools/vis_calib.py @@ -1,34 +1,45 @@ from xpdtools.calib4 import findrings +import numpy as np +import tifffile as tf +from pkg_resources import resource_filename as rs_fn +import os import matplotlib as mpl mpl.use("TkAgg") import matplotlib.pyplot as plt - +DATA_DIR=rs_fn("xpdtools", "data/") +filename=["Ni_onTape_forSlimes_andWahsers_20180812-234250_fe70b9_0001.tiff", +'Ni_calib_20180811-191034_63e554_0001.tiff', 'Ni_pin_20181101-075909_973de2_0001.tiff', +'Ni_calib_20180920-230956_0eedc4_0001.tiff','Ni_calib_20180923-133223_c2a848_0001.tiff', +'Ni_20180922-001850_2a1c3b_0001.tiff', 'Ni_cryostream_bracket_20190402-220917_229125_0001_dark_corrected_img.tiff', +'sub_20170802-212828_Ni_LongSoham_start_ct_30_3bda69_0001.tiff'] +impath = os.path.join(DATA_DIR, filename[0]) +imarray = tf.imread(impath) points_image, center_pt=findrings(imarray) new_img = np.empty((imarray.shape[0], imarray.shape[1], 4)) - max_img = np.amax(imarray) - min_img = np.amin(imarray) - for i, row in enumerate(new_img): - for j, elem in enumerate(row): - old_val = imarray[i][j] - scaled = (old_val - min_img) / (max_img - min_img) - new_img[i][j] = np.array( +max_img = np.amax(imarray) +min_img = np.amin(imarray) +for i, row in enumerate(new_img): + for j, elem in enumerate(row): + old_val = imarray[i][j] + scaled = (old_val - min_img) / (max_img - min_img) + new_img[i][j] = np.array( [1.0 - scaled, 1.0 - scaled, 1.0 - scaled, 1.0] ) - for point_image in points_image: - for i in range(-2, 2): - for j in range(-2, 2): - new_img[point_image[0] + i][point_image[1] + j] = np.array( +for point_image in points_image: + for i in range(-2, 2): + for j in range(-2, 2): + new_img[point_image[0] + i][point_image[1] + j] = np.array( [1.0, 0.0, 0.0, 1.0] ) - for i in range(-2, 2): - for j in range(-2, 2): - new_img[center_pt[0] + i][center_pt[1] + j] = np.array( +for i in range(-2, 2): + for j in range(-2, 2): + new_img[center_pt[0] + i][center_pt[1] + j] = np.array( [1.0, 0.0, 0.0, 1.0] ) - plt.imshow(new_img) - plt.show() +plt.imshow(new_img) +plt.show()