mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-16 11:21:25 +08:00
Merge pull request #875 from blink1073/lineprofile-overlay
Add Shaded Polygon to LineProfile Plugin Output Closes #865
This commit is contained in:
+39
-14
@@ -50,6 +50,44 @@ def profile_line(img, src, dst, linewidth=1,
|
||||
The destination point is included in the profile, in contrast to
|
||||
standard numpy indexing.
|
||||
"""
|
||||
perp_lines = _line_profile_coordinates(src, dst, linewidth=linewidth)
|
||||
if img.ndim == 3:
|
||||
pixels = [nd.map_coordinates(img[..., i], perp_lines,
|
||||
order=order, mode=mode, cval=cval)
|
||||
for i in range(img.shape[2])]
|
||||
pixels = np.transpose(np.asarray(pixels), (1, 2, 0))
|
||||
else:
|
||||
pixels = nd.map_coordinates(img, perp_lines,
|
||||
order=order, mode=mode, cval=cval)
|
||||
intensities = pixels.mean(axis=1)
|
||||
|
||||
return intensities
|
||||
|
||||
|
||||
def _line_profile_coordinates(src, dst, linewidth=1):
|
||||
"""Return the coordinates of the profile of an image along a scan line.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
src : 2-tuple of numeric scalar (float or int)
|
||||
The start point of the scan line.
|
||||
dst : 2-tuple of numeric scalar (float or int)
|
||||
The end point of the scan line.
|
||||
linewidth : int, optional
|
||||
Width of the scan, perpendicular to the line
|
||||
|
||||
Returns
|
||||
-------
|
||||
coords : array, shape (2, N, C), float
|
||||
The coordinates of the profile along the scan line. The length of the
|
||||
profile is the ceil of the computed length of the scan line.
|
||||
|
||||
Notes
|
||||
-----
|
||||
This is a utility method meant to be used internally by skimage functions.
|
||||
The destination point is included in the profile, in contrast to
|
||||
standard numpy indexing.
|
||||
"""
|
||||
src_row, src_col = src = np.asarray(src, dtype=float)
|
||||
dst_row, dst_col = dst = np.asarray(dst, dtype=float)
|
||||
d_row, d_col = dst - src
|
||||
@@ -70,18 +108,5 @@ def profile_line(img, src, dst, linewidth=1,
|
||||
linewidth) for row_i in line_row])
|
||||
perp_cols = np.array([np.linspace(col_i - col_width, col_i + col_width,
|
||||
linewidth) for col_i in line_col])
|
||||
perp_lines = np.array([perp_rows, perp_cols])
|
||||
|
||||
if img.ndim == 3:
|
||||
pixels = [nd.map_coordinates(img[..., i], perp_lines,
|
||||
order=order, mode=mode, cval=cval)
|
||||
for i in range(img.shape[2])]
|
||||
pixels = np.transpose(np.asarray(pixels), (1, 2, 0))
|
||||
else:
|
||||
pixels = nd.map_coordinates(img, perp_lines,
|
||||
order=order, mode=mode, cval=cval)
|
||||
|
||||
intensities = pixels.mean(axis=1)
|
||||
|
||||
return intensities
|
||||
return np.array([perp_rows, perp_cols])
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from __future__ import division
|
||||
import warnings
|
||||
|
||||
import numpy as np
|
||||
@@ -147,12 +148,24 @@ class LineProfile(PlotPlugin):
|
||||
-------
|
||||
line_image : (M, N) uint8 array, same shape as image
|
||||
An array of 0s with the scanned line set to 255.
|
||||
If the linewidth of the line tool is greater than 1,
|
||||
sets the values within the profiled polygon to 128.
|
||||
scan : (P,) or (P, 3) array of int or float
|
||||
The line scan values across the image.
|
||||
"""
|
||||
(x1, y1), (x2, y2) = self.line_tool.end_points
|
||||
end_points = self.line_tool.end_points
|
||||
line_image = np.zeros(self.image_viewer.original_image.shape[:2],
|
||||
np.uint8)
|
||||
width = self.line_tool.linewidth
|
||||
if width > 1:
|
||||
rp, cp = measure.profile._line_profile_coordinates(
|
||||
*end_points[:, ::-1], linewidth=width)
|
||||
# the points are aliased, so create a polygon using the corners
|
||||
yp = np.rint(rp[[0, 0, -1, -1],[0, -1, -1, 0]]).astype(int)
|
||||
xp = np.rint(cp[[0, 0, -1, -1],[0, -1, -1, 0]]).astype(int)
|
||||
rp, cp = draw.polygon(yp, xp, line_image.shape)
|
||||
line_image[rp, cp] = 128
|
||||
(x1, y1), (x2, y2) = end_points.astype(int)
|
||||
rr, cc = draw.line(y1, x1, y2, x2)
|
||||
line_image[rr, cc] = 255
|
||||
return line_image, self.scan_data
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import skimage
|
||||
import skimage.data as data
|
||||
from skimage.viewer import ImageViewer
|
||||
from numpy.testing import assert_equal, assert_allclose
|
||||
|
||||
|
||||
def setup_line_profile(image):
|
||||
from skimage.viewer.plugins.lineprofile import LineProfile
|
||||
viewer = ImageViewer(skimage.img_as_float(image))
|
||||
plugin = LineProfile()
|
||||
viewer += plugin
|
||||
return plugin
|
||||
|
||||
|
||||
def test_line_profile():
|
||||
""" Test a line profile using an ndim=2 image"""
|
||||
plugin = setup_line_profile(data.camera())
|
||||
line_image, scan_data = plugin.output()
|
||||
for inp in [line_image.nonzero()[0].size,
|
||||
line_image.sum() / line_image.max(),
|
||||
scan_data.size]:
|
||||
assert_equal(inp, 172)
|
||||
assert_equal(line_image.shape, (512, 512))
|
||||
assert_allclose(scan_data.max(), 0.9139, rtol=1e-3)
|
||||
assert_allclose(scan_data.mean(), 0.2828, rtol=1e-3)
|
||||
|
||||
|
||||
def test_line_profile_rgb():
|
||||
""" Test a line profile using an ndim=3 image"""
|
||||
plugin = setup_line_profile(data.chelsea())
|
||||
for i in range(6):
|
||||
plugin.line_tool._thicken_scan_line()
|
||||
line_image, scan_data = plugin.output()
|
||||
assert_equal(line_image[line_image == 128].size, 755)
|
||||
assert_equal(line_image[line_image == 255].size, 151)
|
||||
assert_equal(line_image.shape, (300, 451))
|
||||
assert_equal(scan_data.shape, (152, 3))
|
||||
assert_allclose(scan_data.max(), 0.772, rtol=1e-3)
|
||||
assert_allclose(scan_data.mean(), 0.4355, rtol=1e-3)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from numpy.testing import run_module_suite
|
||||
run_module_suite()
|
||||
Reference in New Issue
Block a user