diff --git a/doc/tutorials/objdetect/generalized_hough_ballard_guil/generalized_hough_ballard_guil.markdown b/doc/tutorials/objdetect/generalized_hough_ballard_guil/generalized_hough_ballard_guil.markdown new file mode 100644 index 0000000000..6507e0f4a1 --- /dev/null +++ b/doc/tutorials/objdetect/generalized_hough_ballard_guil/generalized_hough_ballard_guil.markdown @@ -0,0 +1,177 @@ +Object detection with Generalized Ballard and Guil Hough Transform {#tutorial_generalized_hough_ballard_guil} +================================================================== + +@tableofcontents + +@prev_tutorial{tutorial_traincascade} + +Goal +---- + +In this tutorial you will lern how to: + +- Use @ref cv::GeneralizedHoughBallard and @ref cv::GeneralizedHoughGuil to detect an object + +Example +------- + +### What does this program do? + +1. Load the image and template + +![image](images/generalized_hough_mini_image.jpg) +![template](images/generalized_hough_mini_template.jpg) + +2. Instantiate @ref cv::GeneralizedHoughBallard with the help of `createGeneralizedHoughBallard()` +3. Instantiate @ref cv::GeneralizedHoughGuil with the help of `createGeneralizedHoughGuil()` +4. Set the required parameters for both GeneralizedHough variants +5. Detect and show found results + +Note: + +- Both variants can't be instantiated directly. Using the create methods is required. +- Guil Hough is very slow. Calculating the results for the "mini" files used in this tutorial + takes only a few seconds. With image and template in a higher resolution, as shown below, + my notebook requires about 5 minutes to calculate a result. + +![image](images/generalized_hough_image.jpg) +![template](images/generalized_hough_template.jpg) + +### Code + +The complete code for this tutorial is shown below. +@include generalizedHoughTransform.cpp + +Explanation +----------- + +### Load image, template and setup variables + +```c++ +// load source images +Mat image = imread("images/generalized_hough_mini_image.jpg"); +Mat imgTemplate = imread("images/generalized_hough_mini_template.jpg"); + +// create grayscale image and template +Mat templ = Mat(imgTemplate.rows, imgTemplate.cols, CV_8UC1); +Mat grayImage; +cvtColor(imgTemplate, templ, COLOR_RGB2GRAY); +cvtColor(image, grayImage, COLOR_RGB2GRAY); + +// create variable for location, scale and rotation of detected templates +vector positionBallard, positionGuil; + +// template width and height +int w = templ.cols; +int h = templ.rows; +``` + +The position vectors will contain the matches the detectors will find. +Every entry contains four floating point values: +position vector + +- *[0]*: x coordinate of center point +- *[1]*: y coordinate of center point +- *[2]*: scale of detected object compared to template +- *[3]*: rotation of detected object in degree in relation to template + +An example could look as follows: `[200, 100, 0.9, 120]` + +### Setup parameters + +```c++ +// create ballard and set options +Ptr ballard = createGeneralizedHoughBallard(); +ballard->setMinDist(10); +ballard->setLevels(360); +ballard->setDp(2); +ballard->setMaxBufferSize(1000); +ballard->setVotesThreshold(40); + +ballard->setCannyLowThresh(30); +ballard->setCannyHighThresh(110); +ballard->setTemplate(templ); + + +// create guil and set options +Ptr guil = createGeneralizedHoughGuil(); +guil->setMinDist(10); +guil->setLevels(360); +guil->setDp(3); +guil->setMaxBufferSize(1000); + +guil->setMinAngle(0); +guil->setMaxAngle(360); +guil->setAngleStep(1); +guil->setAngleThresh(1500); + +guil->setMinScale(0.5); +guil->setMaxScale(2.0); +guil->setScaleStep(0.05); +guil->setScaleThresh(50); + +guil->setPosThresh(10); + +guil->setCannyLowThresh(30); +guil->setCannyHighThresh(110); + +guil->setTemplate(templ); +``` + +Finding the optimal values can end up in trial and error and depends on many factors, such as the image resolution. + +### Run detection + +```c++ +// execute ballard detection + ballard->detect(grayImage, positionBallard); +// execute guil detection + guil->detect(grayImage, positionGuil); +``` + +As mentioned above, this step will take some time, especially with larger images and when using Guil. + +### Draw results and show image + +```c++ +// draw ballard +for (vector::iterator iter = positionBallard.begin(); iter != positionBallard.end(); ++iter) { +RotatedRect rRect = RotatedRect(Point2f((*iter)[0], (*iter)[1]), +Size2f(w * (*iter)[2], h * (*iter)[2]), +(*iter)[3]); +Point2f vertices[4]; +rRect.points(vertices); +for (int i = 0; i < 4; i++) +line(image, vertices[i], vertices[(i + 1) % 4], Scalar(255, 0, 0), 6); +} + +// draw guil +for (vector::iterator iter = positionGuil.begin(); iter != positionGuil.end(); ++iter) { +RotatedRect rRect = RotatedRect(Point2f((*iter)[0], (*iter)[1]), +Size2f(w * (*iter)[2], h * (*iter)[2]), +(*iter)[3]); +Point2f vertices[4]; +rRect.points(vertices); +for (int i = 0; i < 4; i++) +line(image, vertices[i], vertices[(i + 1) % 4], Scalar(0, 255, 0), 2); +} + +imshow("result_img", image); +waitKey(); +return EXIT_SUCCESS; +``` + +Result +------ + +![result image](images/generalized_hough_result_img.jpg) + +The blue rectangle shows the result of @ref cv::GeneralizedHoughBallard and the green rectangles the results of @ref +cv::GeneralizedHoughGuil. + +Getting perfect results like in this example is unlikely if the parameters are not perfectly adapted to the sample. +An example with less perfect parameters is shown below. +For the Ballard variant, only the center of the result is marked as a black dot on this image. The rectangle would be +the same as on the previous image. + +![less perfect result](images/generalized_hough_less_perfect_result_img.jpg) diff --git a/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_image.jpg b/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_image.jpg new file mode 100644 index 0000000000..06f53823b2 Binary files /dev/null and b/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_image.jpg differ diff --git a/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_less_perfect_result_img.jpg b/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_less_perfect_result_img.jpg new file mode 100644 index 0000000000..4f6bf315a8 Binary files /dev/null and b/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_less_perfect_result_img.jpg differ diff --git a/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_mini_image.jpg b/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_mini_image.jpg new file mode 100644 index 0000000000..bcc8b9e414 Binary files /dev/null and b/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_mini_image.jpg differ diff --git a/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_mini_template.jpg b/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_mini_template.jpg new file mode 100644 index 0000000000..69ab30eed3 Binary files /dev/null and b/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_mini_template.jpg differ diff --git a/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_result_img.jpg b/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_result_img.jpg new file mode 100644 index 0000000000..782f730fbc Binary files /dev/null and b/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_result_img.jpg differ diff --git a/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_template.jpg b/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_template.jpg new file mode 100644 index 0000000000..393db734ef Binary files /dev/null and b/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_template.jpg differ diff --git a/doc/tutorials/objdetect/table_of_content_objdetect.markdown b/doc/tutorials/objdetect/table_of_content_objdetect.markdown index 0b019d88a5..6d646a8481 100644 --- a/doc/tutorials/objdetect/table_of_content_objdetect.markdown +++ b/doc/tutorials/objdetect/table_of_content_objdetect.markdown @@ -16,3 +16,13 @@ Ever wondered how your digital camera detects peoples and faces? Look here to fi - @subpage tutorial_traincascade This tutorial describes _opencv_traincascade_ application and its parameters. + +- @subpage tutorial_generalized_hough_ballard_guil + + Detect an object in a picture with the help of GeneralizedHoughBallard and GeneralizedHoughGuil. + + *Languages:* C++ + + *Compatibility:* \> OpenCV 3.4 + + *Author:* Markus Heck \ No newline at end of file diff --git a/doc/tutorials/objdetect/traincascade.markdown b/doc/tutorials/objdetect/traincascade.markdown index d78de2ec9a..7ff39b5a90 100644 --- a/doc/tutorials/objdetect/traincascade.markdown +++ b/doc/tutorials/objdetect/traincascade.markdown @@ -2,6 +2,8 @@ Cascade Classifier Training {#tutorial_traincascade} =========================== @prev_tutorial{tutorial_cascade_classifier} +@next_tutorial{tutorial_generalized_hough_ballard_guil} + Introduction ------------ diff --git a/samples/cpp/tutorial_code/objectDetection/generalizedHoughTransform.cpp b/samples/cpp/tutorial_code/objectDetection/generalizedHoughTransform.cpp new file mode 100644 index 0000000000..3e0e095a9e --- /dev/null +++ b/samples/cpp/tutorial_code/objectDetection/generalizedHoughTransform.cpp @@ -0,0 +1,100 @@ +/** + @file generalizedHoughTransform.cpp + @author Markus Heck + @brief Detects an object, given by a template, in an image using GeneralizedHoughBallard and GeneralizedHoughGuil. +*/ + +#include "opencv2/highgui.hpp" +#include "opencv2/imgproc.hpp" + +using namespace cv; +using namespace std; + +int main() { +// load source images + Mat image = imread("images/generalized_hough_mini_image.jpg"); + Mat imgTemplate = imread("images/generalized_hough_mini_template.jpg"); + +// create grayscale image and template + Mat templ = Mat(imgTemplate.rows, imgTemplate.cols, CV_8UC1); + Mat grayImage; + cvtColor(imgTemplate, templ, COLOR_RGB2GRAY); + cvtColor(image, grayImage, COLOR_RGB2GRAY); + +// create variable for location, scale and rotation of detected templates + vector positionBallard, positionGuil; + +// template width and height + int w = templ.cols; + int h = templ.rows; + +// create ballard and set options + Ptr ballard = createGeneralizedHoughBallard(); + ballard->setMinDist(10); + ballard->setLevels(360); + ballard->setDp(2); + ballard->setMaxBufferSize(1000); + ballard->setVotesThreshold(40); + + ballard->setCannyLowThresh(30); + ballard->setCannyHighThresh(110); + ballard->setTemplate(templ); + + +// create guil and set options + Ptr guil = createGeneralizedHoughGuil(); + guil->setMinDist(10); + guil->setLevels(360); + guil->setDp(3); + guil->setMaxBufferSize(1000); + + guil->setMinAngle(0); + guil->setMaxAngle(360); + guil->setAngleStep(1); + guil->setAngleThresh(1500); + + guil->setMinScale(0.5); + guil->setMaxScale(2.0); + guil->setScaleStep(0.05); + guil->setScaleThresh(50); + + guil->setPosThresh(10); + + guil->setCannyLowThresh(30); + guil->setCannyHighThresh(110); + + guil->setTemplate(templ); + + +// execute ballard detection + ballard->detect(grayImage, positionBallard); +// execute guil detection + guil->detect(grayImage, positionGuil); + + +// draw ballard + for (vector::iterator iter = positionBallard.begin(); iter != positionBallard.end(); ++iter) { + RotatedRect rRect = RotatedRect(Point2f((*iter)[0], (*iter)[1]), + Size2f(w * (*iter)[2], h * (*iter)[2]), + (*iter)[3]); + Point2f vertices[4]; + rRect.points(vertices); + for (int i = 0; i < 4; i++) + line(image, vertices[i], vertices[(i + 1) % 4], Scalar(255, 0, 0), 6); + } + +// draw guil + for (vector::iterator iter = positionGuil.begin(); iter != positionGuil.end(); ++iter) { + RotatedRect rRect = RotatedRect(Point2f((*iter)[0], (*iter)[1]), + Size2f(w * (*iter)[2], h * (*iter)[2]), + (*iter)[3]); + Point2f vertices[4]; + rRect.points(vertices); + for (int i = 0; i < 4; i++) + line(image, vertices[i], vertices[(i + 1) % 4], Scalar(0, 255, 0), 2); + } + + imshow("result_img", image); + waitKey(); + return EXIT_SUCCESS; +} \ No newline at end of file