From a68434b330b72173cb063273d98f87e0f8690c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Boulogne?= Date: Sun, 24 Mar 2013 15:11:55 +0100 Subject: [PATCH] big clean-up! --- skimage/transform/__init__.py | 3 + skimage/transform/_hough_transform.pyx | 77 +++++++- skimage/transform/hough_transform.py | 172 ++---------------- .../transform/tests/test_hough_transform.py | 9 - 4 files changed, 90 insertions(+), 171 deletions(-) diff --git a/skimage/transform/__init__.py b/skimage/transform/__init__.py index 089487ee..efe8f0b4 100644 --- a/skimage/transform/__init__.py +++ b/skimage/transform/__init__.py @@ -1,3 +1,6 @@ +from ._hough_transform import hough_circle, + hough_line, + probabilistic_hough_line from .hough_transform import * from .radon_transform import * from .finite_radon_transform import * diff --git a/skimage/transform/_hough_transform.pyx b/skimage/transform/_hough_transform.pyx index b6ff2bb7..a8dabcfc 100644 --- a/skimage/transform/_hough_transform.pyx +++ b/skimage/transform/_hough_transform.pyx @@ -20,7 +20,7 @@ cdef inline Py_ssize_t round(double r): return ((r + 0.5) if (r > 0.0) else (r - 0.5)) -def _hough_circle(cnp.ndarray img, +def hough_circle(cnp.ndarray img, cnp.ndarray[ndim=1, dtype=cnp.intp_t] radius, char normalize=True): """Perform a circular Hough transform. @@ -88,8 +88,51 @@ def _hough_circle(cnp.ndarray img, return acc -def _hough(cnp.ndarray img, cnp.ndarray[ndim=1, dtype=cnp.double_t] theta=None): +def hough_line(cnp.ndarray img, cnp.ndarray[ndim=1, dtype=cnp.double_t] theta=None): + """Perform a straight line Hough transform. + Parameters + ---------- + img : (M, N) ndarray + Input image with nonzero values representing edges. + theta : 1D ndarray of double + Angles at which to compute the transform, in radians. + Defaults to -pi/2 .. pi/2 + + Returns + ------- + H : 2-D ndarray of uint64 + Hough transform accumulator. + theta : ndarray + Angles at which the transform was computed, in radians. + distances : ndarray + Distance values. + + Notes + ----- + The origin is the top left corner of the original image. + X and Y axis are horizontal and vertical edges respectively. + The distance is the minimal algebraic distance from the origin to the detected line. + + Examples + -------- + Generate a test image: + + >>> img = np.zeros((100, 150), dtype=bool) + >>> img[30, :] = 1 + >>> img[:, 65] = 1 + >>> img[35:45, 35:50] = 1 + >>> for i in range(90): + ... img[i, i] = 1 + >>> img += np.random.random(img.shape) > 0.95 + + Apply the Hough transform: + + >>> out, angles, d = hough_line(img) + + .. plot:: hough_tf.py + + """ if img.ndim != 2: raise ValueError('The input image must be 2D.') @@ -131,10 +174,38 @@ def _hough(cnp.ndarray img, cnp.ndarray[ndim=1, dtype=cnp.double_t] theta=None): return accum, theta, bins -def _probabilistic_hough(cnp.ndarray img, int value_threshold, +def probabilistic_hough_line(cnp.ndarray img, int value_threshold, int line_length, int line_gap, cnp.ndarray[ndim=1, dtype=cnp.double_t] theta=None): + """Return lines from a progressive probabilistic line Hough transform. + Parameters + ---------- + img : (M, N) ndarray + Input image with nonzero values representing edges. + threshold : int + Threshold + line_length : int, optional (default 50) + Minimum accepted length of detected lines. + Increase the parameter to extract longer lines. + line_gap : int, optional, (default 10) + Maximum gap between pixels to still form a line. + Increase the parameter to merge broken lines more aggresively. + theta : 1D ndarray, dtype=double, optional, default (-pi/2 .. pi/2) + Angles at which to compute the transform, in radians. + + Returns + ------- + lines : list + List of lines identified, lines in format ((x0, y0), (x1, y0)), indicating + line start and end. + + References + ---------- + .. [1] C. Galamhos, J. Matas and J. Kittler, "Progressive probabilistic + Hough transform for line detection", in IEEE Computer Society + Conference on Computer Vision and Pattern Recognition, 1999. + """ if img.ndim != 2: raise ValueError('The input image must be 2D.') diff --git a/skimage/transform/hough_transform.py b/skimage/transform/hough_transform.py index bd5e3a2b..0c1747d4 100644 --- a/skimage/transform/hough_transform.py +++ b/skimage/transform/hough_transform.py @@ -1,179 +1,32 @@ -__all__ = ['hough', 'hough_line', 'hough_circle', 'hough_peaks', 'probabilistic_hough'] +__all__ = ['hough_peaks'] from itertools import izip as zip import numpy as np from scipy import ndimage -from ._hough_transform import _probabilistic_hough from skimage import measure, morphology -def _hough(img, theta=None): - if img.ndim != 2: - raise ValueError('The input image must be 2-D') - - if theta is None: - theta = np.linspace(-np.pi / 2, np.pi / 2, 180) - - # compute the vertical bins (the distances) - d = np.ceil(np.hypot(*img.shape)) - nr_bins = 2 * d - bins = np.linspace(-d, d, nr_bins) - - # allocate the output image - out = np.zeros((nr_bins, len(theta)), dtype=np.uint64) - - # precompute the sin and cos of the angles - cos_theta = np.cos(theta) - sin_theta = np.sin(theta) - - # find the indices of the non-zero values in - # the input image - y, x = np.nonzero(img) - - # x and y can be large, so we can't just broadcast to 2D - # arrays as we may run out of memory. Instead we process - # one vertical slice at a time. - for i, (cT, sT) in enumerate(zip(cos_theta, sin_theta)): - - # compute the base distances - distances = x * cT + y * sT - - # round the distances to the nearest integer - # and shift them to a nonzero bin - shifted = np.round(distances) - bins[0] - - # cast the shifted values to ints to use as indices - indices = shifted.astype(np.int) - - # use bin count to accumulate the coefficients - bincount = np.bincount(indices) - - # finally assign the proper values to the out array - out[:len(bincount), i] = bincount - - return out, theta, bins - -_py_hough = _hough - -# try to import and use the faster Cython version if it exists -try: - from ._hough_transform import _hough -except ImportError: - pass - - -def probabilistic_hough(img, threshold=10, line_length=50, line_gap=10, - theta=None): - """Return lines from a progressive probabilistic line Hough transform. - - Parameters - ---------- - img : (M, N) ndarray - Input image with nonzero values representing edges. - threshold : int - Threshold - line_length : int, optional (default 50) - Minimum accepted length of detected lines. - Increase the parameter to extract longer lines. - line_gap : int, optional, (default 10) - Maximum gap between pixels to still form a line. - Increase the parameter to merge broken lines more aggresively. - theta : 1D ndarray, dtype=double, optional, default (-pi/2 .. pi/2) - Angles at which to compute the transform, in radians. - - Returns - ------- - lines : list - List of lines identified, lines in format ((x0, y0), (x1, y0)), indicating - line start and end. - - References - ---------- - .. [1] C. Galamhos, J. Matas and J. Kittler, "Progressive probabilistic - Hough transform for line detection", in IEEE Computer Society - Conference on Computer Vision and Pattern Recognition, 1999. - """ - return _probabilistic_hough(img, threshold, line_length, line_gap, theta) - +from ._hough_transform import hough_line, probabilistic_hough_line from skimage._shared.utils import deprecated @deprecated('hough_line') def hough(img, theta=None): return hough_line(img, theta) -from ._hough_transform import _hough_circle - -def hough_line(img, theta=None): - """Perform a straight line Hough transform. - - Parameters - ---------- - img : (M, N) ndarray - Input image with nonzero values representing edges. - theta : 1D ndarray of double - Angles at which to compute the transform, in radians. - Defaults to -pi/2 .. pi/2 - - Returns - ------- - H : 2-D ndarray of uint64 - Hough transform accumulator. - theta : ndarray - Angles at which the transform was computed, in radians. - distances : ndarray - Distance values. - - Notes - ----- - The origin is the top left corner of the original image. - X and Y axis are horizontal and vertical edges respectively. - The distance is the minimal algebraic distance from the origin to the detected line. - - Examples - -------- - Generate a test image: - - >>> img = np.zeros((100, 150), dtype=bool) - >>> img[30, :] = 1 - >>> img[:, 65] = 1 - >>> img[35:45, 35:50] = 1 - >>> for i in range(90): - ... img[i, i] = 1 - >>> img += np.random.random(img.shape) > 0.95 - - Apply the Hough transform: - - >>> out, angles, d = hough_line(img) - - .. plot:: hough_tf.py - - """ - return _hough(img, theta) - -def hough_circle(img, radius, normalize=True): - """Perform a circular Hough transform. - - Parameters - ---------- - img : (M, N) ndarray - Input image with nonzero values representing edges. - radius : ndarray - Radii at which to compute the Hough transform. - normalize : boolean, optional - Normalize the accumulator with the number - of pixels used to draw the radius - - Returns - ------- - H : 3D ndarray (radius index, (M, N) ndarray) - Hough transform accumulator for each radius - - """ - return _hough_circle(img, radius.astype(np.intp), normalize) +@deprecated('probabilistic_hough') +def probabilistic_hough(img, threshold=10, line_length=50, line_gap=10, + theta=None): + return probabilistic_hough_line(img, threshold, line_length, line_gap, theta) +@deprecated('hough_peaks') def hough_peaks(hspace, angles, dists, min_distance=10, min_angle=10, threshold=None, num_peaks=np.inf): + return hough_line_peaks(hspace, angles, dists, min_distance, min_angle, + threshold, num_peaks) + +def hough_line_peaks(hspace, angles, dists, min_distance=10, min_angle=10, + threshold=None, num_peaks=np.inf): """Return peaks in hough transform. Identifies most prominent lines separated by a certain angle and distance in @@ -187,6 +40,7 @@ def hough_peaks(hspace, angles, dists, min_distance=10, min_angle=10, Hough space returned by the `hough_line` function. angles : (M,) array Angles returned by the `hough_line` function. Assumed to be continuous. + (`angles[-1] - angles[0] == PI`). dists : (N, ) array Distances returned by the `hough_line` function. min_distance : int diff --git a/skimage/transform/tests/test_hough_transform.py b/skimage/transform/tests/test_hough_transform.py index 2bf7b30c..5e175945 100644 --- a/skimage/transform/tests/test_hough_transform.py +++ b/skimage/transform/tests/test_hough_transform.py @@ -41,15 +41,6 @@ def test_hough_line_angles(): assert_equal(len(angles), 10) -def test_py_hough(): - ht._hough, fast_hough = ht._py_hough, ht._hough - - yield append_desc(test_hough_line, '_python') - yield append_desc(test_hough_line_angles, '_python') - - tf._hough = fast_hough - - def test_probabilistic_hough(): # Generate a test image img = np.zeros((100, 100), dtype=int)