Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Circle Hough Transform #1186

Merged
merged 28 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
62790ed
[vpCircleHoughTransform] Creating the tutorial for vpCircleHoughTrans…
Jun 30, 2023
d185f20
Merge remote-tracking branch 'origin/master' into vpCircleHoughTransform
Jun 30, 2023
425ce95
[CLEAN] Corrected signeness of rad to solve compilation warning
Jul 3, 2023
8023dc7
[TUTORIAL] Added how to sections and first draft of detailed explanat…
Jul 3, 2023
41af520
Merge branch 'master' into vpCircleHoughTransform
Jul 6, 2023
a1c946f
[CLEAN] Commented lower because it rose a warning unused variable. Le…
Jul 6, 2023
31c0eaf
[TUTORIAL][vpCHT] Added visp_copy_dir to copy the config folder in th…
Jul 6, 2023
b13fcd8
[vpCHT] Switched to float and added support for detecting circles who…
Jul 6, 2023
c2996e0
Merge branch 'master' into vpCircleHoughTransform
Aug 9, 2023
245b170
[FIX] Corrected the sorting way when the user ask for a particular nu…
Aug 16, 2023
7f34041
Merge branch 'master' into vpCircleHoughTransform
Aug 17, 2023
e8325b4
[FIX] Remvoed normalization of the Gaussian filters used to compute t…
Aug 24, 2023
97abac3
Added safeguards to check if OpenCV core is available
Aug 29, 2023
e6d5eb9
Convert coin1.pgm and coin2.pgm images into jpeg format
fspindle Aug 29, 2023
a5f5230
Add newline at end of file
fspindle Aug 29, 2023
18f2224
Code indentation and newline at end of file
fspindle Aug 29, 2023
dbcdbd0
Minor changes
fspindle Aug 29, 2023
2065133
Merge branch 'master' into vpCircleHoughTransform
fspindle Aug 30, 2023
3839152
Remove HAVE_OPENCV_IMGPROC around canny() when useless
fspindle Aug 30, 2023
6549d69
Merge branch 'master' into vpCircleHoughTransform
fspindle Aug 30, 2023
6fb5f29
Merge branch 'master' into vpCircleHoughTransform
Aug 30, 2023
bd67b5f
[TUTO] Removed test ifdef HAVE_OPENCV_IMGPROC that protected the call…
Aug 30, 2023
04f122a
[CLEAN] Removed some useless cout + [CORPS] Changed inteernal class v…
Aug 30, 2023
2367af0
Fix merge conflict
Aug 30, 2023
db9779e
Removed redundant vpImageMedian file (methods exist in vpImageFilter)…
Aug 30, 2023
2e70005
[TUTO] Changed README section name
Aug 30, 2023
9c20c0c
Removed useless dependancy for CHT tutorial
Aug 30, 2023
dc114dd
Put back visp_imgproc dependancy for CHT tutorial as vpCHT is defined…
Aug 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@
"__nullptr": "cpp",
"__string": "cpp",
"compare": "cpp",
"concepts": "cpp"
"concepts": "cpp",
"*.ipp": "cpp"
},
"C_Cpp.vcFormat.indent.namespaceContents": false,
"editor.formatOnSave": true,
Expand Down
34 changes: 21 additions & 13 deletions ChangeLog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,22 @@ ViSP 3.5.1 (under development)
- Contributors:
. Fabien Spindler, Souriya Trinh, Romain Lagneau, Antonio Marino, Samuel Felton,
Francois Chaumette, Olivier Roussel
- New classes
. vpMocapVicon an interface over Vicon motion capture system
. vpMocapQualisys an interface over Qualisys motion capture system
. vpPclViewer that enables real time plotting of 3D point clouds based on PCL library
. vpRobotUniversalRobots that allows to control an Universal Robots robot
. vpRobotMavsdk that allows to control a robot equiped with a Pixhawk (drone, rover...)
. vpDetectorDNNOpenCV a wrapper over the OpenCV DNN module that allows
to detect objects using Faster-RCNN, SSD-MobileNet, ResNet 10, Yolo v3, Yolo v4,
Yolo v5, Yolo v7 and Yolo v8 convolutional networks
. vpImageCircle that refers to a 2D circle in an image
. vpCircleHoughTransform that allows to detect circles in an image
. vpCannyEdgeDetection that allows to detect Canny edges without using OpenCV
. vpMegaPose and vpMegaPoseTracker classes that are wrapper over MegaPose
https://megapose6d.github.io/ that allows 6D pose estimation using a DNN approach
- New features and improvements
. Video writer is now able to create the output folder recursively (see vpVideoWriter)
. Introduce Universal Robots support with new vpRobotUniversalRobots class that
allows to control an UR robot
. Introduce Vicon and Qualisys motion capture system interfaces in vpMocapVicon and
vpMocapQualisys classes respectively
. Image-based and position-based examples with UR robot
. Tutorial for extrinsic calibration improved with UR robot and Panda robot use cases
. Tutorials in tutorial/grabber folder have now a new --no-display command line option
Expand All @@ -24,20 +34,16 @@ ViSP 3.5.1 (under development)
. Image-based visual-servoing, position and velocity control examples to control robots
equipped with Pixhawk (see vpRobotMavsdk doc)
. Windows 11 support
. New vpDetectorDNNOpenCV class a wrapper over the OpenCV DNN module that allows
to detect objects using Faster-RCNN, SSD-MobileNet, ResNet 10, Yolo v3, Yolo v4,
Yolo v5, Yolo v7 and Yolo v8 convolutional networks
. New capabilities to ease C++ inference to detect objects using convolutional networks
(see vpDetectorDNNOpenCV)
. Support of JSON for modern C++ third-party to enable serialization capabilities
in vpMbGenericTracker, vpCameraParameters, vpPoseVector, vpHomogeneousMatrix,
vpPolygon3D to load/save internal data or settings from/to JSON files
. New vpPclViewer class that enables real time plotting of 3D point clouds based on
PCL library
in vpArray2D, vpCameraParameters, vpCircleHoughTransform, vpColVector, vpDetectorDNNOpenCV,
vpHomogeneousMatrix, vpMbGenericTracker, vpMe, vpPolygon3D, vpPoseVector to load/save
internal data or settings from/to JSON files
. Remove deprecated OpenCV IplImage interfaces
. Remove deprecated vpOpenCVGrabber, vpKeyPointSurf classes and corresponding
tutorials
. Minimum OpenCV version is 2.4.8
. New vpMegaPose and vpMegaPoseTracker classes that are wrapper over MegaPose
https://megapose6d.github.io/ that allows 6D pose estimation using a DNN approach
. Introduce a new moving-edges threshold parameter for the contrast between each side
of the feature to track. Its value corresponds to a gray level in range [0; 255]
. In moving-edges ellipse tracker (vpMeEllipse and vpMbTracker and its derived classes),
Expand Down Expand Up @@ -73,6 +79,8 @@ ViSP 3.5.1 (under development)
https://visp-doc.inria.fr/doxygen/visp-daily/tutorial-tracking-megapose.html
. New tutorial: Exporting a 3D model to MegaPose
https://visp-doc.inria.fr/doxygen/visp-daily/tutorial-megapose-model.html
. New tutorial: Gradient-based Circle Hough Transform
https://visp-doc.inria.fr/doxygen/visp-daily/tutorial-imgproc-cht.html
- Bug fixed
. [#1041] [example/device/framegrabber/saveRealSenseData] Wrong camera parameters
and depth_M_color homogeneous matrix when aligned depth is requested
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
152 changes: 152 additions & 0 deletions doc/tutorial/imgproc/tutorial-imgproc-cht.dox
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/**

\page tutorial-imgproc-cht Tutorial: Gradient-based Circle Hough Transform
\tableofcontents

\section imgproc_cht_intro Introduction

The Circle Hough Transform (*CHT*) is an image processing algorithm that permits to
detect circles in an image. We refer the interested reader to the
[Wikipedia page](https://en.wikipedia.org/wiki/Circle_Hough_Transform) to have a better
understanding on the principles of the algorithm.

The ViSP implementation relies on the Gradient-based implementation of the
algorithm.

During the step where the algorithm votes for center candidates, we use the gradient information
in order to reduce the dimensionality of the search space. Instead of voting in circular pattern,
we vote along a straight line that follows the gradient.

\image html img-tutorial-cht-center-votes.png

Then, during the step where the algorithm votes for radius candidates for each center candidate,
we check the colinearity between the gradient at a considered point and the line which links the
point towards the center candidate. If they are "enough" colinear, we increment the corresponding
radius bin vote by 1. The "enough" characteristic is controlled by the circle perfectness
parameter.

\image html img-tutorial-cht-radius-votes.png

\section imgproc_cht_requirements Requirements

With the current implementation, the `vpCircleHoughTransform` requires ViSP to be compiled with OpenCV.
If you do not know how to do it, please refer to the installation guidelines of \ref soft_vision_opencv.

\section imgproc_cht_howto How to use the tutorial

It is possible to configure the `vpCircleHoughTransform` class using a JSON file.
To do so, you need to install [JSON for modern C++](https://visp-doc.inria.fr/doxygen/visp-daily/supported-third-parties.html#soft_tool_json)
and compile ViSP with it.

You can also configure the `vpCircleHoughTransform` class using command line arguments.
To know what are the different command line arguments the software accept, please run:
```
$ cd tutorial/imgproc/hough-transform
$ ./tutorial-circle-hough --help
```

\subsection imgproc_cht_howto_synthetic How to use synthetic images


To run the software on the synthetic images using a JSON configuration file,
please run:
```
$ TARGET=full # or TARGET=half # or TARGET=quarter
$ ./tutorial-circle-hough --input ${TARGET}_disks --config config/detector_${TARGET}.json
```

To run the software on the synthetic images using the default parameters,
please run:
```
$ TARGET=full # or TARGET=half # or TARGET=quarter
$ ./tutorial-circle-hough --input ${TARGET}_disks
```

\subsection imgproc_cht_howto_images How to use actual images

To run the software on an actual image like `coins2.jpg` provided with the tutorial and using a JSON configuration file, please run:
```
$ ./tutorial-circle-hough --input coins2.jpg --config config/detector_img.json
```

\note The configuration file `config/detector_img.json` has been tuned to detect circles in the image `coins2.jpg`.
If the detections seem a bit off, you might need to change the parameters in `config/detector_img.json`.

To run the software on an actual image using command line arguments instead, please run:
```
$ ./tutorial-circle-hough --input /path/to/my/image --gaussian-kernel 5 --gaussian-sigma 1 --canny-thresh -1. --dilatation-repet 1 --center-thresh 200 --radius-bin 2 --radius-thresh 2 --radius-limits 80 90 --merging-thresh 15 2 --circle-perfectness 0.9
```

If the detections seem a bit off, you might need to change the parameters

\subsection imgproc_cht_howto_video How to use a video

You can use the software to run circle detection on a video saved as a
sequence of images that are named `${BASENAME}%d.png`.
For instance with `${BASENAME}` = `video_`, you can have the following list
of images: `video_0001.png`, `video_0002.png` and so on.

To run the software using a JSON configuration file, please run:
```
$ ./tutorial-circle-hough --input /path/to/video/${BASENAME}%d.png --config config/detector_img.json
```

To run the software using the command arguments, please run:
```
./tutorial-circle-hough --input /path/to/video/${BASENAME}%d.png --gaussian-kernel 5 --gaussian-sigma 1 --canny-thresh -1. --dilatation-repet 1 --center-thresh 200 --radius-bin 2 --radius-thresh 2 --radius-limits 80 90 --merging-thresh 15 2 --circle-perfectness 0.9
```

\section imgproc_cht_explanations Detailed explanations about the tutorial

An enumeration permits to choose between the different types of synthetic images
or using actual images or videos:

\snippet tutorial-circle-hough.cpp Enum input

You can choose the type you want using the command line arguments. To know how to do it,
please run:
```
$ ./tutorial-circle-hough --help
```

If you decide to use a video as input, the relevant piece of code that permits to
perform circle detection on the successive images of the video is the following:
\snippet tutorial-circle-hough.cpp Manage video

If you decide to use a single image as input, the relevant piece of code that permits to
perform circle detection on the image is the following:
\snippet tutorial-circle-hough.cpp Manage single image

If you decide to use a synthetic image as input, the relevant piece of code that
launches the detection on the synthetic image is the following:
\snippet tutorial-circle-hough.cpp Manage synthetic image

The function that draws the synthetic image is the following:
\snippet tutorial-circle-hough.cpp Draw synthetic

It relies on the following function to draw the disks:
\snippet tutorial-circle-hough.cpp Draw disks

If you did not use a JSON file to configure the `vpCircleHoughTransform` detector,
the following structure defines the parameters of the algorithm based on the
command line arguments:
\snippet tutorial-circle-hough.cpp Algo params

The initialization of the algorithm is performed in the following piece of code.
If a JSON configuration file is given as input configuration, it will be preferred
to the command line arguments:
\snippet tutorial-circle-hough.cpp Algo init

To run the circle detection, you must call the following method:
\snippet tutorial-circle-hough.cpp Run detection

You could have also used the following method to get only the `num_best` best
detections:
\code
int num_best; // Set it to the number of circles you want to keep
std::vector<vvpImageCircle> detections = detector.detect(I, num_best);
\endcode

Then, you can iterate on the vector of detections using a synthax similar to the following:
\snippet tutorial-circle-hough.cpp Iterate detections
*/
2 changes: 1 addition & 1 deletion doc/tutorial/imgproc/tutorial-imgproc-count-coins.dox
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ $ ./tutorial-count-coins
To run the demo code for the sample image 2:

\code
$ ./tutorial-count-coins --input coins2.pgm --white_foreground
$ ./tutorial-count-coins --input coins2.jpg --white_foreground
\endcode

The functions we will use needs the following includes:
Expand Down
2 changes: 1 addition & 1 deletion doc/tutorial/tutorial-users.dox
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ This page introduces some image processing methods.
- \subpage tutorial-imgproc-connected-components <br>This tutorial will show you how to do a connected-components labeling.
- \subpage tutorial-imgproc-flood-fill <br>This tutorial will show you how to use the flood fill algorithm.
- \subpage tutorial-imgproc-count-coins <br>This tutorial will show you how to count the number of coins in an image.

- \subpage tutorial-imgproc-cht <br>This tutorial will show you how to use the gradient-based Circle Hough Transform to detect circles in an image.
*/

/*! \page tutorial_calib Camera calibration
Expand Down
2 changes: 2 additions & 0 deletions modules/core/include/visp3/core/vpImageFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -1217,6 +1217,8 @@ class VISP_EXPORT vpImageFilter
}

#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
static double computeCannyThreshold(const cv::Mat &cv_I, const cv::Mat *p_cv_blur, double &lowerThresh);
static double computeCannyThreshold(const vpImage<unsigned char> &I, double &lowerThresh);
static double median(const cv::Mat &cv_I);
static double median(const vpImage<unsigned char> &Isrc);
static std::vector<double> median(const vpImage<vpRGBa> &Isrc);
Expand Down
8 changes: 6 additions & 2 deletions modules/core/src/image/vpImageFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
*****************************************************************************/

#include <visp3/core/vpCannyEdgeDetection.h>
#include <visp3/core/vpException.h>
#include <visp3/core/vpImageConvert.h>
#include <visp3/core/vpImageFilter.h>
#include <visp3/core/vpRGBa.h>
Expand Down Expand Up @@ -214,30 +215,30 @@
* \param[out] lowerThresh The lower threshold for the Canny edge filter.
* \return double The upper Canny edge filter threshold.
*/
double computeCannyThreshold(const cv::Mat &cv_I, const cv::Mat *p_cv_blur, double &lowerThresh)
double vpImageFilter::computeCannyThreshold(const cv::Mat &cv_I, const cv::Mat *p_cv_blur, double &lowerThresh)

Check warning on line 218 in modules/core/src/image/vpImageFilter.cpp

View check run for this annotation

Codecov / codecov/patch

modules/core/src/image/vpImageFilter.cpp#L218

Added line #L218 was not covered by tests
{
cv::Mat cv_I_blur;
if (p_cv_blur != nullptr) {
cv_I_blur = *p_cv_blur;

Check warning on line 222 in modules/core/src/image/vpImageFilter.cpp

View check run for this annotation

Codecov / codecov/patch

modules/core/src/image/vpImageFilter.cpp#L220-L222

Added lines #L220 - L222 were not covered by tests
}
else {
cv::GaussianBlur(cv_I, cv_I_blur, cv::Size(9, 9), 2, 2);

Check warning on line 225 in modules/core/src/image/vpImageFilter.cpp

View check run for this annotation

Codecov / codecov/patch

modules/core/src/image/vpImageFilter.cpp#L225

Added line #L225 was not covered by tests
}

// Subsample image to reach a 256 x 256 size
int req_size = 256;
int orig_size = std::min(static_cast<int>(cv_I.rows), static_cast<int>(cv_I.cols));
int scale_down = std::max(1, static_cast<int>(orig_size / req_size));
cv::Mat cv_I_scaled_down;
resize(cv_I_blur, cv_I_scaled_down, cv::Size(), scale_down, scale_down, cv::INTER_NEAREST);

Check warning on line 233 in modules/core/src/image/vpImageFilter.cpp

View check run for this annotation

Codecov / codecov/patch

modules/core/src/image/vpImageFilter.cpp#L230-L233

Added lines #L230 - L233 were not covered by tests

double median_pix = vpImageFilter::median(cv_I_scaled_down);
double lower = std::max(0., 0.7 * median_pix);
double upper = std::min(255., 1.3 * median_pix);
upper = std::max(1., upper);
lowerThresh = lower;
return upper;
}

Check warning on line 241 in modules/core/src/image/vpImageFilter.cpp

View check run for this annotation

Codecov / codecov/patch

modules/core/src/image/vpImageFilter.cpp#L235-L241

Added lines #L235 - L241 were not covered by tests

/**
* \brief Compute the upper Canny edge filter threshold.
Expand All @@ -245,12 +246,12 @@
* \param[in] I : The gray-scale image, in ViSP format.
* \return double The upper Canny edge filter threshold.
*/
double computeCannyThreshold(const vpImage<unsigned char> &I, double &lowerThresh)
double vpImageFilter::computeCannyThreshold(const vpImage<unsigned char> &I, double &lowerThresh)

Check warning on line 249 in modules/core/src/image/vpImageFilter.cpp

View check run for this annotation

Codecov / codecov/patch

modules/core/src/image/vpImageFilter.cpp#L249

Added line #L249 was not covered by tests
{
cv::Mat cv_I;
vpImageConvert::convert(I, cv_I);
return computeCannyThreshold(cv_I, nullptr, lowerThresh);
}

Check warning on line 254 in modules/core/src/image/vpImageFilter.cpp

View check run for this annotation

Codecov / codecov/patch

modules/core/src/image/vpImageFilter.cpp#L251-L254

Added lines #L251 - L254 were not covered by tests
#endif

/*!
Expand Down Expand Up @@ -296,18 +297,21 @@
unsigned int gaussianFilterSize, double thresholdCanny, unsigned int apertureSobel)
{
#if defined(HAVE_OPENCV_IMGPROC)
cv::Mat img_cvmat, cv_I_blur, edges_cvmat;

Check warning on line 300 in modules/core/src/image/vpImageFilter.cpp

View check run for this annotation

Codecov / codecov/patch

modules/core/src/image/vpImageFilter.cpp#L300

Added line #L300 was not covered by tests
vpImageConvert::convert(Isrc, img_cvmat);
cv::GaussianBlur(img_cvmat, cv_I_blur, cv::Size((int)gaussianFilterSize, (int)gaussianFilterSize), 0, 0);

Check warning on line 302 in modules/core/src/image/vpImageFilter.cpp

View check run for this annotation

Codecov / codecov/patch

modules/core/src/image/vpImageFilter.cpp#L302

Added line #L302 was not covered by tests
double upperCannyThresh = thresholdCanny;
double lowerCannyThresh = thresholdCanny / 3.;
if (upperCannyThresh < 0) {
upperCannyThresh = computeCannyThreshold(img_cvmat, &cv_I_blur, lowerCannyThresh);

Check warning on line 306 in modules/core/src/image/vpImageFilter.cpp

View check run for this annotation

Codecov / codecov/patch

modules/core/src/image/vpImageFilter.cpp#L304-L306

Added lines #L304 - L306 were not covered by tests
}
cv::Canny(cv_I_blur, edges_cvmat, lowerCannyThresh, upperCannyThresh, (int)apertureSobel);

Check warning on line 308 in modules/core/src/image/vpImageFilter.cpp

View check run for this annotation

Codecov / codecov/patch

modules/core/src/image/vpImageFilter.cpp#L308

Added line #L308 was not covered by tests
vpImageConvert::convert(edges_cvmat, Ires);
#else
(void)apertureSobel;
if (thresholdCanny < 0) {
throw(vpException(vpException::badValue, "OpenCV imgproc module missing to be able to compute automatically the Canny thresholds"));
}
vpCannyEdgeDetection edgeDetector(gaussianFilterSize, 0.1, thresholdCanny * 0.5, thresholdCanny);
Ires = edgeDetector.detect(Isrc);
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,17 @@
\ingroup module_imgproc
\defgroup group_imgproc_threshold Automatic thresholding
Automatic thresholding using various well-known methods.

\image html img-auto-threshold-grid36-03.png Input image.
\image html img-auto-threshold-grid36-03-otsu.png Image automatically thresholded with the Otsu method.
*/
/*!
\ingroup module_imgproc
\defgroup group_hough_transform Hough-transform-based image detection
Detection of image features based on the Hough transform.
*/
/*!
\ingroup module_imgproc
\defgroup group_image_median Image median
Image median computation and additional functionalities using image median for Canny edges detection threshold computation.
*/
Loading
Loading