Skip to content

Commit

Permalink
[CORPS] Allow the configuration of the lower Canny threshold
Browse files Browse the repository at this point in the history
  • Loading branch information
rlagneau committed Sep 12, 2023
1 parent dde4641 commit f91582b
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 35 deletions.
40 changes: 26 additions & 14 deletions modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ class VISP_EXPORT vpCircleHoughTransform
int m_sobelKernelSize; /*!< Size of the Sobel kernels used to compute the gradients. Must be an odd number.*/

// // Edge detection attributes
float m_cannyThresh; /*!< The threshold for the Canny operator. Only value greater than this value are marked as an edge.
A negative value makes the algorithm compute this threshold automatically.*/
float m_lowerCannyThresh; /*!< The lower threshold for the Canny operator. Values lower than this value are rejected.
A negative value makes the algorithm compute the lower threshold automatically.*/
float m_upperCannyThresh; /*!< The upper threshold for the Canny operator. Only values greater than this value are marked as an edge.
A negative value makes the algorithm compute the upper and lower thresholds automatically.*/
int m_edgeMapFilteringNbIter; /*!< Number of iterations of 8-neighbor connectivity filtering to apply to the edge map*/

// // Center candidates computation attributes
Expand All @@ -107,7 +109,8 @@ class VISP_EXPORT vpCircleHoughTransform
: m_gaussianKernelSize(5)
, m_gaussianStdev(1.f)
, m_sobelKernelSize(3)
, m_cannyThresh(-1.f)
, m_lowerCannyThresh(-1.f)
, m_upperCannyThresh(-1.f)
, m_edgeMapFilteringNbIter(1)
, m_centerXlimits(std::pair<int, int>(std::numeric_limits<int>::min(), std::numeric_limits<int>::max()))
, m_centerYlimits(std::pair<int, int>(std::numeric_limits<int>::min(), std::numeric_limits<int>::max()))
Expand All @@ -129,8 +132,10 @@ class VISP_EXPORT vpCircleHoughTransform
* \param[in] gaussianKernelSize Size of the Gaussian filter kernel used to smooth the input image. Must be an odd number.
* \param[in] gaussianStdev Standard deviation of the Gaussian filter.
* \param[in] sobelKernelSize Size of the Sobel kernels used to compute the gradients. Must be an odd number.
* \param[in] cannyThresh The threshold for the Canny operator. Only value greater than this value are marked as an edge.
A negative value makes the algorithm compute this threshold automatically.
* \param[in] lowerCannyThresh The lower threshold for the Canny operator. Values lower than this value are rejected.
A negative value makes the algorithm compute this threshold and the lower one automatically.
* \param[in] upperCannyThresh The upper threshold for the Canny operator. Only values greater than this value are marked as an edge.
A negative value makes the algorithm compute this threshold and the lower one automatically.
* \param[in] edgeMapFilterNbIter Number of 8-neighbor connectivity filtering iterations to apply to the edge map.
* \param[in] centerXlimits Minimum and maximum position on the horizontal axis of the center of the circle we want to detect.
* \param[in] centerYlimits Minimum and maximum position on the vertical axis of the center of the circle we want to detect.
Expand All @@ -147,7 +152,8 @@ class VISP_EXPORT vpCircleHoughTransform
const int &gaussianKernelSize
, const float &gaussianStdev
, const int &sobelKernelSize
, const float &cannyThresh
, const float &lowerCannyThresh
, const float &upperCannyThresh
, const int &edgeMapFilterNbIter
, const std::pair<int, int> &centerXlimits
, const std::pair<int, int> &centerYlimits
Expand All @@ -163,7 +169,8 @@ class VISP_EXPORT vpCircleHoughTransform
: m_gaussianKernelSize(gaussianKernelSize)
, m_gaussianStdev(gaussianStdev)
, m_sobelKernelSize(sobelKernelSize)
, m_cannyThresh(cannyThresh)
, m_lowerCannyThresh(lowerCannyThresh)
, m_upperCannyThresh(upperCannyThresh)
, m_edgeMapFilteringNbIter(edgeMapFilterNbIter)
, m_centerXlimits(centerXlimits)
, m_centerYlimits(centerYlimits)
Expand All @@ -185,7 +192,7 @@ class VISP_EXPORT vpCircleHoughTransform
txt += "\tGaussian filter kernel size = " + std::to_string(m_gaussianKernelSize) + "\n";
txt += "\tGaussian filter standard deviation = " + std::to_string(m_gaussianStdev) + "\n";
txt += "\tSobel filter kernel size = " + std::to_string(m_sobelKernelSize) + "\n";
txt += "\tCanny edge filter threshold = " + std::to_string(m_cannyThresh) + "\n";
txt += "\tCanny edge filter thresholds = [" + std::to_string(m_lowerCannyThresh) + " ; " + std::to_string(m_upperCannyThresh) + "]\n";
txt += "\tEdge map 8-neighbor connectivity filtering number of iterations = " + std::to_string(m_edgeMapFilteringNbIter) + "\n";
txt += "\tCenter horizontal position limits: min = " + std::to_string(m_centerXlimits.first) + "\tmax = " + std::to_string(m_centerXlimits.second) +"\n";
txt += "\tCenter vertical position limits: min = " + std::to_string(m_centerYlimits.first) + "\tmax = " + std::to_string(m_centerYlimits.second) +"\n";
Expand Down Expand Up @@ -271,7 +278,8 @@ class VISP_EXPORT vpCircleHoughTransform
throw vpException(vpException::badValue, "Sobel Kernel size should be odd.");
}

params.m_cannyThresh = j.value("cannyThresh", params.m_cannyThresh);
params.m_lowerCannyThresh = j.value("lowerCannyThresh", params.m_lowerCannyThresh);
params.m_upperCannyThresh = j.value("upperCannyThresh", params.m_upperCannyThresh);
params.m_edgeMapFilteringNbIter = j.value("edgeMapFilteringNbIter", params.m_edgeMapFilteringNbIter);

params.m_centerXlimits = j.value("centerXlimits", params.m_centerXlimits);
Expand Down Expand Up @@ -320,7 +328,8 @@ class VISP_EXPORT vpCircleHoughTransform
{"gaussianKernelSize", params.m_gaussianKernelSize},
{"gaussianStdev", params.m_gaussianStdev},
{"sobelKernelSize", params.m_sobelKernelSize},
{"cannyThresh", params.m_cannyThresh},
{"lowerCannyThresh", params.m_lowerCannyThresh},
{"upperCannyThresh", params.m_upperCannyThresh},
{"edgeMapFilteringNbIter", params.m_edgeMapFilteringNbIter},
{"centerXlimits", params.m_centerXlimits},
{"centerYlimits", params.m_centerYlimits},
Expand Down Expand Up @@ -482,12 +491,15 @@ class VISP_EXPORT vpCircleHoughTransform
* Set the threshold for the Canny operator.
* Only value greater than this value are marked as an edge.
* If negative, the threshold is automatically computed.
* \param[in] canny_threshold : Canny filter upper threshold. When set to -1 (default), compute
* \param[in] lowerCannyThreshold : Canny filter lower threshold. When set to -1 (default), compute
* automatically this threshold.
* \param[in] upperCannyThreshold : Canny filter upper threshold. When set to -1 (default), compute
* automatically this threshold.
*/
inline void setCannyThreshold(const float &canny_threshold)
inline void setCannyThreshold(const float &lowerCannyThreshold, const float &upperCannyThreshold)
{
m_algoParams.m_cannyThresh = canny_threshold;
m_algoParams.m_lowerCannyThresh = lowerCannyThreshold;
m_algoParams.m_upperCannyThresh = upperCannyThreshold;
}

/*!
Expand Down Expand Up @@ -680,7 +692,7 @@ class VISP_EXPORT vpCircleHoughTransform
*/
inline float getCannyThreshold() const
{
return m_algoParams.m_cannyThresh;
return m_algoParams.m_upperCannyThresh;
}

/*!
Expand Down
15 changes: 9 additions & 6 deletions modules/imgproc/src/vpCircleHoughTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,16 +220,19 @@ void
vpCircleHoughTransform::edgeDetection(const vpImage<unsigned char> &I)
{
#if defined(HAVE_OPENCV_IMGPROC)
float cannyThresh = m_algoParams.m_cannyThresh;
float lowerThresh;
float upperCannyThresh = m_algoParams.m_upperCannyThresh;
float lowerCannyThresh = m_algoParams.m_lowerCannyThresh;
// Apply the Canny edge operator to compute the edge map
// The canny method performs Gaussian blur and gradient computation
if (m_algoParams.m_cannyThresh < 0.) {
cannyThresh = vpImageFilter::computeCannyThreshold(I, lowerThresh);
if (m_algoParams.m_upperCannyThresh < 0.) {
upperCannyThresh = vpImageFilter::computeCannyThreshold(I, lowerCannyThresh);
}
vpImageFilter::canny(I, m_edgeMap, m_algoParams.m_gaussianKernelSize, cannyThresh, m_algoParams.m_sobelKernelSize);
else if (m_algoParams.m_lowerCannyThresh < 0) {
lowerCannyThresh = upperCannyThresh / 3.;
}
vpImageFilter::canny(I, m_edgeMap, m_algoParams.m_gaussianKernelSize, lowerCannyThresh, upperCannyThresh, m_algoParams.m_sobelKernelSize);
#else
m_cannyVisp.setCannyThresholds(-1, m_algoParams.m_cannyThresh);
m_cannyVisp.setCannyThresholds(m_algoParams.m_lowerCannyThresh, m_algoParams.m_upperCannyThresh);
m_cannyVisp.setGradients(m_dIx, m_dIy);
m_edgeMap = m_cannyVisp.detect(I);
#endif
Expand Down
3 changes: 2 additions & 1 deletion tutorial/imgproc/hough-transform/config/detector_full.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"cannyThresh": 150.0,
"lowerCannyThresh": 50.0,
"upperCannyThresh": 150.0,
"centerMinDistance": 15.0,
"centerThresh": 100.0,
"centerXlimits": [
Expand Down
3 changes: 2 additions & 1 deletion tutorial/imgproc/hough-transform/config/detector_half.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"cannyThresh": 150.0,
"lowerCannyThresh": 50.0,
"upperCannyThresh": 150.0,
"centerMinDistance": 15.0,
"centerThresh": 50.0,
"centerXlimits": [
Expand Down
3 changes: 2 additions & 1 deletion tutorial/imgproc/hough-transform/config/detector_img.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"cannyThresh": -1.0,
"lowerCannyThresh": -1.0,
"upperCannyThresh": -1.0,
"centerMinDistance": 5.0,
"centerThresh": 100.0,
"centerXlimits": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"cannyThresh": 150.0,
"lowerCannyThresh": 50.0,
"upperCannyThresh": 150.0,
"centerMinDistance": 15.0,
"centerThresh": 25.0,
"centerXlimits": [
Expand Down
27 changes: 16 additions & 11 deletions tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,11 @@ int main(int argc, char **argv)
const float def_gaussianSigma = 1.f;
const int def_sobelKernelSize = 3;
#ifdef HAVE_OPENCV_IMGPROC
const float def_cannyThresh = 150.f;
const float def_lowerCannyThresh = 50.f;
const float def_upperCannyThresh = 150.f;
#else
const float def_cannyThresh = 25.f;
const float def_lowerCannyThresh = 8.f;
const float def_upperCannyThresh = 25.f;
#endif
const int def_nbEdgeFilteringIter = 2;
const std::pair<int, int> def_centerXlimits = std::pair<int, int>(0, 640);
Expand All @@ -221,7 +223,8 @@ int main(int argc, char **argv)
int opt_gaussianKernelSize = def_gaussianKernelSize;
float opt_gaussianSigma = def_gaussianSigma;
int opt_sobelKernelSize = def_sobelKernelSize;
float opt_cannyThresh = def_cannyThresh;
float opt_lowerCannyThresh = def_lowerCannyThresh;
float opt_upperCannyThresh = def_upperCannyThresh;
int opt_nbEdgeFilteringIter = def_nbEdgeFilteringIter;
std::pair<int, int> opt_centerXlimits = def_centerXlimits;
std::pair<int, int> opt_centerYlimits = def_centerYlimits;
Expand Down Expand Up @@ -263,9 +266,10 @@ int main(int argc, char **argv)
opt_sobelKernelSize = atoi(argv[i + 1]);
i++;
}
else if (argName == "--canny-thresh" && i + 1 < argc) {
opt_cannyThresh = static_cast<float>(atof(argv[i + 1]));
i++;
else if (argName == "--canny-thresh" && i + 2 < argc) {
opt_lowerCannyThresh = static_cast<float>(atof(argv[i + 1]));
opt_upperCannyThresh = static_cast<float>(atof(argv[i + 2]));
i += 2;
}
else if (argName == "--edge-filter" && i + 1 < argc) {
opt_nbEdgeFilteringIter = atoi(argv[i + 1]);
Expand Down Expand Up @@ -322,7 +326,7 @@ int main(int argc, char **argv)
<< "\t [--gaussian-kernel <kernel-size>] (default: " << def_gaussianKernelSize << ")" << std::endl
<< "\t [--gaussian-sigma <stddev>] (default: " << def_gaussianSigma << ")" << std::endl
<< "\t [--sobel-kernel <kernel-size>] (default: " << def_sobelKernelSize << ")" << std::endl
<< "\t [--canny-thresh <canny-thresh>] (default: " << def_cannyThresh << ")" << std::endl
<< "\t [--canny-thresh <lower-canny-thresh upper-canny-thresh>] (default: " << def_lowerCannyThresh << " ; " << def_upperCannyThresh << ")" << std::endl
<< "\t [--edge-filter <nb-iter>] (default: " << def_nbEdgeFilteringIter << ")" << std::endl
<< "\t [--radius-limits <radius-min> <radius-max>] (default: min = " << def_minRadius << ", max = " << def_maxRadius << ")" << std::endl
<< "\t [--dilatation-repet <nb-repetitions>] (default: " << def_dilatationRepet << ")" << std::endl
Expand Down Expand Up @@ -363,9 +367,9 @@ int main(int argc, char **argv)
<< "\t\tDefault: " << def_gaussianSigma << std::endl
<< std::endl
<< "\t--canny-thresh" << std::endl
<< "\t\tPermit to set the upper threshold of the Canny edge detector." << std::endl
<< "\t\tMust be a positive value." << std::endl
<< "\t\tDefault: " << def_cannyThresh << std::endl
<< "\t\tPermit to set the lower and upper thresholds of the Canny edge detector." << std::endl
<< "\t\tIf a value is negative, it will be automatically computed." << std::endl
<< "\t\tDefault: " << def_upperCannyThresh << std::endl
<< std::endl
<< "\t--edge-filter" << std::endl
<< "\t\tPermit to set the number of iteration of 8-neighbor filter iterations of the result of the Canny edge detector." << std::endl
Expand Down Expand Up @@ -478,7 +482,8 @@ int main(int argc, char **argv)
algoParams(opt_gaussianKernelSize
, opt_gaussianSigma
, opt_sobelKernelSize
, opt_cannyThresh
, opt_lowerCannyThresh
, opt_upperCannyThresh
, opt_nbEdgeFilteringIter
, opt_centerXlimits
, opt_centerYlimits
Expand Down

0 comments on commit f91582b

Please sign in to comment.