Skip to content
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
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion xpdtools/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.6.0'
__version__ = "0.6.0"
200 changes: 200 additions & 0 deletions xpdtools/calib4.py
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):
Copy link
Member

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

"""
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


5 changes: 3 additions & 2 deletions xpdtools/tests/test_pipelines.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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:])
54 changes: 54 additions & 0 deletions xpdtools/tests/test_ringfinding.py
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)
45 changes: 45 additions & 0 deletions xpdtools/vis_calib.py
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()