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;
102 std::ifstream file(jsonPath);
104 std::stringstream ss;
105 ss <<
"Problem opening file " << jsonPath <<
". Make sure it exists and is readable" << std::endl;
110 j = json::parse(file);
112 catch (json::parse_error &e) {
113 std::stringstream msg;
114 msg <<
"Could not parse JSON file : \n";
116 msg << e.what() << std::endl;
117 msg <<
"Byte position of error: " << e.byte;
136 const int filterHalfSize = (
m_algoParams.m_gaussianKernelSize + 1) / 2;
145 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
148 const unsigned int nbRows = filter.
getRows();
149 const unsigned int nbCols = filter.
getCols();
150 for (
unsigned int r = 0; r < nbRows; ++r) {
151 for (
unsigned int c = 0; c < nbCols; ++c) {
152 filter[r][c] = filter[r][c] * scale;
158 const int moduloCheckForOddity = 2;
159 if ((
m_algoParams.m_gradientFilterKernelSize % moduloCheckForOddity) != 1) {
168 unsigned int filterHalfSize = (
m_algoParams.m_gradientFilterKernelSize - 1) / 2;
181 std::string errMsg =
"[vpCircleHoughTransform::initGradientFilters] Error: gradient filtering method \"";
183 errMsg +=
"\" has not been implemented yet\n";
190 std::vector<vpImageCircle>
198 #ifdef HAVE_OPENCV_CORE
199 std::vector<vpImageCircle>
208 std::vector<vpImageCircle>
211 std::vector<vpImageCircle> detections =
detect(I);
212 size_t nbDetections = detections.size();
215 std::vector<std::pair<size_t, float> > v_id_proba;
216 for (
size_t i = 0; i < nbDetections; ++i) {
218 v_id_proba.push_back(id_proba);
221 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
224 = [](std::pair<size_t, float> a, std::pair<size_t, float> b) {
225 return (a.second > b.second);
228 std::sort(v_id_proba.begin(), v_id_proba.end(), hasBetterProba);
234 limitMin = nbDetections;
237 limitMin = std::min(nbDetections,
static_cast<size_t>(nbCircles));
240 std::vector<vpImageCircle> bestCircles;
245 for (
size_t i = 0; i < nbDetections; ++i) {
246 size_t id = v_id_proba[i].first;
261 std::vector<vpImageCircle>
279 const float minRadiusDiff = 3.f;
293 const float minCenterPositionDiff = 3.f;
295 m_algoParams.m_centerXlimits.second +=
static_cast<int>(minCenterPositionDiff / 2.f);
296 m_algoParams.m_centerXlimits.first -=
static_cast<int>(minCenterPositionDiff / 2.f);
299 m_algoParams.m_centerYlimits.second +=
static_cast<int>(minCenterPositionDiff / 2.f);
300 m_algoParams.m_centerYlimits.first -=
static_cast<int>(minCenterPositionDiff / 2.f);
335 bool haveSameCenter = (std::abs(aCenter.
get_u() - bCenter.
get_u())
336 + std::abs(aCenter.
get_v() - bCenter.
get_v())) <= (2. * std::numeric_limits<double>::epsilon());
337 bool haveSameRadius = std::abs(a.
getRadius() - b.
getRadius()) <= (2.f * std::numeric_limits<float>::epsilon());
338 return (haveSameCenter && haveSameRadius);
341 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
343 std::optional<
vpImage<bool> > &mask, std::optional<std::vector<std::vector<std::pair<unsigned int, unsigned int>>>> &opt_votingPoints)
const
346 vpImage<bool> **mask, std::vector<std::vector<std::pair<unsigned int, unsigned int> > > **opt_votingPoints)
const
349 if (!m_algoParams.m_recordVotingPoints) {
351 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
353 opt_votingPoints = std::nullopt;
356 *opt_votingPoints =
nullptr;
361 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
363 opt_votingPoints = std::vector<std::vector<std::pair<unsigned int, unsigned int>>>();
366 *opt_votingPoints =
new std::vector<std::vector<std::pair<unsigned int, unsigned int> > >();
369 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
370 for (
const auto &detection : detections)
372 const size_t nbDetections = detections.size();
373 for (
size_t i = 0; i < nbDetections; ++i)
376 bool hasFoundSimilarCircle =
false;
377 unsigned int nbPreviouslyDetected =
static_cast<unsigned int>(m_finalCircles.size());
380 while ((
id < nbPreviouslyDetected) && (!hasFoundSimilarCircle)) {
382 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
383 if (previouslyDetected == detection)
385 if (previouslyDetected == detections[i])
388 hasFoundSimilarCircle =
true;
390 const unsigned int nbVotingPoints =
static_cast<unsigned int>(m_finalCirclesVotingPoints[id].size());
391 for (
unsigned int idPoint = 0; idPoint < nbVotingPoints; ++idPoint) {
392 const std::pair<unsigned int, unsigned int> &votingPoint = m_finalCirclesVotingPoints[id][idPoint];
393 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
394 (*mask)[votingPoint.first][votingPoint.second] =
true;
396 (**mask)[votingPoint.first][votingPoint.second] =
true;
399 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
400 opt_votingPoints->push_back(m_finalCirclesVotingPoints[
id]);
402 (**opt_votingPoints).push_back(m_finalCirclesVotingPoints[
id]);
420 std::cout <<
"\tUse mask: " << (detector.
mp_mask ==
nullptr ?
"false" :
"true") << std::endl;
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