From 62790ed371f00a34d5fdc986a44e002977c3cd73 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Fri, 30 Jun 2023 16:07:55 +0200 Subject: [PATCH 01/20] [vpCircleHoughTransform] Creating the tutorial for vpCircleHoughTransform --- .../imgproc/img-tutorial-cht-center-votes.png | Bin 0 -> 22417 bytes .../imgproc/img-tutorial-cht-radius-votes.png | Bin 0 -> 25050 bytes doc/tutorial/imgproc/tutorial-imgproc-cht.dox | 36 + doc/tutorial/tutorial-users.dox | 2 +- modules/imgproc/doc/module.doc | 5 + .../visp3/imgproc/vpCircleHoughTransform.h | 788 ++++++++++++++++++ .../include/visp3/imgproc/vpImageMedian.h | 69 ++ .../imgproc/src/vpCircleHoughTransform.cpp | 450 ++++++++++ modules/imgproc/src/vpImageMedian.cpp | 101 +++ tutorial/CMakeLists.txt | 1 + .../imgproc/hough-transform/CMakeLists.txt | 24 + tutorial/imgproc/hough-transform/README.md | 62 ++ .../hough-transform/config/detector_full.json | 16 + .../hough-transform/config/detector_half.json | 16 + .../hough-transform/config/detector_img.json | 16 + .../config/detector_quarter.json | 16 + .../hough-transform/drawingHelpers.cpp | 54 ++ .../imgproc/hough-transform/drawingHelpers.h | 30 + .../hough-transform/tutorial-circle-hough.cpp | 459 ++++++++++ 19 files changed, 2144 insertions(+), 1 deletion(-) create mode 100644 doc/image/tutorial/imgproc/img-tutorial-cht-center-votes.png create mode 100644 doc/image/tutorial/imgproc/img-tutorial-cht-radius-votes.png create mode 100644 doc/tutorial/imgproc/tutorial-imgproc-cht.dox create mode 100644 modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h create mode 100644 modules/imgproc/include/visp3/imgproc/vpImageMedian.h create mode 100644 modules/imgproc/src/vpCircleHoughTransform.cpp create mode 100644 modules/imgproc/src/vpImageMedian.cpp create mode 100644 tutorial/imgproc/hough-transform/CMakeLists.txt create mode 100644 tutorial/imgproc/hough-transform/README.md create mode 100644 tutorial/imgproc/hough-transform/config/detector_full.json create mode 100644 tutorial/imgproc/hough-transform/config/detector_half.json create mode 100644 tutorial/imgproc/hough-transform/config/detector_img.json create mode 100644 tutorial/imgproc/hough-transform/config/detector_quarter.json create mode 100644 tutorial/imgproc/hough-transform/drawingHelpers.cpp create mode 100644 tutorial/imgproc/hough-transform/drawingHelpers.h create mode 100644 tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp diff --git a/doc/image/tutorial/imgproc/img-tutorial-cht-center-votes.png b/doc/image/tutorial/imgproc/img-tutorial-cht-center-votes.png new file mode 100644 index 0000000000000000000000000000000000000000..273bdbc83360a0c8f52f4cee8e94569cdbb2e9f1 GIT binary patch literal 22417 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 z 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 A&j0`b literal 0 HcmV?d00001 diff --git a/doc/tutorial/imgproc/tutorial-imgproc-cht.dox b/doc/tutorial/imgproc/tutorial-imgproc-cht.dox new file mode 100644 index 0000000000..8db6dd140b --- /dev/null +++ b/doc/tutorial/imgproc/tutorial-imgproc-cht.dox @@ -0,0 +1,36 @@ +/** + +\page tutorial-imgproc-cht 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 + +\section imgproc_cht_howto How to use the tutorial + +\section imgproc_cht_explanations Detailed explanations about the tutorial + +*/ diff --git a/doc/tutorial/tutorial-users.dox b/doc/tutorial/tutorial-users.dox index b70e38db58..96609e86b1 100644 --- a/doc/tutorial/tutorial-users.dox +++ b/doc/tutorial/tutorial-users.dox @@ -73,7 +73,7 @@ This page introduces some image processing methods. - \subpage tutorial-imgproc-connected-components
This tutorial will show you how to do a connected-components labeling. - \subpage tutorial-imgproc-flood-fill
This tutorial will show you how to use the flood fill algorithm. - \subpage tutorial-imgproc-count-coins
This tutorial will show you how to count the number of coins in an image. - +- \subpage tutorial-imgproc-cht
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 diff --git a/modules/imgproc/doc/module.doc b/modules/imgproc/doc/module.doc index 5bfee3bdf2..fcab9acb59 100644 --- a/modules/imgproc/doc/module.doc +++ b/modules/imgproc/doc/module.doc @@ -67,3 +67,8 @@ \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. +*/ \ No newline at end of file diff --git a/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h b/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h new file mode 100644 index 0000000000..fade9dfe9f --- /dev/null +++ b/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h @@ -0,0 +1,788 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + *****************************************************************************/ + +#ifndef _vpCircleHoughTransform_h_ +#define _vpCircleHoughTransform_h_ + +// System includes +#include +#include + +// ViSP includes +#include +#include +#include +#include +#include +#include +#include + +// 3rd parties inclue +#ifdef VISP_HAVE_NLOHMANN_JSON +#include +using json = nlohmann::json; +#endif + +/** + * \brief Class that permits to detect 2D circles in a image using + * the gradient-based Circle Hough transform. + * Please find more information on the algorithm + * [here](https://theailearner.com/tag/hough-gradient-method-opencv/) + * + */ +class VISP_EXPORT vpCircleHoughTransform +{ +public: + /** + * \brief Class that gather the algorithm parameters. + */ + class CHTransformParameters + { + private: + // // Gaussian smoothing attributes + int m_gaussianKernelSize; /*!< Size of the Gaussian filter kernel used to smooth the input image. Must be an odd number.*/ + double m_gaussianStdev; /*!< Standard deviation of the Gaussian filter.*/ + + // // Gradient computation attributes + int m_sobelKernelSize; /*!< Size of the Sobel kernels used to compute the gradients. Must be an odd number.*/ + + // // Edge detection attributes + double 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.*/ + + // // Center candidates computation attributes + unsigned int m_minRadius; /*!< Minimum radius of the circles we want to detect.*/ + unsigned int m_maxRadius; /*!< Maximum radius of the circles we want to detect.*/ + int m_dilatationNbIter; /*!< Number of times dilatation is performed to detect the maximum number of votes for the center candidates.*/ + double m_centerThresh; /*!< Minimum number of votes a point must exceed to be considered as center candidate.*/ + + // // Circle candidates computation attributes + double m_radiusRatioThresh; /*!< Minimum number of votes per radian a radius candidate RC_ij of a center candidate CeC_i must have in order that the circle of center CeC_i and radius RC_ij must be considered as circle candidate.*/ + double m_circlePerfectness; /*!< The scalar product radius RC_ij . gradient(Ep_j) >= m_circlePerfectness * || RC_ij || * || gradient(Ep_j) || to add a vote for the radius RC_ij. */ + + // // Circle candidates merging atttributes + double m_centerMinDist; /*!< Maximum distance between two circle candidates centers to consider merging them.*/ + double m_mergingRadiusDiffThresh; /*!< Maximum radius difference between two circle candidates to consider merging them.*/ + + friend vpCircleHoughTransform; + public: + CHTransformParameters() + : m_gaussianKernelSize(5) + , m_gaussianStdev(1.) + , m_sobelKernelSize(3) + , m_cannyThresh(-1) + , m_minRadius(0) + , m_maxRadius(1000) + , m_dilatationNbIter(1) + , m_centerThresh(50.) + , m_radiusRatioThresh(2.) + , m_circlePerfectness(0.9) + , m_centerMinDist(15.) + , m_mergingRadiusDiffThresh(1.5 * (double)m_centerMinDist) + { + + } + + /** + * \brief Construct a new CHTransformParameters object. + * + * \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] minRadius Minimum radius of the circles we want to detect. + * \param[in] maxRadius Maximum radius of the circles we want to detect. + * \param[in] dilatationNbIter Number of times dilatation is performed to detect the maximum number of votes for the center candidates + * \param[in] centerThresh Minimum number of votes a point must exceed to be considered as center candidate. + * \param[in] radiusThreshRatio Minimum number of votes per radian a radius candidate RC_ij of a center candidate CeC_i must have in order that the circle of center CeC_i and radius RC_ij must be considered as circle candidate. + * \param[in] circlePerfectness The scalar product radius RC_ij . gradient(Ep_j) >= m_circlePerfectness * || RC_ij || * || gradient(Ep_j) || to add a vote for the radius RC_ij. + * \param[in] centerMinDistThresh Two circle candidates whose centers are closer than this threshold are considered for merging. + * \param[in] mergingRadiusDiffThresh Maximum radius difference between two circle candidates to consider merging them. + */ + CHTransformParameters( + const int &gaussianKernelSize + , const double &gaussianStdev + , const int &sobelKernelSize + , const double &cannyThresh + , const unsigned int &minRadius + , const unsigned int &maxRadius + , const int &dilatationNbIter + , const double ¢erThresh + , const double &radiusThreshRatio + , const double &circlePerfectness + , const double ¢erMinDistThresh + , const double &mergingRadiusDiffThresh + ) + : m_gaussianKernelSize(gaussianKernelSize) + , m_gaussianStdev(gaussianStdev) + , m_sobelKernelSize(sobelKernelSize) + , m_cannyThresh(cannyThresh) + , m_minRadius(std::min(minRadius, maxRadius)) + , m_maxRadius(std::max(minRadius, maxRadius)) + , m_dilatationNbIter(dilatationNbIter) + , m_centerThresh(centerThresh) + , m_radiusRatioThresh(radiusThreshRatio) + , m_circlePerfectness(circlePerfectness) + , m_centerMinDist(centerMinDistThresh) + , m_mergingRadiusDiffThresh(mergingRadiusDiffThresh) + { + + } + + std::string toString() const + { + std::string txt("Hough Circle Transform Configuration:\n"); + 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 += "\tRadius limits: min = " + std::to_string(m_minRadius) + "\tmax = " + std::to_string(m_maxRadius) +"\n"; + txt += "\tNumber of repetitions of the dilatation filter = " + std::to_string(m_dilatationNbIter) + "\n"; + txt += "\tCenters votes threshold = " + std::to_string(m_centerThresh) + "\n"; + txt += "\tRadius votes per radian threshold = " + std::to_string(m_radiusRatioThresh) + "\n"; + txt += "\tCircle perfectness threshold = " + std::to_string(m_circlePerfectness) + "\n"; + txt += "\tCenters minimum distance = " + std::to_string(m_centerMinDist) + "\n"; + txt += "\tRadius difference merging threshold = " + std::to_string(m_mergingRadiusDiffThresh) + "\n"; + return txt; + } + + // // Configuration from files + #ifdef VISP_HAVE_NLOHMANN_JSON + /** + * \brief Create a new CHTransformParameters from a JSON file. + * + * \param[in] jsonFile The path towards the JSON file. + * \return CHTransformParameters The corresponding CHTransformParameters object. + */ + inline static CHTransformParameters createFromJSON(const std::string & jsonFile) + { + std::ifstream file(jsonFile); + if (!file.good()) { + std::stringstream ss; + ss << "Problem opening file " << jsonFile << ". Make sure it exists and is readable" << std::endl; + throw vpException(vpException::ioError, ss.str()); + } + json j; + try { + j = json::parse(file); + } + catch (json::parse_error &e) { + std::stringstream msg; + msg << "Could not parse JSON file : \n"; + + msg << e.what() << std::endl; + msg << "Byte position of error: " << e.byte; + throw vpException(vpException::ioError, msg.str()); + } + CHTransformParameters params = j; // Call from_json(const json& j, vpDetectorDNN& *this) to read json + file.close(); + return params; + } + + /** + * \brief Save the configuration of the detector in a JSON file + * described by the path \b jsonPath. Throw a \b vpException + * is the file cannot be created. + * + * \param[in] jsonPath The path towards the JSON output file. + */ + inline void saveConfigurationInJSON(const std::string &jsonPath) const + { + std::ofstream file(jsonPath); + const json j = *this; + file << j.dump(4); + file.close(); + } + + /** + * \brief Read the detector configuration from JSON. All values are optional and if an argument is not present, + * the default value defined in the constructor is kept + * + * \param j The JSON object, resulting from the parsing of a JSON file. + * \param detector The detector, that will be initialized from the JSON data. + */ + inline friend void from_json(const json &j, CHTransformParameters ¶ms) + { + params.m_gaussianKernelSize = j.value("gaussianKernelSize", params.m_gaussianKernelSize); + if ((params.m_gaussianKernelSize % 2) != 1) + { + throw vpException(vpException::badValue, "Gaussian Kernel size should be odd."); + } + + params.m_gaussianStdev = j.value("gaussianStdev", params.m_gaussianStdev); + if (params.m_gaussianStdev <= 0) + { + throw vpException(vpException::badValue, "Standard deviation should be > 0"); + } + + params.m_sobelKernelSize = j.value("sobelKernelSize", params.m_sobelKernelSize); + if ((params.m_sobelKernelSize % 2) != 1) + { + throw vpException(vpException::badValue, "Sobel Kernel size should be odd."); + } + + params.m_cannyThresh = j.value("cannyThresh", params.m_cannyThresh); + + std::pair radiusLimits = j.value("radiusLimits", std::pair(params.m_minRadius, params.m_maxRadius)); + params.m_minRadius = std::min(radiusLimits.first, radiusLimits.second); + params.m_maxRadius = std::max(radiusLimits.first, radiusLimits.second); + + params.m_dilatationNbIter = j.value("dilatationNbIter", params.m_dilatationNbIter); + + params.m_centerThresh = j.value("centerThresh", params.m_centerThresh); + if (params.m_centerThresh <= 0) + { + throw vpException(vpException::badValue, "Votes thresholds for center detection must be positive."); + } + + params.m_radiusRatioThresh = j.value("radiusThreshRatio", params.m_radiusRatioThresh); + + params.m_circlePerfectness = j.value("circlePerfectnessThreshold", params.m_circlePerfectness); + + if (params.m_circlePerfectness <= 0 || params.m_circlePerfectness > 1) + { + throw vpException(vpException::badValue, "Circle perfectness must be in the interval ] 0; 1]."); + } + + params.m_centerMinDist = j.value("centerMinDistance", params.m_centerMinDist); + if (params.m_centerMinDist <= 0) + { + throw vpException(vpException::badValue, "Centers minimum distance threshold must be positive."); + } + + params.m_mergingRadiusDiffThresh = j.value("mergingRadiusDiffThresh", params.m_mergingRadiusDiffThresh); + if (params.m_mergingRadiusDiffThresh <= 0) + { + throw vpException(vpException::badValue, "Radius difference merging threshold must be positive."); + } + } + + /** + * \brief Parse a vpCircleHoughTransform into JSON format. + * + * \param j A JSON parser object. + * \param config The vpCircleHoughTransform that must be parsed into JSON format. + */ + inline friend void to_json(json &j, const CHTransformParameters ¶ms) + { + std::pair radiusLimits = {params.m_minRadius, params.m_maxRadius}; + + j = json{ + {"gaussianKernelSize", params.m_gaussianKernelSize}, + {"gaussianStdev", params.m_gaussianStdev}, + {"sobelKernelSize", params.m_sobelKernelSize}, + {"cannyThresh", params.m_cannyThresh}, + {"radiusLimits", radiusLimits}, + {"dilatationNbIter", params.m_dilatationNbIter}, + {"centerThresh", params.m_centerThresh}, + {"radiusThreshRatio", params.m_radiusRatioThresh}, + {"circlePerfectnessThreshold", params.m_circlePerfectness}, + {"centerMinDistance", params.m_centerMinDist}, + {"mergingRadiusDiffThresh", params.m_mergingRadiusDiffThresh}}; + } + #endif + } ; + + /** + * \brief Class that defines a 2D circle in an image. + */ + class vpCircle2D + { + public: + /*! + * Default constructor. + */ + vpCircle2D() : m_center(), m_radius(0.) { } + + /*! + * Constructor from a center and radius. + */ + vpCircle2D(const vpImagePoint ¢er, double radius) : m_center(center), m_radius(radius) { } + + /*! + * Constructor from an OpenCV vector that contains [center_x, center_y, radius]. + */ + vpCircle2D(const cv::Vec3f &vec) : m_center(vec[1], vec[0]), m_radius(vec[2]) { } + + /*! + * Default destructor. + */ + virtual ~vpCircle2D() { }; + + /*! + * Return the center of the 2D circle. + */ + vpImagePoint getCenter() const { return m_center; }; + + /*! + * Return the radius of the 2D circle. + */ + double getRadius() const { return m_radius; }; + + /*! + * Return the 2D circle bounding box. + */ + vpRect getBBox() const + { + vpRect bbox(m_center - vpImagePoint(m_radius, m_radius), 2 * m_radius, 2 * m_radius); + return bbox; + }; + + /*! + * Return normalized moment \f$n_{20}\f$. + */ + double get_n20() const { return m_radius * m_radius / 4; }; + + /*! + * Return normalized moment \f$n_{02}\f$. + */ + double get_n02() const { return m_radius * m_radius / 4; }; + + /*! + * Return normalized moment \f$n_{02}\f$. + */ + double get_n11() const { return 0.; }; + + template < typename Type > + void display( vpImage< Type > &img, const vpColor &color = vpColor::blue, unsigned int thickness = 1, unsigned int size = 5 ) const; + + private: + vpImagePoint m_center; + double m_radius; + }; + + /** + * \brief Construct a new vpCircleHoughTransform object with default parameters. + */ + vpCircleHoughTransform(); + + /** + * \brief Construct a new vpCircleHoughTransform object + * from a \b CHTransformParameters object. + * \param algoParams The parameters of the Circle Hough Transform. + */ + vpCircleHoughTransform(const CHTransformParameters &algoParams); + + /** + * \brief Destroy the vp Circle Hough Transform object + */ + virtual ~vpCircleHoughTransform(); + + // // Detection methods + + /** + * \brief Perform Circle Hough Transform to detect the circles in an OpenCV image. + * + * \param[in] I The input gray scale image. + * \return std::vector The list of 2D circles detected in the image. + */ + std::vector detect(const cv::Mat &cv_I); + + /** + * \brief Convert the input image in a gray-scale image and then + * perform Circle Hough Transform to detect the circles in it + * + * \param[in] I The input color image. + * \return std::vector The list of 2D circles detected in the image. + */ + std::vector detect(const vpImage &I); + + /** + * \brief Perform Circle Hough Transform to detect the circles in a gray-scale image + * + * \param[in] I The input gray scale image. + * \return std::vector The list of 2D circles detected in the image. + */ + std::vector detect(const vpImage &I); + + /** + * \brief Perform Circle Hough Transform to detect the circles in in a gray-scale image. + * Get only the \b nbCircles circles having the greatest number of votes. + * + * \param[in] I The input gray scale image. + * \param[in] nbCircles The number of circles we want to get. If negative, all the circles will be + * returned, sorted such as result[0] has the highest number of votes and result[end -1] the lowest. + * \return std::vector The list of 2D circles with the most number + * of votes detected in the image. + */ + std::vector detect(const vpImage &I, const int &nbCircles); + +// // Configuration from files +#ifdef VISP_HAVE_NLOHMANN_JSON + /** + * \brief Construct a new vpCircleHoughTransform object configured according to + * the JSON file whose path is \b jsonPath. Throw a \b vpException error if the file + * does not exist. + * \param[in] jsonPath The path towards the JSON configuration file. + */ + vpCircleHoughTransform(const std::string &jsonPath); + + /** + * \brief Initialize all the algorithm parameters using the JSON file + * whose path is \b jsonPath. Throw a \b vpException error if the file + * does not exist. + * + * \param[in] jsonPath The path towards the JSON configuration file. + */ + void initFromJSON(const std::string &jsonPath); + + /** + * \brief Save the configuration of the detector in a JSON file + * described by the path \b jsonPath. Throw a \b vpException + * is the file cannot be created. + * + * \param[in] jsonPath The path towards the JSON output file. + */ + void saveConfigurationInJSON(const std::string &jsonPath) const; + + /** + * \brief Read the detector configuration from JSON. All values are optional and if an argument is not present, + * the default value defined in the constructor is kept + * + * \param j The JSON object, resulting from the parsing of a JSON file. + * \param detector The detector, that will be initialized from the JSON data. + */ + inline friend void from_json(const json &j, vpCircleHoughTransform &detector) + { + detector.m_algoParams = j; + } + + /** + * \brief Parse a vpCircleHoughTransform into JSON format. + * + * \param j A JSON parser object. + * \param config The vpCircleHoughTransform that must be parsed into JSON format. + */ + inline friend void to_json(json &j, const vpCircleHoughTransform &detector) + { + j = detector.m_algoParams; + } +#endif + + // // Setters + /** + * \brief Initialize all the algorithm parameters. + * + * \param[in] algoParams The algorithm parameters. + */ + void init(const CHTransformParameters &algoParams); + + /** + * \brief Set the parameters of the Gaussian filter, that computes the + * gradients of the image. + * + * \param[in] kernelSize The size of the Gaussian kernel. Must be an odd value. + * \param[in] stdev The standard deviation of the Gaussian function. + */ + inline void setGaussianParameters(const int &kernelSize, const double &stdev) + { + m_algoParams.m_gaussianKernelSize = kernelSize; + m_algoParams.m_gaussianStdev = stdev; + + if ((m_algoParams.m_gaussianKernelSize % 2) != 1) + { + throw vpException(vpException::badValue, "Gaussian Kernel size should be odd."); + } + + if (m_algoParams.m_gaussianStdev <= 0) + { + throw vpException(vpException::badValue, "Standard deviation should be > 0"); + } + + initGaussianFilters(); + } + + /*! + * 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 + * automatically this threshold. + */ + inline void setCannyThreshold(double canny_threshold) + { + m_algoParams.m_cannyThresh = canny_threshold; + } + + /*! + * Set circles center min distance. + * Change this value to detect circles with different distances to each other. + * + * \param[in] center_min_dist : Center min distance in pixels. + */ + inline void setCircleCenterMinDist(double center_min_dist) + { + m_algoParams.m_centerMinDist = center_min_dist; + + if (m_algoParams.m_centerMinDist <= 0) + { + throw vpException(vpException::badValue, "Circles center min distance must be positive."); + } + } + + /*! + * Set circles min radius. + * \param[in] circle_min_radius : Min radius in pixels. + */ + inline void setCircleMinRadius(double circle_min_radius) + { + m_algoParams.m_minRadius = circle_min_radius; + } + + /*! + * Set circles max radius. + * \param[in] circle_max_radius : Max radius in pixels. + */ + inline void setCircleMaxRadius(double circle_max_radius) + { + m_algoParams.m_maxRadius = circle_max_radius; + } + + /*! + * Set circles perfectness. The scalar product radius RC_ij . gradient(Ep_j) >= m_circlePerfectness * || RC_ij || * || gradient(Ep_j) || to add a vote for the radius RC_ij. + * \param[in] circle_perfectness : Circle perfectness. Value between 0 and 1. A perfect circle has value 1. + */ + void setCirclePerfectness(double circle_perfectness) + { + m_algoParams.m_circlePerfectness = circle_perfectness; + if (m_algoParams.m_circlePerfectness <= 0 || m_algoParams.m_circlePerfectness > 1) + { + throw vpException(vpException::badValue, "Circle perfectness must be in the interval ] 0; 1]."); + } + } + + /** + * \brief Set the parameters of the computation of the circle center candidates. + * + * \param[in] dilatationRepet Number of repetition of the dilatation operation to detect the maxima in the center accumulator. + * \param[in] centerThresh Minimum number of votes a point must exceed to be considered as center candidate. + */ + inline void setCenterComputationParameters(const int &dilatationRepet, const double ¢erThresh) + { + m_algoParams.m_dilatationNbIter = dilatationRepet; + m_algoParams.m_centerThresh = centerThresh; + + if (m_algoParams.m_centerThresh <= 0) + { + throw vpException(vpException::badValue, "Votes thresholds for center detection must be positive."); + } + } + + /** + * \brief Set the parameters of the computation of the circle radius candidates. + * + * \param[in] radiusRatioThresh Minimum number of votes per radian a radius candidate RC_ij of a center candidate CeC_i must have in order that the circle of center CeC_i and radius RC_ij must be considered as circle candidate. + */ + inline void setRadiusRatioThreshold( const double &radiusRatioThresh ) + { + m_algoParams.m_radiusRatioThresh = radiusRatioThresh; + + if (m_algoParams.m_radiusRatioThresh <= 0) + { + throw vpException(vpException::badValue, "Radius ratio threshold must be > 0."); + } + } + + /** + * \brief Set the radius merging threshold used during the merging step in order + * to merge the circles that are similar. + * + * \param[in] radiusDifferenceThresh Maximum radius difference between two circle candidates to consider merging them. + */ + inline void setRadiusMergingThresholds(const double &radiusDifferenceThresh) + { + m_algoParams.m_mergingRadiusDiffThresh = radiusDifferenceThresh; + + if (m_algoParams.m_mergingRadiusDiffThresh <= 0) + { + throw vpException(vpException::badValue, "Radius difference merging threshold must be positive."); + } + } + + // // Getters + + /** + * \brief Get the list of Center Candidates, stored as pair + * + * \return std::vector> The list of Center Candidates, stored as pair + */ + inline std::vector> getCenterCandidatesList() + { + return m_centerCandidatesList; + } + + /** + * \brief Get the gradient along the horizontal axis of the image. + * + * \return vpImage The gradient along the horizontal axis of the image. + */ + inline vpImage getGradientX() + { + return m_dIx; + } + + /** + * \brief Get the gradient along the vertical axis of the image. + * + * \return vpImage The gradient along the vertical axis of the image. + */ + inline vpImage getGradientY() + { + return m_dIy; + } + + /*! + * Get internal Canny filter upper threshold. When value is equal to -1 (default), it means that the threshold is computed + * automatically. + */ + inline double getCannyThreshold() const + { + return m_algoParams.m_cannyThresh; + } + + /*! + * Get circles center min distance in pixels. + */ + inline double getCircleCenterMinDist() const + { + return m_algoParams.m_centerMinDist; + } + + /*! + * Get circles min radius in pixels. + */ + inline double getCircleMinRadius() const + { + return m_algoParams.m_minRadius; + } + + /*! + * Get circles max radius in pixels. + */ + inline double getCircleMaxRadius() const + { + return m_algoParams.m_maxRadius; + } + + // // Debug methods + std::string toString() const; + + friend VISP_EXPORT std::ostream &operator<<(std::ostream &os, const vpCircleHoughTransform &detector); + +private: + void initGaussianFilters(); + + /** + * \brief Perform Gaussian smoothing on the input image to reduce the noise + * that would perturbate the edge detection. + * Then, compute the x-gradient and y-gradient of the input images. + * + * \param[in] I The input gray scale image. + */ + void computeGradientsAfterGaussianSmoothing(const vpImage &I); + + /** + * \brief Perform edge detection based on the computed gradients. + * Stores the edge points and the edge points connectivity. + * + * \param[in] I The input gray scale image. + */ + void edgeDetection(const vpImage &I); + + /** + * \brief Determine the image points that are circle center candidates. + * Increment the center accumulator based on the edge points and gradient information. + * Perform thresholding to keep only the center candidates that exceed the threshold. + */ + void computeCenterCandidates(); + + /** + * \brief For each center candidate CeC_i, do: + * - For each edge point EP_j, compute the distance d_ij = distance(CeC_i; EP_j) + * - Determine to which radius candidate bin RCB_k the distance d_ij belongs to + * - Increment the radius candidate accumulator accum_rc[CeC_i][RCB_k] + * - If accum_rc[CeC_i][RCB_k] > radius_count_thresh, add the circle candidate (CeC_i, RCB_k) + * to the list of circle candidates + */ + void computeCircleCandidates(); + + /** + * \brief For each circle candidate CiC_i do: + * - For each other circle candidate CiC_j do: + * +- Compute the similarity between CiC_i and CiC_j + * +- If the similarity exceeds a threshold, merge the circle candidates CiC_i and CiC_j and remove CiC_j of the list + * - Add the circle candidate CiC_i to the final list of detected circles + */ + void mergeCircleCandidates(); + + + CHTransformParameters m_algoParams; /*!< Attributes containing all the algorithm parameters.*/ + // // Gaussian smoothing attributes + vpMatrix m_fg; + vpMatrix m_fgDg; + vpImage m_Ifilt; /*!< Filtered version of the input image, after having used a Gaussian filter.*/ + + // // Gradient computation attributes + vpImage m_dIx; /*!< Gradient along the x-axis of the input image.*/ + vpImage m_dIy; /*!< Gradient along the y-axis of the input image.*/ + + // // Edge detection attributes + vpImage m_edgeMap; /*!< Edge map resulting from the edge detection algorithm.*/ + + // // Center candidates computation attributes + std::vector> m_edgePointsList; /*!< Vector that contains the list of edge points, to make faster some parts of the algo. They are stored as pair<#row, #col>.*/ + std::vector> m_centerCandidatesList; /*!< Vector that contains the list of center candidates. They are stored as pair<#row, #col>.*/ + + // // Circle candidates computation attributes + std::vector m_circleCandidates; /*!< List of the candidate circles.*/ + std::vector m_circleCandidatesVotes; /*!< Number of votes for the candidate circles.*/ + + // // Circle candidates merging atttributes + std::vector m_finalCircles; /*!< List of the final circles, i.e. the ones resulting from the merge of the circle candidates.*/ +}; + +/*! + * Display the \b vpCircle2D in an image. + * + * \param[in] img : Image used as background. + * \param[in] color : Color used to draw the CAD model. + * \param[in] thickness : Thickness used to draw the CAD model. + */ +template < typename Type > +inline void +vpCircleHoughTransform::vpCircle2D::display( vpImage< Type > &img, const vpColor &color, unsigned int thickness, unsigned int size ) const +{ + vpImageDraw::drawCross(img, m_center, size, color, thickness); + vpImageDraw::drawCircle(img, m_center, m_radius, color, thickness); +} +#endif \ No newline at end of file diff --git a/modules/imgproc/include/visp3/imgproc/vpImageMedian.h b/modules/imgproc/include/visp3/imgproc/vpImageMedian.h new file mode 100644 index 0000000000..9ef830bbaf --- /dev/null +++ b/modules/imgproc/include/visp3/imgproc/vpImageMedian.h @@ -0,0 +1,69 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ + +#ifndef _vpImageMedian_h_ +#define _vpImageMedian_h_ + +#include + +#if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020408) +#include +#elif defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020101) +#include +#elif defined(VISP_HAVE_OPENCV) +#include +#endif + +namespace ImageFilter +{ +// calculates the median value of a single channel +// based on https://github.com/arnaudgelas/OpenCVExamples/blob/master/cvMat/Statistics/Median/Median.cpp +double median(const cv::Mat &channel); + +/** + * \brief Compute the upper Canny edge filter threshold. + * + * \param[in] cv_I The image, in cv format. + * \return double The upper Canny edge filter threshold. + */ +double computeCannyThreshold(const cv::Mat &cv_I); + +/** + * \brief Compute the upper Canny edge filter threshold. + * + * \param[in] I The gray-scale image, in ViSP format. + * \return double The upper Canny edge filter threshold. + */ +double computeCannyThreshold(const vpImage &I); +} // namespace ImageFilter + +#endif diff --git a/modules/imgproc/src/vpCircleHoughTransform.cpp b/modules/imgproc/src/vpCircleHoughTransform.cpp new file mode 100644 index 0000000000..a98a20dcfe --- /dev/null +++ b/modules/imgproc/src/vpCircleHoughTransform.cpp @@ -0,0 +1,450 @@ +#include +#include +#include + +#include + +vpCircleHoughTransform::vpCircleHoughTransform() + : m_algoParams() +{ + initGaussianFilters(); +} + +vpCircleHoughTransform::vpCircleHoughTransform(const CHTransformParameters &algoParams) + : m_algoParams(algoParams) +{ + initGaussianFilters(); +} + +void +vpCircleHoughTransform::init(const CHTransformParameters &algoParams) +{ + m_algoParams = algoParams; + initGaussianFilters(); +} + +vpCircleHoughTransform::~vpCircleHoughTransform() +{ +} + +#ifdef VISP_HAVE_NLOHMANN_JSON +vpCircleHoughTransform::vpCircleHoughTransform(const std::string &jsonPath) +{ + initFromJSON(jsonPath); +} + +void +vpCircleHoughTransform::initFromJSON(const std::string &jsonPath) +{ + std::ifstream file(jsonPath); + if (!file.good()) { + std::stringstream ss; + ss << "Problem opening file " << jsonPath << ". Make sure it exists and is readable" << std::endl; + throw vpException(vpException::ioError, ss.str()); + } + json j; + try { + j = json::parse(file); + } + catch (json::parse_error &e) { + std::stringstream msg; + msg << "Could not parse JSON file : \n"; + + msg << e.what() << std::endl; + msg << "Byte position of error: " << e.byte; + throw vpException(vpException::ioError, msg.str()); + } + m_algoParams = j; // Call from_json(const json& j, vpDetectorDNN& *this) to read json + file.close(); + initGaussianFilters(); +} + +void +vpCircleHoughTransform::saveConfigurationInJSON(const std::string &jsonPath) const +{ + m_algoParams.saveConfigurationInJSON(jsonPath); +} +#endif + +void +vpCircleHoughTransform::initGaussianFilters() +{ + m_fg.resize(1,(m_algoParams.m_gaussianKernelSize + 1)/2); + vpImageFilter::getGaussianKernel(m_fg.data, m_algoParams.m_gaussianKernelSize, m_algoParams.m_gaussianStdev, true); + m_fgDg.resize(1,(m_algoParams.m_gaussianKernelSize + 1)/2); + vpImageFilter::getGaussianDerivativeKernel(m_fgDg.data, m_algoParams.m_gaussianKernelSize, m_algoParams.m_gaussianStdev, true); +} + +std::vector +vpCircleHoughTransform::detect(const vpImage &I) +{ + vpImage I_gray; + vpImageConvert::convert(I, I_gray); + return detect(I_gray); +} + +std::vector +vpCircleHoughTransform::detect(const cv::Mat &cv_I) +{ + vpImage I_gray; + vpImageConvert::convert(cv_I, I_gray); + return detect(I_gray); +} + +std::vector +vpCircleHoughTransform::detect(const vpImage &I, const int &nbCircles) +{ + std::vector detections = detect(I); + size_t nbDetections = detections.size(); + std::vector bestCircles; + std::vector> detectionsWithVotes; + for(size_t i = 0; i < nbDetections; i++) + { + std::pair detectionWithVote(detections[i], m_circleCandidatesVotes[i]); + detectionsWithVotes.push_back(detectionWithVote); + } + + bool (*hasMoreVotes)(std::pair, std::pair) + = [](std::pair a, std::pair b) + { + return (a.second > b.second); + }; + + std::sort(detectionsWithVotes.begin(), detectionsWithVotes.end(), hasMoreVotes); + + size_t limitMin; + if(nbCircles < 0) + { + limitMin = nbDetections; + } + else + { + limitMin = std::min(nbDetections, (size_t) nbCircles); + } + for(size_t i = 0; i < limitMin; i++) + { + bestCircles.push_back(detectionsWithVotes[i].first); + } + + return bestCircles; +} + +std::vector +vpCircleHoughTransform::detect(const vpImage &I) +{ + // Cleaning results of potential previous detection + m_centerCandidatesList.clear(); + m_edgePointsList.clear(); + m_circleCandidates.clear(); + m_circleCandidatesVotes.clear(); + m_finalCircles.clear(); + + // First thing, we need to apply a Gaussian filter on the image to remove some spurious noise + // Then, we need to compute the image gradients in order to be able to perform edge detection + computeGradientsAfterGaussianSmoothing(I); + + // Using the gradients, it is now possible to perform edge detection + // We rely on the Canny edge detector + // It will also give us the connected edged points + edgeDetection(I); + + // From the edge map and gradient information, it is possible to compute + // the center point candidates + computeCenterCandidates(); + + // From the edge map and center point candidates, we can compute candidate + // circles. These candidate circles are circles whose center belong to + // the center point candidates and whose radius is a "radius bin" that got + // enough votes by computing the distance between each point of the edge map + // and the center point candidate + computeCircleCandidates(); + + // Finally, we perform a merging operation that permits to merge circles + // respecting similarity criteria (distance between centers and similar radius) + mergeCircleCandidates(); + + return m_finalCircles; +} + +void +vpCircleHoughTransform::computeGradientsAfterGaussianSmoothing(const vpImage &I) +{ + vpImageFilter::getGradXGauss2D ( I, + m_dIx, + m_fg.data, + m_fgDg.data, + m_algoParams.m_gaussianKernelSize + ); + vpImageFilter::getGradYGauss2D ( I, + m_dIy, + m_fg.data, + m_fgDg.data, + m_algoParams.m_gaussianKernelSize + ); +} + +void +vpCircleHoughTransform::edgeDetection(const vpImage &I) +{ + #if VISP_HAVE_OPENCV_VERSION >= 0x020100 // Canny uses OpenCV >=2.1.0 + //Apply the Canny edge operator to compute the edge map + // The canny method performs Gaussian blurr and gradient computation + if(m_algoParams.m_cannyThresh < 0.) + { + m_algoParams.m_cannyThresh = ImageFilter::computeCannyThreshold(I); + } + vpImageFilter::canny(I, m_edgeMap, m_algoParams.m_gaussianKernelSize, m_algoParams.m_cannyThresh, m_algoParams.m_sobelKernelSize); + #else + throw(vpException(vpException::functionNotImplementedError, "Canny edge detection has not been implemented yet !")); + #endif +} + +void +vpCircleHoughTransform::computeCenterCandidates() +{ + // For each edge point EP_i, check the image gradient at EP_i + // Then, for each image point in the direction of the gradient, + // increment the accumulator + // We can perform bilinear interpolation in order not to vote for a "line" of + // points, but for an "area" of points + unsigned int nbRows = m_edgeMap.getRows(); + unsigned int nbCols = m_edgeMap.getCols(); + vpImage centersAccum(nbRows, nbCols + 1, 0.); /*!< Matrix that contains the votes for the center candidates.*/ + + m_algoParams.m_maxRadius = std::min(m_algoParams.m_maxRadius, (unsigned int)(std::min(nbCols, nbRows)*0.5)); + + for (unsigned int r = 0; r < nbRows; r++) + { + for (unsigned int c = 0; c < nbCols; c++) + { + if (m_edgeMap[r][c] == 255) + { + // Saving the edge point for further use + m_edgePointsList.push_back(std::pair(r, c)); + + // Voting for points in both direction of the gradient + // Step from min_radius to max_radius in both directions of the gradient + double mag = std::sqrt(m_dIx[r][c] * m_dIx[r][c] + m_dIy[r][c] * m_dIy[r][c]); + + double sx = m_dIx[r][c] / mag; + double sy = m_dIy[r][c] / mag; + + for (int k1 = 0; k1 < 2; k1++) + { + for (int rad = m_algoParams.m_minRadius; rad <= m_algoParams.m_maxRadius; rad++) + { + double x1 = (double)c + (double) rad * sx; + double y1 = (double)r + (double) rad * sy; + + unsigned int x_low = std::floor(x1); + unsigned int y_low = std::floor(y1); + + unsigned int x_high = std::ceil(x1); + unsigned int y_high = std::ceil(y1); + + if( (unsigned)x_low >= nbCols || + (unsigned)y_low >= nbRows ) + break; + centersAccum[y_low][x_low] += std::sqrt(std::pow(x1 - (double)x_low,2) + std::pow(y1 - (double)y_low,2)); + + if( (unsigned)x_high >= nbCols || + (unsigned)y_high >= nbRows ) + break; + centersAccum[y_high][x_high] += std::sqrt(std::pow(x1 - (double)x_high,2) + std::pow(y1 - (double)y_high,2)); + } + + sx = -sx; + sy = -sy; + } + } + } + } + + // Use dilatation with large kernel in order to determine the + // accumulator maxima + vpImage centerCandidatesMaxima = centersAccum; + int niters = std::max(m_algoParams.m_dilatationNbIter, 1); + for (int i = 0; i < niters; i++) + { + vpImageMorphology::dilatation(centerCandidatesMaxima, vpImageMorphology::CONNEXITY_4); + } + + // Look for the image points that correspond to the accumulator maxima + // These points will become the center candidates + // find the possible circle centers + for (unsigned int y = 0; y < nbRows; y++) + { + int left = -1; + for (unsigned int x = 0; x < nbCols; x++) + { + if ( centersAccum[y][x] >= m_algoParams.m_centerThresh + && centersAccum[y][x] == centerCandidatesMaxima[y][x] + && centersAccum[y][x] > centersAccum[y][x + 1] + ) + { + if (left < 0) + left = x; + } + else if (left >= 0) + { + unsigned int cx = (unsigned int)((left + x - 1) * 0.5f); + m_centerCandidatesList.push_back(std::pair(y, cx)); + left = -1; + } + } + } +} + +void +vpCircleHoughTransform::computeCircleCandidates() +{ + size_t nbCenterCandidates = m_centerCandidatesList.size(); + unsigned int nbBins = (m_algoParams.m_maxRadius - m_algoParams.m_minRadius + 1)/ m_algoParams.m_centerMinDist; + nbBins = std::max((unsigned int)1, nbBins); // Avoid having 0 bins, which causes segfault + std::vector radiusAccumList; /*!< Radius accumulator for each center candidates.*/ + std::vector radiusActualValueList; /*!< Vector that contains the actual distance between the edge points and the center candidates.*/ + + unsigned int rmin2 = m_algoParams.m_minRadius * m_algoParams.m_minRadius; + unsigned int rmax2 = m_algoParams.m_maxRadius * m_algoParams.m_maxRadius; + int circlePerfectness2 = m_algoParams.m_circlePerfectness * m_algoParams.m_circlePerfectness; + + for(size_t i = 0; i < nbCenterCandidates; i++) + { + std::pair centerCandidate = m_centerCandidatesList[i]; + // Initialize the radius accumulator of the candidate with 0s + radiusAccumList.clear(); + radiusAccumList.resize(nbBins, 0); + radiusActualValueList.clear(); + radiusActualValueList.resize(nbBins, 0.); + + for(auto edgePoint : m_edgePointsList) + { + // For each center candidate CeC_i, compute the distance with each edge point EP_j d_ij = dist(CeC_i; EP_j) + unsigned int rx = edgePoint.first - centerCandidate.first; + unsigned int ry = edgePoint.second - centerCandidate.second; + unsigned int r2 = rx * rx + ry * ry; + + if((r2 > rmin2) && (r2 < rmax2)) + { + double r = std::sqrt(r2); + + double gx = m_dIx[edgePoint.first][edgePoint.second]; + double gy = m_dIy[edgePoint.first][edgePoint.second]; + double grad2 = gx * gx + gy * gy; + + int scalProd = rx * gx + ry * gy; + int scalProd2 = scalProd * scalProd; + if(scalProd2 >= circlePerfectness2 * r2 * grad2) + { + // Look for the Radius Candidate Bin RCB_k to which d_ij is "the closest" will have an additionnal vote + unsigned int r_bin = std::ceil((r - m_algoParams.m_minRadius)/ m_algoParams.m_centerMinDist); + r_bin = std::min(r_bin, nbBins - 1); + radiusAccumList[r_bin]++; + radiusActualValueList[r_bin] +=r; + } + } + } + + for(unsigned int idBin = 0; idBin < nbBins; idBin++) + { + // If the circle of center CeC_i and radius RCB_k has enough votes, it is added to the list + // of Circle Candidates + double r_effective = radiusActualValueList[idBin] / (double)radiusAccumList[idBin]; + if((double)radiusAccumList[idBin] / r_effective > m_algoParams.m_radiusRatioThresh ) + { + m_circleCandidates.push_back(vpCircleHoughTransform::vpCircle2D( vpImagePoint(centerCandidate.first, centerCandidate.second) + , r_effective + ) + ); + m_circleCandidatesVotes.push_back(radiusAccumList[idBin]); + } + } + } +} + +void +vpCircleHoughTransform::mergeCircleCandidates() +{ + // For each circle candidate CiC_i do: + size_t nbCandidates = m_circleCandidates.size(); + for(size_t i = 0; i < nbCandidates; i++) + { + vpCircleHoughTransform::vpCircle2D cic_i = m_circleCandidates[i]; + // // For each other circle candidate CiC_j do: + for(size_t j = i + 1; j < nbCandidates; j++) + { + vpCircleHoughTransform::vpCircle2D cic_j = m_circleCandidates[j]; + // // // Compute the similarity between CiC_i and CiC_j + double distanceBetweenCenters = vpImagePoint::distance(cic_i.getCenter(), cic_j.getCenter()); + double radiusDifference = std::abs(cic_i.getRadius() - cic_j.getRadius()); + bool areCirclesSimilar = ( distanceBetweenCenters < m_algoParams.m_centerMinDist + && radiusDifference < m_algoParams.m_mergingRadiusDiffThresh + ); + + if( areCirclesSimilar ) + { + // // // If the similarity exceeds a threshold, merge the circle candidates CiC_i and CiC_j and remove CiC_j of the list + unsigned int totalVotes = m_circleCandidatesVotes[i] + m_circleCandidatesVotes[j]; + cic_i = vpCircleHoughTransform::vpCircle2D( (cic_i.getCenter() * m_circleCandidatesVotes[i]+ cic_j.getCenter() * m_circleCandidatesVotes[j]) / totalVotes + , (cic_i.getRadius() * m_circleCandidatesVotes[i] + cic_j.getRadius() * m_circleCandidatesVotes[j]) / totalVotes + ); + m_circleCandidates[j] = m_circleCandidates[nbCandidates - 1]; + m_circleCandidatesVotes[i] = totalVotes; + m_circleCandidatesVotes[j] = m_circleCandidatesVotes[nbCandidates - 1]; + m_circleCandidates.pop_back(); + m_circleCandidatesVotes.pop_back(); + nbCandidates--; + j--; + } + } + // // Add the circle candidate CiC_i, potentially merged with other circle candidates, to the final list of detected circles + m_finalCircles.push_back(cic_i); + } + + nbCandidates = m_finalCircles.size(); + for(size_t i = 0; i < nbCandidates; i++) + { + vpCircleHoughTransform::vpCircle2D cic_i = m_finalCircles[i]; + // // For each other circle candidate CiC_j do: + for(size_t j = i + 1; j < nbCandidates; j++) + { + vpCircleHoughTransform::vpCircle2D cic_j = m_finalCircles[j]; + // // // Compute the similarity between CiC_i and CiC_j + double distanceBetweenCenters = vpImagePoint::distance(cic_i.getCenter(), cic_j.getCenter()); + double radiusDifference = std::abs(cic_i.getRadius() - cic_j.getRadius()); + bool areCirclesSimilar = ( distanceBetweenCenters < m_algoParams.m_centerMinDist + && radiusDifference < m_algoParams.m_mergingRadiusDiffThresh + ); + + if( areCirclesSimilar ) + { + // // // If the similarity exceeds a threshold, merge the circle candidates CiC_i and CiC_j and remove CiC_j of the list + unsigned int totalVotes = m_circleCandidatesVotes[i] + m_circleCandidatesVotes[j]; + cic_i = vpCircleHoughTransform::vpCircle2D( (cic_i.getCenter() * m_circleCandidatesVotes[i]+ cic_j.getCenter() * m_circleCandidatesVotes[j]) / totalVotes + , (cic_i.getRadius() * m_circleCandidatesVotes[i] + cic_j.getRadius() * m_circleCandidatesVotes[j]) / totalVotes + ); + m_finalCircles[j] = m_finalCircles[nbCandidates - 1]; + m_circleCandidatesVotes[i] = totalVotes; + m_circleCandidatesVotes[j] = m_circleCandidatesVotes[nbCandidates - 1]; + m_finalCircles.pop_back(); + m_circleCandidatesVotes.pop_back(); + nbCandidates--; + j--; + } + } + // // Add the circle candidate CiC_i, potentially merged with other circle candidates, to the final list of detected circles + m_finalCircles[i] = cic_i; + } +} + +std::string +vpCircleHoughTransform::toString() const +{ + return m_algoParams.toString(); +} + +std::ostream &operator<<(std::ostream &os, const vpCircleHoughTransform &detector) +{ + os << detector.toString(); + return os; +} \ No newline at end of file diff --git a/modules/imgproc/src/vpImageMedian.cpp b/modules/imgproc/src/vpImageMedian.cpp new file mode 100644 index 0000000000..accd32a47c --- /dev/null +++ b/modules/imgproc/src/vpImageMedian.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ + +#include + +#include + +namespace ImageFilter +{ +// calculates the median value of a single channel +// based on https://github.com/arnaudgelas/OpenCVExamples/blob/master/cvMat/Statistics/Median/Median.cpp +double median(const cv::Mat &channel) +{ + double m = (channel.rows * channel.cols) / 2; + int bin = 0; + double med = -1.0; + + int histSize = 256; + float range [] = { 0, 256 }; + const float *histRange = { range }; + bool uniform = true; + bool accumulate = false; + cv::Mat hist; + cv::calcHist(&channel, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange, uniform, accumulate); + + for (int i = 0; i < histSize && med < 0.0; ++i) { + bin += cvRound(hist.at(i)); + if (bin > m && med < 0.0) + med = i; + } + + return med; +} + +/** + * \brief Compute the upper Canny edge filter threshold. + * + * \param[in] cv_I The image, in cv format. + * \return double The upper Canny edge filter threshold. + */ +double computeCannyThreshold(const cv::Mat &cv_I) +{ + cv::Mat cv_I_blur; + cv::GaussianBlur(cv_I, cv_I_blur, cv::Size(9, 9), 2, 2); + + // Subsample image to reach a 256 x 256 size + int req_size = 256; + int orig_size = std::min(static_cast(cv_I.rows), static_cast(cv_I.cols)); + int scale_down = std::max(1, static_cast(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); + + double median_pix = ImageFilter::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); + return upper; +} + +/** + * \brief Compute the upper Canny edge filter threshold. + * + * \param[in] I The gray-scale image, in ViSP format. + * \return double The upper Canny edge filter threshold. + */ +double computeCannyThreshold(const vpImage &I) +{ + cv::Mat cv_I; + vpImageConvert::convert(I, cv_I); + return computeCannyThreshold(cv_I); +} +} // namespace ImageFilter \ No newline at end of file diff --git a/tutorial/CMakeLists.txt b/tutorial/CMakeLists.txt index 8dbfc4db20..fba157d97c 100644 --- a/tutorial/CMakeLists.txt +++ b/tutorial/CMakeLists.txt @@ -44,6 +44,7 @@ visp_add_subdirectory(imgproc/contour REQUIRED_DEPS visp_co visp_add_subdirectory(imgproc/contrast-sharpening REQUIRED_DEPS visp_core visp_io visp_gui visp_imgproc) visp_add_subdirectory(imgproc/count-coins REQUIRED_DEPS visp_core visp_io visp_gui visp_imgproc) visp_add_subdirectory(imgproc/flood-fill REQUIRED_DEPS visp_core visp_io visp_gui visp_imgproc) +visp_add_subdirectory(imgproc/hough-transform REQUIRED_DEPS visp_core visp_gui visp_imgproc) visp_add_subdirectory(munkres REQUIRED_DEPS visp_core visp_gui) visp_add_subdirectory(robot/flir-ptu REQUIRED_DEPS visp_core visp_robot visp_sensor visp_vision visp_gui visp_vs visp_visual_features visp_detection) visp_add_subdirectory(robot/pioneer REQUIRED_DEPS visp_core visp_robot visp_vs visp_gui) diff --git a/tutorial/imgproc/hough-transform/CMakeLists.txt b/tutorial/imgproc/hough-transform/CMakeLists.txt new file mode 100644 index 0000000000..fdbe6d6120 --- /dev/null +++ b/tutorial/imgproc/hough-transform/CMakeLists.txt @@ -0,0 +1,24 @@ +project(tutorial-) + +cmake_minimum_required(VERSION 3.0) + +find_package(VISP REQUIRED visp_core visp_gui visp_imgproc) + +# set the list of source files +set(tutorial_cpp + tutorial-circle-hough.cpp + ) + +list(APPEND tutorial_data "${CMAKE_CURRENT_SOURCE_DIR}/config") + +foreach(cpp ${tutorial_cpp}) + visp_add_target(${cpp} drawingHelpers.cpp) + if(COMMAND visp_add_dependency) + visp_add_dependency(${cpp} "tutorials") + endif() +endforeach() + +# Copy the data files to the same location than the target +foreach(data ${tutorial_data}) + visp_copy_data(tutorial-circle-hough.cpp ${data}) +endforeach() diff --git a/tutorial/imgproc/hough-transform/README.md b/tutorial/imgproc/hough-transform/README.md new file mode 100644 index 0000000000..faedb9594c --- /dev/null +++ b/tutorial/imgproc/hough-transform/README.md @@ -0,0 +1,62 @@ +# tutorial-cht + +## Running the tutorial-cht software + +### On synthetic images + +#### Using a JSON file as configuration file +To use a JSON file as configuration, 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. +Then, recompile the Trasys project as explained in section [Building the Trasys project](#building_trasys) + +To run the software on the synthetic images, please run: +``` +$ TARGET=full # or TARGET=half # or TARGET=quarter +$ cd ${TRASYS_WS}/trasys-dev-build +$ ./tutorial-circle-hough --input ${TARGET}_disks --config config/detector_${TARGET}.json +``` + +#### Using command lines + +To run the software on the synthetic images without a JSON configuration file, please run: +``` +$ TARGET=full # or TARGET=half # or TARGET=quarter +$ cd ${TRASYS_WS}/trasys-dev-build +$ ./tutorial-circle-hough --input ${TARGET}_disks +``` + +### On actual images + +#### Using a JSON configuration file +To run the software on an actual image, please run: +``` +$ ./tutorial-circle-hough --input /path/to/my/image --config config/detector_img.json +``` + +If the detections seem a bit off, you might need to change the parameters + +#### Using command lines + +To run the software on an actual image without a JSON configuration file, please run: +``` +$ TARGET=full # or TARGET=half # or TARGET=quarter +$ cd ${TRASYS_WS}/trasys-dev-build +$ ./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 +``` + +### On 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. + +#### Using a JSON file as input + +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 +``` + +#### Using program arguments +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 +``` \ No newline at end of file diff --git a/tutorial/imgproc/hough-transform/config/detector_full.json b/tutorial/imgproc/hough-transform/config/detector_full.json new file mode 100644 index 0000000000..0b3f2b7017 --- /dev/null +++ b/tutorial/imgproc/hough-transform/config/detector_full.json @@ -0,0 +1,16 @@ +{ + "cannyThresh": 150.0, + "centerMinDistance": 15.0, + "centerThresh": 50.0, + "circlePerfectnessThreshold": 0.9, + "dilatationNbIter": 1, + "gaussianKernelSize": 5, + "gaussianStdev": 1.0, + "mergingRadiusDiffThresh": 15.0, + "radiusLimits": [ + 0, + 1000 + ], + "radiusThreshRatio": 5, + "sobelKernelSize": 3 +} diff --git a/tutorial/imgproc/hough-transform/config/detector_half.json b/tutorial/imgproc/hough-transform/config/detector_half.json new file mode 100644 index 0000000000..c4928b1fd6 --- /dev/null +++ b/tutorial/imgproc/hough-transform/config/detector_half.json @@ -0,0 +1,16 @@ +{ + "cannyThresh": 150.0, + "centerMinDistance": 15.0, + "centerThresh": 25.0, + "circlePerfectnessThreshold": 0.9, + "dilatationNbIter": 1, + "gaussianKernelSize": 5, + "gaussianStdev": 1.0, + "mergingRadiusDiffThresh": 15.0, + "radiusLimits": [ + 0, + 1000 + ], + "radiusThreshRatio": 2, + "sobelKernelSize": 3 +} diff --git a/tutorial/imgproc/hough-transform/config/detector_img.json b/tutorial/imgproc/hough-transform/config/detector_img.json new file mode 100644 index 0000000000..1c654f3d20 --- /dev/null +++ b/tutorial/imgproc/hough-transform/config/detector_img.json @@ -0,0 +1,16 @@ +{ + "cannyThresh": -1.0, + "centerMinDistance": 5.0, + "centerThresh": 200.0, + "circlePerfectnessThreshold": 0.9, + "dilatationNbIter": 1, + "gaussianKernelSize": 5, + "gaussianStdev": 1.0, + "mergingRadiusDiffThresh": 5.0, + "radiusLimits": [ + 80, + 90 + ], + "radiusThreshRatio": 2, + "sobelKernelSize": 3 +} diff --git a/tutorial/imgproc/hough-transform/config/detector_quarter.json b/tutorial/imgproc/hough-transform/config/detector_quarter.json new file mode 100644 index 0000000000..3b51e18ef7 --- /dev/null +++ b/tutorial/imgproc/hough-transform/config/detector_quarter.json @@ -0,0 +1,16 @@ +{ + "cannyThresh": 150.0, + "centerMinDistance": 15.0, + "centerThresh": 15.0, + "circlePerfectnessThreshold": 0.9, + "dilatationNbIter": 1, + "gaussianKernelSize": 5, + "gaussianStdev": 1.0, + "mergingRadiusDiffThresh": 15.0, + "radiusLimits": [ + 0, + 1000 + ], + "radiusThreshRatio": 1, + "sobelKernelSize": 3 +} diff --git a/tutorial/imgproc/hough-transform/drawingHelpers.cpp b/tutorial/imgproc/hough-transform/drawingHelpers.cpp new file mode 100644 index 0000000000..4215a52270 --- /dev/null +++ b/tutorial/imgproc/hough-transform/drawingHelpers.cpp @@ -0,0 +1,54 @@ +#include "drawingHelpers.h" + +#if defined(VISP_HAVE_X11) + vpDisplayX drawingHelpers::d; +#elif defined(VISP_HAVE_OPENCV) + vpDisplayOpenCV drawingHelpers::d; +#elif defined(VISP_HAVE_GTK) + vpDisplayGTK drawingHelpers::d; +#elif defined(VISP_HAVE_GDI) + vpDisplayGDI drawingHelpers::d; +#elif defined(VISP_HAVE_D3D9) + vpDisplayD3D drawingHelpers::d; +#endif + +vpImage drawingHelpers::I_disp; + +bool drawingHelpers::display(vpImage &I, const std::string &title, const bool &blockingMode) +{ + I_disp = I; + if(! d.isInitialised()) + { + d.init(I_disp); + vpDisplay::setTitle(I_disp, title.c_str()); + } + + vpDisplay::display(I_disp); + vpDisplay::displayText(I_disp, 15, 15, "Left click to continue...", vpColor::red); + vpDisplay::displayText(I_disp, 35, 15, "Right click to stop...", vpColor::red); + vpDisplay::flush(I_disp); + vpMouseButton::vpMouseButtonType button; + vpDisplay::getClick(I_disp, button, blockingMode); + bool hasToContinue = true; + if (button == vpMouseButton::button3) + { + // Right click => stop the program + hasToContinue = false; + } + + return hasToContinue; +} + +bool drawingHelpers::display(vpImage &D, const std::string &title, const bool &blockingMode) +{ + vpImage I; // Image to display + vpImageConvert::convert(D, I); + return display(I, title, blockingMode); +} + +bool drawingHelpers::display(vpImage &D, const std::string &title, const bool &blockingMode) +{ + vpImage I; // Image to display + vpImageConvert::convert(D, I); + return display(I, title, blockingMode); +} \ No newline at end of file diff --git a/tutorial/imgproc/hough-transform/drawingHelpers.h b/tutorial/imgproc/hough-transform/drawingHelpers.h new file mode 100644 index 0000000000..d58df2abd5 --- /dev/null +++ b/tutorial/imgproc/hough-transform/drawingHelpers.h @@ -0,0 +1,30 @@ +#ifndef _drawingHelpers_h_ +#define _drawingHelpers_h_ + +#include +#include +#include +#include + +namespace drawingHelpers +{ + #if defined(VISP_HAVE_X11) + extern vpDisplayX d; + #elif defined(VISP_HAVE_OPENCV) + extern vpDisplayOpenCV d; + #elif defined(VISP_HAVE_GTK) + extern vpDisplayGTK d; + #elif defined(VISP_HAVE_GDI) + extern vpDisplayGDI d; + #elif defined(VISP_HAVE_D3D9) + extern vpDisplayD3D d; + #endif + + extern vpImage I_disp; + + bool display(vpImage &I, const std::string &title, const bool &blockingMode); + bool display(vpImage &I, const std::string &title, const bool &blockingMode); + bool display(vpImage &D, const std::string &title, const bool &blockingMode); +} + +#endif \ No newline at end of file diff --git a/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp new file mode 100644 index 0000000000..7e0c8f29a4 --- /dev/null +++ b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp @@ -0,0 +1,459 @@ +// ViSP includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "drawingHelpers.h" + +typedef enum TypeInputImage +{ + FULL_DISKS = 0, + HALF_DISKS = 1, + QUARTER_DISKS = 2, + USER_IMG = 3 +}TypeInputImage; + +std::string typeInputImageToString(const TypeInputImage &type) +{ + std::string name; + switch (type) { + case FULL_DISKS: + name = "full_disks"; + break; + case HALF_DISKS: + name = "half_disks"; + break; + case QUARTER_DISKS: + name = "quarter_disks"; + break; + case USER_IMG: + name = "path/to/your/image"; + } + return name; +} + +TypeInputImage typeInputImageFromString(const std::string &name) +{ + TypeInputImage type(USER_IMG); + bool hasFound(false); + for (unsigned int id = 0; id < USER_IMG && !hasFound; id++) { + TypeInputImage candidate = (TypeInputImage)id; + if (name == typeInputImageToString(candidate)) { + type = candidate; + hasFound = true; + } + } + return type; +} + +std::string getAvailableTypeInputImage(const std::string &prefix = "<", const std::string &sep = " , ", const std::string &suffix = ">") +{ + std::string list(prefix); + for (unsigned int id = 0; id < USER_IMG; id++) { + list += typeInputImageToString((TypeInputImage)id) + sep; + } + list += typeInputImageToString(USER_IMG) + suffix; + return list; +} + +void +drawDisk(vpImage &I, const vpImagePoint ¢er, const unsigned int &radius + , const unsigned int &borderColor, const unsigned int &fillingColor, const unsigned int &thickness, const unsigned int &bckg) +{ + vpImageDraw::drawCircle(I, center, radius, borderColor, thickness); + vp::floodFill(I, + center, + bckg, + fillingColor, + vpImageMorphology::CONNEXITY_4 + ); +} + +vpImage +generateImage(const TypeInputImage &inputType) +{ + // // Image dimensions and background + const unsigned int width = 640; + const unsigned int height = 480; + const unsigned int bckg = 0; + + // // Disks parameters + const unsigned int circleColor = 128; + const unsigned int circleRadius = 50; + const unsigned int circleThickness = 1; + + // // Disks position when full circles + const double topFull = height / 4; + const double bottomFull = 3 * height / 4; + const double leftFull = width / 4; + const double rightFull = 3 * width / 4; + + // // Disks position when Half of circles + const double topHalf = 1; // m_centerThresh(25) , m_radiusBinSize(10) , m_radiusRatioThresh(50) , m_mergingDistanceThresh(15) , m_mergingRadiusDiffThresh(1.5 * (double) m_radiusBinSize) + const double bottomHalf = height - 1; + const double leftHalf = width / 4; + const double rightHalf = 3 * width / 4; + + // // Disks position when Quarter of circles + const double topQuarter = 1; // m_centerThresh(15) , m_radiusBinSize(10) , m_radiusRatioThresh(50) , m_mergingDistanceThresh(15) , m_mergingRadiusDiffThresh(1.5 * (double) m_radiusBinSize) + const double bottomQuarter = height - 1; + const double leftQuarter = 1; + const double rightQuarter = width - 1; + vpImage I_src(height, width, bckg); + + // // Selecting position of the disks depending on their visibility + double top, left, bottom, right; + switch (inputType) { + case FULL_DISKS: + top = topFull; + left = leftFull; + bottom = bottomFull; + right = rightFull; + break; + case HALF_DISKS: + top = topHalf; + left = leftHalf; + bottom = bottomHalf; + right = rightHalf; + break; + case QUARTER_DISKS: + top = topQuarter; + left = leftQuarter; + bottom = bottomQuarter; + right = rightQuarter; + break; + default: + throw(vpException(vpException::badValue, "Using other type of input than the one that has been implemented to generate disks.")); + break; + } + + drawDisk(I_src, vpImagePoint(top, left), circleRadius, circleColor, circleColor, circleThickness, bckg); + drawDisk(I_src, vpImagePoint(top, left), circleRadius * 0.50, circleColor / 2, circleColor / 2, circleThickness, circleColor); + drawDisk(I_src, vpImagePoint(bottom, left), circleRadius, circleColor, circleColor, circleThickness, bckg); + drawDisk(I_src, vpImagePoint(bottom, left), circleRadius * 0.50, circleColor / 2, circleColor / 2, circleThickness, circleColor); + drawDisk(I_src, vpImagePoint(top, right), circleRadius, circleColor, circleColor, circleThickness, bckg); + drawDisk(I_src, vpImagePoint(top, right), circleRadius * 0.50, circleColor / 2, circleColor / 2, circleThickness, circleColor); + drawDisk(I_src, vpImagePoint(bottom, right), circleRadius, circleColor, circleColor, circleThickness, bckg); + drawDisk(I_src, vpImagePoint(bottom, right), circleRadius * 0.50, circleColor / 2, circleColor / 2, circleThickness, circleColor); + + std::cout << "Done drawing" << std::endl << std::flush; + return I_src; +} + +bool test_detection(const vpImage &I_src, vpCircleHoughTransform &detector, const int &nbCirclesToDetect, const bool &blockingMode) +{ + double t0 = vpTime::measureTimeMicros(); + std::vector detectedCircles = detector.detect(I_src, nbCirclesToDetect); + double tF = vpTime::measureTimeMicros(); + std::cout << "Process time = " << (tF - t0) * 0.001 << "ms" << std::endl << std::flush; + // vpImage I_dX = detector.getGradientX(); + // vpImage I_dY = detector.getGradientY(); + vpImage I_disp; + vpImageConvert::convert(I_src, I_disp); + + unsigned int id = 0; + std::vector v_colors = { vpColor::red, vpColor::purple, vpColor::orange, vpColor::yellow, vpColor::blue }; + unsigned int idColor = 0; + for (auto circleCandidate : detectedCircles) { + circleCandidate.display(I_disp, v_colors[idColor], 2); + std::cout << "Circle #" << id << ":" << std::endl; + std::cout << "\tCenter: (" << circleCandidate.getCenter() << ")" << std::endl; + std::cout << "\tRadius: (" << circleCandidate.getRadius() << ")" << std::endl; + id++; + idColor = (idColor + 1) % v_colors.size(); + } + + return drawingHelpers::display(I_disp, "Detection results", blockingMode); + // drawingHelpers::display(I_dX, "Gradient along X", blockingMode); + // drawingHelpers::display(I_dY, "Gradient along Y", blockingMode); +} + +int main(int argc, char **argv) +{ + const std::string def_input(typeInputImageToString(FULL_DISKS)); + const std::string def_jsonFilePath = std::string(""); + const int def_nbCirclesToDetect = -1; + const int def_gaussianKernelSize = 5; + const double def_gaussianSigma = 1.; + const int def_sobelKernelSize = 3; + const double def_cannyThresh = 150.; + const unsigned int def_minRadius = 0; + const unsigned int def_maxRadius = 1000; + const int def_dilatationRepet = 1; + const double def_centerThresh = -1.; + const double def_radiusThreshRatio = -1.; + const double def_circlePerfectness = 0.85; + const double def_centerDistanceThresh = 15; + const double def_radiusDifferenceThresh = 1.5 * def_centerDistanceThresh; + + + std::string opt_input(def_input); + std::string opt_jsonFilePath = def_jsonFilePath; + int opt_nbCirclesToDetect = def_nbCirclesToDetect; + int opt_gaussianKernelSize = def_gaussianKernelSize; + double opt_gaussianSigma = def_gaussianSigma; + int opt_sobelKernelSize = def_sobelKernelSize; + double opt_cannyThresh = def_cannyThresh; + unsigned int opt_minRadius = def_minRadius; + unsigned int opt_maxRadius = def_maxRadius; + int opt_dilatationRepet = def_dilatationRepet; + double opt_centerThresh = def_centerThresh; + int opt_radiusThreshRatio = def_radiusThreshRatio; + double opt_circlePerfectness = def_circlePerfectness; + double opt_centerDistanceThresh = def_centerDistanceThresh; + double opt_radiusDifferenceThresh = def_radiusDifferenceThresh; + + for (int i = 1; i < argc; i++) { + std::string argName(argv[i]); + if (argName == "--input" && i + 1 < argc) { + opt_input = std::string(argv[i + 1]); + i++; + } +#ifdef VISP_HAVE_NLOHMANN_JSON + else if (argName == "--json" && i + 1 < argc) { + opt_jsonFilePath = std::string(argv[i + 1]); + i++; + } +#endif + else if (argName == "--nb-circles" && i + 1 < argc) { + opt_nbCirclesToDetect = atoi(argv[i + 1]); + i++; + } + else if (argName == "--gaussian-kernel" && i + 1 < argc) { + opt_gaussianKernelSize = atoi(argv[i + 1]); + i++; + } + else if (argName == "--gaussian-sigma" && i + 1 < argc) { + opt_gaussianSigma = atof(argv[i + 1]); + i++; + } + else if (argName == "--sobel-kernel" && i + 1 < argc) { + opt_sobelKernelSize = atoi(argv[i + 1]); + i++; + } + else if (argName == "--canny-thresh" && i + 1 < argc) { + opt_cannyThresh = atof(argv[i + 1]); + i++; + } + else if (argName == "--dilatation-repet" && i + 1 < argc) { + opt_dilatationRepet = atoi(argv[i + 1]); + i++; + } + else if (argName == "--radius-limits" && i + 2 < argc) { + opt_minRadius = atoi(argv[i + 1]); + opt_maxRadius = atoi(argv[i + 2]); + i += 2; + } + else if (argName == "--center-thresh" && i + 1 < argc) { + opt_centerThresh = atof(argv[i + 1]); + i++; + } + else if (argName == "--radius-thresh" && i + 1 < argc) { + opt_radiusThreshRatio = atof(argv[i + 1]); + i++; + } + else if (argName == "--circle-perfectness" && i + 1 < argc) { + opt_circlePerfectness = atof(argv[i + 1]); + i++; + } + else if (argName == "--merging-thresh" && i + 2 < argc) { + opt_centerDistanceThresh = atof(argv[i + 1]); + opt_radiusDifferenceThresh = atof(argv[i + 2]); + i += 2; + } + else if (argName == "--help" || argName == "-h") { + std::cout << "NAME" << std::endl; + std::cout << "\t" << argv[0] << " Test program for the home-made Hough Circle Detection algorithm" << std::endl + << std::endl; + std::cout << "SYNOPSIS" << std::endl; + std::cout << "\t" << argv[0] + << "\t [--input " << getAvailableTypeInputImage() << "]" << std::endl +#ifdef VISP_HAVE_NLOHMANN_JSON + << "\t [--json ] (default: " << (def_jsonFilePath.empty() ? "unused" : def_jsonFilePath) << ")" << std::endl +#endif + << "\t [--nb-circles ] (default: " << def_nbCirclesToDetect << ")" << std::endl + << "\t [--gaussian-kernel ] (default: " << def_gaussianKernelSize << ")" << std::endl + << "\t [--gaussian-sigma ] (default: " << def_gaussianSigma << ")" << std::endl + << "\t [--sobel-kernel ] (default: " << def_sobelKernelSize << ")" << std::endl + << "\t [--canny-thresh ] (default: " << def_cannyThresh << ")" << std::endl + << "\t [--radius-limits ] (default: min = " << def_minRadius << ", max = " << def_maxRadius << ")" << std::endl + << "\t [--dilatation-repet ] (default: " << def_dilatationRepet << ")" << std::endl + << "\t [--center-thresh ] (default: " << (def_centerThresh < 0 ? "auto" : std::to_string(def_centerThresh)) << ")" << std::endl + << "\t [--radius-thresh ] (default: " << (def_radiusThreshRatio < 0 ? "auto" : std::to_string(def_radiusThreshRatio)) << ")" << std::endl + << "\t [--circle-perfectness ] (default: " << def_radiusThreshRatio << ")" << std::endl + << "\t [--merging-thresh ] (default: centers distance threshold = " << def_centerDistanceThresh << ", radius difference threshold = " << def_radiusDifferenceThresh << ")" << std::endl + << "\t [--help] [-h]" << std::endl + << std::endl; + + std::cout << "DESCRIPTION" << std::endl + << "\t--input" << std::endl + << "\t\tPermit to choose the type of input of the Hough Circle Algorithm" << std::endl + << "\t\tDefault: " << def_input << std::endl + << std::endl +#ifdef VISP_HAVE_NLOHMANN_JSON + << "\t--json" << std::endl + << "\t\tPermit to configure the Hough Circle Algorithm using a JSON file." << std::endl + << "\t\tDefault: " << (def_jsonFilePath.empty() ? "unused" : def_jsonFilePath) << std::endl + << std::endl +#endif + << "\t--nb-circles" << std::endl + << "\t\tPermit to choose the number of circles we want to detect in the image" << std::endl + << "\t\tThe results will be the circles having the greatest number of votes." << std::endl + << "\t\tDefault: " << def_nbCirclesToDetect << std::endl + << std::endl + << "\t--gaussian-kernel" << std::endl + << "\t\tPermit to set the size of the Gaussian filter used to smooth the input image and compute its gradients." << std::endl + << "\t\tMust be an odd value." << std::endl + << "\t\tDefault: " << def_gaussianKernelSize << std::endl + << std::endl + << "\t--gaussian-sigma" << std::endl + << "\t\tPermit to set the standard deviation of the Gaussian filter." << std::endl + << "\t\tMust be a positive value." << std::endl + << "\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 + << std::endl + << "\t--radius-limits" << std::endl + << "\t\tPermit to set the minimum and maximum radii of the circles we are looking for." << std::endl + << "\t\tDefault: min = " << def_minRadius << ", max = " << def_maxRadius << std::endl + << std::endl + << "\t--merging-thresh" << std::endl + << std::endl + << "\t--dilatation-repet" << std::endl + << "\t\tPermit to set the number of iterations of the dilatation operation used to detect the maxima of the centers votes." << std::endl + << "\t\tMinimum tolerated value is 1." << std::endl + << "\t\tDefault: " << def_dilatationRepet << std::endl + << std::endl + << "\t--center-thresh" << std::endl + << "\t\tPermit to set the minimum number of votes a point must reach to be considered as a center candidate." << std::endl + << "\t\tIf the input is a real image, must be a positive value." << std::endl + << "\t\tOtherwise, if the input is a synthetic image and the value is negative, a fine-tuned value will be used." << std::endl + << "\t\tDefault: " << (def_centerThresh < 0 ? "auto" : std::to_string(def_centerThresh)) << std::endl + << std::endl + << "\t--radius-thresh" << std::endl + << "\t\tPermit to to set the minimum number of votes per radian a radius must reach to be considered as a circle candidate a given pair (center candidate, radius candidate)." << std::endl + << "\t\tDefault: " << (def_radiusThreshRatio < 0 ? "auto" : std::to_string(def_radiusThreshRatio)) << std::endl + << std::endl + << "\t--circle-perfectness" << std::endl + << "\t\tPermit to set the set the circle perfectness threshold." << std::endl + << "\t\tThis parameter is used during the radius candidates computation." << std::endl + << "\t\tThe scalar product radius RC_ij . gradient(Ep_j) >= m_circlePerfectness * || RC_ij || * || gradient(Ep_j) || to add a vote for the radius RC_ij." << std::endl + << "\t\tDefault: " << def_circlePerfectness << std::endl + << std::endl + << "\t\tPermit to set the thresholds used during the merging stage of the algorithm." << std::endl + << "\t\tThe center distance threshold indicates the maximum distance the centers can be in order to be merged." << std::endl + << "\t\tThe radius difference threshold indicates the maximum absolute difference between the two circle candidates in order to be merged." << std::endl + << "\t\tTwo circle candidates must met these two conditions in order to be merged together." << std::endl + << "\t\tDefault: centers distance threshold = " << def_centerDistanceThresh << ", radius difference threshold = " << def_radiusDifferenceThresh << std::endl; + return EXIT_SUCCESS; + } + } + + if (opt_centerThresh < 0 && opt_jsonFilePath.empty()) { + // The user asked to use the parameter value that has been fine-tuned + TypeInputImage inputType = typeInputImageFromString(opt_input); + switch (inputType) { + case TypeInputImage::FULL_DISKS: + opt_centerThresh = 50.; + break; + case TypeInputImage::HALF_DISKS: + opt_centerThresh = 25.; + break; + case TypeInputImage::QUARTER_DISKS: + opt_centerThresh = 15.; + break; + default: + throw(vpException(vpException::badValue, "Missing center threshold value to use with actual pictures as input. See the help for more information.")); + } + } + + if (opt_radiusThreshRatio < 0 && opt_jsonFilePath.empty()) { + // The user asked to use the parameter value that has been fine-tuned + TypeInputImage inputType = typeInputImageFromString(opt_input); + switch (inputType) { + case TypeInputImage::FULL_DISKS: + opt_radiusThreshRatio = 5.; + break; + case TypeInputImage::HALF_DISKS: + opt_radiusThreshRatio = 2.; + break; + case TypeInputImage::QUARTER_DISKS: + opt_radiusThreshRatio = 1.; + break; + default: + throw(vpException(vpException::badValue, "Missing radius threshold value to use with actual pictures as input. See the help for more information.")); + } + } + + vpCircleHoughTransform::CHTransformParameters + algoParams(opt_gaussianKernelSize + , opt_gaussianSigma + , opt_sobelKernelSize + , opt_cannyThresh + , opt_minRadius + , opt_maxRadius + , opt_dilatationRepet + , opt_centerThresh + , opt_radiusThreshRatio + , opt_circlePerfectness + , opt_centerDistanceThresh + , opt_radiusDifferenceThresh + ); + + vpCircleHoughTransform detector; + if (opt_jsonFilePath.empty()) { + std::cout << "Initializing detector from the program arguments [...]" << std::endl; + detector.init(algoParams); + } + else { +#ifdef VISP_HAVE_NLOHMANN_JSON + std::cout << "Initializing detector from JSON file \"" << opt_jsonFilePath << "\", some of the program arguments will be ignored [...]" << std::endl; + detector.initFromJSON(opt_jsonFilePath); +#else + throw(vpException(vpException::functionNotImplementedError, "You must install nlohmann JSON library to use this feature, see https://visp-doc.inria.fr/doxygen/visp-daily/supported-third-parties.html#soft_tool_json for more information.")); +#endif + } + std::cout << detector; + + vpImage I_src; + TypeInputImage inputType = typeInputImageFromString(opt_input); + if (inputType == USER_IMG) { + if (opt_input.find("%") != std::string::npos) { + // The user wants to read a sequence of images from different files + bool hasToContinue = true; + vpVideoReader g; + g.setFileName(opt_input); + g.open(I_src); + while (!g.end() && hasToContinue) { + g.acquire(I_src); + hasToContinue = test_detection(I_src, detector, opt_nbCirclesToDetect, false); + vpTime::wait(40); + } + } + else { + // Check if opt_input exists + if (!vpIoTools::checkFilename(opt_input)) { + throw(vpException(vpException::ioError, "Input file \"" + opt_input + "\" does not exist !")); + } + // Read the image and perform detection on it + vpImageIo::read(I_src, opt_input); + test_detection(I_src, detector, opt_nbCirclesToDetect, true); + } + } + else { + I_src = generateImage(inputType); + test_detection(I_src, detector, opt_nbCirclesToDetect, true); + } + return EXIT_SUCCESS; +} From 425ce95ca2eaebe8b4fbe73089d071f1a5bb51cc Mon Sep 17 00:00:00 2001 From: rlagneau Date: Mon, 3 Jul 2023 09:10:21 +0200 Subject: [PATCH 02/20] [CLEAN] Corrected signeness of rad to solve compilation warning --- modules/imgproc/src/vpCircleHoughTransform.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/imgproc/src/vpCircleHoughTransform.cpp b/modules/imgproc/src/vpCircleHoughTransform.cpp index a98a20dcfe..a4d47cd531 100644 --- a/modules/imgproc/src/vpCircleHoughTransform.cpp +++ b/modules/imgproc/src/vpCircleHoughTransform.cpp @@ -231,7 +231,7 @@ vpCircleHoughTransform::computeCenterCandidates() for (int k1 = 0; k1 < 2; k1++) { - for (int rad = m_algoParams.m_minRadius; rad <= m_algoParams.m_maxRadius; rad++) + for (unsigned int rad = m_algoParams.m_minRadius; rad <= m_algoParams.m_maxRadius; rad++) { double x1 = (double)c + (double) rad * sx; double y1 = (double)r + (double) rad * sy; From 8023dc7e0a52bba7566343b54ee35813cb976fe5 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Mon, 3 Jul 2023 09:11:33 +0200 Subject: [PATCH 03/20] [TUTORIAL] Added how to sections and first draft of detailed explanations about the tutorial --- doc/tutorial/imgproc/tutorial-imgproc-cht.dox | 113 ++++++++++++++++++ tutorial/imgproc/hough-transform/README.md | 4 - .../hough-transform/tutorial-circle-hough.cpp | 30 +++-- 3 files changed, 136 insertions(+), 11 deletions(-) diff --git a/doc/tutorial/imgproc/tutorial-imgproc-cht.dox b/doc/tutorial/imgproc/tutorial-imgproc-cht.dox index 8db6dd140b..8ff04a8c2c 100644 --- a/doc/tutorial/imgproc/tutorial-imgproc-cht.dox +++ b/doc/tutorial/imgproc/tutorial-imgproc-cht.dox @@ -29,8 +29,121 @@ parameter. \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: +``` +$ ./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 using a JSON configuration file, please run: +``` +$ ./tutorial-circle-hough --input /path/to/my/image --config config/detector_img.json +``` + +If the detections seem a bit off, you might need to change the parameters + +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 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 */ diff --git a/tutorial/imgproc/hough-transform/README.md b/tutorial/imgproc/hough-transform/README.md index faedb9594c..d8127823aa 100644 --- a/tutorial/imgproc/hough-transform/README.md +++ b/tutorial/imgproc/hough-transform/README.md @@ -6,12 +6,10 @@ #### Using a JSON file as configuration file To use a JSON file as configuration, 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. -Then, recompile the Trasys project as explained in section [Building the Trasys project](#building_trasys) To run the software on the synthetic images, please run: ``` $ TARGET=full # or TARGET=half # or TARGET=quarter -$ cd ${TRASYS_WS}/trasys-dev-build $ ./tutorial-circle-hough --input ${TARGET}_disks --config config/detector_${TARGET}.json ``` @@ -20,7 +18,6 @@ $ ./tutorial-circle-hough --input ${TARGET}_disks --config config/detector_${TAR To run the software on the synthetic images without a JSON configuration file, please run: ``` $ TARGET=full # or TARGET=half # or TARGET=quarter -$ cd ${TRASYS_WS}/trasys-dev-build $ ./tutorial-circle-hough --input ${TARGET}_disks ``` @@ -39,7 +36,6 @@ If the detections seem a bit off, you might need to change the parameters To run the software on an actual image without a JSON configuration file, please run: ``` $ TARGET=full # or TARGET=half # or TARGET=quarter -$ cd ${TRASYS_WS}/trasys-dev-build $ ./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 ``` diff --git a/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp index 7e0c8f29a4..1c349f7e92 100644 --- a/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp +++ b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp @@ -13,6 +13,7 @@ #include "drawingHelpers.h" +//! [Enum input] typedef enum TypeInputImage { FULL_DISKS = 0, @@ -39,6 +40,7 @@ std::string typeInputImageToString(const TypeInputImage &type) } return name; } +//! [Enum input] TypeInputImage typeInputImageFromString(const std::string &name) { @@ -64,9 +66,11 @@ std::string getAvailableTypeInputImage(const std::string &prefix = "<", const st return list; } +//! [Draw disks] void drawDisk(vpImage &I, const vpImagePoint ¢er, const unsigned int &radius , const unsigned int &borderColor, const unsigned int &fillingColor, const unsigned int &thickness, const unsigned int &bckg) +//! [Draw disks] { vpImageDraw::drawCircle(I, center, radius, borderColor, thickness); vp::floodFill(I, @@ -77,8 +81,10 @@ drawDisk(vpImage &I, const vpImagePoint ¢er, const unsigned i ); } +//! [Draw synthetic] vpImage generateImage(const TypeInputImage &inputType) +//! [Draw synthetic] { // // Image dimensions and background const unsigned int width = 640; @@ -151,17 +157,18 @@ generateImage(const TypeInputImage &inputType) bool test_detection(const vpImage &I_src, vpCircleHoughTransform &detector, const int &nbCirclesToDetect, const bool &blockingMode) { double t0 = vpTime::measureTimeMicros(); + //! [Run detection] std::vector detectedCircles = detector.detect(I_src, nbCirclesToDetect); + //! [Run detection] double tF = vpTime::measureTimeMicros(); std::cout << "Process time = " << (tF - t0) * 0.001 << "ms" << std::endl << std::flush; - // vpImage I_dX = detector.getGradientX(); - // vpImage I_dY = detector.getGradientY(); vpImage I_disp; vpImageConvert::convert(I_src, I_disp); unsigned int id = 0; std::vector v_colors = { vpColor::red, vpColor::purple, vpColor::orange, vpColor::yellow, vpColor::blue }; unsigned int idColor = 0; + //! [Iterate detections] for (auto circleCandidate : detectedCircles) { circleCandidate.display(I_disp, v_colors[idColor], 2); std::cout << "Circle #" << id << ":" << std::endl; @@ -170,10 +177,9 @@ bool test_detection(const vpImage &I_src, vpCircleHoughTransform id++; idColor = (idColor + 1) % v_colors.size(); } + //! [Iterate detections] return drawingHelpers::display(I_disp, "Detection results", blockingMode); - // drawingHelpers::display(I_dX, "Gradient along X", blockingMode); - // drawingHelpers::display(I_dY, "Gradient along Y", blockingMode); } int main(int argc, char **argv) @@ -218,7 +224,7 @@ int main(int argc, char **argv) i++; } #ifdef VISP_HAVE_NLOHMANN_JSON - else if (argName == "--json" && i + 1 < argc) { + else if (argName == "--config" && i + 1 < argc) { opt_jsonFilePath = std::string(argv[i + 1]); i++; } @@ -277,7 +283,7 @@ int main(int argc, char **argv) std::cout << "\t" << argv[0] << "\t [--input " << getAvailableTypeInputImage() << "]" << std::endl #ifdef VISP_HAVE_NLOHMANN_JSON - << "\t [--json ] (default: " << (def_jsonFilePath.empty() ? "unused" : def_jsonFilePath) << ")" << std::endl + << "\t [--config ] (default: " << (def_jsonFilePath.empty() ? "unused" : def_jsonFilePath) << ")" << std::endl #endif << "\t [--nb-circles ] (default: " << def_nbCirclesToDetect << ")" << std::endl << "\t [--gaussian-kernel ] (default: " << def_gaussianKernelSize << ")" << std::endl @@ -299,7 +305,7 @@ int main(int argc, char **argv) << "\t\tDefault: " << def_input << std::endl << std::endl #ifdef VISP_HAVE_NLOHMANN_JSON - << "\t--json" << std::endl + << "\t--config" << std::endl << "\t\tPermit to configure the Hough Circle Algorithm using a JSON file." << std::endl << "\t\tDefault: " << (def_jsonFilePath.empty() ? "unused" : def_jsonFilePath) << std::endl << std::endl @@ -396,6 +402,7 @@ int main(int argc, char **argv) } } + //! [Algo params] vpCircleHoughTransform::CHTransformParameters algoParams(opt_gaussianKernelSize , opt_gaussianSigma @@ -410,7 +417,9 @@ int main(int argc, char **argv) , opt_centerDistanceThresh , opt_radiusDifferenceThresh ); + //! [Algo params] + //! [Algo init] vpCircleHoughTransform detector; if (opt_jsonFilePath.empty()) { std::cout << "Initializing detector from the program arguments [...]" << std::endl; @@ -424,11 +433,13 @@ int main(int argc, char **argv) throw(vpException(vpException::functionNotImplementedError, "You must install nlohmann JSON library to use this feature, see https://visp-doc.inria.fr/doxygen/visp-daily/supported-third-parties.html#soft_tool_json for more information.")); #endif } + //! [Algo init] std::cout << detector; vpImage I_src; TypeInputImage inputType = typeInputImageFromString(opt_input); if (inputType == USER_IMG) { + //! [Manage video] if (opt_input.find("%") != std::string::npos) { // The user wants to read a sequence of images from different files bool hasToContinue = true; @@ -441,7 +452,9 @@ int main(int argc, char **argv) vpTime::wait(40); } } + //! [Manage video] else { + //! [Manage single image] // Check if opt_input exists if (!vpIoTools::checkFilename(opt_input)) { throw(vpException(vpException::ioError, "Input file \"" + opt_input + "\" does not exist !")); @@ -449,11 +462,14 @@ int main(int argc, char **argv) // Read the image and perform detection on it vpImageIo::read(I_src, opt_input); test_detection(I_src, detector, opt_nbCirclesToDetect, true); + //! [Manage single image] } } else { + //! [Manage synthetic image] I_src = generateImage(inputType); test_detection(I_src, detector, opt_nbCirclesToDetect, true); + //! [Manage synthetic image] } return EXIT_SUCCESS; } From a1c946f65007b6882734ca861a3ab9f273358852 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Thu, 6 Jul 2023 11:14:38 +0200 Subject: [PATCH 04/20] [CLEAN] Commented lower because it rose a warning unused variable. Left the comment to keep in mind the existing formula --- modules/imgproc/src/vpImageMedian.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/imgproc/src/vpImageMedian.cpp b/modules/imgproc/src/vpImageMedian.cpp index accd32a47c..d4cc9258a7 100644 --- a/modules/imgproc/src/vpImageMedian.cpp +++ b/modules/imgproc/src/vpImageMedian.cpp @@ -80,7 +80,7 @@ double computeCannyThreshold(const cv::Mat &cv_I) resize(cv_I_blur, cv_I_scaled_down, cv::Size(), scale_down, scale_down, cv::INTER_NEAREST); double median_pix = ImageFilter::median(cv_I_scaled_down); - double lower = std::max(0., 0.7 * median_pix); + // double lower = std::max(0., 0.7 * median_pix); // Unused, but to know the formula exists double upper = std::min(255., 1.3 * median_pix); upper = std::max(1., upper); return upper; From 31c0eaf153769d0b34e5eaa1ea56e83469663b87 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Thu, 6 Jul 2023 11:15:27 +0200 Subject: [PATCH 05/20] [TUTORIAL][vpCHT] Added visp_copy_dir to copy the config folder in the tutorial folder --- tutorial/imgproc/hough-transform/CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tutorial/imgproc/hough-transform/CMakeLists.txt b/tutorial/imgproc/hough-transform/CMakeLists.txt index fdbe6d6120..0601279e4f 100644 --- a/tutorial/imgproc/hough-transform/CMakeLists.txt +++ b/tutorial/imgproc/hough-transform/CMakeLists.txt @@ -19,6 +19,4 @@ foreach(cpp ${tutorial_cpp}) endforeach() # Copy the data files to the same location than the target -foreach(data ${tutorial_data}) - visp_copy_data(tutorial-circle-hough.cpp ${data}) -endforeach() +visp_copy_dir(tutorial-circle-hough "${CMAKE_CURRENT_SOURCE_DIR}" config) From b13fcd8522bd2801cc5c2d82afe7ae3af37d4cc5 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Thu, 6 Jul 2023 11:16:14 +0200 Subject: [PATCH 06/20] [vpCHT] Switched to float and added support for detecting circles whose center is outside the image --- .../visp3/imgproc/vpCircleHoughTransform.h | 131 +++++++----- .../imgproc/src/vpCircleHoughTransform.cpp | 191 +++++++++++++----- .../hough-transform/config/detector_full.json | 38 ++-- .../hough-transform/config/detector_half.json | 38 ++-- .../hough-transform/config/detector_img.json | 38 ++-- .../config/detector_quarter.json | 38 ++-- .../hough-transform/tutorial-circle-hough.cpp | 37 +++- 7 files changed, 342 insertions(+), 169 deletions(-) diff --git a/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h b/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h index fade9dfe9f..8e5fe5ecb6 100644 --- a/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h +++ b/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h @@ -70,28 +70,30 @@ class VISP_EXPORT vpCircleHoughTransform private: // // Gaussian smoothing attributes int m_gaussianKernelSize; /*!< Size of the Gaussian filter kernel used to smooth the input image. Must be an odd number.*/ - double m_gaussianStdev; /*!< Standard deviation of the Gaussian filter.*/ + float m_gaussianStdev; /*!< Standard deviation of the Gaussian filter.*/ // // Gradient computation attributes int m_sobelKernelSize; /*!< Size of the Sobel kernels used to compute the gradients. Must be an odd number.*/ // // Edge detection attributes - double m_cannyThresh; /*!< The threshold for the Canny operator. Only value greater than this value are marked as an edge. + 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.*/ // // Center candidates computation attributes + std::pair m_centerXlimits; /*!< Minimum and maximum position on the horizontal axis of the center of the circle we want to detect.*/ + std::pair m_centerYlimits; /*!< Minimum and maximum position on the vertical axis of the center of the circle we want to detect.*/ unsigned int m_minRadius; /*!< Minimum radius of the circles we want to detect.*/ unsigned int m_maxRadius; /*!< Maximum radius of the circles we want to detect.*/ int m_dilatationNbIter; /*!< Number of times dilatation is performed to detect the maximum number of votes for the center candidates.*/ - double m_centerThresh; /*!< Minimum number of votes a point must exceed to be considered as center candidate.*/ + float m_centerThresh; /*!< Minimum number of votes a point must exceed to be considered as center candidate.*/ // // Circle candidates computation attributes - double m_radiusRatioThresh; /*!< Minimum number of votes per radian a radius candidate RC_ij of a center candidate CeC_i must have in order that the circle of center CeC_i and radius RC_ij must be considered as circle candidate.*/ - double m_circlePerfectness; /*!< The scalar product radius RC_ij . gradient(Ep_j) >= m_circlePerfectness * || RC_ij || * || gradient(Ep_j) || to add a vote for the radius RC_ij. */ + float m_radiusRatioThresh; /*!< Minimum number of votes per radian a radius candidate RC_ij of a center candidate CeC_i must have in order that the circle of center CeC_i and radius RC_ij must be considered as circle candidate.*/ + float m_circlePerfectness; /*!< The scalar product radius RC_ij . gradient(Ep_j) >= m_circlePerfectness * || RC_ij || * || gradient(Ep_j) || to add a vote for the radius RC_ij. */ // // Circle candidates merging atttributes - double m_centerMinDist; /*!< Maximum distance between two circle candidates centers to consider merging them.*/ - double m_mergingRadiusDiffThresh; /*!< Maximum radius difference between two circle candidates to consider merging them.*/ + float m_centerMinDist; /*!< Maximum distance between two circle candidates centers to consider merging them.*/ + float m_mergingRadiusDiffThresh; /*!< Maximum radius difference between two circle candidates to consider merging them.*/ friend vpCircleHoughTransform; public: @@ -100,6 +102,8 @@ class VISP_EXPORT vpCircleHoughTransform , m_gaussianStdev(1.) , m_sobelKernelSize(3) , m_cannyThresh(-1) + , m_centerXlimits(std::pair(std::numeric_limits::min(), std::numeric_limits::max())) + , m_centerYlimits(std::pair(std::numeric_limits::min(), std::numeric_limits::max())) , m_minRadius(0) , m_maxRadius(1000) , m_dilatationNbIter(1) @@ -107,7 +111,7 @@ class VISP_EXPORT vpCircleHoughTransform , m_radiusRatioThresh(2.) , m_circlePerfectness(0.9) , m_centerMinDist(15.) - , m_mergingRadiusDiffThresh(1.5 * (double)m_centerMinDist) + , m_mergingRadiusDiffThresh(1.5 * (float)m_centerMinDist) { } @@ -120,6 +124,8 @@ class VISP_EXPORT vpCircleHoughTransform * \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] 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. * \param[in] minRadius Minimum radius of the circles we want to detect. * \param[in] maxRadius Maximum radius of the circles we want to detect. * \param[in] dilatationNbIter Number of times dilatation is performed to detect the maximum number of votes for the center candidates @@ -131,22 +137,26 @@ class VISP_EXPORT vpCircleHoughTransform */ CHTransformParameters( const int &gaussianKernelSize - , const double &gaussianStdev + , const float &gaussianStdev , const int &sobelKernelSize - , const double &cannyThresh + , const float &cannyThresh + , const std::pair ¢erXlimits + , const std::pair ¢erYlimits , const unsigned int &minRadius , const unsigned int &maxRadius , const int &dilatationNbIter - , const double ¢erThresh - , const double &radiusThreshRatio - , const double &circlePerfectness - , const double ¢erMinDistThresh - , const double &mergingRadiusDiffThresh + , const float ¢erThresh + , const float &radiusThreshRatio + , const float &circlePerfectness + , const float ¢erMinDistThresh + , const float &mergingRadiusDiffThresh ) : m_gaussianKernelSize(gaussianKernelSize) , m_gaussianStdev(gaussianStdev) , m_sobelKernelSize(sobelKernelSize) , m_cannyThresh(cannyThresh) + , m_centerXlimits(centerXlimits) + , m_centerYlimits(centerYlimits) , m_minRadius(std::min(minRadius, maxRadius)) , m_maxRadius(std::max(minRadius, maxRadius)) , m_dilatationNbIter(dilatationNbIter) @@ -166,6 +176,8 @@ class VISP_EXPORT vpCircleHoughTransform 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 += "\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"; txt += "\tRadius limits: min = " + std::to_string(m_minRadius) + "\tmax = " + std::to_string(m_maxRadius) +"\n"; txt += "\tNumber of repetitions of the dilatation filter = " + std::to_string(m_dilatationNbIter) + "\n"; txt += "\tCenters votes threshold = " + std::to_string(m_centerThresh) + "\n"; @@ -253,6 +265,8 @@ class VISP_EXPORT vpCircleHoughTransform params.m_cannyThresh = j.value("cannyThresh", params.m_cannyThresh); + params.m_centerXlimits = j.value("centerXlimits", params.m_centerXlimits); + params.m_centerYlimits = j.value("centerYlimits", params.m_centerYlimits); std::pair radiusLimits = j.value("radiusLimits", std::pair(params.m_minRadius, params.m_maxRadius)); params.m_minRadius = std::min(radiusLimits.first, radiusLimits.second); params.m_maxRadius = std::max(radiusLimits.first, radiusLimits.second); @@ -302,6 +316,8 @@ class VISP_EXPORT vpCircleHoughTransform {"gaussianStdev", params.m_gaussianStdev}, {"sobelKernelSize", params.m_sobelKernelSize}, {"cannyThresh", params.m_cannyThresh}, + {"centerXlimits", params.m_centerXlimits}, + {"centerYlimits", params.m_centerYlimits}, {"radiusLimits", radiusLimits}, {"dilatationNbIter", params.m_dilatationNbIter}, {"centerThresh", params.m_centerThresh}, @@ -327,7 +343,7 @@ class VISP_EXPORT vpCircleHoughTransform /*! * Constructor from a center and radius. */ - vpCircle2D(const vpImagePoint ¢er, double radius) : m_center(center), m_radius(radius) { } + vpCircle2D(const vpImagePoint ¢er, const float &radius) : m_center(center), m_radius(radius) { } /*! * Constructor from an OpenCV vector that contains [center_x, center_y, radius]. @@ -347,7 +363,7 @@ class VISP_EXPORT vpCircleHoughTransform /*! * Return the radius of the 2D circle. */ - double getRadius() const { return m_radius; }; + float getRadius() const { return m_radius; }; /*! * Return the 2D circle bounding box. @@ -361,24 +377,24 @@ class VISP_EXPORT vpCircleHoughTransform /*! * Return normalized moment \f$n_{20}\f$. */ - double get_n20() const { return m_radius * m_radius / 4; }; + float get_n20() const { return m_radius * m_radius / 4; }; /*! * Return normalized moment \f$n_{02}\f$. */ - double get_n02() const { return m_radius * m_radius / 4; }; + float get_n02() const { return m_radius * m_radius / 4; }; /*! * Return normalized moment \f$n_{02}\f$. */ - double get_n11() const { return 0.; }; + float get_n11() const { return 0.; }; template < typename Type > - void display( vpImage< Type > &img, const vpColor &color = vpColor::blue, unsigned int thickness = 1, unsigned int size = 5 ) const; + void display( vpImage< Type > &img, const vpColor &color = vpColor::blue, const unsigned int &thickness = 1, const unsigned int &size = 5 ) const; private: vpImagePoint m_center; - double m_radius; + float m_radius; }; /** @@ -504,7 +520,7 @@ class VISP_EXPORT vpCircleHoughTransform * \param[in] kernelSize The size of the Gaussian kernel. Must be an odd value. * \param[in] stdev The standard deviation of the Gaussian function. */ - inline void setGaussianParameters(const int &kernelSize, const double &stdev) + inline void setGaussianParameters(const int &kernelSize, const float &stdev) { m_algoParams.m_gaussianKernelSize = kernelSize; m_algoParams.m_gaussianStdev = stdev; @@ -529,7 +545,7 @@ class VISP_EXPORT vpCircleHoughTransform * \param[in] canny_threshold : Canny filter upper threshold. When set to -1 (default), compute * automatically this threshold. */ - inline void setCannyThreshold(double canny_threshold) + inline void setCannyThreshold(const float &canny_threshold) { m_algoParams.m_cannyThresh = canny_threshold; } @@ -540,7 +556,7 @@ class VISP_EXPORT vpCircleHoughTransform * * \param[in] center_min_dist : Center min distance in pixels. */ - inline void setCircleCenterMinDist(double center_min_dist) + inline void setCircleCenterMinDist(const float ¢er_min_dist) { m_algoParams.m_centerMinDist = center_min_dist; @@ -550,11 +566,32 @@ class VISP_EXPORT vpCircleHoughTransform } } + /*! + * Set circles center min and max location in the image. + * If one value is equal to \b std::numeric_limits::min or + * \b std::numeric_limits::max(), the algorithm will set it + * either to -maxRadius or +maxRadius depending on if + * it is the lower or upper limit that is missing. + * + * \param[in] center_min_x : Center min location on the horizontal axis, expressed in pixels. + * \param[in] center_max_x : Center max location on the horizontal axis, expressed in pixels. + * \param[in] center_min_y : Center min location on the vertical axis, expressed in pixels. + * \param[in] center_max_y : Center max location on the vertical axis, expressed in pixels. + */ + void setCircleCenterBoundingBox(const int ¢er_min_x, const int ¢er_max_x, + const int ¢er_min_y, const int ¢er_max_y) + { + m_algoParams.m_centerXlimits.first = center_min_x; + m_algoParams.m_centerXlimits.second = center_max_x; + m_algoParams.m_centerYlimits.first = center_min_y; + m_algoParams.m_centerYlimits.second = center_max_y; + } + /*! * Set circles min radius. * \param[in] circle_min_radius : Min radius in pixels. */ - inline void setCircleMinRadius(double circle_min_radius) + inline void setCircleMinRadius(const float &circle_min_radius) { m_algoParams.m_minRadius = circle_min_radius; } @@ -563,7 +600,7 @@ class VISP_EXPORT vpCircleHoughTransform * Set circles max radius. * \param[in] circle_max_radius : Max radius in pixels. */ - inline void setCircleMaxRadius(double circle_max_radius) + inline void setCircleMaxRadius(const float &circle_max_radius) { m_algoParams.m_maxRadius = circle_max_radius; } @@ -572,7 +609,7 @@ class VISP_EXPORT vpCircleHoughTransform * Set circles perfectness. The scalar product radius RC_ij . gradient(Ep_j) >= m_circlePerfectness * || RC_ij || * || gradient(Ep_j) || to add a vote for the radius RC_ij. * \param[in] circle_perfectness : Circle perfectness. Value between 0 and 1. A perfect circle has value 1. */ - void setCirclePerfectness(double circle_perfectness) + void setCirclePerfectness(const float &circle_perfectness) { m_algoParams.m_circlePerfectness = circle_perfectness; if (m_algoParams.m_circlePerfectness <= 0 || m_algoParams.m_circlePerfectness > 1) @@ -587,7 +624,7 @@ class VISP_EXPORT vpCircleHoughTransform * \param[in] dilatationRepet Number of repetition of the dilatation operation to detect the maxima in the center accumulator. * \param[in] centerThresh Minimum number of votes a point must exceed to be considered as center candidate. */ - inline void setCenterComputationParameters(const int &dilatationRepet, const double ¢erThresh) + inline void setCenterComputationParameters(const int &dilatationRepet, const float ¢erThresh) { m_algoParams.m_dilatationNbIter = dilatationRepet; m_algoParams.m_centerThresh = centerThresh; @@ -603,7 +640,7 @@ class VISP_EXPORT vpCircleHoughTransform * * \param[in] radiusRatioThresh Minimum number of votes per radian a radius candidate RC_ij of a center candidate CeC_i must have in order that the circle of center CeC_i and radius RC_ij must be considered as circle candidate. */ - inline void setRadiusRatioThreshold( const double &radiusRatioThresh ) + inline void setRadiusRatioThreshold( const float &radiusRatioThresh ) { m_algoParams.m_radiusRatioThresh = radiusRatioThresh; @@ -619,7 +656,7 @@ class VISP_EXPORT vpCircleHoughTransform * * \param[in] radiusDifferenceThresh Maximum radius difference between two circle candidates to consider merging them. */ - inline void setRadiusMergingThresholds(const double &radiusDifferenceThresh) + inline void setRadiusMergingThresholds(const float &radiusDifferenceThresh) { m_algoParams.m_mergingRadiusDiffThresh = radiusDifferenceThresh; @@ -636,7 +673,7 @@ class VISP_EXPORT vpCircleHoughTransform * * \return std::vector> The list of Center Candidates, stored as pair */ - inline std::vector> getCenterCandidatesList() + inline std::vector> getCenterCandidatesList() { return m_centerCandidatesList; } @@ -644,9 +681,9 @@ class VISP_EXPORT vpCircleHoughTransform /** * \brief Get the gradient along the horizontal axis of the image. * - * \return vpImage The gradient along the horizontal axis of the image. + * \return vpImage The gradient along the horizontal axis of the image. */ - inline vpImage getGradientX() + inline vpImage getGradientX() { return m_dIx; } @@ -654,9 +691,9 @@ class VISP_EXPORT vpCircleHoughTransform /** * \brief Get the gradient along the vertical axis of the image. * - * \return vpImage The gradient along the vertical axis of the image. + * \return vpImage The gradient along the vertical axis of the image. */ - inline vpImage getGradientY() + inline vpImage getGradientY() { return m_dIy; } @@ -665,7 +702,7 @@ class VISP_EXPORT vpCircleHoughTransform * Get internal Canny filter upper threshold. When value is equal to -1 (default), it means that the threshold is computed * automatically. */ - inline double getCannyThreshold() const + inline float getCannyThreshold() const { return m_algoParams.m_cannyThresh; } @@ -673,7 +710,7 @@ class VISP_EXPORT vpCircleHoughTransform /*! * Get circles center min distance in pixels. */ - inline double getCircleCenterMinDist() const + inline float getCircleCenterMinDist() const { return m_algoParams.m_centerMinDist; } @@ -681,7 +718,7 @@ class VISP_EXPORT vpCircleHoughTransform /*! * Get circles min radius in pixels. */ - inline double getCircleMinRadius() const + inline float getCircleMinRadius() const { return m_algoParams.m_minRadius; } @@ -689,7 +726,7 @@ class VISP_EXPORT vpCircleHoughTransform /*! * Get circles max radius in pixels. */ - inline double getCircleMaxRadius() const + inline float getCircleMaxRadius() const { return m_algoParams.m_maxRadius; } @@ -748,20 +785,20 @@ class VISP_EXPORT vpCircleHoughTransform CHTransformParameters m_algoParams; /*!< Attributes containing all the algorithm parameters.*/ // // Gaussian smoothing attributes - vpMatrix m_fg; - vpMatrix m_fgDg; - vpImage m_Ifilt; /*!< Filtered version of the input image, after having used a Gaussian filter.*/ + vpArray2D m_fg; + vpArray2D m_fgDg; + vpImage m_Ifilt; /*!< Filtered version of the input image, after having used a Gaussian filter.*/ // // Gradient computation attributes - vpImage m_dIx; /*!< Gradient along the x-axis of the input image.*/ - vpImage m_dIy; /*!< Gradient along the y-axis of the input image.*/ + vpImage m_dIx; /*!< Gradient along the x-axis of the input image.*/ + vpImage m_dIy; /*!< Gradient along the y-axis of the input image.*/ // // Edge detection attributes vpImage m_edgeMap; /*!< Edge map resulting from the edge detection algorithm.*/ // // Center candidates computation attributes std::vector> m_edgePointsList; /*!< Vector that contains the list of edge points, to make faster some parts of the algo. They are stored as pair<#row, #col>.*/ - std::vector> m_centerCandidatesList; /*!< Vector that contains the list of center candidates. They are stored as pair<#row, #col>.*/ + std::vector> m_centerCandidatesList; /*!< Vector that contains the list of center candidates. They are stored as pair<#row, #col>.*/ // // Circle candidates computation attributes std::vector m_circleCandidates; /*!< List of the candidate circles.*/ @@ -780,7 +817,7 @@ class VISP_EXPORT vpCircleHoughTransform */ template < typename Type > inline void -vpCircleHoughTransform::vpCircle2D::display( vpImage< Type > &img, const vpColor &color, unsigned int thickness, unsigned int size ) const +vpCircleHoughTransform::vpCircle2D::display( vpImage< Type > &img, const vpColor &color, const unsigned int &thickness, const unsigned int &size ) const { vpImageDraw::drawCross(img, m_center, size, color, thickness); vpImageDraw::drawCircle(img, m_center, m_radius, color, thickness); diff --git a/modules/imgproc/src/vpCircleHoughTransform.cpp b/modules/imgproc/src/vpCircleHoughTransform.cpp index a4d47cd531..a2e699c99a 100644 --- a/modules/imgproc/src/vpCircleHoughTransform.cpp +++ b/modules/imgproc/src/vpCircleHoughTransform.cpp @@ -94,18 +94,18 @@ vpCircleHoughTransform::detect(const cv::Mat &cv_I) std::vector vpCircleHoughTransform::detect(const vpImage &I, const int &nbCircles) { - std::vector detections = detect(I); + std::vector detections = detect(I); size_t nbDetections = detections.size(); - std::vector bestCircles; - std::vector> detectionsWithVotes; + std::vector bestCircles; + std::vector> detectionsWithVotes; for(size_t i = 0; i < nbDetections; i++) { - std::pair detectionWithVote(detections[i], m_circleCandidatesVotes[i]); + std::pair detectionWithVote(detections[i], m_circleCandidatesVotes[i]); detectionsWithVotes.push_back(detectionWithVote); } - bool (*hasMoreVotes)(std::pair, std::pair) - = [](std::pair a, std::pair b) + bool (*hasMoreVotes)(std::pair, std::pair) + = [](std::pair a, std::pair b) { return (a.second > b.second); }; @@ -186,9 +186,9 @@ vpCircleHoughTransform::computeGradientsAfterGaussianSmoothing(const vpImage &I) { - #if VISP_HAVE_OPENCV_VERSION >= 0x020100 // Canny uses OpenCV >=2.1.0 - //Apply the Canny edge operator to compute the edge map - // The canny method performs Gaussian blurr and gradient computation + #if defined(HAVE_OPENCV_IMGPROC) + // 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.) { m_algoParams.m_cannyThresh = ImageFilter::computeCannyThreshold(I); @@ -209,9 +209,40 @@ vpCircleHoughTransform::computeCenterCandidates() // points, but for an "area" of points unsigned int nbRows = m_edgeMap.getRows(); unsigned int nbCols = m_edgeMap.getCols(); - vpImage centersAccum(nbRows, nbCols + 1, 0.); /*!< Matrix that contains the votes for the center candidates.*/ - m_algoParams.m_maxRadius = std::min(m_algoParams.m_maxRadius, (unsigned int)(std::min(nbCols, nbRows)*0.5)); + m_algoParams.m_maxRadius = std::min(m_algoParams.m_maxRadius, std::min(nbCols, nbRows)); + + // Computing the minimum and maximum horizontal position of the center candidates + // The miminum horizontal position of the center is at worst -maxRadius outside the image + // The maxinum horizontal position of the center is at worst +maxRadiusoutside the image + // The width of the accumulator is the difference between the max and the min + int minimumXposition = std::max(m_algoParams.m_centerXlimits.first, -1 * (int) m_algoParams.m_maxRadius); + int maximumXposition = std::min(m_algoParams.m_centerXlimits.second, (int) (m_algoParams.m_maxRadius + nbCols)); + minimumXposition = std::min(minimumXposition, maximumXposition - 1); + float minimumXpositionDouble = minimumXposition; + int offsetX = minimumXposition; + int accumulatorWidth = maximumXposition - minimumXposition + 1; + if(accumulatorWidth <= 0) + { + std::cout << "Width <= 0 !" << std::endl << std::flush; + } + + // Computing the minimum and maximum vertical position of the center candidates + // The miminum vertical position of the center is at worst -maxRadius outside the image + // The maxinum vertical position of the center is at worst +maxRadiusoutside the image + // The height of the accumulator is the difference between the max and the min + int minimumYposition = std::max(m_algoParams.m_centerYlimits.first, -1 * (int) m_algoParams.m_maxRadius); + int maximumYposition = std::min(m_algoParams.m_centerYlimits.second, (int) (m_algoParams.m_maxRadius + nbRows)); + minimumYposition = std::min(minimumYposition, maximumYposition - 1); + float minimumYpositionDouble = minimumYposition; + int offsetY = minimumYposition; + int accumulatorHeight = maximumYposition - minimumYposition + 1; + if(accumulatorHeight <= 0) + { + std::cout << "accumulatorHeight <= 0 !" << std::endl << std::flush; + } + + vpImage centersAccum(accumulatorHeight, accumulatorWidth + 1, 0.); /*!< Matrix that contains the votes for the center candidates.*/ for (unsigned int r = 0; r < nbRows; r++) { @@ -224,33 +255,80 @@ vpCircleHoughTransform::computeCenterCandidates() // Voting for points in both direction of the gradient // Step from min_radius to max_radius in both directions of the gradient - double mag = std::sqrt(m_dIx[r][c] * m_dIx[r][c] + m_dIy[r][c] * m_dIy[r][c]); + float mag = std::sqrt(m_dIx[r][c] * m_dIx[r][c] + m_dIy[r][c] * m_dIy[r][c]); - double sx = m_dIx[r][c] / mag; - double sy = m_dIy[r][c] / mag; + float sx = m_dIx[r][c] / mag; + float sy = m_dIy[r][c] / mag; for (int k1 = 0; k1 < 2; k1++) { - for (unsigned int rad = m_algoParams.m_minRadius; rad <= m_algoParams.m_maxRadius; rad++) + bool hasToStopLoop = false; + for (int rad = m_algoParams.m_minRadius; rad <= m_algoParams.m_maxRadius && !hasToStopLoop; rad++) { - double x1 = (double)c + (double) rad * sx; - double y1 = (double)r + (double) rad * sy; - - unsigned int x_low = std::floor(x1); - unsigned int y_low = std::floor(y1); - - unsigned int x_high = std::ceil(x1); - unsigned int y_high = std::ceil(y1); - - if( (unsigned)x_low >= nbCols || - (unsigned)y_low >= nbRows ) - break; - centersAccum[y_low][x_low] += std::sqrt(std::pow(x1 - (double)x_low,2) + std::pow(y1 - (double)y_low,2)); - - if( (unsigned)x_high >= nbCols || - (unsigned)y_high >= nbRows ) - break; - centersAccum[y_high][x_high] += std::sqrt(std::pow(x1 - (double)x_high,2) + std::pow(y1 - (double)y_high,2)); + float x1 = (float)c + (float) rad * sx; + float y1 = (float)r + (float) rad * sy; + + if(x1 < minimumXpositionDouble || y1 < minimumYpositionDouble) + { + continue; // If either value is lower than maxRadius, it means that the center is outside the search region. + } + + int x_low, x_high; + int y_low, y_high; + + if(x1 > 0.) + { + x_low = std::floor(x1); + x_high = std::ceil(x1); + } + else + { + x_low = -1 * std::ceil(-1. * x1); + x_high = -1 * std::floor(-1. * x1); + } + + if(y1 > 0.) + { + y_low = std::floor(y1); + y_high = std::ceil(y1); + } + else + { + y_low = -1 * std::ceil(-1. * y1); + y_high = -1 * std::floor(-1. * y1); + } + + auto updateAccumulator = + []( const float &x_orig, const float &y_orig, + const unsigned int &x, const unsigned int &y, + const int &offsetX, const int &offsetY, + const unsigned int &nbCols, const unsigned int &nbRows, + vpImage &accum, bool &hasToStop) + { + if( x - offsetX >= nbCols || + y - offsetY >= nbRows + ) + { + hasToStop = true; + } + else{ + float dx = (x_orig - (float)x); + float dy = (y_orig - (float)y); + accum[y - offsetY][x - offsetX] += std::abs(dx) + std::abs(dy); + } + }; + + updateAccumulator( x1, y1, x_low, y_low, + offsetX, offsetY, + accumulatorWidth, accumulatorHeight, + centersAccum, hasToStopLoop + ); + + updateAccumulator( x1, y1, x_high, y_high, + offsetX, offsetY, + accumulatorWidth, accumulatorHeight, + centersAccum, hasToStopLoop + ); } sx = -sx; @@ -262,20 +340,22 @@ vpCircleHoughTransform::computeCenterCandidates() // Use dilatation with large kernel in order to determine the // accumulator maxima - vpImage centerCandidatesMaxima = centersAccum; - int niters = std::max(m_algoParams.m_dilatationNbIter, 1); + vpImage centerCandidatesMaxima = centersAccum; + int niters = std::max(m_algoParams.m_dilatationNbIter, 1); // Ensure at least one dilatation operation for (int i = 0; i < niters; i++) { - vpImageMorphology::dilatation(centerCandidatesMaxima, vpImageMorphology::CONNEXITY_4); + vpImageMorphology::dilatation(centerCandidatesMaxima, vpImageMorphology::CONNEXITY_4); } // Look for the image points that correspond to the accumulator maxima // These points will become the center candidates // find the possible circle centers - for (unsigned int y = 0; y < nbRows; y++) + int nbColsAccum = centersAccum.getCols(); + int nbRowsAccum = centersAccum.getRows(); + for (int y = 0; y < nbRowsAccum; y++) { int left = -1; - for (unsigned int x = 0; x < nbCols; x++) + for (int x = 0; x < nbColsAccum; x++) { if ( centersAccum[y][x] >= m_algoParams.m_centerThresh && centersAccum[y][x] == centerCandidatesMaxima[y][x] @@ -287,8 +367,8 @@ vpCircleHoughTransform::computeCenterCandidates() } else if (left >= 0) { - unsigned int cx = (unsigned int)((left + x - 1) * 0.5f); - m_centerCandidatesList.push_back(std::pair(y, cx)); + int cx = (int)((left + x - 1) * 0.5f); + m_centerCandidatesList.push_back(std::pair(y + offsetY, cx + offsetX)); left = -1; } } @@ -302,7 +382,7 @@ vpCircleHoughTransform::computeCircleCandidates() unsigned int nbBins = (m_algoParams.m_maxRadius - m_algoParams.m_minRadius + 1)/ m_algoParams.m_centerMinDist; nbBins = std::max((unsigned int)1, nbBins); // Avoid having 0 bins, which causes segfault std::vector radiusAccumList; /*!< Radius accumulator for each center candidates.*/ - std::vector radiusActualValueList; /*!< Vector that contains the actual distance between the edge points and the center candidates.*/ + std::vector radiusActualValueList; /*!< Vector that contains the actual distance between the edge points and the center candidates.*/ unsigned int rmin2 = m_algoParams.m_minRadius * m_algoParams.m_minRadius; unsigned int rmax2 = m_algoParams.m_maxRadius * m_algoParams.m_maxRadius; @@ -310,7 +390,7 @@ vpCircleHoughTransform::computeCircleCandidates() for(size_t i = 0; i < nbCenterCandidates; i++) { - std::pair centerCandidate = m_centerCandidatesList[i]; + std::pair centerCandidate = m_centerCandidatesList[i]; // Initialize the radius accumulator of the candidate with 0s radiusAccumList.clear(); radiusAccumList.resize(nbBins, 0); @@ -326,17 +406,16 @@ vpCircleHoughTransform::computeCircleCandidates() if((r2 > rmin2) && (r2 < rmax2)) { - double r = std::sqrt(r2); - - double gx = m_dIx[edgePoint.first][edgePoint.second]; - double gy = m_dIy[edgePoint.first][edgePoint.second]; - double grad2 = gx * gx + gy * gy; + float gx = m_dIx[edgePoint.first][edgePoint.second]; + float gy = m_dIy[edgePoint.first][edgePoint.second]; + float grad2 = gx * gx + gy * gy; int scalProd = rx * gx + ry * gy; int scalProd2 = scalProd * scalProd; if(scalProd2 >= circlePerfectness2 * r2 * grad2) { // Look for the Radius Candidate Bin RCB_k to which d_ij is "the closest" will have an additionnal vote + float r = std::sqrt(r2); unsigned int r_bin = std::ceil((r - m_algoParams.m_minRadius)/ m_algoParams.m_centerMinDist); r_bin = std::min(r_bin, nbBins - 1); radiusAccumList[r_bin]++; @@ -349,10 +428,10 @@ vpCircleHoughTransform::computeCircleCandidates() { // If the circle of center CeC_i and radius RCB_k has enough votes, it is added to the list // of Circle Candidates - double r_effective = radiusActualValueList[idBin] / (double)radiusAccumList[idBin]; - if((double)radiusAccumList[idBin] / r_effective > m_algoParams.m_radiusRatioThresh ) + float r_effective = radiusActualValueList[idBin] / (float)radiusAccumList[idBin]; + if((float)radiusAccumList[idBin] / r_effective > m_algoParams.m_radiusRatioThresh ) { - m_circleCandidates.push_back(vpCircleHoughTransform::vpCircle2D( vpImagePoint(centerCandidate.first, centerCandidate.second) + m_circleCandidates.push_back(vpCircle2D( vpImagePoint(centerCandidate.first, centerCandidate.second) , r_effective ) ); @@ -369,11 +448,11 @@ vpCircleHoughTransform::mergeCircleCandidates() size_t nbCandidates = m_circleCandidates.size(); for(size_t i = 0; i < nbCandidates; i++) { - vpCircleHoughTransform::vpCircle2D cic_i = m_circleCandidates[i]; + vpCircle2D cic_i = m_circleCandidates[i]; // // For each other circle candidate CiC_j do: for(size_t j = i + 1; j < nbCandidates; j++) { - vpCircleHoughTransform::vpCircle2D cic_j = m_circleCandidates[j]; + vpCircle2D cic_j = m_circleCandidates[j]; // // // Compute the similarity between CiC_i and CiC_j double distanceBetweenCenters = vpImagePoint::distance(cic_i.getCenter(), cic_j.getCenter()); double radiusDifference = std::abs(cic_i.getRadius() - cic_j.getRadius()); @@ -385,7 +464,7 @@ vpCircleHoughTransform::mergeCircleCandidates() { // // // If the similarity exceeds a threshold, merge the circle candidates CiC_i and CiC_j and remove CiC_j of the list unsigned int totalVotes = m_circleCandidatesVotes[i] + m_circleCandidatesVotes[j]; - cic_i = vpCircleHoughTransform::vpCircle2D( (cic_i.getCenter() * m_circleCandidatesVotes[i]+ cic_j.getCenter() * m_circleCandidatesVotes[j]) / totalVotes + cic_i = vpCircle2D( (cic_i.getCenter() * m_circleCandidatesVotes[i]+ cic_j.getCenter() * m_circleCandidatesVotes[j]) / totalVotes , (cic_i.getRadius() * m_circleCandidatesVotes[i] + cic_j.getRadius() * m_circleCandidatesVotes[j]) / totalVotes ); m_circleCandidates[j] = m_circleCandidates[nbCandidates - 1]; @@ -404,11 +483,11 @@ vpCircleHoughTransform::mergeCircleCandidates() nbCandidates = m_finalCircles.size(); for(size_t i = 0; i < nbCandidates; i++) { - vpCircleHoughTransform::vpCircle2D cic_i = m_finalCircles[i]; + vpCircle2D cic_i = m_finalCircles[i]; // // For each other circle candidate CiC_j do: for(size_t j = i + 1; j < nbCandidates; j++) { - vpCircleHoughTransform::vpCircle2D cic_j = m_finalCircles[j]; + vpCircle2D cic_j = m_finalCircles[j]; // // // Compute the similarity between CiC_i and CiC_j double distanceBetweenCenters = vpImagePoint::distance(cic_i.getCenter(), cic_j.getCenter()); double radiusDifference = std::abs(cic_i.getRadius() - cic_j.getRadius()); @@ -420,7 +499,7 @@ vpCircleHoughTransform::mergeCircleCandidates() { // // // If the similarity exceeds a threshold, merge the circle candidates CiC_i and CiC_j and remove CiC_j of the list unsigned int totalVotes = m_circleCandidatesVotes[i] + m_circleCandidatesVotes[j]; - cic_i = vpCircleHoughTransform::vpCircle2D( (cic_i.getCenter() * m_circleCandidatesVotes[i]+ cic_j.getCenter() * m_circleCandidatesVotes[j]) / totalVotes + cic_i = vpCircle2D( (cic_i.getCenter() * m_circleCandidatesVotes[i]+ cic_j.getCenter() * m_circleCandidatesVotes[j]) / totalVotes , (cic_i.getRadius() * m_circleCandidatesVotes[i] + cic_j.getRadius() * m_circleCandidatesVotes[j]) / totalVotes ); m_finalCircles[j] = m_finalCircles[nbCandidates - 1]; diff --git a/tutorial/imgproc/hough-transform/config/detector_full.json b/tutorial/imgproc/hough-transform/config/detector_full.json index 0b3f2b7017..117951fc5b 100644 --- a/tutorial/imgproc/hough-transform/config/detector_full.json +++ b/tutorial/imgproc/hough-transform/config/detector_full.json @@ -1,16 +1,24 @@ { - "cannyThresh": 150.0, - "centerMinDistance": 15.0, - "centerThresh": 50.0, - "circlePerfectnessThreshold": 0.9, - "dilatationNbIter": 1, - "gaussianKernelSize": 5, - "gaussianStdev": 1.0, - "mergingRadiusDiffThresh": 15.0, - "radiusLimits": [ - 0, - 1000 - ], - "radiusThreshRatio": 5, - "sobelKernelSize": 3 -} + "cannyThresh": 150.0, + "centerMinDistance": 15.0, + "centerThresh": 100.0, + "centerXlimits": [ + 0, + 640 + ], + "centerYlimits": [ + 0, + 480 + ], + "circlePerfectnessThreshold": 0.9, + "dilatationNbIter": 1, + "gaussianKernelSize": 5, + "gaussianStdev": 1.0, + "mergingRadiusDiffThresh": 10.0, + "radiusLimits": [ + 0, + 1000 + ], + "radiusThreshRatio": 5, + "sobelKernelSize": 3 +} \ No newline at end of file diff --git a/tutorial/imgproc/hough-transform/config/detector_half.json b/tutorial/imgproc/hough-transform/config/detector_half.json index c4928b1fd6..ce757e37cf 100644 --- a/tutorial/imgproc/hough-transform/config/detector_half.json +++ b/tutorial/imgproc/hough-transform/config/detector_half.json @@ -1,16 +1,24 @@ { - "cannyThresh": 150.0, - "centerMinDistance": 15.0, - "centerThresh": 25.0, - "circlePerfectnessThreshold": 0.9, - "dilatationNbIter": 1, - "gaussianKernelSize": 5, - "gaussianStdev": 1.0, - "mergingRadiusDiffThresh": 15.0, - "radiusLimits": [ - 0, - 1000 - ], - "radiusThreshRatio": 2, - "sobelKernelSize": 3 -} + "cannyThresh": 150.0, + "centerMinDistance": 15.0, + "centerThresh": 50.0, + "centerXlimits": [ + 0, + 640 + ], + "centerYlimits": [ + 0, + 480 + ], + "circlePerfectnessThreshold": 0.9, + "dilatationNbIter": 1, + "gaussianKernelSize": 5, + "gaussianStdev": 1.0, + "mergingRadiusDiffThresh": 10.0, + "radiusLimits": [ + 0, + 1000 + ], + "radiusThreshRatio": 2, + "sobelKernelSize": 3 +} \ No newline at end of file diff --git a/tutorial/imgproc/hough-transform/config/detector_img.json b/tutorial/imgproc/hough-transform/config/detector_img.json index 1c654f3d20..e6eb410b82 100644 --- a/tutorial/imgproc/hough-transform/config/detector_img.json +++ b/tutorial/imgproc/hough-transform/config/detector_img.json @@ -1,16 +1,24 @@ { - "cannyThresh": -1.0, - "centerMinDistance": 5.0, - "centerThresh": 200.0, - "circlePerfectnessThreshold": 0.9, - "dilatationNbIter": 1, - "gaussianKernelSize": 5, - "gaussianStdev": 1.0, - "mergingRadiusDiffThresh": 5.0, - "radiusLimits": [ - 80, - 90 - ], - "radiusThreshRatio": 2, - "sobelKernelSize": 3 -} + "cannyThresh": -1.0, + "centerMinDistance": 2.0, + "centerThresh": 200.0, + "centerXlimits": [ + -1000000, + 1000000 + ], + "centerYlimits": [ + -1000000, + 1000000 + ], + "circlePerfectnessThreshold": 0.9, + "dilatationNbIter": 1, + "gaussianKernelSize": 5, + "gaussianStdev": 1.0, + "mergingRadiusDiffThresh": 2.0, + "radiusLimits": [ + 80, + 90 + ], + "radiusThreshRatio": 2, + "sobelKernelSize": 3 +} \ No newline at end of file diff --git a/tutorial/imgproc/hough-transform/config/detector_quarter.json b/tutorial/imgproc/hough-transform/config/detector_quarter.json index 3b51e18ef7..415546b8a5 100644 --- a/tutorial/imgproc/hough-transform/config/detector_quarter.json +++ b/tutorial/imgproc/hough-transform/config/detector_quarter.json @@ -1,16 +1,24 @@ { - "cannyThresh": 150.0, - "centerMinDistance": 15.0, - "centerThresh": 15.0, - "circlePerfectnessThreshold": 0.9, - "dilatationNbIter": 1, - "gaussianKernelSize": 5, - "gaussianStdev": 1.0, - "mergingRadiusDiffThresh": 15.0, - "radiusLimits": [ - 0, - 1000 - ], - "radiusThreshRatio": 1, - "sobelKernelSize": 3 -} + "cannyThresh": 150.0, + "centerMinDistance": 15.0, + "centerThresh": 25.0, + "centerXlimits": [ + 0, + 640 + ], + "centerYlimits": [ + 0, + 480 + ], + "circlePerfectnessThreshold": 0.9, + "dilatationNbIter": 1, + "gaussianKernelSize": 5, + "gaussianStdev": 1.0, + "mergingRadiusDiffThresh": 15.0, + "radiusLimits": [ + 0, + 1000 + ], + "radiusThreshRatio": 1, + "sobelKernelSize": 3 +} \ No newline at end of file diff --git a/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp index 1c349f7e92..c9749959d5 100644 --- a/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp +++ b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp @@ -191,6 +191,8 @@ int main(int argc, char **argv) const double def_gaussianSigma = 1.; const int def_sobelKernelSize = 3; const double def_cannyThresh = 150.; + const std::pair def_centerXlimits = std::pair(0, 640); + const std::pair def_centerYlimits = std::pair(0, 480); const unsigned int def_minRadius = 0; const unsigned int def_maxRadius = 1000; const int def_dilatationRepet = 1; @@ -198,7 +200,7 @@ int main(int argc, char **argv) const double def_radiusThreshRatio = -1.; const double def_circlePerfectness = 0.85; const double def_centerDistanceThresh = 15; - const double def_radiusDifferenceThresh = 1.5 * def_centerDistanceThresh; + const double def_radiusDifferenceThresh = 15; std::string opt_input(def_input); @@ -208,6 +210,8 @@ int main(int argc, char **argv) double opt_gaussianSigma = def_gaussianSigma; int opt_sobelKernelSize = def_sobelKernelSize; double opt_cannyThresh = def_cannyThresh; + std::pair opt_centerXlimits = def_centerXlimits; + std::pair opt_centerYlimits = def_centerYlimits; unsigned int opt_minRadius = def_minRadius; unsigned int opt_maxRadius = def_maxRadius; int opt_dilatationRepet = def_dilatationRepet; @@ -262,6 +266,14 @@ int main(int argc, char **argv) opt_centerThresh = atof(argv[i + 1]); i++; } + else if (argName == "--center-xlim" && i + 2 < argc) { + opt_centerXlimits = std::pair (atoi(argv[i + 1]), atoi(argv[i + 2])); + i+=2; + } + else if (argName == "--center-ylim" && i + 2 < argc) { + opt_centerYlimits = std::pair (atoi(argv[i + 1]), atoi(argv[i + 2])); + i+=2; + } else if (argName == "--radius-thresh" && i + 1 < argc) { opt_radiusThreshRatio = atof(argv[i + 1]); i++; @@ -293,6 +305,8 @@ int main(int argc, char **argv) << "\t [--radius-limits ] (default: min = " << def_minRadius << ", max = " << def_maxRadius << ")" << std::endl << "\t [--dilatation-repet ] (default: " << def_dilatationRepet << ")" << std::endl << "\t [--center-thresh ] (default: " << (def_centerThresh < 0 ? "auto" : std::to_string(def_centerThresh)) << ")" << std::endl + << "\t [--center-xlim ] (default: " << def_centerXlimits.first << " , " << def_centerXlimits.second << ")" << std::endl + << "\t [--center-ylim ] (default: " << def_centerYlimits.first << " , " << def_centerYlimits.second << ")" << std::endl << "\t [--radius-thresh ] (default: " << (def_radiusThreshRatio < 0 ? "auto" : std::to_string(def_radiusThreshRatio)) << ")" << std::endl << "\t [--circle-perfectness ] (default: " << def_radiusThreshRatio << ")" << std::endl << "\t [--merging-thresh ] (default: centers distance threshold = " << def_centerDistanceThresh << ", radius difference threshold = " << def_radiusDifferenceThresh << ")" << std::endl @@ -334,8 +348,6 @@ int main(int argc, char **argv) << "\t\tPermit to set the minimum and maximum radii of the circles we are looking for." << std::endl << "\t\tDefault: min = " << def_minRadius << ", max = " << def_maxRadius << std::endl << std::endl - << "\t--merging-thresh" << std::endl - << std::endl << "\t--dilatation-repet" << std::endl << "\t\tPermit to set the number of iterations of the dilatation operation used to detect the maxima of the centers votes." << std::endl << "\t\tMinimum tolerated value is 1." << std::endl @@ -347,6 +359,16 @@ int main(int argc, char **argv) << "\t\tOtherwise, if the input is a synthetic image and the value is negative, a fine-tuned value will be used." << std::endl << "\t\tDefault: " << (def_centerThresh < 0 ? "auto" : std::to_string(def_centerThresh)) << std::endl << std::endl + << "\t--center-xlim" << std::endl + << "\t\tPermit to set the minimum and maximum horizontal position to be considered as a center candidate." << std::endl + << "\t\tThe search area is limited to [-maxRadius; +image.width + maxRadius]." << std::endl + << "\t\tDefault: " << def_centerXlimits.first << " , " << def_centerXlimits.second << std::endl + << std::endl + << "\t--center-ylim" << std::endl + << "\t\tPermit to set the minimum and maximum vertical position to be considered as a center candidate." << std::endl + << "\t\tThe search area is limited to [-maxRadius; +image.height + maxRadius]." << std::endl + << "\t\tDefault: " << def_centerYlimits.first << " , " << def_centerYlimits.second << std::endl + << std::endl << "\t--radius-thresh" << std::endl << "\t\tPermit to to set the minimum number of votes per radian a radius must reach to be considered as a circle candidate a given pair (center candidate, radius candidate)." << std::endl << "\t\tDefault: " << (def_radiusThreshRatio < 0 ? "auto" : std::to_string(def_radiusThreshRatio)) << std::endl @@ -357,6 +379,7 @@ int main(int argc, char **argv) << "\t\tThe scalar product radius RC_ij . gradient(Ep_j) >= m_circlePerfectness * || RC_ij || * || gradient(Ep_j) || to add a vote for the radius RC_ij." << std::endl << "\t\tDefault: " << def_circlePerfectness << std::endl << std::endl + << "\t--merging-thresh" << std::endl << "\t\tPermit to set the thresholds used during the merging stage of the algorithm." << std::endl << "\t\tThe center distance threshold indicates the maximum distance the centers can be in order to be merged." << std::endl << "\t\tThe radius difference threshold indicates the maximum absolute difference between the two circle candidates in order to be merged." << std::endl @@ -371,13 +394,13 @@ int main(int argc, char **argv) TypeInputImage inputType = typeInputImageFromString(opt_input); switch (inputType) { case TypeInputImage::FULL_DISKS: - opt_centerThresh = 50.; + opt_centerThresh = 100.; break; case TypeInputImage::HALF_DISKS: - opt_centerThresh = 25.; + opt_centerThresh = 50.; break; case TypeInputImage::QUARTER_DISKS: - opt_centerThresh = 15.; + opt_centerThresh = 25.; break; default: throw(vpException(vpException::badValue, "Missing center threshold value to use with actual pictures as input. See the help for more information.")); @@ -408,6 +431,8 @@ int main(int argc, char **argv) , opt_gaussianSigma , opt_sobelKernelSize , opt_cannyThresh + , opt_centerXlimits + , opt_centerYlimits , opt_minRadius , opt_maxRadius , opt_dilatationRepet From 245b170d55d285c6089eec78a53d1bfa7f8e0fbb Mon Sep 17 00:00:00 2001 From: rlagneau Date: Wed, 16 Aug 2023 11:49:09 +0200 Subject: [PATCH 07/20] [FIX] Corrected the sorting way when the user ask for a particular number of detections [TUTO] Optimized detector_img.json for an example image --- .vscode/settings.json | 3 +- doc/tutorial/imgproc/tutorial-imgproc-cht.dox | 37 +- .../visp3/imgproc/vpCircleHoughTransform.h | 716 ++++++++++-------- .../imgproc/src/vpCircleHoughTransform.cpp | 368 ++++----- .../imgproc/hough-transform/CMakeLists.txt | 6 +- tutorial/imgproc/hough-transform/coins2.pgm | Bin 0 -> 178674 bytes .../hough-transform/config/detector_img.json | 29 +- .../hough-transform/tutorial-circle-hough.cpp | 48 +- 8 files changed, 656 insertions(+), 551 deletions(-) create mode 100644 tutorial/imgproc/hough-transform/coins2.pgm diff --git a/.vscode/settings.json b/.vscode/settings.json index c42037bbb3..aa4bed3ea2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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, diff --git a/doc/tutorial/imgproc/tutorial-imgproc-cht.dox b/doc/tutorial/imgproc/tutorial-imgproc-cht.dox index 8ff04a8c2c..d1efce2c9c 100644 --- a/doc/tutorial/imgproc/tutorial-imgproc-cht.dox +++ b/doc/tutorial/imgproc/tutorial-imgproc-cht.dox @@ -6,8 +6,8 @@ \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 +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 @@ -17,15 +17,15 @@ During the step where the algorithm votes for center candidates, we use the grad 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 +\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 +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 +\image html img-tutorial-cht-radius-votes.png \section imgproc_cht_requirements Requirements @@ -35,29 +35,29 @@ If you do not know how to do it, please refer to the installation guidelines of \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) +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. +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: ``` -$ ./tutorial-circle-hough --help +$ ./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, +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 +$ ./tutorial-circle-hough --input ${TARGET}_disks --config config/detector_${TARGET}.json ``` -To run the software on the synthetic images using the default parameters, +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 +$ ./tutorial-circle-hough --input ${TARGET}_disks ``` \subsection imgproc_cht_howto_images How to use actual images @@ -67,7 +67,8 @@ To run the software on an actual image using a JSON configuration file, please r $ ./tutorial-circle-hough --input /path/to/my/image --config config/detector_img.json ``` -If the detections seem a bit off, you might need to change the parameters +**NB**: the configuration file `config/detector_img.json` has been tuned to detect coins in the image `coins2.pgm`. +If the detections seem a bit off, you might need to change the parameters. To run the software on an actual image using command line arguments instead, please run: ``` @@ -78,9 +79,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 +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: @@ -106,11 +107,11 @@ please run: $ ./tutorial-circle-hough --help ``` -If you decide to use a video as input, the relevant piece of code that permits to +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 +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 diff --git a/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h b/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h index 8e5fe5ecb6..f7fe990317 100644 --- a/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h +++ b/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h @@ -33,7 +33,7 @@ #ifndef _vpCircleHoughTransform_h_ #define _vpCircleHoughTransform_h_ -// System includes + // System includes #include #include @@ -55,9 +55,9 @@ using json = nlohmann::json; /** * \brief Class that permits to detect 2D circles in a image using * the gradient-based Circle Hough transform. - * Please find more information on the algorithm + * Please find more information on the algorithm * [here](https://theailearner.com/tag/hough-gradient-method-opencv/) - * + * */ class VISP_EXPORT vpCircleHoughTransform { @@ -67,334 +67,335 @@ class VISP_EXPORT vpCircleHoughTransform */ class CHTransformParameters { - private: - // // Gaussian smoothing attributes - int m_gaussianKernelSize; /*!< Size of the Gaussian filter kernel used to smooth the input image. Must be an odd number.*/ - float m_gaussianStdev; /*!< Standard deviation of the Gaussian filter.*/ - - // // Gradient computation attributes - 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.*/ - - // // Center candidates computation attributes - std::pair m_centerXlimits; /*!< Minimum and maximum position on the horizontal axis of the center of the circle we want to detect.*/ - std::pair m_centerYlimits; /*!< Minimum and maximum position on the vertical axis of the center of the circle we want to detect.*/ - unsigned int m_minRadius; /*!< Minimum radius of the circles we want to detect.*/ - unsigned int m_maxRadius; /*!< Maximum radius of the circles we want to detect.*/ - int m_dilatationNbIter; /*!< Number of times dilatation is performed to detect the maximum number of votes for the center candidates.*/ - float m_centerThresh; /*!< Minimum number of votes a point must exceed to be considered as center candidate.*/ - - // // Circle candidates computation attributes - float m_radiusRatioThresh; /*!< Minimum number of votes per radian a radius candidate RC_ij of a center candidate CeC_i must have in order that the circle of center CeC_i and radius RC_ij must be considered as circle candidate.*/ - float m_circlePerfectness; /*!< The scalar product radius RC_ij . gradient(Ep_j) >= m_circlePerfectness * || RC_ij || * || gradient(Ep_j) || to add a vote for the radius RC_ij. */ - - // // Circle candidates merging atttributes - float m_centerMinDist; /*!< Maximum distance between two circle candidates centers to consider merging them.*/ - float m_mergingRadiusDiffThresh; /*!< Maximum radius difference between two circle candidates to consider merging them.*/ - - friend vpCircleHoughTransform; - public: - CHTransformParameters() - : m_gaussianKernelSize(5) - , m_gaussianStdev(1.) - , m_sobelKernelSize(3) - , m_cannyThresh(-1) - , m_centerXlimits(std::pair(std::numeric_limits::min(), std::numeric_limits::max())) - , m_centerYlimits(std::pair(std::numeric_limits::min(), std::numeric_limits::max())) - , m_minRadius(0) - , m_maxRadius(1000) - , m_dilatationNbIter(1) - , m_centerThresh(50.) - , m_radiusRatioThresh(2.) - , m_circlePerfectness(0.9) - , m_centerMinDist(15.) - , m_mergingRadiusDiffThresh(1.5 * (float)m_centerMinDist) - { + private: + // // Gaussian smoothing attributes + int m_gaussianKernelSize; /*!< Size of the Gaussian filter kernel used to smooth the input image. Must be an odd number.*/ + float m_gaussianStdev; /*!< Standard deviation of the Gaussian filter.*/ + + // // Gradient computation attributes + 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.*/ + int m_edgeMapFilteringNbIter; /*!< Number of iterations of 8-neighbor connectivity filtering to apply to the edge map*/ + + // // Center candidates computation attributes + std::pair m_centerXlimits; /*!< Minimum and maximum position on the horizontal axis of the center of the circle we want to detect.*/ + std::pair m_centerYlimits; /*!< Minimum and maximum position on the vertical axis of the center of the circle we want to detect.*/ + unsigned int m_minRadius; /*!< Minimum radius of the circles we want to detect.*/ + unsigned int m_maxRadius; /*!< Maximum radius of the circles we want to detect.*/ + int m_dilatationNbIter; /*!< Number of times dilatation is performed to detect the maximum number of votes for the center candidates.*/ + float m_centerThresh; /*!< Minimum number of votes a point must exceed to be considered as center candidate.*/ + + // // Circle candidates computation attributes + float m_radiusRatioThresh; /*!< Minimum number of votes per radian a radius candidate RC_ij of a center candidate CeC_i must have in order that the circle of center CeC_i and radius RC_ij must be considered as circle candidate.*/ + float m_circlePerfectness; /*!< The scalar product radius RC_ij . gradient(Ep_j) >= m_circlePerfectness * || RC_ij || * || gradient(Ep_j) || to add a vote for the radius RC_ij. */ + + // // Circle candidates merging atttributes + float m_centerMinDist; /*!< Maximum distance between two circle candidates centers to consider merging them.*/ + float m_mergingRadiusDiffThresh; /*!< Maximum radius difference between two circle candidates to consider merging them.*/ + + friend vpCircleHoughTransform; + public: + CHTransformParameters() + : m_gaussianKernelSize(5) + , m_gaussianStdev(1.) + , m_sobelKernelSize(3) + , m_cannyThresh(-1) + , m_edgeMapFilteringNbIter(1) + , m_centerXlimits(std::pair(std::numeric_limits::min(), std::numeric_limits::max())) + , m_centerYlimits(std::pair(std::numeric_limits::min(), std::numeric_limits::max())) + , m_minRadius(0) + , m_maxRadius(1000) + , m_dilatationNbIter(1) + , m_centerThresh(50.) + , m_radiusRatioThresh(2.) + , m_circlePerfectness(0.9) + , m_centerMinDist(15.) + , m_mergingRadiusDiffThresh(1.5 * (float)m_centerMinDist) + { + + } + + /** + * \brief Construct a new CHTransformParameters object. + * + * \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] 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. + * \param[in] minRadius Minimum radius of the circles we want to detect. + * \param[in] maxRadius Maximum radius of the circles we want to detect. + * \param[in] dilatationNbIter Number of times dilatation is performed to detect the maximum number of votes for the center candidates + * \param[in] centerThresh Minimum number of votes a point must exceed to be considered as center candidate. + * \param[in] radiusThreshRatio Minimum number of votes per radian a radius candidate RC_ij of a center candidate CeC_i must have in order that the circle of center CeC_i and radius RC_ij must be considered as circle candidate. + * \param[in] circlePerfectness The scalar product radius RC_ij . gradient(Ep_j) >= m_circlePerfectness * || RC_ij || * || gradient(Ep_j) || to add a vote for the radius RC_ij. + * \param[in] centerMinDistThresh Two circle candidates whose centers are closer than this threshold are considered for merging. + * \param[in] mergingRadiusDiffThresh Maximum radius difference between two circle candidates to consider merging them. + */ + CHTransformParameters( + const int &gaussianKernelSize + , const float &gaussianStdev + , const int &sobelKernelSize + , const float &cannyThresh + , const int &edgeMapFilterNbIter + , const std::pair ¢erXlimits + , const std::pair ¢erYlimits + , const unsigned int &minRadius + , const unsigned int &maxRadius + , const int &dilatationNbIter + , const float ¢erThresh + , const float &radiusThreshRatio + , const float &circlePerfectness + , const float ¢erMinDistThresh + , const float &mergingRadiusDiffThresh + ) + : m_gaussianKernelSize(gaussianKernelSize) + , m_gaussianStdev(gaussianStdev) + , m_sobelKernelSize(sobelKernelSize) + , m_cannyThresh(cannyThresh) + , m_edgeMapFilteringNbIter(edgeMapFilterNbIter) + , m_centerXlimits(centerXlimits) + , m_centerYlimits(centerYlimits) + , m_minRadius(std::min(minRadius, maxRadius)) + , m_maxRadius(std::max(minRadius, maxRadius)) + , m_dilatationNbIter(dilatationNbIter) + , m_centerThresh(centerThresh) + , m_radiusRatioThresh(radiusThreshRatio) + , m_circlePerfectness(circlePerfectness) + , m_centerMinDist(centerMinDistThresh) + , m_mergingRadiusDiffThresh(mergingRadiusDiffThresh) + { + + } + + std::string toString() const + { + std::string txt("Hough Circle Transform Configuration:\n"); + 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 += "\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"; + txt += "\tRadius limits: min = " + std::to_string(m_minRadius) + "\tmax = " + std::to_string(m_maxRadius) +"\n"; + txt += "\tNumber of repetitions of the dilatation filter = " + std::to_string(m_dilatationNbIter) + "\n"; + txt += "\tCenters votes threshold = " + std::to_string(m_centerThresh) + "\n"; + txt += "\tRadius votes per radian threshold = " + std::to_string(m_radiusRatioThresh) + "\n"; + txt += "\tCircle perfectness threshold = " + std::to_string(m_circlePerfectness) + "\n"; + txt += "\tCenters minimum distance = " + std::to_string(m_centerMinDist) + "\n"; + txt += "\tRadius difference merging threshold = " + std::to_string(m_mergingRadiusDiffThresh) + "\n"; + return txt; + } + + // // Configuration from files +#ifdef VISP_HAVE_NLOHMANN_JSON + /** + * \brief Create a new CHTransformParameters from a JSON file. + * + * \param[in] jsonFile The path towards the JSON file. + * \return CHTransformParameters The corresponding CHTransformParameters object. + */ + inline static CHTransformParameters createFromJSON(const std::string &jsonFile) + { + std::ifstream file(jsonFile); + if (!file.good()) { + std::stringstream ss; + ss << "Problem opening file " << jsonFile << ". Make sure it exists and is readable" << std::endl; + throw vpException(vpException::ioError, ss.str()); + } + json j; + try { + j = json::parse(file); + } + catch (json::parse_error &e) { + std::stringstream msg; + msg << "Could not parse JSON file : \n"; + msg << e.what() << std::endl; + msg << "Byte position of error: " << e.byte; + throw vpException(vpException::ioError, msg.str()); } + CHTransformParameters params = j; // Call from_json(const json& j, vpDetectorDNN& *this) to read json + file.close(); + return params; + } - /** - * \brief Construct a new CHTransformParameters object. - * - * \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] 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. - * \param[in] minRadius Minimum radius of the circles we want to detect. - * \param[in] maxRadius Maximum radius of the circles we want to detect. - * \param[in] dilatationNbIter Number of times dilatation is performed to detect the maximum number of votes for the center candidates - * \param[in] centerThresh Minimum number of votes a point must exceed to be considered as center candidate. - * \param[in] radiusThreshRatio Minimum number of votes per radian a radius candidate RC_ij of a center candidate CeC_i must have in order that the circle of center CeC_i and radius RC_ij must be considered as circle candidate. - * \param[in] circlePerfectness The scalar product radius RC_ij . gradient(Ep_j) >= m_circlePerfectness * || RC_ij || * || gradient(Ep_j) || to add a vote for the radius RC_ij. - * \param[in] centerMinDistThresh Two circle candidates whose centers are closer than this threshold are considered for merging. - * \param[in] mergingRadiusDiffThresh Maximum radius difference between two circle candidates to consider merging them. - */ - CHTransformParameters( - const int &gaussianKernelSize - , const float &gaussianStdev - , const int &sobelKernelSize - , const float &cannyThresh - , const std::pair ¢erXlimits - , const std::pair ¢erYlimits - , const unsigned int &minRadius - , const unsigned int &maxRadius - , const int &dilatationNbIter - , const float ¢erThresh - , const float &radiusThreshRatio - , const float &circlePerfectness - , const float ¢erMinDistThresh - , const float &mergingRadiusDiffThresh - ) - : m_gaussianKernelSize(gaussianKernelSize) - , m_gaussianStdev(gaussianStdev) - , m_sobelKernelSize(sobelKernelSize) - , m_cannyThresh(cannyThresh) - , m_centerXlimits(centerXlimits) - , m_centerYlimits(centerYlimits) - , m_minRadius(std::min(minRadius, maxRadius)) - , m_maxRadius(std::max(minRadius, maxRadius)) - , m_dilatationNbIter(dilatationNbIter) - , m_centerThresh(centerThresh) - , m_radiusRatioThresh(radiusThreshRatio) - , m_circlePerfectness(circlePerfectness) - , m_centerMinDist(centerMinDistThresh) - , m_mergingRadiusDiffThresh(mergingRadiusDiffThresh) - { + /** + * \brief Save the configuration of the detector in a JSON file + * described by the path \b jsonPath. Throw a \b vpException + * is the file cannot be created. + * + * \param[in] jsonPath The path towards the JSON output file. + */ + inline void saveConfigurationInJSON(const std::string &jsonPath) const + { + std::ofstream file(jsonPath); + const json j = *this; + file << j.dump(4); + file.close(); + } + /** + * \brief Read the detector configuration from JSON. All values are optional and if an argument is not present, + * the default value defined in the constructor is kept + * + * \param[in] j The JSON object, resulting from the parsing of a JSON file. + * \param[out] detector The detector, that will be initialized from the JSON data. + */ + inline friend void from_json(const json &j, CHTransformParameters ¶ms) + { + params.m_gaussianKernelSize = j.value("gaussianKernelSize", params.m_gaussianKernelSize); + if ((params.m_gaussianKernelSize % 2) != 1) { + throw vpException(vpException::badValue, "Gaussian Kernel size should be odd."); } - std::string toString() const - { - std::string txt("Hough Circle Transform Configuration:\n"); - 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 += "\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"; - txt += "\tRadius limits: min = " + std::to_string(m_minRadius) + "\tmax = " + std::to_string(m_maxRadius) +"\n"; - txt += "\tNumber of repetitions of the dilatation filter = " + std::to_string(m_dilatationNbIter) + "\n"; - txt += "\tCenters votes threshold = " + std::to_string(m_centerThresh) + "\n"; - txt += "\tRadius votes per radian threshold = " + std::to_string(m_radiusRatioThresh) + "\n"; - txt += "\tCircle perfectness threshold = " + std::to_string(m_circlePerfectness) + "\n"; - txt += "\tCenters minimum distance = " + std::to_string(m_centerMinDist) + "\n"; - txt += "\tRadius difference merging threshold = " + std::to_string(m_mergingRadiusDiffThresh) + "\n"; - return txt; + params.m_gaussianStdev = j.value("gaussianStdev", params.m_gaussianStdev); + if (params.m_gaussianStdev <= 0) { + throw vpException(vpException::badValue, "Standard deviation should be > 0"); } - // // Configuration from files - #ifdef VISP_HAVE_NLOHMANN_JSON - /** - * \brief Create a new CHTransformParameters from a JSON file. - * - * \param[in] jsonFile The path towards the JSON file. - * \return CHTransformParameters The corresponding CHTransformParameters object. - */ - inline static CHTransformParameters createFromJSON(const std::string & jsonFile) - { - std::ifstream file(jsonFile); - if (!file.good()) { - std::stringstream ss; - ss << "Problem opening file " << jsonFile << ". Make sure it exists and is readable" << std::endl; - throw vpException(vpException::ioError, ss.str()); - } - json j; - try { - j = json::parse(file); - } - catch (json::parse_error &e) { - std::stringstream msg; - msg << "Could not parse JSON file : \n"; - - msg << e.what() << std::endl; - msg << "Byte position of error: " << e.byte; - throw vpException(vpException::ioError, msg.str()); - } - CHTransformParameters params = j; // Call from_json(const json& j, vpDetectorDNN& *this) to read json - file.close(); - return params; + params.m_sobelKernelSize = j.value("sobelKernelSize", params.m_sobelKernelSize); + if ((params.m_sobelKernelSize % 2) != 1) { + throw vpException(vpException::badValue, "Sobel Kernel size should be odd."); } - /** - * \brief Save the configuration of the detector in a JSON file - * described by the path \b jsonPath. Throw a \b vpException - * is the file cannot be created. - * - * \param[in] jsonPath The path towards the JSON output file. - */ - inline void saveConfigurationInJSON(const std::string &jsonPath) const - { - std::ofstream file(jsonPath); - const json j = *this; - file << j.dump(4); - file.close(); + params.m_cannyThresh = j.value("cannyThresh", params.m_cannyThresh); + params.m_edgeMapFilteringNbIter = j.value("edgeMapFilteringNbIter", params.m_edgeMapFilteringNbIter); + + params.m_centerXlimits = j.value("centerXlimits", params.m_centerXlimits); + params.m_centerYlimits = j.value("centerYlimits", params.m_centerYlimits); + std::pair radiusLimits = j.value("radiusLimits", std::pair(params.m_minRadius, params.m_maxRadius)); + params.m_minRadius = std::min(radiusLimits.first, radiusLimits.second); + params.m_maxRadius = std::max(radiusLimits.first, radiusLimits.second); + + params.m_dilatationNbIter = j.value("dilatationNbIter", params.m_dilatationNbIter); + + params.m_centerThresh = j.value("centerThresh", params.m_centerThresh); + if (params.m_centerThresh <= 0) { + throw vpException(vpException::badValue, "Votes thresholds for center detection must be positive."); } - /** - * \brief Read the detector configuration from JSON. All values are optional and if an argument is not present, - * the default value defined in the constructor is kept - * - * \param j The JSON object, resulting from the parsing of a JSON file. - * \param detector The detector, that will be initialized from the JSON data. - */ - inline friend void from_json(const json &j, CHTransformParameters ¶ms) - { - params.m_gaussianKernelSize = j.value("gaussianKernelSize", params.m_gaussianKernelSize); - if ((params.m_gaussianKernelSize % 2) != 1) - { - throw vpException(vpException::badValue, "Gaussian Kernel size should be odd."); - } - - params.m_gaussianStdev = j.value("gaussianStdev", params.m_gaussianStdev); - if (params.m_gaussianStdev <= 0) - { - throw vpException(vpException::badValue, "Standard deviation should be > 0"); - } - - params.m_sobelKernelSize = j.value("sobelKernelSize", params.m_sobelKernelSize); - if ((params.m_sobelKernelSize % 2) != 1) - { - throw vpException(vpException::badValue, "Sobel Kernel size should be odd."); - } - - params.m_cannyThresh = j.value("cannyThresh", params.m_cannyThresh); - - params.m_centerXlimits = j.value("centerXlimits", params.m_centerXlimits); - params.m_centerYlimits = j.value("centerYlimits", params.m_centerYlimits); - std::pair radiusLimits = j.value("radiusLimits", std::pair(params.m_minRadius, params.m_maxRadius)); - params.m_minRadius = std::min(radiusLimits.first, radiusLimits.second); - params.m_maxRadius = std::max(radiusLimits.first, radiusLimits.second); - - params.m_dilatationNbIter = j.value("dilatationNbIter", params.m_dilatationNbIter); - - params.m_centerThresh = j.value("centerThresh", params.m_centerThresh); - if (params.m_centerThresh <= 0) - { - throw vpException(vpException::badValue, "Votes thresholds for center detection must be positive."); - } - - params.m_radiusRatioThresh = j.value("radiusThreshRatio", params.m_radiusRatioThresh); - - params.m_circlePerfectness = j.value("circlePerfectnessThreshold", params.m_circlePerfectness); - - if (params.m_circlePerfectness <= 0 || params.m_circlePerfectness > 1) - { - throw vpException(vpException::badValue, "Circle perfectness must be in the interval ] 0; 1]."); - } - - params.m_centerMinDist = j.value("centerMinDistance", params.m_centerMinDist); - if (params.m_centerMinDist <= 0) - { - throw vpException(vpException::badValue, "Centers minimum distance threshold must be positive."); - } - - params.m_mergingRadiusDiffThresh = j.value("mergingRadiusDiffThresh", params.m_mergingRadiusDiffThresh); - if (params.m_mergingRadiusDiffThresh <= 0) - { - throw vpException(vpException::badValue, "Radius difference merging threshold must be positive."); - } + params.m_radiusRatioThresh = j.value("radiusThreshRatio", params.m_radiusRatioThresh); + + params.m_circlePerfectness = j.value("circlePerfectnessThreshold", params.m_circlePerfectness); + + if (params.m_circlePerfectness <= 0 || params.m_circlePerfectness > 1) { + throw vpException(vpException::badValue, "Circle perfectness must be in the interval ] 0; 1]."); + } + + params.m_centerMinDist = j.value("centerMinDistance", params.m_centerMinDist); + if (params.m_centerMinDist <= 0) { + throw vpException(vpException::badValue, "Centers minimum distance threshold must be positive."); } - /** - * \brief Parse a vpCircleHoughTransform into JSON format. - * - * \param j A JSON parser object. - * \param config The vpCircleHoughTransform that must be parsed into JSON format. - */ - inline friend void to_json(json &j, const CHTransformParameters ¶ms) - { - std::pair radiusLimits = {params.m_minRadius, params.m_maxRadius}; - - j = json{ - {"gaussianKernelSize", params.m_gaussianKernelSize}, - {"gaussianStdev", params.m_gaussianStdev}, - {"sobelKernelSize", params.m_sobelKernelSize}, - {"cannyThresh", params.m_cannyThresh}, - {"centerXlimits", params.m_centerXlimits}, - {"centerYlimits", params.m_centerYlimits}, - {"radiusLimits", radiusLimits}, - {"dilatationNbIter", params.m_dilatationNbIter}, - {"centerThresh", params.m_centerThresh}, - {"radiusThreshRatio", params.m_radiusRatioThresh}, - {"circlePerfectnessThreshold", params.m_circlePerfectness}, - {"centerMinDistance", params.m_centerMinDist}, - {"mergingRadiusDiffThresh", params.m_mergingRadiusDiffThresh}}; + params.m_mergingRadiusDiffThresh = j.value("mergingRadiusDiffThresh", params.m_mergingRadiusDiffThresh); + if (params.m_mergingRadiusDiffThresh <= 0) { + throw vpException(vpException::badValue, "Radius difference merging threshold must be positive."); } - #endif - } ; + } + + /** + * \brief Parse a vpCircleHoughTransform into JSON format. + * + * \param[out] j A JSON parser object. + * \param[in] config The vpCircleHoughTransform that must be parsed into JSON format. + */ + inline friend void to_json(json &j, const CHTransformParameters ¶ms) + { + std::pair radiusLimits = { params.m_minRadius, params.m_maxRadius }; + + j = json { + {"gaussianKernelSize", params.m_gaussianKernelSize}, + {"gaussianStdev", params.m_gaussianStdev}, + {"sobelKernelSize", params.m_sobelKernelSize}, + {"cannyThresh", params.m_cannyThresh}, + {"edgeMapFilteringNbIter", params.m_edgeMapFilteringNbIter}, + {"centerXlimits", params.m_centerXlimits}, + {"centerYlimits", params.m_centerYlimits}, + {"radiusLimits", radiusLimits}, + {"dilatationNbIter", params.m_dilatationNbIter}, + {"centerThresh", params.m_centerThresh}, + {"radiusThreshRatio", params.m_radiusRatioThresh}, + {"circlePerfectnessThreshold", params.m_circlePerfectness}, + {"centerMinDistance", params.m_centerMinDist}, + {"mergingRadiusDiffThresh", params.m_mergingRadiusDiffThresh} }; + } +#endif + }; /** * \brief Class that defines a 2D circle in an image. */ class vpCircle2D { - public: - /*! - * Default constructor. - */ - vpCircle2D() : m_center(), m_radius(0.) { } - - /*! - * Constructor from a center and radius. - */ - vpCircle2D(const vpImagePoint ¢er, const float &radius) : m_center(center), m_radius(radius) { } - - /*! - * Constructor from an OpenCV vector that contains [center_x, center_y, radius]. - */ - vpCircle2D(const cv::Vec3f &vec) : m_center(vec[1], vec[0]), m_radius(vec[2]) { } - - /*! - * Default destructor. - */ - virtual ~vpCircle2D() { }; - - /*! - * Return the center of the 2D circle. - */ - vpImagePoint getCenter() const { return m_center; }; - - /*! - * Return the radius of the 2D circle. - */ - float getRadius() const { return m_radius; }; - - /*! - * Return the 2D circle bounding box. - */ - vpRect getBBox() const - { - vpRect bbox(m_center - vpImagePoint(m_radius, m_radius), 2 * m_radius, 2 * m_radius); - return bbox; - }; - - /*! - * Return normalized moment \f$n_{20}\f$. - */ - float get_n20() const { return m_radius * m_radius / 4; }; - - /*! - * Return normalized moment \f$n_{02}\f$. - */ - float get_n02() const { return m_radius * m_radius / 4; }; - - /*! - * Return normalized moment \f$n_{02}\f$. - */ - float get_n11() const { return 0.; }; - - template < typename Type > - void display( vpImage< Type > &img, const vpColor &color = vpColor::blue, const unsigned int &thickness = 1, const unsigned int &size = 5 ) const; - - private: - vpImagePoint m_center; - float m_radius; + public: + /*! + * Default constructor. + */ + vpCircle2D() : m_center(), m_radius(0.) { } + + /*! + * Constructor from a center and radius. + */ + vpCircle2D(const vpImagePoint ¢er, const float &radius) : m_center(center), m_radius(radius) { } + + /*! + * Constructor from an OpenCV vector that contains [center_x, center_y, radius]. + */ + vpCircle2D(const cv::Vec3f &vec) : m_center(vec[1], vec[0]), m_radius(vec[2]) { } + + /*! + * Default destructor. + */ + virtual ~vpCircle2D() { }; + + /*! + * Return the center of the 2D circle. + */ + vpImagePoint getCenter() const { return m_center; }; + + /*! + * Return the radius of the 2D circle. + */ + float getRadius() const { return m_radius; }; + + /*! + * Return the 2D circle bounding box. + */ + vpRect getBBox() const + { + vpRect bbox(m_center - vpImagePoint(m_radius, m_radius), 2 * m_radius, 2 * m_radius); + return bbox; + }; + + /*! + * Return normalized moment \f$n_{20}\f$. + */ + float get_n20() const { return m_radius * m_radius / 4; }; + + /*! + * Return normalized moment \f$n_{02}\f$. + */ + float get_n02() const { return m_radius * m_radius / 4; }; + + /*! + * Return normalized moment \f$n_{02}\f$. + */ + float get_n11() const { return 0.; }; + + template < typename Type > + void display(vpImage< Type > &img, const vpColor &color = vpColor::blue, const unsigned int &thickness = 1, const unsigned int &size = 5) const; + + private: + vpImagePoint m_center; + float m_radius; }; /** @@ -405,7 +406,7 @@ class VISP_EXPORT vpCircleHoughTransform /** * \brief Construct a new vpCircleHoughTransform object * from a \b CHTransformParameters object. - * \param algoParams The parameters of the Circle Hough Transform. + * \param[in] algoParams The parameters of the Circle Hough Transform. */ vpCircleHoughTransform(const CHTransformParameters &algoParams); @@ -453,7 +454,7 @@ class VISP_EXPORT vpCircleHoughTransform */ std::vector detect(const vpImage &I, const int &nbCircles); -// // Configuration from files + // // Configuration from files #ifdef VISP_HAVE_NLOHMANN_JSON /** * \brief Construct a new vpCircleHoughTransform object configured according to @@ -485,8 +486,8 @@ class VISP_EXPORT vpCircleHoughTransform * \brief Read the detector configuration from JSON. All values are optional and if an argument is not present, * the default value defined in the constructor is kept * - * \param j The JSON object, resulting from the parsing of a JSON file. - * \param detector The detector, that will be initialized from the JSON data. + * \param[in] j The JSON object, resulting from the parsing of a JSON file. + * \param[out] detector The detector, that will be initialized from the JSON data. */ inline friend void from_json(const json &j, vpCircleHoughTransform &detector) { @@ -496,8 +497,8 @@ class VISP_EXPORT vpCircleHoughTransform /** * \brief Parse a vpCircleHoughTransform into JSON format. * - * \param j A JSON parser object. - * \param config The vpCircleHoughTransform that must be parsed into JSON format. + * \param[out] j A JSON parser object. + * \param[in] config The vpCircleHoughTransform that must be parsed into JSON format. */ inline friend void to_json(json &j, const vpCircleHoughTransform &detector) { @@ -508,7 +509,7 @@ class VISP_EXPORT vpCircleHoughTransform // // Setters /** * \brief Initialize all the algorithm parameters. - * + * * \param[in] algoParams The algorithm parameters. */ void init(const CHTransformParameters &algoParams); @@ -525,13 +526,11 @@ class VISP_EXPORT vpCircleHoughTransform m_algoParams.m_gaussianKernelSize = kernelSize; m_algoParams.m_gaussianStdev = stdev; - if ((m_algoParams.m_gaussianKernelSize % 2) != 1) - { + if ((m_algoParams.m_gaussianKernelSize % 2) != 1) { throw vpException(vpException::badValue, "Gaussian Kernel size should be odd."); } - if (m_algoParams.m_gaussianStdev <= 0) - { + if (m_algoParams.m_gaussianStdev <= 0) { throw vpException(vpException::badValue, "Standard deviation should be > 0"); } @@ -560,16 +559,15 @@ class VISP_EXPORT vpCircleHoughTransform { m_algoParams.m_centerMinDist = center_min_dist; - if (m_algoParams.m_centerMinDist <= 0) - { + if (m_algoParams.m_centerMinDist <= 0) { throw vpException(vpException::badValue, "Circles center min distance must be positive."); } } /*! * Set circles center min and max location in the image. - * If one value is equal to \b std::numeric_limits::min or - * \b std::numeric_limits::max(), the algorithm will set it + * If one value is equal to \b std::numeric_limits::min or + * \b std::numeric_limits::max(), the algorithm will set it * either to -maxRadius or +maxRadius depending on if * it is the lower or upper limit that is missing. * @@ -612,8 +610,7 @@ class VISP_EXPORT vpCircleHoughTransform void setCirclePerfectness(const float &circle_perfectness) { m_algoParams.m_circlePerfectness = circle_perfectness; - if (m_algoParams.m_circlePerfectness <= 0 || m_algoParams.m_circlePerfectness > 1) - { + if (m_algoParams.m_circlePerfectness <= 0 || m_algoParams.m_circlePerfectness > 1) { throw vpException(vpException::badValue, "Circle perfectness must be in the interval ] 0; 1]."); } } @@ -629,8 +626,7 @@ class VISP_EXPORT vpCircleHoughTransform m_algoParams.m_dilatationNbIter = dilatationRepet; m_algoParams.m_centerThresh = centerThresh; - if (m_algoParams.m_centerThresh <= 0) - { + if (m_algoParams.m_centerThresh <= 0) { throw vpException(vpException::badValue, "Votes thresholds for center detection must be positive."); } } @@ -640,12 +636,11 @@ class VISP_EXPORT vpCircleHoughTransform * * \param[in] radiusRatioThresh Minimum number of votes per radian a radius candidate RC_ij of a center candidate CeC_i must have in order that the circle of center CeC_i and radius RC_ij must be considered as circle candidate. */ - inline void setRadiusRatioThreshold( const float &radiusRatioThresh ) + inline void setRadiusRatioThreshold(const float &radiusRatioThresh) { m_algoParams.m_radiusRatioThresh = radiusRatioThresh; - if (m_algoParams.m_radiusRatioThresh <= 0) - { + if (m_algoParams.m_radiusRatioThresh <= 0) { throw vpException(vpException::badValue, "Radius ratio threshold must be > 0."); } } @@ -660,8 +655,7 @@ class VISP_EXPORT vpCircleHoughTransform { m_algoParams.m_mergingRadiusDiffThresh = radiusDifferenceThresh; - if (m_algoParams.m_mergingRadiusDiffThresh <= 0) - { + if (m_algoParams.m_mergingRadiusDiffThresh <= 0) { throw vpException(vpException::badValue, "Radius difference merging threshold must be positive."); } } @@ -678,6 +672,37 @@ class VISP_EXPORT vpCircleHoughTransform return m_centerCandidatesList; } + /** + * \brief Get the number of votes of each Center Candidates. + * + * \return std::vector The number of votes of each Center Candidates, ordered in the same way than \b m_centerCandidatesList. + */ + inline std::vector getCenterCandidatesVotes() + { + return m_centerVotes; + } + + /** + * \brief Get the Circle Candidates before merging step. + * + * \return std::vector The list of circle candidates + * that were obtained before the merging step. + */ + inline std::vector getCircleCandidates() + { + return m_circleCandidates; + } + + /** + * \brief Get the votes accumulator of the Circle Candidates. + * + * \return std::vector The votes accumulator. + */ + inline std::vector getCircleCandidatesVotes() + { + return m_circleCandidatesVotes; + } + /** * \brief Get the gradient along the horizontal axis of the image. * @@ -698,6 +723,16 @@ class VISP_EXPORT vpCircleHoughTransform return m_dIy; } + /** + * \brief Get the Edge Map computed thanks to the Canny edge filter. + * + * \return vpImage The edge map computed during the edge detection step. + */ + inline vpImage getEdgeMap() + { + return m_edgeMap; + } + /*! * Get internal Canny filter upper threshold. When value is equal to -1 (default), it means that the threshold is computed * automatically. @@ -737,6 +772,10 @@ class VISP_EXPORT vpCircleHoughTransform friend VISP_EXPORT std::ostream &operator<<(std::ostream &os, const vpCircleHoughTransform &detector); private: + /** + * \brief Initialize the Gaussian filters used to blur the image and + * compute the gradient images. + */ void initGaussianFilters(); /** @@ -756,6 +795,11 @@ class VISP_EXPORT vpCircleHoughTransform */ void edgeDetection(const vpImage &I); + /** + * \brief Filter the edge map in order to remove isolated edge points. + */ + void filterEdgeMap(); + /** * \brief Determine the image points that are circle center candidates. * Increment the center accumulator based on the edge points and gradient information. @@ -799,6 +843,7 @@ class VISP_EXPORT vpCircleHoughTransform // // Center candidates computation attributes std::vector> m_edgePointsList; /*!< Vector that contains the list of edge points, to make faster some parts of the algo. They are stored as pair<#row, #col>.*/ std::vector> m_centerCandidatesList; /*!< Vector that contains the list of center candidates. They are stored as pair<#row, #col>.*/ + std::vector m_centerVotes; /*!< Number of votes for the center candidates that are kept.*/ // // Circle candidates computation attributes std::vector m_circleCandidates; /*!< List of the candidate circles.*/ @@ -806,6 +851,7 @@ class VISP_EXPORT vpCircleHoughTransform // // Circle candidates merging atttributes std::vector m_finalCircles; /*!< List of the final circles, i.e. the ones resulting from the merge of the circle candidates.*/ + std::vector m_finalCircleVotes; /*!< Number of votes for the candidate circles.*/ }; /*! @@ -817,7 +863,7 @@ class VISP_EXPORT vpCircleHoughTransform */ template < typename Type > inline void -vpCircleHoughTransform::vpCircle2D::display( vpImage< Type > &img, const vpColor &color, const unsigned int &thickness, const unsigned int &size ) const +vpCircleHoughTransform::vpCircle2D::display(vpImage< Type > &img, const vpColor &color, const unsigned int &thickness, const unsigned int &size) const { vpImageDraw::drawCross(img, m_center, size, color, thickness); vpImageDraw::drawCircle(img, m_center, m_radius, color, thickness); diff --git a/modules/imgproc/src/vpCircleHoughTransform.cpp b/modules/imgproc/src/vpCircleHoughTransform.cpp index a2e699c99a..342c74263e 100644 --- a/modules/imgproc/src/vpCircleHoughTransform.cpp +++ b/modules/imgproc/src/vpCircleHoughTransform.cpp @@ -6,17 +6,17 @@ vpCircleHoughTransform::vpCircleHoughTransform() : m_algoParams() -{ +{ initGaussianFilters(); } vpCircleHoughTransform::vpCircleHoughTransform(const CHTransformParameters &algoParams) : m_algoParams(algoParams) -{ +{ initGaussianFilters(); } -void +void vpCircleHoughTransform::init(const CHTransformParameters &algoParams) { m_algoParams = algoParams; @@ -24,8 +24,7 @@ vpCircleHoughTransform::init(const CHTransformParameters &algoParams) } vpCircleHoughTransform::~vpCircleHoughTransform() -{ -} +{ } #ifdef VISP_HAVE_NLOHMANN_JSON vpCircleHoughTransform::vpCircleHoughTransform(const std::string &jsonPath) @@ -33,7 +32,7 @@ vpCircleHoughTransform::vpCircleHoughTransform(const std::string &jsonPath) initFromJSON(jsonPath); } -void +void vpCircleHoughTransform::initFromJSON(const std::string &jsonPath) { std::ifstream file(jsonPath); @@ -59,23 +58,23 @@ vpCircleHoughTransform::initFromJSON(const std::string &jsonPath) initGaussianFilters(); } -void +void vpCircleHoughTransform::saveConfigurationInJSON(const std::string &jsonPath) const { m_algoParams.saveConfigurationInJSON(jsonPath); } #endif -void +void vpCircleHoughTransform::initGaussianFilters() { - m_fg.resize(1,(m_algoParams.m_gaussianKernelSize + 1)/2); + m_fg.resize(1, (m_algoParams.m_gaussianKernelSize + 1)/2); vpImageFilter::getGaussianKernel(m_fg.data, m_algoParams.m_gaussianKernelSize, m_algoParams.m_gaussianStdev, true); - m_fgDg.resize(1,(m_algoParams.m_gaussianKernelSize + 1)/2); + m_fgDg.resize(1, (m_algoParams.m_gaussianKernelSize + 1)/2); vpImageFilter::getGaussianDerivativeKernel(m_fgDg.data, m_algoParams.m_gaussianKernelSize, m_algoParams.m_gaussianStdev, true); } -std::vector +std::vector vpCircleHoughTransform::detect(const vpImage &I) { vpImage I_gray; @@ -83,7 +82,7 @@ vpCircleHoughTransform::detect(const vpImage &I) return detect(I_gray); } -std::vector +std::vector vpCircleHoughTransform::detect(const cv::Mat &cv_I) { vpImage I_gray; @@ -91,53 +90,52 @@ vpCircleHoughTransform::detect(const cv::Mat &cv_I) return detect(I_gray); } -std::vector +std::vector vpCircleHoughTransform::detect(const vpImage &I, const int &nbCircles) { std::vector detections = detect(I); size_t nbDetections = detections.size(); std::vector bestCircles; std::vector> detectionsWithVotes; - for(size_t i = 0; i < nbDetections; i++) - { - std::pair detectionWithVote(detections[i], m_circleCandidatesVotes[i]); + for (size_t i = 0; i < nbDetections; i++) { + std::pair detectionWithVote(detections[i], m_finalCircleVotes[i]); detectionsWithVotes.push_back(detectionWithVote); } bool (*hasMoreVotes)(std::pair, std::pair) = [](std::pair a, std::pair b) - { - return (a.second > b.second); - }; + { + // We divide the number of votes by the radius to avoid to favour big circles + return (a.second / a.first.getRadius() > b.second / b.first.getRadius()); + }; std::sort(detectionsWithVotes.begin(), detectionsWithVotes.end(), hasMoreVotes); size_t limitMin; - if(nbCircles < 0) - { + if (nbCircles < 0) { limitMin = nbDetections; } - else - { - limitMin = std::min(nbDetections, (size_t) nbCircles); - } - for(size_t i = 0; i < limitMin; i++) - { + else { + limitMin = std::min(nbDetections, (size_t)nbCircles); + } + for (size_t i = 0; i < limitMin; i++) { bestCircles.push_back(detectionsWithVotes[i].first); } return bestCircles; } -std::vector +std::vector vpCircleHoughTransform::detect(const vpImage &I) { // Cleaning results of potential previous detection m_centerCandidatesList.clear(); + m_centerVotes.clear(); m_edgePointsList.clear(); m_circleCandidates.clear(); m_circleCandidatesVotes.clear(); m_finalCircles.clear(); + m_finalCircleVotes.clear(); // First thing, we need to apply a Gaussian filter on the image to remove some spurious noise // Then, we need to compute the image gradients in order to be able to perform edge detection @@ -166,40 +164,78 @@ vpCircleHoughTransform::detect(const vpImage &I) return m_finalCircles; } -void +void vpCircleHoughTransform::computeGradientsAfterGaussianSmoothing(const vpImage &I) { - vpImageFilter::getGradXGauss2D ( I, - m_dIx, - m_fg.data, - m_fgDg.data, - m_algoParams.m_gaussianKernelSize - ); - vpImageFilter::getGradYGauss2D ( I, - m_dIy, - m_fg.data, - m_fgDg.data, - m_algoParams.m_gaussianKernelSize - ); + vpImageFilter::getGradXGauss2D(I, + m_dIx, + m_fg.data, + m_fgDg.data, + m_algoParams.m_gaussianKernelSize + ); + vpImageFilter::getGradYGauss2D(I, + m_dIy, + m_fg.data, + m_fgDg.data, + m_algoParams.m_gaussianKernelSize + ); } -void +void vpCircleHoughTransform::edgeDetection(const vpImage &I) { - #if defined(HAVE_OPENCV_IMGPROC) - // 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.) - { - m_algoParams.m_cannyThresh = ImageFilter::computeCannyThreshold(I); +#if defined(HAVE_OPENCV_IMGPROC) + int cannyThresh = m_algoParams.m_cannyThresh; + // 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 = ImageFilter::computeCannyThreshold(I); + } + vpImageFilter::canny(I, m_edgeMap, m_algoParams.m_gaussianKernelSize, cannyThresh, m_algoParams.m_sobelKernelSize); +#else + throw(vpException(vpException::functionNotImplementedError, "Canny edge detection has not been implemented yet !")); +#endif + + for (int i = 0; i < m_algoParams.m_edgeMapFilteringNbIter; i++) { + filterEdgeMap(); + } +} + +void +vpCircleHoughTransform::filterEdgeMap() +{ + vpImage J = m_edgeMap; + + for (unsigned int i = 1; i < J.getHeight() - 1; i++) { + for (unsigned int j = 1; j < J.getWidth() - 1; j++) { + if (J[i][j] == 255) { + // Consider 8 neighbors + int topLeftPixel = (int)J[i - 1][j - 1]; + int topPixel = (int)J[i - 1][j]; + int topRightPixel = (int)J[i - 1][j + 1]; + int botLeftPixel = (int)J[i + 1][j - 1]; + int bottomPixel = (int)J[i + 1][j]; + int botRightPixel = (int)J[i + 1][j + 1]; + int leftPixel = (int)J[i][j - 1]; + int rightPixel = (int)J[i][j + 1]; + if ((topLeftPixel + topPixel + topRightPixel + + botLeftPixel + bottomPixel + botRightPixel + + leftPixel + rightPixel + ) >= 2 * 255) { + // At least 2 of the 8-neighbor points are also an edge point + // so we keep the edge point + m_edgeMap[i][j] = 255; + } + else { + // The edge point is isolated => we erase it + m_edgeMap[i][j] = 0; + } + } } - vpImageFilter::canny(I, m_edgeMap, m_algoParams.m_gaussianKernelSize, m_algoParams.m_cannyThresh, m_algoParams.m_sobelKernelSize); - #else - throw(vpException(vpException::functionNotImplementedError, "Canny edge detection has not been implemented yet !")); - #endif + } } -void +void vpCircleHoughTransform::computeCenterCandidates() { // For each edge point EP_i, check the image gradient at EP_i @@ -211,19 +247,18 @@ vpCircleHoughTransform::computeCenterCandidates() unsigned int nbCols = m_edgeMap.getCols(); m_algoParams.m_maxRadius = std::min(m_algoParams.m_maxRadius, std::min(nbCols, nbRows)); - + // Computing the minimum and maximum horizontal position of the center candidates // The miminum horizontal position of the center is at worst -maxRadius outside the image // The maxinum horizontal position of the center is at worst +maxRadiusoutside the image // The width of the accumulator is the difference between the max and the min - int minimumXposition = std::max(m_algoParams.m_centerXlimits.first, -1 * (int) m_algoParams.m_maxRadius); - int maximumXposition = std::min(m_algoParams.m_centerXlimits.second, (int) (m_algoParams.m_maxRadius + nbCols)); + int minimumXposition = std::max(m_algoParams.m_centerXlimits.first, -1 * (int)m_algoParams.m_maxRadius); + int maximumXposition = std::min(m_algoParams.m_centerXlimits.second, (int)(m_algoParams.m_maxRadius + nbCols)); minimumXposition = std::min(minimumXposition, maximumXposition - 1); float minimumXpositionDouble = minimumXposition; int offsetX = minimumXposition; int accumulatorWidth = maximumXposition - minimumXposition + 1; - if(accumulatorWidth <= 0) - { + if (accumulatorWidth <= 0) { std::cout << "Width <= 0 !" << std::endl << std::flush; } @@ -231,25 +266,21 @@ vpCircleHoughTransform::computeCenterCandidates() // The miminum vertical position of the center is at worst -maxRadius outside the image // The maxinum vertical position of the center is at worst +maxRadiusoutside the image // The height of the accumulator is the difference between the max and the min - int minimumYposition = std::max(m_algoParams.m_centerYlimits.first, -1 * (int) m_algoParams.m_maxRadius); - int maximumYposition = std::min(m_algoParams.m_centerYlimits.second, (int) (m_algoParams.m_maxRadius + nbRows)); + int minimumYposition = std::max(m_algoParams.m_centerYlimits.first, -1 * (int)m_algoParams.m_maxRadius); + int maximumYposition = std::min(m_algoParams.m_centerYlimits.second, (int)(m_algoParams.m_maxRadius + nbRows)); minimumYposition = std::min(minimumYposition, maximumYposition - 1); float minimumYpositionDouble = minimumYposition; int offsetY = minimumYposition; int accumulatorHeight = maximumYposition - minimumYposition + 1; - if(accumulatorHeight <= 0) - { + if (accumulatorHeight <= 0) { std::cout << "accumulatorHeight <= 0 !" << std::endl << std::flush; } vpImage centersAccum(accumulatorHeight, accumulatorWidth + 1, 0.); /*!< Matrix that contains the votes for the center candidates.*/ - for (unsigned int r = 0; r < nbRows; r++) - { - for (unsigned int c = 0; c < nbCols; c++) - { - if (m_edgeMap[r][c] == 255) - { + for (unsigned int r = 0; r < nbRows; r++) { + for (unsigned int c = 0; c < nbCols; c++) { + if (m_edgeMap[r][c] == 255) { // Saving the edge point for further use m_edgePointsList.push_back(std::pair(r, c)); @@ -260,75 +291,67 @@ vpCircleHoughTransform::computeCenterCandidates() float sx = m_dIx[r][c] / mag; float sy = m_dIy[r][c] / mag; - for (int k1 = 0; k1 < 2; k1++) - { + for (int k1 = 0; k1 < 2; k1++) { bool hasToStopLoop = false; - for (int rad = m_algoParams.m_minRadius; rad <= m_algoParams.m_maxRadius && !hasToStopLoop; rad++) - { - float x1 = (float)c + (float) rad * sx; - float y1 = (float)r + (float) rad * sy; + for (int rad = m_algoParams.m_minRadius; rad <= m_algoParams.m_maxRadius && !hasToStopLoop; rad++) { + float x1 = (float)c + (float)rad * sx; + float y1 = (float)r + (float)rad * sy; - if(x1 < minimumXpositionDouble || y1 < minimumYpositionDouble) - { + if (x1 < minimumXpositionDouble || y1 < minimumYpositionDouble) { continue; // If either value is lower than maxRadius, it means that the center is outside the search region. } int x_low, x_high; int y_low, y_high; - if(x1 > 0.) - { - x_low = std::floor(x1); + if (x1 > 0.) { + x_low = std::floor(x1); x_high = std::ceil(x1); } - else - { - x_low = -1 * std::ceil(-1. * x1); + else { + x_low = -1 * std::ceil(-1. * x1); x_high = -1 * std::floor(-1. * x1); } - if(y1 > 0.) - { - y_low = std::floor(y1); + if (y1 > 0.) { + y_low = std::floor(y1); y_high = std::ceil(y1); } - else - { - y_low = -1 * std::ceil(-1. * y1); + else { + y_low = -1 * std::ceil(-1. * y1); y_high = -1 * std::floor(-1. * y1); } auto updateAccumulator = - []( const float &x_orig, const float &y_orig, + [](const float &x_orig, const float &y_orig, const unsigned int &x, const unsigned int &y, const int &offsetX, const int &offsetY, const unsigned int &nbCols, const unsigned int &nbRows, vpImage &accum, bool &hasToStop) { - if( x - offsetX >= nbCols || - y - offsetY >= nbRows - ) - { + if (x - offsetX >= nbCols || + y - offsetY >= nbRows + ) { hasToStop = true; } - else{ + else { float dx = (x_orig - (float)x); float dy = (y_orig - (float)y); accum[y - offsetY][x - offsetX] += std::abs(dx) + std::abs(dy); } }; - updateAccumulator( x1, y1, x_low, y_low, + updateAccumulator(x1, y1, x_low, y_low, offsetX, offsetY, - accumulatorWidth, accumulatorHeight, + accumulatorWidth, accumulatorHeight, centersAccum, hasToStopLoop - ); + ); - updateAccumulator( x1, y1, x_high, y_high, + updateAccumulator(x1, y1, x_high, y_high, offsetX, offsetY, - accumulatorWidth, accumulatorHeight, + accumulatorWidth, accumulatorHeight, centersAccum, hasToStopLoop - ); + ); } sx = -sx; @@ -342,8 +365,7 @@ vpCircleHoughTransform::computeCenterCandidates() // accumulator maxima vpImage centerCandidatesMaxima = centersAccum; int niters = std::max(m_algoParams.m_dilatationNbIter, 1); // Ensure at least one dilatation operation - for (int i = 0; i < niters; i++) - { + for (int i = 0; i < niters; i++) { vpImageMorphology::dilatation(centerCandidatesMaxima, vpImageMorphology::CONNEXITY_4); } @@ -352,44 +374,43 @@ vpCircleHoughTransform::computeCenterCandidates() // find the possible circle centers int nbColsAccum = centersAccum.getCols(); int nbRowsAccum = centersAccum.getRows(); - for (int y = 0; y < nbRowsAccum; y++) - { + int nbVotes = -1; + for (int y = 0; y < nbRowsAccum; y++) { int left = -1; - for (int x = 0; x < nbColsAccum; x++) - { - if ( centersAccum[y][x] >= m_algoParams.m_centerThresh - && centersAccum[y][x] == centerCandidatesMaxima[y][x] + for (int x = 0; x < nbColsAccum; x++) { + if (centersAccum[y][x] >= m_algoParams.m_centerThresh + && centersAccum[y][x] == centerCandidatesMaxima[y][x] && centersAccum[y][x] > centersAccum[y][x + 1] - ) - { + ) { if (left < 0) left = x; + nbVotes = std::max(nbVotes, (int)centersAccum[y][x]); } - else if (left >= 0) - { + else if (left >= 0) { int cx = (int)((left + x - 1) * 0.5f); m_centerCandidatesList.push_back(std::pair(y + offsetY, cx + offsetX)); + m_centerVotes.push_back(nbVotes); left = -1; + nbVotes = -1; } } } } -void +void vpCircleHoughTransform::computeCircleCandidates() { size_t nbCenterCandidates = m_centerCandidatesList.size(); unsigned int nbBins = (m_algoParams.m_maxRadius - m_algoParams.m_minRadius + 1)/ m_algoParams.m_centerMinDist; nbBins = std::max((unsigned int)1, nbBins); // Avoid having 0 bins, which causes segfault std::vector radiusAccumList; /*!< Radius accumulator for each center candidates.*/ - std::vector radiusActualValueList; /*!< Vector that contains the actual distance between the edge points and the center candidates.*/ + std::vector radiusActualValueList; /*!< Vector that contains the actual distance between the edge points and the center candidates.*/ unsigned int rmin2 = m_algoParams.m_minRadius * m_algoParams.m_minRadius; unsigned int rmax2 = m_algoParams.m_maxRadius * m_algoParams.m_maxRadius; int circlePerfectness2 = m_algoParams.m_circlePerfectness * m_algoParams.m_circlePerfectness; - for(size_t i = 0; i < nbCenterCandidates; i++) - { + for (size_t i = 0; i < nbCenterCandidates; i++) { std::pair centerCandidate = m_centerCandidatesList[i]; // Initialize the radius accumulator of the candidate with 0s radiusAccumList.clear(); @@ -397,123 +418,128 @@ vpCircleHoughTransform::computeCircleCandidates() radiusActualValueList.clear(); radiusActualValueList.resize(nbBins, 0.); - for(auto edgePoint : m_edgePointsList) - { - // For each center candidate CeC_i, compute the distance with each edge point EP_j d_ij = dist(CeC_i; EP_j) + for (auto edgePoint : m_edgePointsList) { + // For each center candidate CeC_i, compute the distance with each edge point EP_j d_ij = dist(CeC_i; EP_j) unsigned int rx = edgePoint.first - centerCandidate.first; unsigned int ry = edgePoint.second - centerCandidate.second; unsigned int r2 = rx * rx + ry * ry; - if((r2 > rmin2) && (r2 < rmax2)) - { + if ((r2 > rmin2) && (r2 < rmax2)) { float gx = m_dIx[edgePoint.first][edgePoint.second]; float gy = m_dIy[edgePoint.first][edgePoint.second]; float grad2 = gx * gx + gy * gy; - + int scalProd = rx * gx + ry * gy; int scalProd2 = scalProd * scalProd; - if(scalProd2 >= circlePerfectness2 * r2 * grad2) - { + if (scalProd2 >= circlePerfectness2 * r2 * grad2) { // Look for the Radius Candidate Bin RCB_k to which d_ij is "the closest" will have an additionnal vote float r = std::sqrt(r2); unsigned int r_bin = std::ceil((r - m_algoParams.m_minRadius)/ m_algoParams.m_centerMinDist); r_bin = std::min(r_bin, nbBins - 1); radiusAccumList[r_bin]++; - radiusActualValueList[r_bin] +=r; + radiusActualValueList[r_bin] += r; } } } - - for(unsigned int idBin = 0; idBin < nbBins; idBin++) - { - // If the circle of center CeC_i and radius RCB_k has enough votes, it is added to the list + + for (unsigned int idBin = 0; idBin < nbBins; idBin++) { + // If the circle of center CeC_i and radius RCB_k has enough votes, it is added to the list // of Circle Candidates float r_effective = radiusActualValueList[idBin] / (float)radiusAccumList[idBin]; - if((float)radiusAccumList[idBin] / r_effective > m_algoParams.m_radiusRatioThresh ) - { - m_circleCandidates.push_back(vpCircle2D( vpImagePoint(centerCandidate.first, centerCandidate.second) - , r_effective - ) - ); + if ((float)radiusAccumList[idBin] / r_effective > m_algoParams.m_radiusRatioThresh) { + m_circleCandidates.push_back(vpCircle2D(vpImagePoint(centerCandidate.first, centerCandidate.second) + , r_effective + ) + ); m_circleCandidatesVotes.push_back(radiusAccumList[idBin]); } } } } -void +void vpCircleHoughTransform::mergeCircleCandidates() -{ +{ // For each circle candidate CiC_i do: + std::vector circleCandidates = m_circleCandidates; + std::vector circleCandidatesVotes = m_circleCandidatesVotes; size_t nbCandidates = m_circleCandidates.size(); - for(size_t i = 0; i < nbCandidates; i++) - { - vpCircle2D cic_i = m_circleCandidates[i]; + for (size_t i = 0; i < nbCandidates; i++) { + vpCircle2D cic_i = circleCandidates[i]; // // For each other circle candidate CiC_j do: - for(size_t j = i + 1; j < nbCandidates; j++) - { - vpCircle2D cic_j = m_circleCandidates[j]; + std::cout << "< CiC_" << i << " >" << std::endl; + for (size_t j = i + 1; j < nbCandidates; j++) { + vpCircle2D cic_j = circleCandidates[j]; // // // Compute the similarity between CiC_i and CiC_j double distanceBetweenCenters = vpImagePoint::distance(cic_i.getCenter(), cic_j.getCenter()); double radiusDifference = std::abs(cic_i.getRadius() - cic_j.getRadius()); - bool areCirclesSimilar = ( distanceBetweenCenters < m_algoParams.m_centerMinDist + bool areCirclesSimilar = (distanceBetweenCenters < m_algoParams.m_centerMinDist && radiusDifference < m_algoParams.m_mergingRadiusDiffThresh ); - - if( areCirclesSimilar ) - { + + if (areCirclesSimilar) { // // // If the similarity exceeds a threshold, merge the circle candidates CiC_i and CiC_j and remove CiC_j of the list - unsigned int totalVotes = m_circleCandidatesVotes[i] + m_circleCandidatesVotes[j]; - cic_i = vpCircle2D( (cic_i.getCenter() * m_circleCandidatesVotes[i]+ cic_j.getCenter() * m_circleCandidatesVotes[j]) / totalVotes - , (cic_i.getRadius() * m_circleCandidatesVotes[i] + cic_j.getRadius() * m_circleCandidatesVotes[j]) / totalVotes - ); - m_circleCandidates[j] = m_circleCandidates[nbCandidates - 1]; - m_circleCandidatesVotes[i] = totalVotes; - m_circleCandidatesVotes[j] = m_circleCandidatesVotes[nbCandidates - 1]; - m_circleCandidates.pop_back(); - m_circleCandidatesVotes.pop_back(); + unsigned int totalVotes = circleCandidatesVotes[i] + circleCandidatesVotes[j]; + float newRadius = (cic_i.getRadius() * circleCandidatesVotes[i] + cic_j.getRadius() * circleCandidatesVotes[j]) / totalVotes; + vpImagePoint newCenter = (cic_i.getCenter() * circleCandidatesVotes[i]+ cic_j.getCenter() * circleCandidatesVotes[j]) / totalVotes; + std::cout << "\tPrev centers =\n\t" << cic_i.getCenter() << "\n\t" << cic_j.getCenter() << std::endl; + std::cout << "\tNew center = " << newCenter << std::endl; + std::cout << "\tPrev radii =\n\t" << cic_i.getRadius() << "\n\t" << cic_j.getRadius() << std::endl; + std::cout << "\tNew radius = " << newRadius << std::endl; + std::cout << "\tVotes =\n\t" << circleCandidatesVotes[i] << "\n\t" << circleCandidatesVotes[j] << std::endl; + cic_i = vpCircle2D(newCenter, newRadius); + circleCandidates[j] = circleCandidates[nbCandidates - 1]; + circleCandidatesVotes[i] = totalVotes; + circleCandidatesVotes[j] = circleCandidatesVotes[nbCandidates - 1]; + circleCandidates.pop_back(); + circleCandidatesVotes.pop_back(); nbCandidates--; j--; } } // // Add the circle candidate CiC_i, potentially merged with other circle candidates, to the final list of detected circles m_finalCircles.push_back(cic_i); + std::cout << "" << std::endl; } nbCandidates = m_finalCircles.size(); - for(size_t i = 0; i < nbCandidates; i++) - { + for (size_t i = 0; i < nbCandidates; i++) { vpCircle2D cic_i = m_finalCircles[i]; // // For each other circle candidate CiC_j do: - for(size_t j = i + 1; j < nbCandidates; j++) - { + std::cout << "< CiC_" << i << " >" << std::endl; + for (size_t j = i + 1; j < nbCandidates; j++) { vpCircle2D cic_j = m_finalCircles[j]; // // // Compute the similarity between CiC_i and CiC_j double distanceBetweenCenters = vpImagePoint::distance(cic_i.getCenter(), cic_j.getCenter()); double radiusDifference = std::abs(cic_i.getRadius() - cic_j.getRadius()); - bool areCirclesSimilar = ( distanceBetweenCenters < m_algoParams.m_centerMinDist + bool areCirclesSimilar = (distanceBetweenCenters < m_algoParams.m_centerMinDist && radiusDifference < m_algoParams.m_mergingRadiusDiffThresh ); - - if( areCirclesSimilar ) - { + + if (areCirclesSimilar) { // // // If the similarity exceeds a threshold, merge the circle candidates CiC_i and CiC_j and remove CiC_j of the list - unsigned int totalVotes = m_circleCandidatesVotes[i] + m_circleCandidatesVotes[j]; - cic_i = vpCircle2D( (cic_i.getCenter() * m_circleCandidatesVotes[i]+ cic_j.getCenter() * m_circleCandidatesVotes[j]) / totalVotes - , (cic_i.getRadius() * m_circleCandidatesVotes[i] + cic_j.getRadius() * m_circleCandidatesVotes[j]) / totalVotes - ); + unsigned int totalVotes = circleCandidatesVotes[i] + circleCandidatesVotes[j]; + vpImagePoint newCenter = (cic_i.getCenter() * circleCandidatesVotes[i]+ cic_j.getCenter() * circleCandidatesVotes[j]) / totalVotes; + float newRadius = (cic_i.getRadius() * circleCandidatesVotes[i] + cic_j.getRadius() * circleCandidatesVotes[j]) / totalVotes; + std::cout << "Prev centers =\n\t" << cic_i.getCenter() << "\n\t" << cic_j.getCenter() << std::endl; + std::cout << "New center = " << newCenter << std::endl; + std::cout << "Prev radii =\n\t" << cic_i.getRadius() << "\n\t" << cic_j.getRadius() << std::endl; + std::cout << "New radius = " << newRadius << std::endl; + cic_i = vpCircle2D(newCenter, newRadius); m_finalCircles[j] = m_finalCircles[nbCandidates - 1]; - m_circleCandidatesVotes[i] = totalVotes; - m_circleCandidatesVotes[j] = m_circleCandidatesVotes[nbCandidates - 1]; + circleCandidatesVotes[i] = totalVotes; + circleCandidatesVotes[j] = circleCandidatesVotes[nbCandidates - 1]; m_finalCircles.pop_back(); - m_circleCandidatesVotes.pop_back(); + circleCandidatesVotes.pop_back(); nbCandidates--; j--; } } // // Add the circle candidate CiC_i, potentially merged with other circle candidates, to the final list of detected circles m_finalCircles[i] = cic_i; + std::cout << "" << std::endl; } + m_finalCircleVotes = circleCandidatesVotes; } std::string diff --git a/tutorial/imgproc/hough-transform/CMakeLists.txt b/tutorial/imgproc/hough-transform/CMakeLists.txt index 0601279e4f..864704d415 100644 --- a/tutorial/imgproc/hough-transform/CMakeLists.txt +++ b/tutorial/imgproc/hough-transform/CMakeLists.txt @@ -9,7 +9,8 @@ set(tutorial_cpp tutorial-circle-hough.cpp ) -list(APPEND tutorial_data "${CMAKE_CURRENT_SOURCE_DIR}/config") +# list(APPEND tutorial_data "${CMAKE_CURRENT_SOURCE_DIR}/config") +list(APPEND tutorial_data "${CMAKE_CURRENT_SOURCE_DIR}/coins2.pgm") foreach(cpp ${tutorial_cpp}) visp_add_target(${cpp} drawingHelpers.cpp) @@ -20,3 +21,6 @@ endforeach() # Copy the data files to the same location than the target visp_copy_dir(tutorial-circle-hough "${CMAKE_CURRENT_SOURCE_DIR}" config) +foreach(data ${tutorial_data}) + visp_copy_data(tutorial-circle-hough.cpp ${data}) +endforeach() diff --git a/tutorial/imgproc/hough-transform/coins2.pgm b/tutorial/imgproc/hough-transform/coins2.pgm new file mode 100644 index 0000000000000000000000000000000000000000..c8f1d2e9156d55008dee5db1a0e5305910ef466d GIT binary patch literal 178674 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 M1+HI#|Njd7f9NGuh5!Hn literal 0 HcmV?d00001 diff --git a/tutorial/imgproc/hough-transform/config/detector_img.json b/tutorial/imgproc/hough-transform/config/detector_img.json index e6eb410b82..6e53dac8f4 100644 --- a/tutorial/imgproc/hough-transform/config/detector_img.json +++ b/tutorial/imgproc/hough-transform/config/detector_img.json @@ -1,24 +1,25 @@ { "cannyThresh": -1.0, - "centerMinDistance": 2.0, - "centerThresh": 200.0, + "centerMinDistance": 5.0, + "centerThresh": 100.0, "centerXlimits": [ - -1000000, - 1000000 + 0, + 1920 ], "centerYlimits": [ - -1000000, - 1000000 + 0, + 1080 ], - "circlePerfectnessThreshold": 0.9, + "circlePerfectnessThreshold": 0.95, "dilatationNbIter": 1, - "gaussianKernelSize": 5, - "gaussianStdev": 1.0, - "mergingRadiusDiffThresh": 2.0, + "edgeMapFilteringNbIter" : 5, + "gaussianKernelSize": 25, + "gaussianStdev": 2.5, + "mergingRadiusDiffThresh": 5.0, "radiusLimits": [ - 80, - 90 + 34, + 75 ], - "radiusThreshRatio": 2, - "sobelKernelSize": 3 + "radiusThreshRatio": 4.0, + "sobelKernelSize": 7 } \ No newline at end of file diff --git a/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp index c9749959d5..eaf71377c9 100644 --- a/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp +++ b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp @@ -70,7 +70,7 @@ std::string getAvailableTypeInputImage(const std::string &prefix = "<", const st void drawDisk(vpImage &I, const vpImagePoint ¢er, const unsigned int &radius , const unsigned int &borderColor, const unsigned int &fillingColor, const unsigned int &thickness, const unsigned int &bckg) -//! [Draw disks] + //! [Draw disks] { vpImageDraw::drawCircle(I, center, radius, borderColor, thickness); vp::floodFill(I, @@ -154,7 +154,7 @@ generateImage(const TypeInputImage &inputType) return I_src; } -bool test_detection(const vpImage &I_src, vpCircleHoughTransform &detector, const int &nbCirclesToDetect, const bool &blockingMode) +bool test_detection(const vpImage &I_src, vpCircleHoughTransform &detector, const int &nbCirclesToDetect, const bool &blockingMode, const bool &displayCanny) { double t0 = vpTime::measureTimeMicros(); //! [Run detection] @@ -179,6 +179,10 @@ bool test_detection(const vpImage &I_src, vpCircleHoughTransform } //! [Iterate detections] + if (displayCanny) { + vpImage edgeMap = detector.getEdgeMap(); + drawingHelpers::display(edgeMap, "Edge map", true); + } return drawingHelpers::display(I_disp, "Detection results", blockingMode); } @@ -191,6 +195,7 @@ int main(int argc, char **argv) const double def_gaussianSigma = 1.; const int def_sobelKernelSize = 3; const double def_cannyThresh = 150.; + const int def_nbEdgeFilteringIter = 2; const std::pair def_centerXlimits = std::pair(0, 640); const std::pair def_centerYlimits = std::pair(0, 480); const unsigned int def_minRadius = 0; @@ -210,6 +215,7 @@ int main(int argc, char **argv) double opt_gaussianSigma = def_gaussianSigma; int opt_sobelKernelSize = def_sobelKernelSize; double opt_cannyThresh = def_cannyThresh; + int opt_nbEdgeFilteringIter = def_nbEdgeFilteringIter; std::pair opt_centerXlimits = def_centerXlimits; std::pair opt_centerYlimits = def_centerYlimits; unsigned int opt_minRadius = def_minRadius; @@ -220,6 +226,7 @@ int main(int argc, char **argv) double opt_circlePerfectness = def_circlePerfectness; double opt_centerDistanceThresh = def_centerDistanceThresh; double opt_radiusDifferenceThresh = def_radiusDifferenceThresh; + bool opt_displayCanny = false; for (int i = 1; i < argc; i++) { std::string argName(argv[i]); @@ -253,6 +260,10 @@ int main(int argc, char **argv) opt_cannyThresh = atof(argv[i + 1]); i++; } + else if (argName == "--edge-filter" && i + 1 < argc) { + opt_nbEdgeFilteringIter = atoi(argv[i + 1]); + i++; + } else if (argName == "--dilatation-repet" && i + 1 < argc) { opt_dilatationRepet = atoi(argv[i + 1]); i++; @@ -267,12 +278,12 @@ int main(int argc, char **argv) i++; } else if (argName == "--center-xlim" && i + 2 < argc) { - opt_centerXlimits = std::pair (atoi(argv[i + 1]), atoi(argv[i + 2])); - i+=2; + opt_centerXlimits = std::pair(atoi(argv[i + 1]), atoi(argv[i + 2])); + i += 2; } else if (argName == "--center-ylim" && i + 2 < argc) { - opt_centerYlimits = std::pair (atoi(argv[i + 1]), atoi(argv[i + 2])); - i+=2; + opt_centerYlimits = std::pair(atoi(argv[i + 1]), atoi(argv[i + 2])); + i += 2; } else if (argName == "--radius-thresh" && i + 1 < argc) { opt_radiusThreshRatio = atof(argv[i + 1]); @@ -287,6 +298,9 @@ int main(int argc, char **argv) opt_radiusDifferenceThresh = atof(argv[i + 2]); i += 2; } + else if (argName == "--display-edge-map") { + opt_displayCanny = true; + } else if (argName == "--help" || argName == "-h") { std::cout << "NAME" << std::endl; std::cout << "\t" << argv[0] << " Test program for the home-made Hough Circle Detection algorithm" << std::endl @@ -302,6 +316,7 @@ int main(int argc, char **argv) << "\t [--gaussian-sigma ] (default: " << def_gaussianSigma << ")" << std::endl << "\t [--sobel-kernel ] (default: " << def_sobelKernelSize << ")" << std::endl << "\t [--canny-thresh ] (default: " << def_cannyThresh << ")" << std::endl + << "\t [--edge-filter ] (default: " << def_nbEdgeFilteringIter << ")" << std::endl << "\t [--radius-limits ] (default: min = " << def_minRadius << ", max = " << def_maxRadius << ")" << std::endl << "\t [--dilatation-repet ] (default: " << def_dilatationRepet << ")" << std::endl << "\t [--center-thresh ] (default: " << (def_centerThresh < 0 ? "auto" : std::to_string(def_centerThresh)) << ")" << std::endl @@ -310,7 +325,8 @@ int main(int argc, char **argv) << "\t [--radius-thresh ] (default: " << (def_radiusThreshRatio < 0 ? "auto" : std::to_string(def_radiusThreshRatio)) << ")" << std::endl << "\t [--circle-perfectness ] (default: " << def_radiusThreshRatio << ")" << std::endl << "\t [--merging-thresh ] (default: centers distance threshold = " << def_centerDistanceThresh << ", radius difference threshold = " << def_radiusDifferenceThresh << ")" << std::endl - << "\t [--help] [-h]" << std::endl + << "\t [--display-edge-map]" << std::endl + << "\t [--help, -h]" << std::endl << std::endl; std::cout << "DESCRIPTION" << std::endl @@ -344,6 +360,11 @@ int main(int argc, char **argv) << "\t\tMust be a positive value." << std::endl << "\t\tDefault: " << def_cannyThresh << 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 + << "\t\tIf negative, no filtering is performed." << std::endl + << "\t\tDefault: " << def_nbEdgeFilteringIter << std::endl + << std::endl << "\t--radius-limits" << std::endl << "\t\tPermit to set the minimum and maximum radii of the circles we are looking for." << std::endl << "\t\tDefault: min = " << def_minRadius << ", max = " << def_maxRadius << std::endl @@ -384,7 +405,11 @@ int main(int argc, char **argv) << "\t\tThe center distance threshold indicates the maximum distance the centers can be in order to be merged." << std::endl << "\t\tThe radius difference threshold indicates the maximum absolute difference between the two circle candidates in order to be merged." << std::endl << "\t\tTwo circle candidates must met these two conditions in order to be merged together." << std::endl - << "\t\tDefault: centers distance threshold = " << def_centerDistanceThresh << ", radius difference threshold = " << def_radiusDifferenceThresh << std::endl; + << "\t\tDefault: centers distance threshold = " << def_centerDistanceThresh << ", radius difference threshold = " << def_radiusDifferenceThresh << std::endl + << "\t--display-edge-map" << std::endl + << "\t\tPermit to display the edge map used to detect the circles" << std::endl + << "\t\tDefault: off" << std::endl + << std::endl; return EXIT_SUCCESS; } } @@ -431,6 +456,7 @@ int main(int argc, char **argv) , opt_gaussianSigma , opt_sobelKernelSize , opt_cannyThresh + , opt_nbEdgeFilteringIter , opt_centerXlimits , opt_centerYlimits , opt_minRadius @@ -473,7 +499,7 @@ int main(int argc, char **argv) g.open(I_src); while (!g.end() && hasToContinue) { g.acquire(I_src); - hasToContinue = test_detection(I_src, detector, opt_nbCirclesToDetect, false); + hasToContinue = test_detection(I_src, detector, opt_nbCirclesToDetect, false, opt_displayCanny); vpTime::wait(40); } } @@ -486,14 +512,14 @@ int main(int argc, char **argv) } // Read the image and perform detection on it vpImageIo::read(I_src, opt_input); - test_detection(I_src, detector, opt_nbCirclesToDetect, true); + test_detection(I_src, detector, opt_nbCirclesToDetect, true, opt_displayCanny); //! [Manage single image] } } else { //! [Manage synthetic image] I_src = generateImage(inputType); - test_detection(I_src, detector, opt_nbCirclesToDetect, true); + test_detection(I_src, detector, opt_nbCirclesToDetect, true, opt_displayCanny); //! [Manage synthetic image] } return EXIT_SUCCESS; From e8325b4b17b2c8a106e01d09e511c70868733cf8 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Thu, 24 Aug 2023 11:33:15 +0200 Subject: [PATCH 08/20] [FIX] Remvoed normalization of the Gaussian filters used to compute the gradietns --- modules/imgproc/src/vpCircleHoughTransform.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/imgproc/src/vpCircleHoughTransform.cpp b/modules/imgproc/src/vpCircleHoughTransform.cpp index 342c74263e..00a7b84335 100644 --- a/modules/imgproc/src/vpCircleHoughTransform.cpp +++ b/modules/imgproc/src/vpCircleHoughTransform.cpp @@ -69,9 +69,9 @@ void vpCircleHoughTransform::initGaussianFilters() { m_fg.resize(1, (m_algoParams.m_gaussianKernelSize + 1)/2); - vpImageFilter::getGaussianKernel(m_fg.data, m_algoParams.m_gaussianKernelSize, m_algoParams.m_gaussianStdev, true); + vpImageFilter::getGaussianKernel(m_fg.data, m_algoParams.m_gaussianKernelSize, m_algoParams.m_gaussianStdev, false); m_fgDg.resize(1, (m_algoParams.m_gaussianKernelSize + 1)/2); - vpImageFilter::getGaussianDerivativeKernel(m_fgDg.data, m_algoParams.m_gaussianKernelSize, m_algoParams.m_gaussianStdev, true); + vpImageFilter::getGaussianDerivativeKernel(m_fgDg.data, m_algoParams.m_gaussianKernelSize, m_algoParams.m_gaussianStdev, false); } std::vector From 97abac3f91e96be6fe65934dd10df53f37989fe0 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Tue, 29 Aug 2023 09:02:10 +0200 Subject: [PATCH 09/20] Added safeguards to check if OpenCV core is available --- .../imgproc/include/visp3/imgproc/vpCircleHoughTransform.h | 4 ++++ modules/imgproc/src/vpCircleHoughTransform.cpp | 2 ++ 2 files changed, 6 insertions(+) diff --git a/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h b/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h index f7fe990317..904d522607 100644 --- a/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h +++ b/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h @@ -346,10 +346,12 @@ class VISP_EXPORT vpCircleHoughTransform */ vpCircle2D(const vpImagePoint ¢er, const float &radius) : m_center(center), m_radius(radius) { } +#ifdef HAVE_OPENCV_CORE /*! * Constructor from an OpenCV vector that contains [center_x, center_y, radius]. */ vpCircle2D(const cv::Vec3f &vec) : m_center(vec[1], vec[0]), m_radius(vec[2]) { } +#endif /*! * Default destructor. @@ -417,6 +419,7 @@ class VISP_EXPORT vpCircleHoughTransform // // Detection methods +#ifdef HAVE_OPENCV_CORE /** * \brief Perform Circle Hough Transform to detect the circles in an OpenCV image. * @@ -424,6 +427,7 @@ class VISP_EXPORT vpCircleHoughTransform * \return std::vector The list of 2D circles detected in the image. */ std::vector detect(const cv::Mat &cv_I); +#endif /** * \brief Convert the input image in a gray-scale image and then diff --git a/modules/imgproc/src/vpCircleHoughTransform.cpp b/modules/imgproc/src/vpCircleHoughTransform.cpp index 00a7b84335..0c4af49649 100644 --- a/modules/imgproc/src/vpCircleHoughTransform.cpp +++ b/modules/imgproc/src/vpCircleHoughTransform.cpp @@ -82,6 +82,7 @@ vpCircleHoughTransform::detect(const vpImage &I) return detect(I_gray); } +#ifdef HAVE_OPENCV_CORE std::vector vpCircleHoughTransform::detect(const cv::Mat &cv_I) { @@ -89,6 +90,7 @@ vpCircleHoughTransform::detect(const cv::Mat &cv_I) vpImageConvert::convert(cv_I, I_gray); return detect(I_gray); } +#endif std::vector vpCircleHoughTransform::detect(const vpImage &I, const int &nbCircles) From e6d5eb948e5d8fbd4dba64848360e677050eac40 Mon Sep 17 00:00:00 2001 From: Fabien Spindler Date: Tue, 29 Aug 2023 15:29:22 +0200 Subject: [PATCH 10/20] Convert coin1.pgm and coin2.pgm images into jpeg format --- doc/tutorial/imgproc/tutorial-imgproc-cht.dox | 4 +++- .../imgproc/tutorial-imgproc-count-coins.dox | 2 +- tutorial/imgproc/count-coins/CMakeLists.txt | 6 +++--- tutorial/imgproc/count-coins/coins1.jpg | Bin 0 -> 11052 bytes tutorial/imgproc/count-coins/coins1.pgm | 5 ----- tutorial/imgproc/count-coins/coins2.jpg | Bin 0 -> 63935 bytes tutorial/imgproc/count-coins/coins2.pgm | Bin 178674 -> 0 bytes .../count-coins/tutorial-count-coins.cpp | 2 +- .../imgproc/hough-transform/CMakeLists.txt | 4 ++-- tutorial/imgproc/hough-transform/coins2.jpg | Bin 0 -> 63935 bytes tutorial/imgproc/hough-transform/coins2.pgm | Bin 178674 -> 0 bytes 11 files changed, 10 insertions(+), 13 deletions(-) create mode 100644 tutorial/imgproc/count-coins/coins1.jpg delete mode 100644 tutorial/imgproc/count-coins/coins1.pgm create mode 100644 tutorial/imgproc/count-coins/coins2.jpg delete mode 100644 tutorial/imgproc/count-coins/coins2.pgm create mode 100644 tutorial/imgproc/hough-transform/coins2.jpg delete mode 100644 tutorial/imgproc/hough-transform/coins2.pgm diff --git a/doc/tutorial/imgproc/tutorial-imgproc-cht.dox b/doc/tutorial/imgproc/tutorial-imgproc-cht.dox index d1efce2c9c..593fcd7a65 100644 --- a/doc/tutorial/imgproc/tutorial-imgproc-cht.dox +++ b/doc/tutorial/imgproc/tutorial-imgproc-cht.dox @@ -41,11 +41,13 @@ 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: ``` @@ -67,7 +69,7 @@ To run the software on an actual image using a JSON configuration file, please r $ ./tutorial-circle-hough --input /path/to/my/image --config config/detector_img.json ``` -**NB**: the configuration file `config/detector_img.json` has been tuned to detect coins in the image `coins2.pgm`. +**NB**: the configuration file `config/detector_img.json` has been tuned to detect coins in the image `coins2.jpg`. If the detections seem a bit off, you might need to change the parameters. To run the software on an actual image using command line arguments instead, please run: diff --git a/doc/tutorial/imgproc/tutorial-imgproc-count-coins.dox b/doc/tutorial/imgproc/tutorial-imgproc-count-coins.dox index c29d637392..123dd01bdb 100644 --- a/doc/tutorial/imgproc/tutorial-imgproc-count-coins.dox +++ b/doc/tutorial/imgproc/tutorial-imgproc-count-coins.dox @@ -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: diff --git a/tutorial/imgproc/count-coins/CMakeLists.txt b/tutorial/imgproc/count-coins/CMakeLists.txt index 1b6abe42ec..dbc971d193 100644 --- a/tutorial/imgproc/count-coins/CMakeLists.txt +++ b/tutorial/imgproc/count-coins/CMakeLists.txt @@ -1,4 +1,4 @@ -project(tutorial-) +project(tutorial-counting-coins) cmake_minimum_required(VERSION 3.0) @@ -8,8 +8,8 @@ find_package(VISP REQUIRED visp_core visp_io visp_gui visp_imgproc) set(tutorial_cpp tutorial-count-coins.cpp) -list(APPEND tutorial_data "${CMAKE_CURRENT_SOURCE_DIR}/coins1.pgm") -list(APPEND tutorial_data "${CMAKE_CURRENT_SOURCE_DIR}/coins2.pgm") +list(APPEND tutorial_data "${CMAKE_CURRENT_SOURCE_DIR}/coins1.jpg") +list(APPEND tutorial_data "${CMAKE_CURRENT_SOURCE_DIR}/coins2.jpg") foreach(cpp ${tutorial_cpp}) visp_add_target(${cpp}) diff --git a/tutorial/imgproc/count-coins/coins1.jpg b/tutorial/imgproc/count-coins/coins1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bf85bb2da355292e7bfd017d5606364573306f4a GIT binary patch literal 11052 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 K|9|nnrT+(CxV@7A literal 0 HcmV?d00001 diff --git a/tutorial/imgproc/count-coins/coins2.pgm b/tutorial/imgproc/count-coins/coins2.pgm deleted file mode 100644 index c8f1d2e9156d55008dee5db1a0e5305910ef466d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178674 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 M1+HI#|Njd7f9NGuh5!Hn diff --git a/tutorial/imgproc/count-coins/tutorial-count-coins.cpp b/tutorial/imgproc/count-coins/tutorial-count-coins.cpp index 3f7df36eed..710cc91c08 100644 --- a/tutorial/imgproc/count-coins/tutorial-count-coins.cpp +++ b/tutorial/imgproc/count-coins/tutorial-count-coins.cpp @@ -21,7 +21,7 @@ int main(int argc, char *argv[]) #if defined(VISP_HAVE_MODULE_IMGPROC) && (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV)) //! [Macro defined] - std::string input_filename = "coins1.pgm"; + std::string input_filename = "coins1.jpg"; vp::vpAutoThresholdMethod method = vp::AUTO_THRESHOLD_OTSU; bool white_foreground = false; diff --git a/tutorial/imgproc/hough-transform/CMakeLists.txt b/tutorial/imgproc/hough-transform/CMakeLists.txt index 864704d415..710487c12e 100644 --- a/tutorial/imgproc/hough-transform/CMakeLists.txt +++ b/tutorial/imgproc/hough-transform/CMakeLists.txt @@ -1,4 +1,4 @@ -project(tutorial-) +project(tutorial-hough) cmake_minimum_required(VERSION 3.0) @@ -10,7 +10,7 @@ set(tutorial_cpp ) # list(APPEND tutorial_data "${CMAKE_CURRENT_SOURCE_DIR}/config") -list(APPEND tutorial_data "${CMAKE_CURRENT_SOURCE_DIR}/coins2.pgm") +list(APPEND tutorial_data "${CMAKE_CURRENT_SOURCE_DIR}/coins2.jpg") foreach(cpp ${tutorial_cpp}) visp_add_target(${cpp} drawingHelpers.cpp) diff --git a/tutorial/imgproc/hough-transform/coins2.jpg b/tutorial/imgproc/hough-transform/coins2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5476f6e16808959ebe5fb40074feb0185df655f9 GIT binary patch literal 63935 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 K|9|nnrT+(CxV@7A literal 0 HcmV?d00001 diff --git a/tutorial/imgproc/hough-transform/coins2.pgm b/tutorial/imgproc/hough-transform/coins2.pgm deleted file mode 100644 index c8f1d2e9156d55008dee5db1a0e5305910ef466d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178674 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 M1+HI#|Njd7f9NGuh5!Hn From a5f523059fe968bb25daa7e1f683446a6d459463 Mon Sep 17 00:00:00 2001 From: Fabien Spindler Date: Tue, 29 Aug 2023 15:38:31 +0200 Subject: [PATCH 11/20] Add newline at end of file --- tutorial/imgproc/hough-transform/config/detector_full.json | 2 +- tutorial/imgproc/hough-transform/config/detector_half.json | 2 +- tutorial/imgproc/hough-transform/config/detector_img.json | 2 +- tutorial/imgproc/hough-transform/config/detector_quarter.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tutorial/imgproc/hough-transform/config/detector_full.json b/tutorial/imgproc/hough-transform/config/detector_full.json index 117951fc5b..dda67b8b24 100644 --- a/tutorial/imgproc/hough-transform/config/detector_full.json +++ b/tutorial/imgproc/hough-transform/config/detector_full.json @@ -21,4 +21,4 @@ ], "radiusThreshRatio": 5, "sobelKernelSize": 3 -} \ No newline at end of file +} diff --git a/tutorial/imgproc/hough-transform/config/detector_half.json b/tutorial/imgproc/hough-transform/config/detector_half.json index ce757e37cf..4b5f9a4e9f 100644 --- a/tutorial/imgproc/hough-transform/config/detector_half.json +++ b/tutorial/imgproc/hough-transform/config/detector_half.json @@ -21,4 +21,4 @@ ], "radiusThreshRatio": 2, "sobelKernelSize": 3 -} \ No newline at end of file +} diff --git a/tutorial/imgproc/hough-transform/config/detector_img.json b/tutorial/imgproc/hough-transform/config/detector_img.json index 6e53dac8f4..f9537a1d2c 100644 --- a/tutorial/imgproc/hough-transform/config/detector_img.json +++ b/tutorial/imgproc/hough-transform/config/detector_img.json @@ -22,4 +22,4 @@ ], "radiusThreshRatio": 4.0, "sobelKernelSize": 7 -} \ No newline at end of file +} diff --git a/tutorial/imgproc/hough-transform/config/detector_quarter.json b/tutorial/imgproc/hough-transform/config/detector_quarter.json index 415546b8a5..a59fcc6263 100644 --- a/tutorial/imgproc/hough-transform/config/detector_quarter.json +++ b/tutorial/imgproc/hough-transform/config/detector_quarter.json @@ -21,4 +21,4 @@ ], "radiusThreshRatio": 1, "sobelKernelSize": 3 -} \ No newline at end of file +} From 18f222401dbcba4aff65236ae12ea4698fa3d207 Mon Sep 17 00:00:00 2001 From: Fabien Spindler Date: Tue, 29 Aug 2023 15:41:10 +0200 Subject: [PATCH 12/20] Code indentation and newline at end of file --- .../hough-transform/drawingHelpers.cpp | 26 +++++++-------- .../imgproc/hough-transform/drawingHelpers.h | 32 +++++++++---------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/tutorial/imgproc/hough-transform/drawingHelpers.cpp b/tutorial/imgproc/hough-transform/drawingHelpers.cpp index 4215a52270..6c54e7c60c 100644 --- a/tutorial/imgproc/hough-transform/drawingHelpers.cpp +++ b/tutorial/imgproc/hough-transform/drawingHelpers.cpp @@ -1,28 +1,27 @@ #include "drawingHelpers.h" #if defined(VISP_HAVE_X11) - vpDisplayX drawingHelpers::d; +vpDisplayX drawingHelpers::d; #elif defined(VISP_HAVE_OPENCV) - vpDisplayOpenCV drawingHelpers::d; +vpDisplayOpenCV drawingHelpers::d; #elif defined(VISP_HAVE_GTK) - vpDisplayGTK drawingHelpers::d; +vpDisplayGTK drawingHelpers::d; #elif defined(VISP_HAVE_GDI) - vpDisplayGDI drawingHelpers::d; +vpDisplayGDI drawingHelpers::d; #elif defined(VISP_HAVE_D3D9) - vpDisplayD3D drawingHelpers::d; +vpDisplayD3D drawingHelpers::d; #endif vpImage drawingHelpers::I_disp; bool drawingHelpers::display(vpImage &I, const std::string &title, const bool &blockingMode) -{ +{ I_disp = I; - if(! d.isInitialised()) - { + if (!d.isInitialised()) { d.init(I_disp); vpDisplay::setTitle(I_disp, title.c_str()); } - + vpDisplay::display(I_disp); vpDisplay::displayText(I_disp, 15, 15, "Left click to continue...", vpColor::red); vpDisplay::displayText(I_disp, 35, 15, "Right click to stop...", vpColor::red); @@ -30,25 +29,24 @@ bool drawingHelpers::display(vpImage &I, const std::string &title, const vpMouseButton::vpMouseButtonType button; vpDisplay::getClick(I_disp, button, blockingMode); bool hasToContinue = true; - if (button == vpMouseButton::button3) - { + if (button == vpMouseButton::button3) { // Right click => stop the program hasToContinue = false; } return hasToContinue; } - + bool drawingHelpers::display(vpImage &D, const std::string &title, const bool &blockingMode) { vpImage I; // Image to display vpImageConvert::convert(D, I); return display(I, title, blockingMode); -} +} bool drawingHelpers::display(vpImage &D, const std::string &title, const bool &blockingMode) { vpImage I; // Image to display vpImageConvert::convert(D, I); return display(I, title, blockingMode); -} \ No newline at end of file +} diff --git a/tutorial/imgproc/hough-transform/drawingHelpers.h b/tutorial/imgproc/hough-transform/drawingHelpers.h index d58df2abd5..09b5b7323a 100644 --- a/tutorial/imgproc/hough-transform/drawingHelpers.h +++ b/tutorial/imgproc/hough-transform/drawingHelpers.h @@ -8,23 +8,23 @@ namespace drawingHelpers { - #if defined(VISP_HAVE_X11) - extern vpDisplayX d; - #elif defined(VISP_HAVE_OPENCV) - extern vpDisplayOpenCV d; - #elif defined(VISP_HAVE_GTK) - extern vpDisplayGTK d; - #elif defined(VISP_HAVE_GDI) - extern vpDisplayGDI d; - #elif defined(VISP_HAVE_D3D9) - extern vpDisplayD3D d; - #endif +#if defined(VISP_HAVE_X11) +extern vpDisplayX d; +#elif defined(VISP_HAVE_OPENCV) +extern vpDisplayOpenCV d; +#elif defined(VISP_HAVE_GTK) +extern vpDisplayGTK d; +#elif defined(VISP_HAVE_GDI) +extern vpDisplayGDI d; +#elif defined(VISP_HAVE_D3D9) +extern vpDisplayD3D d; +#endif - extern vpImage I_disp; +extern vpImage I_disp; - bool display(vpImage &I, const std::string &title, const bool &blockingMode); - bool display(vpImage &I, const std::string &title, const bool &blockingMode); - bool display(vpImage &D, const std::string &title, const bool &blockingMode); +bool display(vpImage &I, const std::string &title, const bool &blockingMode); +bool display(vpImage &I, const std::string &title, const bool &blockingMode); +bool display(vpImage &D, const std::string &title, const bool &blockingMode); } -#endif \ No newline at end of file +#endif From dbcdbd0a6fbfe9b4d4fae7e9a45558f3272dc1a6 Mon Sep 17 00:00:00 2001 From: Fabien Spindler Date: Tue, 29 Aug 2023 17:18:00 +0200 Subject: [PATCH 13/20] Minor changes - code indentation - doxygen documentation - build without OpenCV - update changelog files --- ChangeLog.txt | 34 +++++++++------ doc/tutorial/imgproc/tutorial-imgproc-cht.dox | 10 ++--- .../imgproc/doc/{module.doc => module.dox} | 7 +++- .../visp3/imgproc/vpCircleHoughTransform.h | 14 ++++--- .../include/visp3/imgproc/vpImageMedian.h | 36 ++++++---------- .../imgproc/src/vpCircleHoughTransform.cpp | 34 +++++++-------- modules/imgproc/src/vpImageMedian.cpp | 42 ++++++++++++------- .../hough-transform/drawingHelpers.cpp | 2 + 8 files changed, 99 insertions(+), 80 deletions(-) rename modules/imgproc/doc/{module.doc => module.dox} (92%) diff --git a/ChangeLog.txt b/ChangeLog.txt index 76b03adb3f..c49191a2f7 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -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 @@ -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), @@ -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 diff --git a/doc/tutorial/imgproc/tutorial-imgproc-cht.dox b/doc/tutorial/imgproc/tutorial-imgproc-cht.dox index 593fcd7a65..8deedcbec4 100644 --- a/doc/tutorial/imgproc/tutorial-imgproc-cht.dox +++ b/doc/tutorial/imgproc/tutorial-imgproc-cht.dox @@ -1,6 +1,6 @@ /** -\page tutorial-imgproc-cht Gradient-based Circle Hough Transform +\page tutorial-imgproc-cht Tutorial: Gradient-based Circle Hough Transform \tableofcontents \section imgproc_cht_intro Introduction @@ -64,13 +64,13 @@ $ ./tutorial-circle-hough --input ${TARGET}_disks \subsection imgproc_cht_howto_images How to use actual images -To run the software on an actual image using a JSON configuration file, please run: +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 /path/to/my/image --config config/detector_img.json +$ ./tutorial-circle-hough --input coins2.jpg --config config/detector_img.json ``` -**NB**: the configuration file `config/detector_img.json` has been tuned to detect coins in the image `coins2.jpg`. -If the detections seem a bit off, you might need to change the parameters. +\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: ``` diff --git a/modules/imgproc/doc/module.doc b/modules/imgproc/doc/module.dox similarity index 92% rename from modules/imgproc/doc/module.doc rename to modules/imgproc/doc/module.dox index fcab9acb59..e5f710d2e0 100644 --- a/modules/imgproc/doc/module.doc +++ b/modules/imgproc/doc/module.dox @@ -63,7 +63,7 @@ \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. */ @@ -71,4 +71,9 @@ \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. */ \ No newline at end of file diff --git a/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h b/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h index 904d522607..5eaeac3b7b 100644 --- a/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h +++ b/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h @@ -53,6 +53,7 @@ using json = nlohmann::json; #endif /** + * \ingroup group_hough_transform * \brief Class that permits to detect 2D circles in a image using * the gradient-based Circle Hough transform. * Please find more information on the algorithm @@ -246,8 +247,8 @@ class VISP_EXPORT vpCircleHoughTransform * \brief Read the detector configuration from JSON. All values are optional and if an argument is not present, * the default value defined in the constructor is kept * - * \param[in] j The JSON object, resulting from the parsing of a JSON file. - * \param[out] detector The detector, that will be initialized from the JSON data. + * \param[in] j : The JSON object, resulting from the parsing of a JSON file. + * \param[out] params : The circle Hough transform parameters that will be initialized from the JSON data. */ inline friend void from_json(const json &j, CHTransformParameters ¶ms) { @@ -304,8 +305,8 @@ class VISP_EXPORT vpCircleHoughTransform /** * \brief Parse a vpCircleHoughTransform into JSON format. * - * \param[out] j A JSON parser object. - * \param[in] config The vpCircleHoughTransform that must be parsed into JSON format. + * \param[out] j : A JSON parser object. + * \param[in] params : The circle Hough transform parameters that will be serialized in the json object. */ inline friend void to_json(json &j, const CHTransformParameters ¶ms) { @@ -502,7 +503,7 @@ class VISP_EXPORT vpCircleHoughTransform * \brief Parse a vpCircleHoughTransform into JSON format. * * \param[out] j A JSON parser object. - * \param[in] config The vpCircleHoughTransform that must be parsed into JSON format. + * \param[in] detector The vpCircleHoughTransform that must be parsed into JSON format. */ inline friend void to_json(json &j, const vpCircleHoughTransform &detector) { @@ -853,7 +854,7 @@ class VISP_EXPORT vpCircleHoughTransform std::vector m_circleCandidates; /*!< List of the candidate circles.*/ std::vector m_circleCandidatesVotes; /*!< Number of votes for the candidate circles.*/ - // // Circle candidates merging atttributes + // // Circle candidates merging attributes std::vector m_finalCircles; /*!< List of the final circles, i.e. the ones resulting from the merge of the circle candidates.*/ std::vector m_finalCircleVotes; /*!< Number of votes for the candidate circles.*/ }; @@ -864,6 +865,7 @@ class VISP_EXPORT vpCircleHoughTransform * \param[in] img : Image used as background. * \param[in] color : Color used to draw the CAD model. * \param[in] thickness : Thickness used to draw the CAD model. + * \param[in] size : Size of the cross used to display the center of the circle. */ template < typename Type > inline void diff --git a/modules/imgproc/include/visp3/imgproc/vpImageMedian.h b/modules/imgproc/include/visp3/imgproc/vpImageMedian.h index 9ef830bbaf..0f0f76749f 100644 --- a/modules/imgproc/include/visp3/imgproc/vpImageMedian.h +++ b/modules/imgproc/include/visp3/imgproc/vpImageMedian.h @@ -33,37 +33,27 @@ #ifndef _vpImageMedian_h_ #define _vpImageMedian_h_ -#include +#include +#include -#if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020408) +#if defined(HAVE_OPENCV_IMGPROC) + +#if (VISP_HAVE_OPENCV_VERSION >= 0x020408) #include -#elif defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020101) +#elif (VISP_HAVE_OPENCV_VERSION >= 0x020101) #include -#elif defined(VISP_HAVE_OPENCV) +#else #include #endif -namespace ImageFilter +namespace vp { -// calculates the median value of a single channel -// based on https://github.com/arnaudgelas/OpenCVExamples/blob/master/cvMat/Statistics/Median/Median.cpp -double median(const cv::Mat &channel); +VISP_EXPORT double median(const cv::Mat &channel); -/** - * \brief Compute the upper Canny edge filter threshold. - * - * \param[in] cv_I The image, in cv format. - * \return double The upper Canny edge filter threshold. - */ -double computeCannyThreshold(const cv::Mat &cv_I); +VISP_EXPORT double computeCannyThreshold(const cv::Mat &cv_I); -/** - * \brief Compute the upper Canny edge filter threshold. - * - * \param[in] I The gray-scale image, in ViSP format. - * \return double The upper Canny edge filter threshold. - */ -double computeCannyThreshold(const vpImage &I); -} // namespace ImageFilter +VISP_EXPORT double computeCannyThreshold(const vpImage &I); +} #endif +#endif diff --git a/modules/imgproc/src/vpCircleHoughTransform.cpp b/modules/imgproc/src/vpCircleHoughTransform.cpp index 0c4af49649..f0935a88b7 100644 --- a/modules/imgproc/src/vpCircleHoughTransform.cpp +++ b/modules/imgproc/src/vpCircleHoughTransform.cpp @@ -105,10 +105,9 @@ vpCircleHoughTransform::detect(const vpImage &I, const int &nbCir } bool (*hasMoreVotes)(std::pair, std::pair) - = [](std::pair a, std::pair b) - { - // We divide the number of votes by the radius to avoid to favour big circles - return (a.second / a.first.getRadius() > b.second / b.first.getRadius()); + = [](std::pair a, std::pair b) { + // We divide the number of votes by the radius to avoid to favour big circles + return (a.second / a.first.getRadius() > b.second / b.first.getRadius()); }; std::sort(detectionsWithVotes.begin(), detectionsWithVotes.end(), hasMoreVotes); @@ -191,7 +190,7 @@ vpCircleHoughTransform::edgeDetection(const vpImage &I) // 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 = ImageFilter::computeCannyThreshold(I); + cannyThresh = vp::computeCannyThreshold(I); } vpImageFilter::canny(I, m_edgeMap, m_algoParams.m_gaussianKernelSize, cannyThresh, m_algoParams.m_sobelKernelSize); #else @@ -295,7 +294,7 @@ vpCircleHoughTransform::computeCenterCandidates() for (int k1 = 0; k1 < 2; k1++) { bool hasToStopLoop = false; - for (int rad = m_algoParams.m_minRadius; rad <= m_algoParams.m_maxRadius && !hasToStopLoop; rad++) { + for (unsigned int rad = m_algoParams.m_minRadius; rad <= m_algoParams.m_maxRadius && !hasToStopLoop; rad++) { float x1 = (float)c + (float)rad * sx; float y1 = (float)r + (float)rad * sy; @@ -329,18 +328,17 @@ vpCircleHoughTransform::computeCenterCandidates() const unsigned int &x, const unsigned int &y, const int &offsetX, const int &offsetY, const unsigned int &nbCols, const unsigned int &nbRows, - vpImage &accum, bool &hasToStop) - { - if (x - offsetX >= nbCols || - y - offsetY >= nbRows - ) { - hasToStop = true; - } - else { - float dx = (x_orig - (float)x); - float dy = (y_orig - (float)y); - accum[y - offsetY][x - offsetX] += std::abs(dx) + std::abs(dy); - } + vpImage &accum, bool &hasToStop) { + if (x - offsetX >= nbCols || + y - offsetY >= nbRows + ) { + hasToStop = true; + } + else { + float dx = (x_orig - (float)x); + float dy = (y_orig - (float)y); + accum[y - offsetY][x - offsetX] += std::abs(dx) + std::abs(dy); + } }; updateAccumulator(x1, y1, x_low, y_low, diff --git a/modules/imgproc/src/vpImageMedian.cpp b/modules/imgproc/src/vpImageMedian.cpp index d4cc9258a7..92a35796d3 100644 --- a/modules/imgproc/src/vpImageMedian.cpp +++ b/modules/imgproc/src/vpImageMedian.cpp @@ -32,12 +32,20 @@ #include +#if defined(HAVE_OPENCV_IMGPROC) + #include -namespace ImageFilter +namespace vp { -// calculates the median value of a single channel -// based on https://github.com/arnaudgelas/OpenCVExamples/blob/master/cvMat/Statistics/Median/Median.cpp +/** + * \ingroup group_image_median + * Calculates the median value of a single channel + * based on https://github.com/arnaudgelas/OpenCVExamples/blob/master/cvMat/Statistics/Median/Median.cpp + * + * \param[in] channel : OpenCV input image. + * \return The median value of the input image. + */ double median(const cv::Mat &channel) { double m = (channel.rows * channel.cols) / 2; @@ -45,7 +53,7 @@ double median(const cv::Mat &channel) double med = -1.0; int histSize = 256; - float range [] = { 0, 256 }; + float range[] = { 0, 256 }; const float *histRange = { range }; bool uniform = true; bool accumulate = false; @@ -62,10 +70,12 @@ double median(const cv::Mat &channel) } /** - * \brief Compute the upper Canny edge filter threshold. - * - * \param[in] cv_I The image, in cv format. - * \return double The upper Canny edge filter threshold. + * \ingroup group_image_median + * \brief Compute the upper Canny edge filter threshold based on image median. + * + * \param[in] cv_I : The image, in cv format. + * \return The upper Canny edge filter threshold. + * \sa median() */ double computeCannyThreshold(const cv::Mat &cv_I) { @@ -79,7 +89,7 @@ double computeCannyThreshold(const cv::Mat &cv_I) cv::Mat cv_I_scaled_down; resize(cv_I_blur, cv_I_scaled_down, cv::Size(), scale_down, scale_down, cv::INTER_NEAREST); - double median_pix = ImageFilter::median(cv_I_scaled_down); + double median_pix = vp::median(cv_I_scaled_down); // double lower = std::max(0., 0.7 * median_pix); // Unused, but to know the formula exists double upper = std::min(255., 1.3 * median_pix); upper = std::max(1., upper); @@ -87,10 +97,12 @@ double computeCannyThreshold(const cv::Mat &cv_I) } /** - * \brief Compute the upper Canny edge filter threshold. - * - * \param[in] I The gray-scale image, in ViSP format. - * \return double The upper Canny edge filter threshold. + * \ingroup group_image_median + * \brief Compute the upper Canny edge filter threshold based on image median. + * + * \param[in] I : The gray-scale image, in ViSP format. + * \return The upper Canny edge filter threshold. + * \sa median() */ double computeCannyThreshold(const vpImage &I) { @@ -98,4 +110,6 @@ double computeCannyThreshold(const vpImage &I) vpImageConvert::convert(I, cv_I); return computeCannyThreshold(cv_I); } -} // namespace ImageFilter \ No newline at end of file +} // namespace ImageFilter + +#endif diff --git a/tutorial/imgproc/hough-transform/drawingHelpers.cpp b/tutorial/imgproc/hough-transform/drawingHelpers.cpp index 6c54e7c60c..ca1e9fb26c 100644 --- a/tutorial/imgproc/hough-transform/drawingHelpers.cpp +++ b/tutorial/imgproc/hough-transform/drawingHelpers.cpp @@ -1,5 +1,7 @@ #include "drawingHelpers.h" +#include + #if defined(VISP_HAVE_X11) vpDisplayX drawingHelpers::d; #elif defined(VISP_HAVE_OPENCV) From 38391524c0775785b25481cb94115c661469958e Mon Sep 17 00:00:00 2001 From: Fabien Spindler Date: Wed, 30 Aug 2023 10:23:48 +0200 Subject: [PATCH 14/20] Remove HAVE_OPENCV_IMGPROC around canny() when useless --- modules/core/src/image/vpImageFilter.cpp | 8 +++--- .../imgproc/src/vpCircleHoughTransform.cpp | 4 --- .../tracker/me/src/moving-edges/vpMeNurbs.cpp | 27 ++++++++----------- tutorial/image/tutorial-image-filter.cpp | 2 -- .../StartedImageProc/ViewController.mm | 3 --- 5 files changed, 16 insertions(+), 28 deletions(-) diff --git a/modules/core/src/image/vpImageFilter.cpp b/modules/core/src/image/vpImageFilter.cpp index ef48358035..4908dbe0ad 100644 --- a/modules/core/src/image/vpImageFilter.cpp +++ b/modules/core/src/image/vpImageFilter.cpp @@ -251,6 +251,7 @@ double computeCannyThreshold(const vpImage &I, double &lowerThres vpImageConvert::convert(I, cv_I); return computeCannyThreshold(cv_I, nullptr, lowerThresh); } +#endif /*! Apply the Canny edge operator on the image \e Isrc and return the resulting @@ -294,6 +295,7 @@ int main() void vpImageFilter::canny(const vpImage &Isrc, vpImage &Ires, unsigned int gaussianFilterSize, double thresholdCanny, unsigned int apertureSobel) { +#if defined(HAVE_OPENCV_IMGPROC) cv::Mat img_cvmat, cv_I_blur, edges_cvmat; vpImageConvert::convert(Isrc, img_cvmat); cv::GaussianBlur(img_cvmat, cv_I_blur, cv::Size((int)gaussianFilterSize, (int)gaussianFilterSize), 0, 0); @@ -305,9 +307,9 @@ void vpImageFilter::canny(const vpImage &Isrc, vpImage &I) { -#if defined(HAVE_OPENCV_IMGPROC) int cannyThresh = m_algoParams.m_cannyThresh; // Apply the Canny edge operator to compute the edge map // The canny method performs Gaussian blur and gradient computation @@ -193,9 +192,6 @@ vpCircleHoughTransform::edgeDetection(const vpImage &I) cannyThresh = vp::computeCannyThreshold(I); } vpImageFilter::canny(I, m_edgeMap, m_algoParams.m_gaussianKernelSize, cannyThresh, m_algoParams.m_sobelKernelSize); -#else - throw(vpException(vpException::functionNotImplementedError, "Canny edge detection has not been implemented yet !")); -#endif for (int i = 0; i < m_algoParams.m_edgeMapFilteringNbIter; i++) { filterEdgeMap(); diff --git a/modules/tracker/me/src/moving-edges/vpMeNurbs.cpp b/modules/tracker/me/src/moving-edges/vpMeNurbs.cpp index bf6c78cc7e..f7cc1bf39d 100644 --- a/modules/tracker/me/src/moving-edges/vpMeNurbs.cpp +++ b/modules/tracker/me/src/moving-edges/vpMeNurbs.cpp @@ -299,7 +299,7 @@ void vpMeNurbs::sample(const vpImage &I, bool doNotTrack) vpImagePoint pt_1(-rows, -cols); while (u <= 1.0) { if (pt != NULL) - delete [] pt; + delete[] pt; pt = nurbs.computeCurveDersPoint(u, 1); double delta = computeDelta(pt[1].get_i(), pt[1].get_j()); @@ -316,7 +316,7 @@ void vpMeNurbs::sample(const vpImage &I, bool doNotTrack) u = u + step; } if (pt != NULL) - delete [] pt; + delete[] pt; } /*! @@ -364,7 +364,7 @@ void vpMeNurbs::updateDelta() u -= step; if (der != NULL) - delete [] der; + delete[] der; der = nurbs.computeCurveDersPoint(u, 1); // vpImagePoint toto(der[0].get_i(),der[0].get_j()); // vpDisplay::displayCross(I,toto,4,vpColor::red); @@ -376,7 +376,7 @@ void vpMeNurbs::updateDelta() d_1 = 1.5e6; } if (der != NULL) - delete [] der; + delete[] der; } /*! @@ -492,8 +492,8 @@ void vpMeNurbs::seekExtremities(const vpImage &I) else { list.pop_front(); } - /*if(begin != NULL)*/ delete [] begin; - /*if(end != NULL) */ delete [] end; + /*if(begin != NULL)*/ delete[] begin; + /*if(end != NULL) */ delete[] end; } /*! @@ -509,7 +509,6 @@ void vpMeNurbs::seekExtremities(const vpImage &I) */ void vpMeNurbs::seekExtremitiesCanny(const vpImage &I) { -#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) vpMeSite pt = list.front(); vpImagePoint firstPoint(pt.ifloat, pt.jfloat); pt = list.back(); @@ -635,7 +634,7 @@ void vpMeNurbs::seekExtremitiesCanny(const vpImage &I) me->setRange(memory_range); } - /* if (begin != NULL) */ delete [] begin; + /* if (begin != NULL) */ delete[] begin; beginPtFound = 0; } @@ -711,7 +710,7 @@ void vpMeNurbs::seekExtremitiesCanny(const vpImage &I) // list.end(); vpMeSite s; - for (std::list::iterator it=list.begin(); it!=list.end(); ++it) { + for (std::list::iterator it = list.begin(); it!=list.end(); ++it) { s = *it; vpImagePoint iP(s.ifloat, s.jfloat); if (inRectangle(iP, rect)) { @@ -765,13 +764,9 @@ void vpMeNurbs::seekExtremitiesCanny(const vpImage &I) me->setRange(memory_range); } - /* if (end != NULL) */ delete [] end; + /* if (end != NULL) */ delete[] end; endPtFound = 0; } -#else - (void)I; - throw(vpException(vpException::fatalError, "To use the canny detection, OpenCV has to be installed.")); -#endif } /*! @@ -858,7 +853,7 @@ void vpMeNurbs::localReSample(const vpImage &I) while (vpImagePoint::sqrDistance(iP[0], iPend) > vpMath::sqr(me->getSampleStep()) && u < uend) { u += 0.01; /*if (iP!=NULL)*/ { - delete [] iP; + delete[] iP; iP = NULL; } iP = nurbs.computeCurveDersPoint(u, 1); @@ -876,7 +871,7 @@ void vpMeNurbs::localReSample(const vpImage &I) } } /*if (iP!=NULL)*/ { - delete [] iP; + delete[] iP; iP = NULL; } } diff --git a/tutorial/image/tutorial-image-filter.cpp b/tutorial/image/tutorial-image-filter.cpp index 5b04b64bfc..85bf396ea8 100644 --- a/tutorial/image/tutorial-image-filter.cpp +++ b/tutorial/image/tutorial-image-filter.cpp @@ -84,11 +84,9 @@ int main(int argc, char **argv) display(dIy, "Gradient dIy"); //! [Canny] -#if defined(HAVE_OPENCV_IMGPROC) vpImage C; vpImageFilter::canny(I, C, 5, -1., 3); display(C, "Canny"); -#endif //! [Canny] //! [Convolution kernel] diff --git a/tutorial/ios/StartedImageProc/StartedImageProc/ViewController.mm b/tutorial/ios/StartedImageProc/StartedImageProc/ViewController.mm index 8a04de6007..07b7544acf 100644 --- a/tutorial/ios/StartedImageProc/StartedImageProc/ViewController.mm +++ b/tutorial/ios/StartedImageProc/StartedImageProc/ViewController.mm @@ -119,7 +119,6 @@ - (void) checkButtonClick:(UIButton *)paramSender{ [myImageView setImage:[ImageConversion UIImageFromVpImageGray:gray]]; } -#if defined(VISP_HAVE_OPENCV) else if([myButton.currentTitle isEqualToString:[process objectAtIndex: 3]]){ // canny detector NSLog(@"Clicked on \"%@\" button ", [process objectAtIndex: 3]); @@ -130,7 +129,6 @@ - (void) checkButtonClick:(UIButton *)paramSender{ vpImageFilter::canny(gray, canny, 5, 15, 3); [myImageView setImage:[ImageConversion UIImageFromVpImageGray:canny]]; } -#endif } - (void)didReceiveMemoryWarning { @@ -141,4 +139,3 @@ - (void)didReceiveMemoryWarning { @end #endif - From bd67b5ffe5f307e014f6e00f1a40cb84d91def6e Mon Sep 17 00:00:00 2001 From: rlagneau Date: Wed, 30 Aug 2023 10:45:04 +0200 Subject: [PATCH 15/20] [TUTO] Removed test ifdef HAVE_OPENCV_IMGPROC that protected the call to canny because canny now has a full-ViSP implementation too --- tutorial/image/tutorial-image-filter.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tutorial/image/tutorial-image-filter.cpp b/tutorial/image/tutorial-image-filter.cpp index 5b04b64bfc..85bf396ea8 100644 --- a/tutorial/image/tutorial-image-filter.cpp +++ b/tutorial/image/tutorial-image-filter.cpp @@ -84,11 +84,9 @@ int main(int argc, char **argv) display(dIy, "Gradient dIy"); //! [Canny] -#if defined(HAVE_OPENCV_IMGPROC) vpImage C; vpImageFilter::canny(I, C, 5, -1., 3); display(C, "Canny"); -#endif //! [Canny] //! [Convolution kernel] From 04f122ae20bf01da822ec0d94fc5eb22204cd3c4 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Wed, 30 Aug 2023 11:12:16 +0200 Subject: [PATCH 16/20] [CLEAN] Removed some useless cout + [CORPS] Changed inteernal class vpCircle2D for ViSP vpImageCircle class --- doc/tutorial/imgproc/tutorial-imgproc-cht.dox | 4 +- .../visp3/imgproc/vpCircleHoughTransform.h | 112 +++--------------- .../imgproc/src/vpCircleHoughTransform.cpp | 62 ++++------ .../hough-transform/tutorial-circle-hough.cpp | 4 +- 4 files changed, 44 insertions(+), 138 deletions(-) diff --git a/doc/tutorial/imgproc/tutorial-imgproc-cht.dox b/doc/tutorial/imgproc/tutorial-imgproc-cht.dox index d1efce2c9c..9e311b291b 100644 --- a/doc/tutorial/imgproc/tutorial-imgproc-cht.dox +++ b/doc/tutorial/imgproc/tutorial-imgproc-cht.dox @@ -67,7 +67,7 @@ To run the software on an actual image using a JSON configuration file, please r $ ./tutorial-circle-hough --input /path/to/my/image --config config/detector_img.json ``` -**NB**: the configuration file `config/detector_img.json` has been tuned to detect coins in the image `coins2.pgm`. +__NB__ : the configuration file `config/detector_img.json` has been tuned to detect coins in the image `coins2.pgm`. If the detections seem a bit off, you might need to change the parameters. To run the software on an actual image using command line arguments instead, please run: @@ -142,7 +142,7 @@ 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 detections = detector.detect(I, num_best); +std::vector detections = detector.detect(I, num_best); \endcode Then, you can iterate on the vector of detections using a synthax similar to the following: diff --git a/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h b/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h index 904d522607..0050fc6f8d 100644 --- a/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h +++ b/modules/imgproc/include/visp3/imgproc/vpCircleHoughTransform.h @@ -40,6 +40,7 @@ // ViSP includes #include #include +#include #include #include #include @@ -330,76 +331,6 @@ class VISP_EXPORT vpCircleHoughTransform #endif }; - /** - * \brief Class that defines a 2D circle in an image. - */ - class vpCircle2D - { - public: - /*! - * Default constructor. - */ - vpCircle2D() : m_center(), m_radius(0.) { } - - /*! - * Constructor from a center and radius. - */ - vpCircle2D(const vpImagePoint ¢er, const float &radius) : m_center(center), m_radius(radius) { } - -#ifdef HAVE_OPENCV_CORE - /*! - * Constructor from an OpenCV vector that contains [center_x, center_y, radius]. - */ - vpCircle2D(const cv::Vec3f &vec) : m_center(vec[1], vec[0]), m_radius(vec[2]) { } -#endif - - /*! - * Default destructor. - */ - virtual ~vpCircle2D() { }; - - /*! - * Return the center of the 2D circle. - */ - vpImagePoint getCenter() const { return m_center; }; - - /*! - * Return the radius of the 2D circle. - */ - float getRadius() const { return m_radius; }; - - /*! - * Return the 2D circle bounding box. - */ - vpRect getBBox() const - { - vpRect bbox(m_center - vpImagePoint(m_radius, m_radius), 2 * m_radius, 2 * m_radius); - return bbox; - }; - - /*! - * Return normalized moment \f$n_{20}\f$. - */ - float get_n20() const { return m_radius * m_radius / 4; }; - - /*! - * Return normalized moment \f$n_{02}\f$. - */ - float get_n02() const { return m_radius * m_radius / 4; }; - - /*! - * Return normalized moment \f$n_{02}\f$. - */ - float get_n11() const { return 0.; }; - - template < typename Type > - void display(vpImage< Type > &img, const vpColor &color = vpColor::blue, const unsigned int &thickness = 1, const unsigned int &size = 5) const; - - private: - vpImagePoint m_center; - float m_radius; - }; - /** * \brief Construct a new vpCircleHoughTransform object with default parameters. */ @@ -424,9 +355,9 @@ class VISP_EXPORT vpCircleHoughTransform * \brief Perform Circle Hough Transform to detect the circles in an OpenCV image. * * \param[in] I The input gray scale image. - * \return std::vector The list of 2D circles detected in the image. + * \return std::vector The list of 2D circles detected in the image. */ - std::vector detect(const cv::Mat &cv_I); + std::vector detect(const cv::Mat &cv_I); #endif /** @@ -434,17 +365,17 @@ class VISP_EXPORT vpCircleHoughTransform * perform Circle Hough Transform to detect the circles in it * * \param[in] I The input color image. - * \return std::vector The list of 2D circles detected in the image. + * \return std::vector The list of 2D circles detected in the image. */ - std::vector detect(const vpImage &I); + std::vector detect(const vpImage &I); /** * \brief Perform Circle Hough Transform to detect the circles in a gray-scale image * * \param[in] I The input gray scale image. - * \return std::vector The list of 2D circles detected in the image. + * \return std::vector The list of 2D circles detected in the image. */ - std::vector detect(const vpImage &I); + std::vector detect(const vpImage &I); /** * \brief Perform Circle Hough Transform to detect the circles in in a gray-scale image. @@ -453,10 +384,10 @@ class VISP_EXPORT vpCircleHoughTransform * \param[in] I The input gray scale image. * \param[in] nbCircles The number of circles we want to get. If negative, all the circles will be * returned, sorted such as result[0] has the highest number of votes and result[end -1] the lowest. - * \return std::vector The list of 2D circles with the most number + * \return std::vector The list of 2D circles with the most number * of votes detected in the image. */ - std::vector detect(const vpImage &I, const int &nbCircles); + std::vector detect(const vpImage &I, const int &nbCircles); // // Configuration from files #ifdef VISP_HAVE_NLOHMANN_JSON @@ -689,10 +620,10 @@ class VISP_EXPORT vpCircleHoughTransform /** * \brief Get the Circle Candidates before merging step. * - * \return std::vector The list of circle candidates + * \return std::vector The list of circle candidates * that were obtained before the merging step. */ - inline std::vector getCircleCandidates() + inline std::vector getCircleCandidates() { return m_circleCandidates; } @@ -850,26 +781,11 @@ class VISP_EXPORT vpCircleHoughTransform std::vector m_centerVotes; /*!< Number of votes for the center candidates that are kept.*/ // // Circle candidates computation attributes - std::vector m_circleCandidates; /*!< List of the candidate circles.*/ + std::vector m_circleCandidates; /*!< List of the candidate circles.*/ std::vector m_circleCandidatesVotes; /*!< Number of votes for the candidate circles.*/ // // Circle candidates merging atttributes - std::vector m_finalCircles; /*!< List of the final circles, i.e. the ones resulting from the merge of the circle candidates.*/ + std::vector m_finalCircles; /*!< List of the final circles, i.e. the ones resulting from the merge of the circle candidates.*/ std::vector m_finalCircleVotes; /*!< Number of votes for the candidate circles.*/ }; - -/*! - * Display the \b vpCircle2D in an image. - * - * \param[in] img : Image used as background. - * \param[in] color : Color used to draw the CAD model. - * \param[in] thickness : Thickness used to draw the CAD model. - */ -template < typename Type > -inline void -vpCircleHoughTransform::vpCircle2D::display(vpImage< Type > &img, const vpColor &color, const unsigned int &thickness, const unsigned int &size) const -{ - vpImageDraw::drawCross(img, m_center, size, color, thickness); - vpImageDraw::drawCircle(img, m_center, m_radius, color, thickness); -} -#endif \ No newline at end of file +#endif diff --git a/modules/imgproc/src/vpCircleHoughTransform.cpp b/modules/imgproc/src/vpCircleHoughTransform.cpp index 0c4af49649..b14eee1b01 100644 --- a/modules/imgproc/src/vpCircleHoughTransform.cpp +++ b/modules/imgproc/src/vpCircleHoughTransform.cpp @@ -74,7 +74,7 @@ vpCircleHoughTransform::initGaussianFilters() vpImageFilter::getGaussianDerivativeKernel(m_fgDg.data, m_algoParams.m_gaussianKernelSize, m_algoParams.m_gaussianStdev, false); } -std::vector +std::vector vpCircleHoughTransform::detect(const vpImage &I) { vpImage I_gray; @@ -83,7 +83,7 @@ vpCircleHoughTransform::detect(const vpImage &I) } #ifdef HAVE_OPENCV_CORE -std::vector +std::vector vpCircleHoughTransform::detect(const cv::Mat &cv_I) { vpImage I_gray; @@ -92,20 +92,20 @@ vpCircleHoughTransform::detect(const cv::Mat &cv_I) } #endif -std::vector +std::vector vpCircleHoughTransform::detect(const vpImage &I, const int &nbCircles) { - std::vector detections = detect(I); + std::vector detections = detect(I); size_t nbDetections = detections.size(); - std::vector bestCircles; - std::vector> detectionsWithVotes; + std::vector bestCircles; + std::vector> detectionsWithVotes; for (size_t i = 0; i < nbDetections; i++) { - std::pair detectionWithVote(detections[i], m_finalCircleVotes[i]); + std::pair detectionWithVote(detections[i], m_finalCircleVotes[i]); detectionsWithVotes.push_back(detectionWithVote); } - bool (*hasMoreVotes)(std::pair, std::pair) - = [](std::pair a, std::pair b) + bool (*hasMoreVotes)(std::pair, std::pair) + = [](std::pair a, std::pair b) { // We divide the number of votes by the radius to avoid to favour big circles return (a.second / a.first.getRadius() > b.second / b.first.getRadius()); @@ -127,7 +127,7 @@ vpCircleHoughTransform::detect(const vpImage &I, const int &nbCir return bestCircles; } -std::vector +std::vector vpCircleHoughTransform::detect(const vpImage &I) { // Cleaning results of potential previous detection @@ -261,7 +261,7 @@ vpCircleHoughTransform::computeCenterCandidates() int offsetX = minimumXposition; int accumulatorWidth = maximumXposition - minimumXposition + 1; if (accumulatorWidth <= 0) { - std::cout << "Width <= 0 !" << std::endl << std::flush; + throw(vpException(vpException::dimensionError, "[vpCircleHoughTransform::computeCenterCandidates] Accumulator width <= 0!")); } // Computing the minimum and maximum vertical position of the center candidates @@ -275,7 +275,7 @@ vpCircleHoughTransform::computeCenterCandidates() int offsetY = minimumYposition; int accumulatorHeight = maximumYposition - minimumYposition + 1; if (accumulatorHeight <= 0) { - std::cout << "accumulatorHeight <= 0 !" << std::endl << std::flush; + throw(vpException(vpException::dimensionError, "[vpCircleHoughTransform::computeCenterCandidates] Accumulator height <= 0!")); } vpImage centersAccum(accumulatorHeight, accumulatorWidth + 1, 0.); /*!< Matrix that contains the votes for the center candidates.*/ @@ -293,9 +293,12 @@ vpCircleHoughTransform::computeCenterCandidates() float sx = m_dIx[r][c] / mag; float sy = m_dIy[r][c] / mag; + int int_minRad = (int)m_algoParams.m_minRadius; + int int_maxRad = (int)m_algoParams.m_maxRadius; + for (int k1 = 0; k1 < 2; k1++) { bool hasToStopLoop = false; - for (int rad = m_algoParams.m_minRadius; rad <= m_algoParams.m_maxRadius && !hasToStopLoop; rad++) { + for (int rad = int_minRad; rad <= int_maxRad && !hasToStopLoop; rad++) { float x1 = (float)c + (float)rad * sx; float y1 = (float)r + (float)rad * sy; @@ -449,8 +452,8 @@ vpCircleHoughTransform::computeCircleCandidates() // of Circle Candidates float r_effective = radiusActualValueList[idBin] / (float)radiusAccumList[idBin]; if ((float)radiusAccumList[idBin] / r_effective > m_algoParams.m_radiusRatioThresh) { - m_circleCandidates.push_back(vpCircle2D(vpImagePoint(centerCandidate.first, centerCandidate.second) - , r_effective + m_circleCandidates.push_back(vpImageCircle(vpImagePoint(centerCandidate.first, centerCandidate.second) + , r_effective ) ); m_circleCandidatesVotes.push_back(radiusAccumList[idBin]); @@ -463,15 +466,14 @@ void vpCircleHoughTransform::mergeCircleCandidates() { // For each circle candidate CiC_i do: - std::vector circleCandidates = m_circleCandidates; + std::vector circleCandidates = m_circleCandidates; std::vector circleCandidatesVotes = m_circleCandidatesVotes; size_t nbCandidates = m_circleCandidates.size(); for (size_t i = 0; i < nbCandidates; i++) { - vpCircle2D cic_i = circleCandidates[i]; + vpImageCircle cic_i = circleCandidates[i]; // // For each other circle candidate CiC_j do: - std::cout << "< CiC_" << i << " >" << std::endl; for (size_t j = i + 1; j < nbCandidates; j++) { - vpCircle2D cic_j = circleCandidates[j]; + vpImageCircle cic_j = circleCandidates[j]; // // // Compute the similarity between CiC_i and CiC_j double distanceBetweenCenters = vpImagePoint::distance(cic_i.getCenter(), cic_j.getCenter()); double radiusDifference = std::abs(cic_i.getRadius() - cic_j.getRadius()); @@ -484,12 +486,7 @@ vpCircleHoughTransform::mergeCircleCandidates() unsigned int totalVotes = circleCandidatesVotes[i] + circleCandidatesVotes[j]; float newRadius = (cic_i.getRadius() * circleCandidatesVotes[i] + cic_j.getRadius() * circleCandidatesVotes[j]) / totalVotes; vpImagePoint newCenter = (cic_i.getCenter() * circleCandidatesVotes[i]+ cic_j.getCenter() * circleCandidatesVotes[j]) / totalVotes; - std::cout << "\tPrev centers =\n\t" << cic_i.getCenter() << "\n\t" << cic_j.getCenter() << std::endl; - std::cout << "\tNew center = " << newCenter << std::endl; - std::cout << "\tPrev radii =\n\t" << cic_i.getRadius() << "\n\t" << cic_j.getRadius() << std::endl; - std::cout << "\tNew radius = " << newRadius << std::endl; - std::cout << "\tVotes =\n\t" << circleCandidatesVotes[i] << "\n\t" << circleCandidatesVotes[j] << std::endl; - cic_i = vpCircle2D(newCenter, newRadius); + cic_i = vpImageCircle(newCenter, newRadius); circleCandidates[j] = circleCandidates[nbCandidates - 1]; circleCandidatesVotes[i] = totalVotes; circleCandidatesVotes[j] = circleCandidatesVotes[nbCandidates - 1]; @@ -501,16 +498,14 @@ vpCircleHoughTransform::mergeCircleCandidates() } // // Add the circle candidate CiC_i, potentially merged with other circle candidates, to the final list of detected circles m_finalCircles.push_back(cic_i); - std::cout << "" << std::endl; } nbCandidates = m_finalCircles.size(); for (size_t i = 0; i < nbCandidates; i++) { - vpCircle2D cic_i = m_finalCircles[i]; + vpImageCircle cic_i = m_finalCircles[i]; // // For each other circle candidate CiC_j do: - std::cout << "< CiC_" << i << " >" << std::endl; for (size_t j = i + 1; j < nbCandidates; j++) { - vpCircle2D cic_j = m_finalCircles[j]; + vpImageCircle cic_j = m_finalCircles[j]; // // // Compute the similarity between CiC_i and CiC_j double distanceBetweenCenters = vpImagePoint::distance(cic_i.getCenter(), cic_j.getCenter()); double radiusDifference = std::abs(cic_i.getRadius() - cic_j.getRadius()); @@ -523,11 +518,7 @@ vpCircleHoughTransform::mergeCircleCandidates() unsigned int totalVotes = circleCandidatesVotes[i] + circleCandidatesVotes[j]; vpImagePoint newCenter = (cic_i.getCenter() * circleCandidatesVotes[i]+ cic_j.getCenter() * circleCandidatesVotes[j]) / totalVotes; float newRadius = (cic_i.getRadius() * circleCandidatesVotes[i] + cic_j.getRadius() * circleCandidatesVotes[j]) / totalVotes; - std::cout << "Prev centers =\n\t" << cic_i.getCenter() << "\n\t" << cic_j.getCenter() << std::endl; - std::cout << "New center = " << newCenter << std::endl; - std::cout << "Prev radii =\n\t" << cic_i.getRadius() << "\n\t" << cic_j.getRadius() << std::endl; - std::cout << "New radius = " << newRadius << std::endl; - cic_i = vpCircle2D(newCenter, newRadius); + cic_i = vpImageCircle(newCenter, newRadius); m_finalCircles[j] = m_finalCircles[nbCandidates - 1]; circleCandidatesVotes[i] = totalVotes; circleCandidatesVotes[j] = circleCandidatesVotes[nbCandidates - 1]; @@ -539,7 +530,6 @@ vpCircleHoughTransform::mergeCircleCandidates() } // // Add the circle candidate CiC_i, potentially merged with other circle candidates, to the final list of detected circles m_finalCircles[i] = cic_i; - std::cout << "" << std::endl; } m_finalCircleVotes = circleCandidatesVotes; } @@ -554,4 +544,4 @@ std::ostream &operator<<(std::ostream &os, const vpCircleHoughTransform &detecto { os << detector.toString(); return os; -} \ No newline at end of file +} diff --git a/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp index eaf71377c9..f13afa0c46 100644 --- a/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp +++ b/tutorial/imgproc/hough-transform/tutorial-circle-hough.cpp @@ -158,7 +158,7 @@ bool test_detection(const vpImage &I_src, vpCircleHoughTransform { double t0 = vpTime::measureTimeMicros(); //! [Run detection] - std::vector detectedCircles = detector.detect(I_src, nbCirclesToDetect); + std::vector detectedCircles = detector.detect(I_src, nbCirclesToDetect); //! [Run detection] double tF = vpTime::measureTimeMicros(); std::cout << "Process time = " << (tF - t0) * 0.001 << "ms" << std::endl << std::flush; @@ -170,7 +170,7 @@ bool test_detection(const vpImage &I_src, vpCircleHoughTransform unsigned int idColor = 0; //! [Iterate detections] for (auto circleCandidate : detectedCircles) { - circleCandidate.display(I_disp, v_colors[idColor], 2); + vpImageDraw::drawCircle(I_disp, circleCandidate, v_colors[idColor], 2); std::cout << "Circle #" << id << ":" << std::endl; std::cout << "\tCenter: (" << circleCandidate.getCenter() << ")" << std::endl; std::cout << "\tRadius: (" << circleCandidate.getRadius() << ")" << std::endl; From db9779ee5f37e02e843120c7f53ea7c982c93a5e Mon Sep 17 00:00:00 2001 From: rlagneau Date: Wed, 30 Aug 2023 11:46:21 +0200 Subject: [PATCH 17/20] Removed redundant vpImageMedian file (methods exist in vpImageFilter) + computation of the Canny threshold if the user set a negaitve value because it is already performed in the vpImageFilter::canny method --- .../core/include/visp3/core/vpImageFilter.h | 2 + modules/core/src/image/vpImageFilter.cpp | 8 +- .../visp3/imgproc/vpCircleHoughTransform.h | 2 +- .../include/visp3/imgproc/vpImageMedian.h | 59 --------- .../imgproc/src/vpCircleHoughTransform.cpp | 23 ++-- modules/imgproc/src/vpImageMedian.cpp | 115 ------------------ 6 files changed, 19 insertions(+), 190 deletions(-) delete mode 100644 modules/imgproc/include/visp3/imgproc/vpImageMedian.h delete mode 100644 modules/imgproc/src/vpImageMedian.cpp diff --git a/modules/core/include/visp3/core/vpImageFilter.h b/modules/core/include/visp3/core/vpImageFilter.h index ff986616ac..80fb105d4b 100644 --- a/modules/core/include/visp3/core/vpImageFilter.h +++ b/modules/core/include/visp3/core/vpImageFilter.h @@ -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 &I, double &lowerThresh); static double median(const cv::Mat &cv_I); static double median(const vpImage &Isrc); static std::vector median(const vpImage &Isrc); diff --git a/modules/core/src/image/vpImageFilter.cpp b/modules/core/src/image/vpImageFilter.cpp index 4908dbe0ad..8280b75b48 100644 --- a/modules/core/src/image/vpImageFilter.cpp +++ b/modules/core/src/image/vpImageFilter.cpp @@ -34,6 +34,7 @@ *****************************************************************************/ #include +#include #include #include #include @@ -214,7 +215,7 @@ std::vector vpImageFilter::median(const vpImage &Isrc) * \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) { cv::Mat cv_I_blur; if (p_cv_blur != nullptr) { @@ -245,7 +246,7 @@ double computeCannyThreshold(const cv::Mat &cv_I, const cv::Mat *p_cv_blur, doub * \param[in] I : The gray-scale image, in ViSP format. * \return double The upper Canny edge filter threshold. */ -double computeCannyThreshold(const vpImage &I, double &lowerThresh) +double vpImageFilter::computeCannyThreshold(const vpImage &I, double &lowerThresh) { cv::Mat cv_I; vpImageConvert::convert(I, cv_I); @@ -308,6 +309,9 @@ void vpImageFilter::canny(const vpImage &Isrc, vpImage #include #include +#include #include #include #include -#include // 3rd parties inclue #ifdef VISP_HAVE_NLOHMANN_JSON diff --git a/modules/imgproc/include/visp3/imgproc/vpImageMedian.h b/modules/imgproc/include/visp3/imgproc/vpImageMedian.h deleted file mode 100644 index 0f0f76749f..0000000000 --- a/modules/imgproc/include/visp3/imgproc/vpImageMedian.h +++ /dev/null @@ -1,59 +0,0 @@ -/**************************************************************************** - * - * ViSP, open source Visual Servoing Platform software. - * Copyright (C) 2005 - 2023 by Inria. All rights reserved. - * - * This software is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * See the file LICENSE.txt at the root directory of this source - * distribution for additional information about the GNU GPL. - * - * For using ViSP with software that can not be combined with the GNU - * GPL, please contact Inria about acquiring a ViSP Professional - * Edition License. - * - * See https://visp.inria.fr for more information. - * - * This software was developed at: - * Inria Rennes - Bretagne Atlantique - * Campus Universitaire de Beaulieu - * 35042 Rennes Cedex - * France - * - * If you have questions regarding the use of this file, please contact - * Inria at visp@inria.fr - * - * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE - * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * -*****************************************************************************/ - -#ifndef _vpImageMedian_h_ -#define _vpImageMedian_h_ - -#include -#include - -#if defined(HAVE_OPENCV_IMGPROC) - -#if (VISP_HAVE_OPENCV_VERSION >= 0x020408) -#include -#elif (VISP_HAVE_OPENCV_VERSION >= 0x020101) -#include -#else -#include -#endif - -namespace vp -{ -VISP_EXPORT double median(const cv::Mat &channel); - -VISP_EXPORT double computeCannyThreshold(const cv::Mat &cv_I); - -VISP_EXPORT double computeCannyThreshold(const vpImage &I); -} - -#endif -#endif diff --git a/modules/imgproc/src/vpCircleHoughTransform.cpp b/modules/imgproc/src/vpCircleHoughTransform.cpp index 12b95e0d78..8bcb7778e6 100644 --- a/modules/imgproc/src/vpCircleHoughTransform.cpp +++ b/modules/imgproc/src/vpCircleHoughTransform.cpp @@ -188,9 +188,6 @@ vpCircleHoughTransform::edgeDetection(const vpImage &I) int cannyThresh = m_algoParams.m_cannyThresh; // 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 = vp::computeCannyThreshold(I); - } vpImageFilter::canny(I, m_edgeMap, m_algoParams.m_gaussianKernelSize, cannyThresh, m_algoParams.m_sobelKernelSize); for (int i = 0; i < m_algoParams.m_edgeMapFilteringNbIter; i++) { @@ -328,16 +325,16 @@ vpCircleHoughTransform::computeCenterCandidates() const int &offsetX, const int &offsetY, const unsigned int &nbCols, const unsigned int &nbRows, vpImage &accum, bool &hasToStop) { - if (x - offsetX >= nbCols || - y - offsetY >= nbRows - ) { - hasToStop = true; - } - else { - float dx = (x_orig - (float)x); - float dy = (y_orig - (float)y); - accum[y - offsetY][x - offsetX] += std::abs(dx) + std::abs(dy); - } + if (x - offsetX >= nbCols || + y - offsetY >= nbRows + ) { + hasToStop = true; + } + else { + float dx = (x_orig - (float)x); + float dy = (y_orig - (float)y); + accum[y - offsetY][x - offsetX] += std::abs(dx) + std::abs(dy); + } }; updateAccumulator(x1, y1, x_low, y_low, diff --git a/modules/imgproc/src/vpImageMedian.cpp b/modules/imgproc/src/vpImageMedian.cpp deleted file mode 100644 index 92a35796d3..0000000000 --- a/modules/imgproc/src/vpImageMedian.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/**************************************************************************** - * - * ViSP, open source Visual Servoing Platform software. - * Copyright (C) 2005 - 2023 by Inria. All rights reserved. - * - * This software is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * See the file LICENSE.txt at the root directory of this source - * distribution for additional information about the GNU GPL. - * - * For using ViSP with software that can not be combined with the GNU - * GPL, please contact Inria about acquiring a ViSP Professional - * Edition License. - * - * See https://visp.inria.fr for more information. - * - * This software was developed at: - * Inria Rennes - Bretagne Atlantique - * Campus Universitaire de Beaulieu - * 35042 Rennes Cedex - * France - * - * If you have questions regarding the use of this file, please contact - * Inria at visp@inria.fr - * - * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE - * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * -*****************************************************************************/ - -#include - -#if defined(HAVE_OPENCV_IMGPROC) - -#include - -namespace vp -{ -/** - * \ingroup group_image_median - * Calculates the median value of a single channel - * based on https://github.com/arnaudgelas/OpenCVExamples/blob/master/cvMat/Statistics/Median/Median.cpp - * - * \param[in] channel : OpenCV input image. - * \return The median value of the input image. - */ -double median(const cv::Mat &channel) -{ - double m = (channel.rows * channel.cols) / 2; - int bin = 0; - double med = -1.0; - - int histSize = 256; - float range[] = { 0, 256 }; - const float *histRange = { range }; - bool uniform = true; - bool accumulate = false; - cv::Mat hist; - cv::calcHist(&channel, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange, uniform, accumulate); - - for (int i = 0; i < histSize && med < 0.0; ++i) { - bin += cvRound(hist.at(i)); - if (bin > m && med < 0.0) - med = i; - } - - return med; -} - -/** - * \ingroup group_image_median - * \brief Compute the upper Canny edge filter threshold based on image median. - * - * \param[in] cv_I : The image, in cv format. - * \return The upper Canny edge filter threshold. - * \sa median() - */ -double computeCannyThreshold(const cv::Mat &cv_I) -{ - cv::Mat cv_I_blur; - cv::GaussianBlur(cv_I, cv_I_blur, cv::Size(9, 9), 2, 2); - - // Subsample image to reach a 256 x 256 size - int req_size = 256; - int orig_size = std::min(static_cast(cv_I.rows), static_cast(cv_I.cols)); - int scale_down = std::max(1, static_cast(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); - - double median_pix = vp::median(cv_I_scaled_down); - // double lower = std::max(0., 0.7 * median_pix); // Unused, but to know the formula exists - double upper = std::min(255., 1.3 * median_pix); - upper = std::max(1., upper); - return upper; -} - -/** - * \ingroup group_image_median - * \brief Compute the upper Canny edge filter threshold based on image median. - * - * \param[in] I : The gray-scale image, in ViSP format. - * \return The upper Canny edge filter threshold. - * \sa median() - */ -double computeCannyThreshold(const vpImage &I) -{ - cv::Mat cv_I; - vpImageConvert::convert(I, cv_I); - return computeCannyThreshold(cv_I); -} -} // namespace ImageFilter - -#endif From 2e70005b09c93869c98375b97efef31804c9a64b Mon Sep 17 00:00:00 2001 From: rlagneau Date: Wed, 30 Aug 2023 11:50:12 +0200 Subject: [PATCH 18/20] [TUTO] Changed README section name --- tutorial/imgproc/hough-transform/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tutorial/imgproc/hough-transform/README.md b/tutorial/imgproc/hough-transform/README.md index d8127823aa..9693f7da7a 100644 --- a/tutorial/imgproc/hough-transform/README.md +++ b/tutorial/imgproc/hough-transform/README.md @@ -1,6 +1,6 @@ # tutorial-cht -## Running the tutorial-cht software +## Running the circle detection tutorial ### On synthetic images @@ -10,7 +10,7 @@ To use a JSON file as configuration, you need to install [JSON for modern C++](h To run the software on the synthetic images, 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 ${TARGET}_disks --config config/detector_${TARGET}.json ``` #### Using command lines @@ -18,7 +18,7 @@ $ ./tutorial-circle-hough --input ${TARGET}_disks --config config/detector_${TAR To run the software on the synthetic images without a JSON configuration file, please run: ``` $ TARGET=full # or TARGET=half # or TARGET=quarter -$ ./tutorial-circle-hough --input ${TARGET}_disks +$ ./tutorial-circle-hough --input ${TARGET}_disks ``` ### On actual images From 9c20c0c21c89b12d19b297c18e6af33a731b7580 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Wed, 30 Aug 2023 11:57:17 +0200 Subject: [PATCH 19/20] Removed useless dependancy for CHT tutorial --- tutorial/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorial/CMakeLists.txt b/tutorial/CMakeLists.txt index 5b811f2ba6..6196c0f941 100644 --- a/tutorial/CMakeLists.txt +++ b/tutorial/CMakeLists.txt @@ -44,7 +44,7 @@ visp_add_subdirectory(imgproc/contour REQUIRED_DEPS visp_co visp_add_subdirectory(imgproc/contrast-sharpening REQUIRED_DEPS visp_core visp_io visp_gui visp_imgproc) visp_add_subdirectory(imgproc/count-coins REQUIRED_DEPS visp_core visp_io visp_gui visp_imgproc) visp_add_subdirectory(imgproc/flood-fill REQUIRED_DEPS visp_core visp_io visp_gui visp_imgproc) -visp_add_subdirectory(imgproc/hough-transform REQUIRED_DEPS visp_core visp_gui visp_imgproc) +visp_add_subdirectory(imgproc/hough-transform REQUIRED_DEPS visp_core visp_gui) visp_add_subdirectory(munkres REQUIRED_DEPS visp_core visp_gui) visp_add_subdirectory(robot/flir-ptu REQUIRED_DEPS visp_core visp_robot visp_sensor visp_vision visp_gui visp_vs visp_visual_features visp_detection) visp_add_subdirectory(robot/pioneer REQUIRED_DEPS visp_core visp_robot visp_vs visp_gui) From dc114ddf86ec763c7e0858eea8d5e72e23e5b22e Mon Sep 17 00:00:00 2001 From: rlagneau Date: Wed, 30 Aug 2023 12:01:29 +0200 Subject: [PATCH 20/20] Put back visp_imgproc dependancy for CHT tutorial as vpCHT is defined in visp_imgproc --- tutorial/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorial/CMakeLists.txt b/tutorial/CMakeLists.txt index 6196c0f941..5b811f2ba6 100644 --- a/tutorial/CMakeLists.txt +++ b/tutorial/CMakeLists.txt @@ -44,7 +44,7 @@ visp_add_subdirectory(imgproc/contour REQUIRED_DEPS visp_co visp_add_subdirectory(imgproc/contrast-sharpening REQUIRED_DEPS visp_core visp_io visp_gui visp_imgproc) visp_add_subdirectory(imgproc/count-coins REQUIRED_DEPS visp_core visp_io visp_gui visp_imgproc) visp_add_subdirectory(imgproc/flood-fill REQUIRED_DEPS visp_core visp_io visp_gui visp_imgproc) -visp_add_subdirectory(imgproc/hough-transform REQUIRED_DEPS visp_core visp_gui) +visp_add_subdirectory(imgproc/hough-transform REQUIRED_DEPS visp_core visp_gui visp_imgproc) visp_add_subdirectory(munkres REQUIRED_DEPS visp_core visp_gui) visp_add_subdirectory(robot/flir-ptu REQUIRED_DEPS visp_core visp_robot visp_sensor visp_vision visp_gui visp_vs visp_visual_features visp_detection) visp_add_subdirectory(robot/pioneer REQUIRED_DEPS visp_core visp_robot visp_vs visp_gui)