diff --git a/doc/examples/plot_circular_elliptical_hough_transform.py b/doc/examples/plot_circular_elliptical_hough_transform.py new file mode 100755 index 00000000..bd036e03 --- /dev/null +++ b/doc/examples/plot_circular_elliptical_hough_transform.py @@ -0,0 +1,147 @@ +""" +======================================== +Circular and Elliptical Hough Transforms +======================================== + +The Hough transform in its simplest form is a `method to detect +straight lines `__ +but it can also be used to detect circles or ellipses. +The algorithm assumes that the edge is detected and it is robust against +noise or missing points. + +Circle detection +================ + +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. + +""" +import numpy as np +import matplotlib.pyplot as plt + +from skimage import data, filter, color +from skimage.transform import hough_circle +from skimage.feature import peak_local_max +from skimage.draw import circle_perimeter +from skimage.util import img_as_ubyte + + +# Load picture and detect edges +image = img_as_ubyte(data.coins()[0:95, 70:370]) +edges = filter.canny(image, sigma=3, low_threshold=10, high_threshold=50) + +fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(6, 6)) + +# Detect two radii +hough_radii = np.arange(15, 30, 2) +hough_res = hough_circle(edges, hough_radii) + +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) + accums.extend(h[peaks[:, 0], peaks[:, 1]]) + radii.extend([radius, radius]) + +# Draw the most prominent 5 circles +image = color.gray2rgb(image) +for idx in np.argsort(accums)[::-1][:5]: + center_x, center_y = centers[idx] + radius = radii[idx] + cx, cy = circle_perimeter(center_y, center_x, radius) + image[cy, cx] = (220, 20, 20) + +ax.imshow(image, cmap=plt.cm.gray) +plt.show() + + +""" +Ellipse detection +================= + +In this second example, the aim is to detect the edge of a coffee cup. +Basically, this is a projection of a circle, i.e. an ellipse. +The problem to solve is much more difficult because five parameters have to be +determined, instead of three for circles. + + +Algorithm overview +------------------ + +The algorithm takes two different points belonging to the ellipse. It assumes +that it is the main axis. A loop on all the other points determines how much +an ellipse passes to them. A good match corresponds to high accumulator values. + +A full description of the algorithm can be found in reference [1]_. + + +References +---------- +.. [1] Xie, Yonghong, and Qiang Ji. "A new efficient ellipse detection + method." Pattern Recognition, 2002. Proceedings. 16th International + Conference on. Vol. 2. IEEE, 2002 +""" +import matplotlib.pyplot as plt + +from skimage import data, filter, color +from skimage.transform import hough_ellipse +from skimage.draw import ellipse_perimeter + +# Load picture, convert to grayscale and detect edges +image_rgb = data.load('coffee.png')[0:220, 100:450] +image_gray = color.rgb2gray(image_rgb) +edges = filter.canny(image_gray, sigma=2.0, + low_threshold=0.55, high_threshold=0.8) + +# Perform a Hough Transform +# The accuracy corresponds to the bin size of a major axis. +# The value is chosen in order to get a single high accumulator. +# The threshold eliminates low accumulators +accum = hough_ellipse(edges, accuracy=10, threshold=170, min_size=50) +accum.sort(key=lambda x:x[5]) +# Estimated parameters for the ellipse +center_y = int(accum[-1][0]) +center_x = int(accum[-1][1]) +xradius = int(accum[-1][2]) +yradius = int(accum[-1][3]) +angle = np.pi - accum[-1][4] + +# Draw the ellipse on the original image +cx, cy = ellipse_perimeter(center_y, center_x, + yradius, xradius, orientation=angle) +image_rgb[cy, cx] = (0, 0, 1) +# Draw the edge (white) and the resulting ellipse (red) +edges = color.gray2rgb(edges) +edges[cy, cx] = (250, 0, 0) + +fig = plt.subplots(figsize=(10, 6)) +plt.subplot(1, 2, 1) +plt.title('Original picture') +plt.imshow(image_rgb) +plt.subplot(1, 2, 2) +plt.title('Edge (white) and result (red)') +plt.imshow(edges) + +plt.show() diff --git a/doc/examples/plot_circular_hough_transform.py b/doc/examples/plot_circular_hough_transform.py deleted file mode 100755 index fe4bea26..00000000 --- a/doc/examples/plot_circular_hough_transform.py +++ /dev/null @@ -1,72 +0,0 @@ -""" -======================== -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. - -""" -import numpy as np -import matplotlib.pyplot as plt - -from skimage import data, filter, color -from skimage.transform import hough_circle -from skimage.feature import peak_local_max -from skimage.draw import circle_perimeter -from skimage.util import img_as_ubyte - - -# Load picture and detect edges -image = img_as_ubyte(data.coins()[0:95, 70:370]) -edges = filter.canny(image, sigma=3, low_threshold=10, high_threshold=50) - -fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(6, 6)) - -# Detect two radii -hough_radii = np.arange(15, 30, 2) -hough_res = hough_circle(edges, hough_radii) - -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) - accums.extend(h[peaks[:, 0], peaks[:, 1]]) - radii.extend([radius, radius]) - -# Draw the most prominent 5 circles -image = color.gray2rgb(image) -for idx in np.argsort(accums)[::-1][:5]: - center_x, center_y = centers[idx] - radius = radii[idx] - cx, cy = circle_perimeter(center_y, center_x, radius) - image[cy, cx] = (220, 20, 20) - -ax.imshow(image, cmap=plt.cm.gray) -plt.show() diff --git a/doc/examples/plot_hough_transform.py b/doc/examples/plot_line_hough_transform.py similarity index 97% rename from doc/examples/plot_hough_transform.py rename to doc/examples/plot_line_hough_transform.py index 985d97ec..e19c37d7 100644 --- a/doc/examples/plot_hough_transform.py +++ b/doc/examples/plot_line_hough_transform.py @@ -1,7 +1,7 @@ """ -=============== -Hough transform -=============== +============================= +Straight line Hough transform +============================= The Hough transform in its simplest form is a `method to detect straight lines `__. diff --git a/skimage/data/__init__.py b/skimage/data/__init__.py index 864e3638..3791089b 100644 --- a/skimage/data/__init__.py +++ b/skimage/data/__init__.py @@ -184,3 +184,16 @@ def chelsea(): """ return load("chelsea.png") + + +def coffee(): + """Coffee cup. + + An example with several shapes (including an ellipse). + + Notes + ----- + No copyright restrictions. CC0 by the photographer. + + """ + return load("coffee.png") diff --git a/skimage/data/coffee.png b/skimage/data/coffee.png new file mode 100644 index 00000000..f8350bf7 Binary files /dev/null and b/skimage/data/coffee.png differ diff --git a/skimage/data/tests/test_data.py b/skimage/data/tests/test_data.py index 94fe3a5e..49cd4b5a 100644 --- a/skimage/data/tests/test_data.py +++ b/skimage/data/tests/test_data.py @@ -44,6 +44,11 @@ def test_chelsea(): data.chelsea() +def test_coffee(): + """ Test that "coffee" image can be loaded. """ + data.coffee() + + if __name__ == "__main__": from numpy.testing import run_module_suite run_module_suite() diff --git a/skimage/transform/_hough_transform.pyx b/skimage/transform/_hough_transform.pyx index d158a84d..a3aa2649 100644 --- a/skimage/transform/_hough_transform.pyx +++ b/skimage/transform/_hough_transform.pyx @@ -130,9 +130,9 @@ def hough_ellipse(cnp.ndarray img, int threshold=4, double accuracy=1, -------- >>> img = np.zeros((25, 25), dtype=int) >>> rr, cc = draw.ellipse_perimeter(10, 10, 6, 8) - >>> img[rr, cc] = 1 - >>> result = hough_ellipse(img, threshold=6) - [(10.0, 10.0, 8.0, 6.0474292058692187, 0.0, 8)] + >>> img[cc, rr] = 1 + >>> result = hough_ellipse(img, threshold=8) + [(10.0, 10.0, 8.0, 6.0, 0.0, 10)] Notes -----