From f27796e8cc6ae4b3d87e71a863a831daf25f09f5 Mon Sep 17 00:00:00 2001 From: Ana Huaman Date: Wed, 29 Jun 2011 04:05:17 +0000 Subject: [PATCH] Added Hough Circle Tutorial in reST --- .../imgtrans/hough_circle/hough_circle.rst | 104 +++++++++++++++++- .../images/Hough_Circle_Tutorial_Theory_0.jpg | Bin 0 -> 18670 bytes 2 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Theory_0.jpg diff --git a/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.rst b/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.rst index feb3bf1cf4..43f7cd0d74 100644 --- a/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.rst +++ b/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.rst @@ -7,7 +7,29 @@ Goal ===== In this tutorial you will learn how to: -* Use the OpenCV functions :hough_circles:`HoughCircles <>` to detect circles in an image. +* Use the OpenCV function :hough_circles:`HoughCircles <>` to detect circles in an image. + +Theory +======= + +Hough Circle Transform +------------------------ + +* The Hough Circle Transform works in a *roughly* analogous way to the Hough Line Transform explained in the previous tutorial. +* In the line detection case, a line was defined by two parameters :math:`(r, \theta)`. In the circle case, we need three parameters to define a circle: + + .. math:: + + C : ( x_{center}, y_{center}, r ) + + where :math:`(x_{center}, y_{center})` define the center position (gree point) and :math:`r` is the radius, which allows us to completely define a circle, as it can be seen below: + + .. image:: images/Hough_Circle_Tutorial_Theory_0.jpg + :alt: Result of detecting circles with Hough Transform + :height: 200pt + :align: center + +* For sake of efficiency, OpenCV implements a detection method slightly trickier than the standard Hough Transform: *The Hough gradient method*. For more details, please check the book *Learning OpenCV* or your favorite Computer Vision bibliography Code ====== @@ -70,9 +92,87 @@ Code return 0; } + +Explanation +============ + + +#. Load an image + + .. code-block:: cpp + + src = imread( argv[1], 1 ); + + if( !src.data ) + { return -1; } + +#. Convert it to grayscale: + + .. code-block:: cpp + + cvtColor( src, src_gray, CV_BGR2GRAY ); + +#. Apply a Gaussian blur to reduce noise and avoid false circle detection: + + .. code-block:: cpp + + GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 ); + +#. Proceed to apply Hough Circle Transform: + + .. code-block:: cpp + + vector circles; + + HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 ); + + with the arguments: + + * *src_gray*: Input image (grayscale) + * *circles*: A vector that stores sets of 3 values: :math:`x_{c}, y_{c}, r` for each detected circle. + * *CV_HOUGH_GRADIENT*: Define the detection method. Currently this is the only one available in OpenCV + * *dp = 1*: The inverse ratio of resolution + * *min_dist = src_gray.rows/8*: Minimum distance between detected centers + * *param_1 = 200*: Upper threshold for the internal Canny edge detector + * *param_2* = 100*: Threshold for center detection. + * *min_radius = 0*: Minimum radio to be detected. If unknown, put zero as default. + * *max_radius = 0*: Maximum radius to be detected. If unknown, put zero as default + +#. Draw the detected circles: + + .. code-block:: cpp + + for( size_t i = 0; i < circles.size(); i++ ) + { + Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); + int radius = cvRound(circles[i][2]); + // circle center + circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 ); + // circle outline + circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 ); + } + + You can see that we will draw the circle(s) on red and the center(s) with a small green dot + +#. Display the detected circle(s): + + .. code-block:: cpp + + namedWindow( "Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE ); + imshow( "Hough Circle Transform Demo", src ); + +#. Wait for the user to exit the program + + .. code-block:: cpp + + waitKey(0); + + Result ======= - + +The result of running the code above with a test image is shown below: + .. image:: images/Hough_Circle_Tutorial_Result.jpg :alt: Result of detecting circles with Hough Transform :align: center diff --git a/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Theory_0.jpg b/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Theory_0.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8b729ca2fdb838e70cb001142cc578b375107a2d GIT binary patch literal 18670 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 C-KQM@ literal 0 HcmV?d00001 -- GitLab