diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 80cb92f0..fd0656db 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -132,7 +132,7 @@ - François Boulogne Andres Method for circle perimeter, ellipse perimeter drawing. - Hough transform for circles + Circular Hough Transform - Thouis Jones Vectorized operators for arrays of 16-bit ints. diff --git a/doc/examples/plot_circular_hough_transform.py b/doc/examples/plot_circular_hough_transform.py index 0caee3c4..cc4ea664 100755 --- a/doc/examples/plot_circular_hough_transform.py +++ b/doc/examples/plot_circular_hough_transform.py @@ -1,14 +1,32 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- -# Author: Francois Boulogne -# License: GPL - """ ======================== Circular Hough Transform ======================== +The Hough transform in its simplest form is a `method to detect +straight lines `__ +but it can also be used to detect circles. +In the following example, the Hough transform is used to detect +coin positions and match their edges. We provide a range of +plausible radii. For each radius, two circles are extracted and +we finally keep the five most prominent candidates. +The result shows that coin positions are well-detected. + + +Algorithm overview +------------------ + +Given a black circle on a white background, we first guess its +radius (or a range of radii) to construct a new circle. +This circle is applied on each black pixel of the original picture +and the coordinates of this circle are voting in an accumulator. +From this geometrical construction, the original circle center +position receives the highest score. + +Note that the accumulator size is built to be larger than the +original picture in order to detect centers outside the frame. +Its size is extended by two times the larger radius. """ @@ -23,23 +41,32 @@ from skimage.feature import peak_local_max # Load picture and detect edges image = data.coins()[0:95, 70:370] -edges = filter.canny(filter.sobel(image), sigma=2.8) - +edges = filter.canny(image, sigma=3, low_threshold=10, high_threshold=50) fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(6, 6)) ax.imshow(image, cmap=plt.cm.gray) # Detect two radii -radii = np.array([21, 25]) -hough_res = hough_circle(edges, radii) +hough_radii = np.arange(15, 30, 2) +hough_res = hough_circle(edges, hough_radii) -for radius, h in zip(radii, hough_res): - # For each radius, keep two circles - maxima = peak_local_max(h, num_peaks=2) - for maximum in maxima: - center_x, center_y = maximum - radii.max() - circ = mpatches.Circle((center_y, center_x), radius, - fill=False, edgecolor='red', linewidth=2) - ax.add_patch(circ) +centers = [] +accums = [] +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()) + accums.extend(h[peaks[:, 0], peaks[:, 1]]) + radii.extend([radius, radius]) + +# Draw the most prominent 5 circles +for idx in np.argsort(accums)[::-1][:5]: + center_x, center_y = centers[idx] + radius = radii[idx] + circ = mpatches.Circle((center_y, center_x), radius, + fill=False, edgecolor='red', linewidth=2) + ax.add_patch(circ) plt.show()