Tutorial for Generalized Hough Ballard and Guil Transform
authorMarkus Heck <markus.heck13396@gmx.de>
Thu, 8 Sep 2022 01:04:19 +0000 (03:04 +0200)
committerMarkus Heck <markus.heck13396@gmx.de>
Thu, 8 Sep 2022 01:40:52 +0000 (03:40 +0200)
doc/tutorials/objdetect/generalized_hough_ballard_guil/generalized_hough_ballard_guil.markdown [new file with mode: 0644]
doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_image.jpg [new file with mode: 0644]
doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_less_perfect_result_img.jpg [new file with mode: 0644]
doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_mini_image.jpg [new file with mode: 0644]
doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_mini_template.jpg [new file with mode: 0644]
doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_result_img.jpg [new file with mode: 0644]
doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_template.jpg [new file with mode: 0644]
doc/tutorials/objdetect/table_of_content_objdetect.markdown
doc/tutorials/objdetect/traincascade.markdown
samples/cpp/tutorial_code/objectDetection/generalizedHoughTransform.cpp [new file with mode: 0644]

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 (file)
index 0000000..6507e0f
--- /dev/null
@@ -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<Vec4f> 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<GeneralizedHoughBallard> 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<GeneralizedHoughGuil> 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<Vec4f>::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<Vec4f>::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 (file)
index 0000000..06f5382
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 (file)
index 0000000..4f6bf31
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 (file)
index 0000000..bcc8b9e
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 (file)
index 0000000..69ab30e
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 (file)
index 0000000..782f730
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 (file)
index 0000000..393db73
Binary files /dev/null and b/doc/tutorials/objdetect/generalized_hough_ballard_guil/images/generalized_hough_template.jpg differ
index 0b019d88a567f236edba612731d927ccb08867ed..6d646a8481765de815e5448a3d017c7cd120135f 100644 (file)
@@ -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
index d78de2ec9a6f4d679f464c73eaa8af84823e2d45..7ff39b5a909af9dbea72ffb62d10d8354be269cf 100644 (file)
@@ -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 (file)
index 0000000..3e0e095
--- /dev/null
@@ -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<Vec4f> positionBallard, positionGuil;
+
+//  template width and height
+    int w = templ.cols;
+    int h = templ.rows;
+
+//  create ballard and set options
+    Ptr<GeneralizedHoughBallard> 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<GeneralizedHoughGuil> 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<Vec4f>::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<Vec4f>::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