Skip to content

Commit

Permalink
Merge pull request #1290 from rolalaro/fixCHT
Browse files Browse the repository at this point in the history
Improved vpCircleHoughTransform
  • Loading branch information
fspindle authored Dec 8, 2023
2 parents 35e3502 + ad17d88 commit dcfe00a
Show file tree
Hide file tree
Showing 10 changed files with 914 additions and 518 deletions.
106 changes: 58 additions & 48 deletions doc/tutorial/imgproc/tutorial-imgproc-cht.dox
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ we vote along a straight line that follows the gradient.
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
radius bin vote by 1. (*NB*: instead of incrementing one bin by one, we increment two bins by a number between
0 and 1 in our implementation to be more robust against the limits min and max of the radius and
the bin size). The "enough" characteristic is controlled by the circle perfectness
parameter.

\image html img-tutorial-cht-radius-votes.png
Expand All @@ -40,44 +42,53 @@ $ 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:
To run the software on an image like `coins2.jpg` provided with the tutorial and 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
$ ./tutorial-circle-hough --input coins2.jpg --config config/detector_img.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
If you would rather use the command line arguments, please run:
```
$ ./tutorial-circle-hough --input coins2.jpg \
--averaging-window-size 5 \
--canny-backend opencv-backend \
--filtering-type gaussianblur+scharr-filtering \
--canny-thresh -1 -1 \
--lower-canny-ratio 0.6 \
--upper-canny-ratio 0.9 \
--gaussian-kernel 5 \
--gaussian-sigma 1 \
--dilatation-kernel-size 5 \
--center-thresh 70 \
--circle-probability-thresh 0.725 \
--radius-limits 34 75 \
--merging-thresh 5 5 \
--circle-perfectness 0.65 \
--circle-probability-thresh 0.725 \
--center-xlim 0 1920 \
--center-ylim 0 1080 \
--expected-nb-centers -1 \
--edge-filter 3 \
--gradient-kernel 3
```

\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`.
If the detections seem a bit off, you might need to change the parameters in `config/detector_img.json` or in the
command line.

To run the software on an actual image using command line arguments instead, please run:
\note The default values of the program corresponds to these fine-tuned parameters. Running the program
without any additionnal parameters should give the same result:
```
$ ./tutorial-circle-hough --input /path/to/my/image --gaussian-kernel 5 --gaussian-sigma 1 --canny-thresh 100. 200. --dilatation-repet 1 --center-thresh 200 --radius-bin 2 --circle-probability-thresh 0.75 --radius-limits 80 90 --merging-thresh 15 2 --circle-perfectness 0.9
./tutorial-circle-hough
```

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`.
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.

Expand All @@ -88,22 +99,31 @@ $ ./tutorial-circle-hough --input /path/to/video/${BASENAME}%d.png --config conf

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
$ ./tutorial-circle-hough --input /path/to/video/${BASENAME}%d.png \
--averaging-window-size 5 \
--canny-backend opencv-backend \
--filtering-type gaussianblur+scharr-filtering \
--canny-thresh -1 -1 \
--lower-canny-ratio 0.6 \
--upper-canny-ratio 0.9 \
--gaussian-kernel 5 \
--gaussian-sigma 1 \
--dilatation-kernel-size 5 \
--center-thresh 70 \
--circle-probability-thresh 0.725 \
--radius-limits 34 75 \
--merging-thresh 5 5 \
--circle-perfectness 0.65 \
--circle-probability-thresh 0.725 \
--center-xlim 0 1920 \
--center-ylim 0 1080 \
--expected-nb-centers -1 \
--edge-filter 3 \
--gradient-kernel 3
```

\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
Expand All @@ -112,16 +132,6 @@ If you decide to use a single image as input, the relevant piece of code that pe
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:
Expand Down
55 changes: 26 additions & 29 deletions modules/core/include/visp3/core/vpImageMorphology.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,15 @@ class VISP_EXPORT vpImageMorphology

/**
* \brief Modify the image by applying the \b operation on each of its elements on a \b size x \b size
* grid. The connexity that is used is a 8-connexity.
* grid.
*
* \tparam T Any type such as double, unsigned char ...
* \param[out] I The image we want to modify.
* \param[in] size The size of the window with which we want to work.
* \param[in] operation The operation to apply to its elements.
* \param[in] operation The operation to apply to its elements on a the grid.
* \param[in] size Size of the kernel of the operation.
*/
template <typename T>
static void imageOperation(vpImage<T> &I, const int &size, const T &(*operation)(const T &, const T &));
static void imageOperation(vpImage<T> &I, const T &(*operation)(const T &, const T &), const int &size = 3);

public:
template <class Type>
Expand Down Expand Up @@ -408,19 +408,11 @@ void vpImageMorphology::dilatation(vpImage<T> &I, const vpConnexityType &connexi
vpImageMorphology::imageOperation(I, std::numeric_limits<T>::min(), operation, connexity);
}

/**
* \brief Dilatation of \b size >=3 with 8-connectivity.
*
* \tparam T Any type of image, except vpRGBa .
* \param[out] I The image to which the dilatation must be applied, where the dilatation corresponds
* to a max operator on a window of size \b size.
* \param[in] size The size of the window on which is performed the max operator for each pixel.
*/
template<typename T>
void vpImageMorphology::imageOperation(vpImage<T> &I, const int &size, const T &(*operation)(const T &, const T &))
void vpImageMorphology::imageOperation(vpImage<T> &I, const T &(*operation)(const T &, const T &), const int &size)
{
if (size % 2 != 1) {
throw(vpException(vpException::badValue, "Dilatation kernel must be odd."));
throw(vpException(vpException::badValue, "Dilatation/erosion kernel must be odd."));
}

const int width_in = I.getWidth();
Expand Down Expand Up @@ -458,6 +450,7 @@ void vpImageMorphology::imageOperation(vpImage<T> &I, const int &size, const T &
}

/*!
* \brief Erosion of \b size >=3 with 8-connectivity.
Erode an image using the given structuring element.
The erosion of \f$ A \left( x, y \right) \f$ by \f$ B \left (x, y
Expand All @@ -475,22 +468,24 @@ void vpImageMorphology::imageOperation(vpImage<T> &I, const int &size, const T &
\left ( x+x', y+y' \right ) | \left ( x', y'\right ) \subseteq D_B \right \}
\f]
\param I : Image to process.
\param size : The size of the kernel
* \tparam T Any type of image, except vpRGBa .
* \param[out] I The image to which the erosion must be applied, where the erosion corresponds
* to a min operator on a window of size \b size.
* \param[in] size The size of the window on which is performed the min operator for each pixel.
\sa dilatation(vpImage<T> &, const int &)
*/
template <typename T>
void vpImageMorphology::erosion(vpImage<T> &I, const int &size)
{
const T &(*operation)(const T & a, const T & b) = std::min;
vpImageMorphology::imageOperation(I, size, operation);
vpImageMorphology::imageOperation(I, operation, size);
}

/*!
Dilate an image using the given structuring element.
The dilatation of \f$ A \left( x, y \right) \f$ by \f$ B \left
/**
* \brief Dilatation of \b size >=3 with 8-connectivity.
*
* The dilatation of \f$ A \left( x, y \right) \f$ by \f$ B \left
(x, y \right) \f$ is defined as: \f[ \left ( A \oplus B \right ) \left( x,y
\right) = \textbf{max} \left \{ A \left ( x-x', y-y' \right ) + B \left (
x', y'\right ) | \left ( x', y'\right ) \subseteq D_B \right \} \f] where
Expand All @@ -504,17 +499,19 @@ void vpImageMorphology::erosion(vpImage<T> &I, const int &size)
\left ( A \oplus B \right ) \left( x,y \right) = \textbf{max} \left \{ A
\left ( x-x', y-y' \right ) | \left ( x', y'\right ) \subseteq D_B \right \}
\f]
\param I : Image to process.
\param size : The size of the kernel.
\sa erosion(vpImage<T> &, const int &)
*/
template <typename T>
*
* \tparam T Any type of image, except vpRGBa .
* \param[out] I The image to which the dilatation must be applied, where the dilatation corresponds
* to a max operator on a window of size \b size.
* \param[in] size The size of the window on which is performed the max operator for each pixel.
*
* \sa erosion(vpImage<T> &, const int &)
*/
template<typename T>
void vpImageMorphology::dilatation(vpImage<T> &I, const int &size)
{
const T &(*operation)(const T & a, const T & b) = std::max;
vpImageMorphology::imageOperation(I, size, operation);
vpImageMorphology::imageOperation(I, operation, size);
}
#endif

Expand Down
1 change: 0 additions & 1 deletion modules/core/src/image/vpImageCircle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,6 @@ float vpImageCircle::computeAngularCoverageInRoI(const vpRect &roi, const float
computeIntersectionsTopRight(u_c, v_c, vmin_roi, umax_roi, radius, delta_theta);
}
else if (touchBottomBorder && touchTopBorder && touchLeftBorder && !touchRightBorder) {
std::cout << "DEBUG ici" << std::endl;
// Touches/intersects the top, left and bottom borders of the RoI
computeIntersectionsTopLeftBottom(u_c, v_c, umin_roi, vmin_roi, vmax_roi, radius, delta_theta);
}
Expand Down
Loading

0 comments on commit dcfe00a

Please sign in to comment.