diff --git a/doc/examples/plot_circular_hough_transform.py b/doc/examples/plot_circular_hough_transform.py index d2f8f2ae..c8b2a3be 100755 --- a/doc/examples/plot_circular_hough_transform.py +++ b/doc/examples/plot_circular_hough_transform.py @@ -56,7 +56,7 @@ radii = [] for radius, h in zip(hough_radii, hough_res): # For each radius, extract two circles peaks = peak_local_max(h, num_peaks=2) - centers.extend(peaks - hough_radii.max()) + centers.extend(peaks) accums.extend(h[peaks[:, 0], peaks[:, 1]]) radii.extend([radius, radius]) diff --git a/skimage/transform/_hough_transform.pyx b/skimage/transform/_hough_transform.pyx index b2250ef3..a85bd6c1 100644 --- a/skimage/transform/_hough_transform.pyx +++ b/skimage/transform/_hough_transform.pyx @@ -22,7 +22,7 @@ cdef inline Py_ssize_t round(double r): def hough_circle(cnp.ndarray img, cnp.ndarray[ndim=1, dtype=cnp.intp_t] radius, - char normalize=True): + char normalize=True, char full_output=False): """Perform a circular Hough transform. Parameters @@ -34,12 +34,17 @@ def hough_circle(cnp.ndarray img, normalize : boolean, optional Normalize the accumulator with the number of pixels used to draw the radius + full_output : boolean, optional + Extend the output size by twice the largest + radius in order to detect centers outside the + input picture. Returns ------- - H : 3D ndarray (radius index, (M, N) ndarray) - Hough transform accumulator for each radius - + H : 3D ndarray (radius index, (M + 2R, N + 2R) ndarray) + Hough transform accumulator for each radius. + R designates the larger radius if full_output is True. + Otherwise, R = 0. """ if img.ndim != 2: raise ValueError('The input image must be 2D.') @@ -50,10 +55,12 @@ def hough_circle(cnp.ndarray img, cdef Py_ssize_t num_pixels = x.size - # Offset the image - cdef Py_ssize_t max_radius = radius.max() - x = x + max_radius - y = y + max_radius + cdef Py_ssize_t offset = 0 + if full_output: + # Offset the image + offset = radius.max() + x = x + offset + y = y + offset cdef Py_ssize_t i, p, c, num_circle_pixels, tx, ty cdef double incr @@ -61,8 +68,8 @@ def hough_circle(cnp.ndarray img, cdef cnp.ndarray[ndim=3, dtype=cnp.double_t] acc = \ np.zeros((radius.size, - img.shape[0] + 2 * max_radius, - img.shape[1] + 2 * max_radius), dtype=np.double) + img.shape[0] + 2 * offset, + img.shape[1] + 2 * offset), dtype=np.double) for i, rad in enumerate(radius): # Store in memory the circle of given radius diff --git a/skimage/transform/tests/test_hough_transform.py b/skimage/transform/tests/test_hough_transform.py index 256c88a8..35360e89 100644 --- a/skimage/transform/tests/test_hough_transform.py +++ b/skimage/transform/tests/test_hough_transform.py @@ -117,11 +117,27 @@ def test_hough_circle(): img = np.zeros((120, 100), dtype=int) radius = 20 x_0, y_0 = (99, 50) - x, y = circle_perimeter(y_0, x_0, radius) - img[y, x] = 1 + y, x = circle_perimeter(y_0, x_0, radius) + img[x, y] = 1 out = tf.hough_circle(img, np.array([radius])) + x, y = np.where(out[0] == out[0].max()) + # Offset for x_0, y_0 + assert_equal(x[0], x_0) + assert_equal(y[0], y_0) + +def test_hough_circle_extended(): + # Prepare picture + # The circle center is outside the image + img = np.zeros((100, 100), dtype=int) + radius = 20 + x_0, y_0 = (-5, 50) + y, x = circle_perimeter(y_0, x_0, radius) + img[x[np.where(x>0)], y[np.where(x>0)]] = 1 + + out = tf.hough_circle(img, np.array([radius]), full_output=True) + x, y = np.where(out[0] == out[0].max()) # Offset for x_0, y_0 assert_equal(x[0], x_0 + radius)