# Source code for ncempy.eval.line_profile

from scipy import ndimage
import numpy as np

def _gen_line(p0, p1, num_points):
""" Generate a set of points on a line between two points.
Helper function for line_profile.

Parameters
----------
p0 : 2-tuple
The x0 and y0 starting points of the line

p1 : 2-tuple
The x1 and y1 ending points of the line

num_points : integer
The number of points along the line

Returns
-------
: tuple, x and y
The x coordintes at which the line proifle was taken at and y the intensity values.

"""

x = np.linspace(p0, p1, num_points)
m = (p1 - p0) / (p1 - p0)
b = p0 - p0 * m
y = m * x + b
return x, y

[docs]def line_profile(im0, p0, p1, num_points, width=0, step=0.5):
""" Use interpolation to measure a line scan across a 2D image. map_coordinates
uses a different convention from numpy indexing. So the x and y positions need
to be flipped.

Parameters
----------
im0 : ndarray
The 2D array of the image
p0 : tuple
The start of the line scan (x0,y0) and (row,col)
p1 : tuple
The end of the line scan (x1,y1)
num_points : int
The number of points in the line scan
width : int
The width of the line scan to average over. Must be an integer.
step : float
The step size laterally for the interpolation. Must be < 1

Returns
-------
: tuple
A tuple containing the line profile and the positions where the interpolation was performed

Note
----
As an example: if width = 1 and step = 0.5 then there will be 3 line scans averaged.

Example
--------
>> line, (xx, yy) = line_profile(image,(0,100),(175,100),50,step=0.5,width=5)
>> fg, ax = plt.subplots(1,2)
>> ax.plot(line,'*-')
>> ax.imshow(image)
>> ax.scatter(xx, yy)
"""

im = im0.astype(np.float32)

# The line scan from p0 to p1
(x0, y0) = _gen_line(p0, p1, num_points)
line0 = ndimage.map_coordinates(im, np.vstack((x0, y0)))  # reverse x and y to switch between row and column major

# Average perpendicular line scans
if width >= 1:
x1 = []  # save all x positions
y1 = []  # save all y positions
x1.append(x0)
y1.append(y0)
x0 = x1
y0 = y1

# Find perpendicular direction to line scan for averaging
v0 = np.matrix([p1 - p0, p1 - p0, 0])
v0 = v0 / np.linalg.norm(v0)
v2 = np.cross(v0, np.matrix([0, 0, 1]))
v2 = v2 / np.linalg.norm(v2)
v2 = v2  # the perpendicular direction

# Positive direction
numLines = int(width / step / 2.0)
for ii in range(0, numLines):
p2 = np.array(p0) + v2[0:2] * step * ii
p3 = np.array(p1) + v2[0:2] * step * ii
(x, y) = _gen_line(p2, p3, num_points)
line0 += ndimage.map_coordinates(im, np.vstack(
(x, y)))  # reverse x and y to switch between row and column major
x0.append(x)
y0.append(y)
# Negative direction
for ii in range(0, numLines):
p4 = np.array(p0) - v2[0:2] * step * ii
p5 = np.array(p1) - v2[0:2] * step * ii
(x, y) = _gen_line(p4, p5, num_points)
line0 += ndimage.map_coordinates(im, np.vstack(
(x, y)))  # reverse x and y to switch between row and column major
x0.append(x)
y0.append(y)
line0 = line0 / (width / step + 1)

return line0, (x0, y0)

if __name__ == '__main__':

XX, YY = np.mgrid[0:100,0:100]
RR = np.sqrt((XX-50)**2 + (YY-50)**2)

profile, (xx, yy) = line_profile(RR, (0,0), (99, 99), 100)
print(profile)