-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: Maddie's ringfinding python modules development branch #83
Open
maddiebrod
wants to merge
15
commits into
xpdAcq:master
Choose a base branch
from
maddiebrod:maddieupdates
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
19d05eb
initial commit of Maddie's ringfinding python modules
dd2ff3f
added comments describing what the code is doing
maddiebrod 624703c
added docstrings to functions and modified findrings() to take in a n…
maddiebrod 9fdcc5c
calib4.py and calib5.py have the Slyce class and functions outside of…
maddiebrod 4d41990
combined calib4.py and calib5.py into one file calib4.py, and made vi…
maddiebrod 3447f37
removed filename from calib4.py and created test function in test_rin…
maddiebrod b8dc4bf
modified test_ringfinding with decorator so that it tests the findrin…
maddiebrod d07e4fb
modified test_ringfinding.py by adding two test functions: one that t…
maddiebrod c24d4eb
modified findrings in calib4.py so that is raises a RuntimeError if i…
maddiebrod 684e1df
cleaning
CJ-Wright 90a0f2c
added extra test files in test_ringfinding.py
maddiebrod acd0cba
resolved merge conflicts
maddiebrod 8c59645
replaced Slyce class with dictionaries, made sure r and c are always …
maddiebrod ba601c9
moved block of code that plots selected points to a new file vis_cali…
maddiebrod a1733cb
modified vis_calib.py file so that it can take in a filename and plot…
maddiebrod File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
__version__ = '0.6.0' | ||
__version__ = "0.6.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
import numpy as np | ||
|
||
import tifffile as tf | ||
|
||
|
||
###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. | ||
|
||
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) | ||
|
||
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 | ||
|
||
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]) | ||
|
||
# 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 | ||
*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) | ||
|
||
values=[] | ||
for i in [-2,-1,0,1,2]: | ||
values.append(list(image[center_pt[0]+i, :])) | ||
|
||
value_cs = np.zeros(np.shape(values[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(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]) :]) | ||
|
||
# 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 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
from xpdtools.calib4 import findrings | ||
import numpy as np | ||
|
||
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_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[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) | ||
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)) | ||
|
||
|
||
@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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +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( | ||
[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() |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe use
numpy.linalg.norm