31 #include <visp3/core/vpImageConvert.h>
32 #include <visp3/core/vpImageMorphology.h>
34 #include <visp3/imgproc/vpCircleHoughTransform.h>
38 #if (VISP_CXX_STANDARD == VISP_CXX_STANDARD_98)
43 bool hasBetterProba(std::pair<size_t, float> a, std::pair<size_t, float> b)
45 return (a.second > b.second);
52 unsigned int nbRows = filter.
getRows();
53 unsigned int nbCols = filter.
getCols();
54 for (
unsigned int r = 0; r < nbRows; ++r) {
55 for (
unsigned int c = 0; c < nbCols; ++c) {
56 filter[r][c] = filter[r][c] * scale;
72 : m_algoParams(algoParams)
90 #ifdef VISP_HAVE_NLOHMANN_JSON
91 using json = nlohmann::json;
101 std::ifstream file(jsonPath);
103 std::stringstream ss;
104 ss <<
"Problem opening file " << jsonPath <<
". Make sure it exists and is readable" << std::endl;
109 j = json::parse(file);
111 catch (json::parse_error &e) {
112 std::stringstream msg;
113 msg <<
"Could not parse JSON file : \n";
115 msg << e.what() << std::endl;
116 msg <<
"Byte position of error: " << e.byte;
135 const int filterHalfSize = (
m_algoParams.m_gaussianKernelSize + 1) / 2;
144 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
147 const unsigned int nbRows = filter.
getRows();
148 const unsigned int nbCols = filter.
getCols();
149 for (
unsigned int r = 0; r < nbRows; ++r) {
150 for (
unsigned int c = 0; c < nbCols; ++c) {
151 filter[r][c] = filter[r][c] * scale;
157 const int moduloCheckForOddity = 2;
158 if ((
m_algoParams.m_gradientFilterKernelSize % moduloCheckForOddity) != 1) {
167 unsigned int filterHalfSize = (
m_algoParams.m_gradientFilterKernelSize - 1) / 2;
180 std::string errMsg =
"[vpCircleHoughTransform::initGradientFilters] Error: gradient filtering method \"";
182 errMsg +=
"\" has not been implemented yet\n";
189 std::vector<vpImageCircle>
197 #ifdef HAVE_OPENCV_CORE
198 std::vector<vpImageCircle>
207 std::vector<vpImageCircle>
210 std::vector<vpImageCircle> detections =
detect(I);
211 size_t nbDetections = detections.size();
214 std::vector<std::pair<size_t, float> > v_id_proba;
215 for (
size_t i = 0; i < nbDetections; ++i) {
217 v_id_proba.push_back(id_proba);
220 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
223 = [](std::pair<size_t, float> a, std::pair<size_t, float> b) {
224 return (a.second > b.second);
227 std::sort(v_id_proba.begin(), v_id_proba.end(), hasBetterProba);
233 limitMin = nbDetections;
236 limitMin = std::min(nbDetections,
static_cast<size_t>(nbCircles));
239 std::vector<vpImageCircle> bestCircles;
244 for (
size_t i = 0; i < nbDetections; ++i) {
245 size_t id = v_id_proba[i].first;
260 std::vector<vpImageCircle>
275 const float minRadiusDiff = 3.f;
289 const float minCenterPositionDiff = 3.f;
291 m_algoParams.m_centerXlimits.second +=
static_cast<int>(minCenterPositionDiff / 2.f);
292 m_algoParams.m_centerXlimits.first -=
static_cast<int>(minCenterPositionDiff / 2.f);
295 m_algoParams.m_centerYlimits.second +=
static_cast<int>(minCenterPositionDiff / 2.f);
296 m_algoParams.m_centerYlimits.first -=
static_cast<int>(minCenterPositionDiff / 2.f);
331 bool haveSameCenter = (std::abs(aCenter.
get_u() - bCenter.
get_u())
332 + std::abs(aCenter.
get_v() - bCenter.
get_v())) <= (2. * std::numeric_limits<double>::epsilon());
333 bool haveSameRadius = std::abs(a.
getRadius() - b.
getRadius()) <= (2.f * std::numeric_limits<float>::epsilon());
334 return (haveSameCenter && haveSameRadius);
337 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
339 std::optional<
vpImage<bool> > &mask, std::optional<std::vector<std::vector<std::pair<unsigned int, unsigned int>>>> &opt_votingPoints)
const
342 vpImage<bool> **mask, std::vector<std::vector<std::pair<unsigned int, unsigned int> > > **opt_votingPoints)
const
345 if (!m_algoParams.m_recordVotingPoints) {
347 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
349 opt_votingPoints = std::nullopt;
352 *opt_votingPoints =
nullptr;
357 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
359 opt_votingPoints = std::vector<std::vector<std::pair<unsigned int, unsigned int>>>();
362 *opt_votingPoints =
new std::vector<std::vector<std::pair<unsigned int, unsigned int> > >();
365 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
366 for (
const auto &detection : detections)
368 const size_t nbDetections = detections.size();
369 for (
size_t i = 0; i < nbDetections; ++i)
372 bool hasFoundSimilarCircle =
false;
373 unsigned int nbPreviouslyDetected =
static_cast<unsigned int>(m_finalCircles.size());
376 while ((
id < nbPreviouslyDetected) && (!hasFoundSimilarCircle)) {
378 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
379 if (previouslyDetected == detection)
381 if (previouslyDetected == detections[i])
384 hasFoundSimilarCircle =
true;
386 const unsigned int nbVotingPoints =
static_cast<unsigned int>(m_finalCirclesVotingPoints[id].size());
387 for (
unsigned int idPoint = 0; idPoint < nbVotingPoints; ++idPoint) {
388 const std::pair<unsigned int, unsigned int> &votingPoint = m_finalCirclesVotingPoints[id][idPoint];
389 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
390 (*mask)[votingPoint.first][votingPoint.second] =
true;
392 (**mask)[votingPoint.first][votingPoint.second] =
true;
395 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
396 opt_votingPoints->push_back(m_finalCirclesVotingPoints[
id]);
398 (**opt_votingPoints).push_back(m_finalCirclesVotingPoints[
id]);
bool operator==(const vpArray2D< double > &A) const
unsigned int getCols() const
Type * data
Address of the first element of the data array.
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
friend std::ostream & operator<<(std::ostream &s, const vpArray2D< Type > &A)
unsigned int getRows() const
void setGradientFilterAperture(const unsigned int &apertureSize)
Set the parameters of the gradient filter (Sobel or Scharr) kernel size filters.
void setGaussianFilterParameters(const int &kernelSize, const float &stdev)
Set the Gaussian Filters kernel size and standard deviation and initialize the aforementioned filters...
error that can be emitted by ViSP classes.
@ badValue
Used to indicate that a value is not in the allowed range.
@ notImplementedError
Not implemented.
Class that defines a 2D circle in an image.
vpImagePoint getCenter() const
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
static FilterType getSobelKernelX(FilterType *filter, unsigned int size)
static std::string vpCannyFiltAndGradTypeToStr(const vpCannyFilteringAndGradientType &type)
Cast a vpImageFilter::vpCannyFilteringAndGradientType into a string, to know its name.
@ CANNY_GBLUR_SOBEL_FILTERING
Apply Gaussian blur + Sobel operator on the input image.
@ CANNY_GBLUR_SCHARR_FILTERING
Apply Gaussian blur + Scharr operator on the input image.
static void getGaussianKernel(FilterType *filter, unsigned int size, FilterType sigma=0., bool normalize=true)
static FilterType getScharrKernelY(FilterType *filter, unsigned int size)
static FilterType getSobelKernelY(FilterType *filter, unsigned int size)
static FilterType getScharrKernelX(FilterType *filter, unsigned int size)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
unsigned int getWidth() const
unsigned int getHeight() const