diff --git a/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.markdown b/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.markdown index 36c03cd143..fe2f88be15 100644 --- a/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.markdown +++ b/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.markdown @@ -1,12 +1,15 @@ Hough Circle Transform {#tutorial_hough_circle} ====================== +@prev_tutorial{tutorial_hough_lines} +@next_tutorial{tutorial_remap} + Goal ---- In this tutorial you will learn how to: -- Use the OpenCV function @ref cv::HoughCircles to detect circles in an image. +- Use the OpenCV function **HoughCircles()** to detect circles in an image. Theory ------ @@ -31,31 +34,96 @@ Theory the best radius for each candidate center. For more details, please check the book *Learning OpenCV* or your favorite Computer Vision bibliography +#### What does this program do? +- Loads an image and blur it to reduce the noise +- Applies the *Hough Circle Transform* to the blurred image . +- Display the detected circle in a window. + Code ---- --# **What does this program do?** - - Loads an image and blur it to reduce the noise - - Applies the *Hough Circle Transform* to the blurred image . - - Display the detected circle in a window. - --# The sample code that we will explain can be downloaded from [here](https://github.com/opencv/opencv/tree/master/samples/cpp/houghcircles.cpp). - A slightly fancier version (which shows trackbars for - changing the threshold values) can be found [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/HoughCircle_Demo.cpp). - @include samples/cpp/houghcircles.cpp +@add_toggle_cpp +The sample code that we will explain can be downloaded from +[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp). +A slightly fancier version (which shows trackbars for changing the threshold values) can be found +[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgTrans/HoughCircle_Demo.cpp). +@include samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp +@end_toggle + +@add_toggle_java +The sample code that we will explain can be downloaded from +[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java). +@include samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java +@end_toggle + +@add_toggle_python +The sample code that we will explain can be downloaded from +[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py). +@include samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py +@end_toggle Explanation ----------- --# Load an image - @snippet samples/cpp/houghcircles.cpp load --# Convert it to grayscale: - @snippet samples/cpp/houghcircles.cpp convert_to_gray --# Apply a Median blur to reduce noise and avoid false circle detection: - @snippet samples/cpp/houghcircles.cpp reduce_noise --# Proceed to apply Hough Circle Transform: - @snippet samples/cpp/houghcircles.cpp houghcircles - with the arguments: +The image we used can be found [here](https://raw.githubusercontent.com/opencv/opencv/master/samples/data/smarties.png) + +#### Load an image: + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp load +@end_toggle + +@add_toggle_java +@snippet samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py load +@end_toggle + +@add_toggle_python +@snippet samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java load +@end_toggle + +#### Convert it to grayscale: + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp convert_to_gray +@end_toggle + +@add_toggle_java +@snippet samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py convert_to_gray +@end_toggle + +@add_toggle_python +@snippet samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java convert_to_gray +@end_toggle + +#### Apply a Median blur to reduce noise and avoid false circle detection: + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp reduce_noise +@end_toggle + +@add_toggle_java +@snippet samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py reduce_noise +@end_toggle + +@add_toggle_python +@snippet samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java reduce_noise +@end_toggle + +#### Proceed to apply Hough Circle Transform: + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp houghcircles +@end_toggle + +@add_toggle_java +@snippet samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py houghcircles +@end_toggle + +@add_toggle_python +@snippet samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java houghcircles +@end_toggle + +- with the arguments: - *gray*: Input image (grayscale). - *circles*: A vector that stores sets of 3 values: \f$x_{c}, y_{c}, r\f$ for each detected @@ -69,16 +137,39 @@ Explanation - *min_radius = 0*: Minimum radius 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: - @snippet samples/cpp/houghcircles.cpp draw - You can see that we will draw the circle(s) on red and the center(s) with a small green dot +#### Draw the detected circles: + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp draw +@end_toggle + +@add_toggle_java +@snippet samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py draw +@end_toggle + +@add_toggle_python +@snippet samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java draw +@end_toggle + +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) and wait for the user to exit the program: + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp display +@end_toggle + +@add_toggle_java +@snippet samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py display +@end_toggle --# Display the detected circle(s) and wait for the user to exit the program: - @snippet samples/cpp/houghcircles.cpp display +@add_toggle_python +@snippet samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java display +@end_toggle Result ------ The result of running the code above with a test image is shown below: -![](images/Hough_Circle_Tutorial_Result.jpg) +![](images/Hough_Circle_Tutorial_Result.png) diff --git a/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Result.png b/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Result.png new file mode 100644 index 0000000000..b19ee00ac3 Binary files /dev/null and b/doc/tutorials/imgproc/imgtrans/hough_circle/images/Hough_Circle_Tutorial_Result.png differ diff --git a/doc/tutorials/imgproc/table_of_content_imgproc.markdown b/doc/tutorials/imgproc/table_of_content_imgproc.markdown index d91ec4a953..4bfe9dc967 100644 --- a/doc/tutorials/imgproc/table_of_content_imgproc.markdown +++ b/doc/tutorials/imgproc/table_of_content_imgproc.markdown @@ -133,6 +133,8 @@ In this section you will learn about the image processing (manipulation) functio - @subpage tutorial_hough_circle + *Languages:* C++, Java, Python + *Compatibility:* \> OpenCV 2.0 *Author:* Ana Huamán diff --git a/samples/cpp/houghcircles.cpp b/samples/cpp/houghcircles.cpp deleted file mode 100644 index f749b0e247..0000000000 --- a/samples/cpp/houghcircles.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "opencv2/imgcodecs.hpp" -#include "opencv2/highgui.hpp" -#include "opencv2/imgproc.hpp" - -#include - -using namespace cv; -using namespace std; - -static void help() -{ - cout << "\nThis program demonstrates circle finding with the Hough transform.\n" - "Usage:\n" - "./houghcircles , Default is ../data/board.jpg\n" << endl; -} - -int main(int argc, char** argv) -{ - cv::CommandLineParser parser(argc, argv, - "{help h ||}{@image|../data/board.jpg|}" - ); - if (parser.has("help")) - { - help(); - return 0; - } - //![load] - string filename = parser.get("@image"); - Mat img = imread(filename, IMREAD_COLOR); - if(img.empty()) - { - help(); - cout << "can not open " << filename << endl; - return -1; - } - //![load] - - //![convert_to_gray] - Mat gray; - cvtColor(img, gray, COLOR_BGR2GRAY); - //![convert_to_gray] - - //![reduce_noise] - medianBlur(gray, gray, 5); - //![reduce_noise] - - //![houghcircles] - vector circles; - HoughCircles(gray, circles, HOUGH_GRADIENT, 1, - gray.rows/16, // change this value to detect circles with different distances to each other - 100, 30, 1, 30 // change the last two parameters - // (min_radius & max_radius) to detect larger circles - ); - //![houghcircles] - - //![draw] - for( size_t i = 0; i < circles.size(); i++ ) - { - Vec3i c = circles[i]; - circle( img, Point(c[0], c[1]), c[2], Scalar(0,0,255), 3, LINE_AA); - circle( img, Point(c[0], c[1]), 2, Scalar(0,255,0), 3, LINE_AA); - } - //![draw] - - //![display] - imshow("detected circles", img); - waitKey(); - //![display] - - return 0; -} diff --git a/samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp b/samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp new file mode 100644 index 0000000000..bd0722017d --- /dev/null +++ b/samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp @@ -0,0 +1,65 @@ +/** + * @file houghcircles.cpp + * @brief This program demonstrates circle finding with the Hough transform + */ +#include "opencv2/imgcodecs.hpp" +#include "opencv2/highgui.hpp" +#include "opencv2/imgproc.hpp" + +using namespace cv; +using namespace std; + +int main(int argc, char** argv) +{ + //![load] + const char* filename = argc >=2 ? argv[1] : "../../../data/smarties.png"; + + // Loads an image + Mat src = imread( filename, IMREAD_COLOR ); + + // Check if image is loaded fine + if(src.empty()){ + printf(" Error opening image\n"); + printf(" Program Arguments: [image_name -- default %s] \n", filename); + return -1; + } + //![load] + + //![convert_to_gray] + Mat gray; + cvtColor(src, gray, COLOR_BGR2GRAY); + //![convert_to_gray] + + //![reduce_noise] + medianBlur(gray, gray, 5); + //![reduce_noise] + + //![houghcircles] + vector circles; + HoughCircles(gray, circles, HOUGH_GRADIENT, 1, + gray.rows/16, // change this value to detect circles with different distances to each other + 100, 30, 1, 30 // change the last two parameters + // (min_radius & max_radius) to detect larger circles + ); + //![houghcircles] + + //![draw] + for( size_t i = 0; i < circles.size(); i++ ) + { + Vec3i c = circles[i]; + Point center = Point(c[0], c[1]); + // circle center + circle( src, center, 1, Scalar(0,100,100), 3, LINE_AA); + // circle outline + int radius = c[2]; + circle( src, center, radius, Scalar(255,0,255), 3, LINE_AA); + } + //![draw] + + //![display] + imshow("detected circles", src); + waitKey(); + //![display] + + return 0; +} diff --git a/samples/data/smarties.png b/samples/data/smarties.png new file mode 100644 index 0000000000..90bf22dd3b Binary files /dev/null and b/samples/data/smarties.png differ diff --git a/samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java b/samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java new file mode 100644 index 0000000000..40f97ff874 --- /dev/null +++ b/samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java @@ -0,0 +1,77 @@ +package sample; +/** + * @file HoughCircles.java + * @brief This program demonstrates circle finding with the Hough transform + */ + +import org.opencv.core.*; +import org.opencv.core.Point; +import org.opencv.highgui.HighGui; +import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.imgproc.Imgproc; + +class HoughCirclesRun { + + public void run(String[] args) { + + //! [load] + String default_file = "../../../../data/smarties.png"; + String filename = ((args.length > 0) ? args[0] : default_file); + + // Load an image + Mat src = Imgcodecs.imread(filename, Imgcodecs.IMREAD_COLOR); + + // Check if image is loaded fine + if( src.empty() ) { + System.out.println("Error opening image!"); + System.out.println("Program Arguments: [image_name -- default " + + default_file +"] \n"); + System.exit(-1); + } + //! [load] + + //! [convert_to_gray] + Mat gray = new Mat(); + Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY); + //! [convert_to_gray] + + //![reduce_noise] + Imgproc.medianBlur(gray, gray, 5); + //![reduce_noise] + + //! [houghcircles] + Mat circles = new Mat(); + Imgproc.HoughCircles(gray, circles, Imgproc.HOUGH_GRADIENT, 1.0, + (double)gray.rows()/16, // change this value to detect circles with different distances to each other + 100.0, 30.0, 1, 30); // change the last two parameters + // (min_radius & max_radius) to detect larger circles + //! [houghcircles] + + //! [draw] + for (int x = 0; x < circles.cols(); x++) { + double[] c = circles.get(0, x); + Point center = new Point(Math.round(c[0]), Math.round(c[1])); + // circle center + Imgproc.circle(src, center, 1, new Scalar(0,100,100), 3, 8, 0 ); + // circle outline + int radius = (int) Math.round(c[2]); + Imgproc.circle(src, center, radius, new Scalar(255,0,255), 3, 8, 0 ); + } + //! [draw] + + //! [display] + HighGui.imshow("detected circles", src); + HighGui.waitKey(); + //! [display] + + System.exit(0); + } +} + +public class HoughCircles { + public static void main(String[] args) { + // Load the native library. + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + new HoughCirclesRun().run(args); + } +} diff --git a/samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py b/samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py new file mode 100644 index 0000000000..c8c472f0f8 --- /dev/null +++ b/samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py @@ -0,0 +1,59 @@ +import sys +import cv2 +import numpy as np + + +def main(argv): + ## [load] + default_file = "../../../../data/smarties.png" + filename = argv[0] if len(argv) > 0 else default_file + + # Loads an image + src = cv2.imread(filename, cv2.IMREAD_COLOR) + + # Check if image is loaded fine + if src is None: + print ('Error opening image!') + print ('Usage: hough_circle.py [image_name -- default ' + default_file + '] \n') + return -1 + ## [load] + + ## [convert_to_gray] + # Convert it to gray + gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY) + ## [convert_to_gray] + + ## [reduce_noise] + # Reduce the noise to avoid false circle detection + gray = cv2.medianBlur(gray, 5) + ## [reduce_noise] + + ## [houghcircles] + rows = gray.shape[0] + circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, rows / 8, + param1=100, param2=30, + minRadius=1, maxRadius=30) + ## [houghcircles] + + ## [draw] + if circles is not None: + circles = np.uint16(np.around(circles)) + for i in circles[0, :]: + center = (i[0], i[1]) + # circle center + cv2.circle(src, center, 1, (0, 100, 100), 3) + # circle outline + radius = i[2] + cv2.circle(src, center, radius, (255, 0, 255), 3) + ## [draw] + + ## [display] + cv2.imshow("detected circles", src) + cv2.waitKey(0) + ## [display] + + return 0 + + +if __name__ == "__main__": + main(sys.argv[1:])