139 nbBins = std::max<int>(
static_cast<int>(1), nbBins);
140 std::vector<float> radiusAccumList;
141 std::vector<float> radiusActualValueList;
148 data.m_nbBins = nbBins;
149 data.m_circlePerfectness2 = circlePerfectness2;
151 data.m_mergingRadiusDiffThresh =
m_algoParams.m_mergingRadiusDiffThresh;
152 data.m_recordVotingPoints =
m_algoParams.m_recordVotingPoints;
154 for (
size_t i = 0; i < nbCenterCandidates; ++i) {
155 std::vector<std::vector<std::pair<unsigned int, unsigned int> > > votingPoints(nbBins);
158 radiusAccumList.clear();
159 radiusAccumList.resize(nbBins, 0);
160 radiusActualValueList.clear();
161 radiusActualValueList.resize(nbBins, 0.);
163 const unsigned int nbEdgePoints =
static_cast<unsigned int>(
m_edgePointsList.size());
164 for (
unsigned int e = 0; e < nbEdgePoints; ++e) {
165 const std::pair<unsigned int, unsigned int> &edgePoint =
m_edgePointsList[e];
168 float rx = edgePoint.second - centerCandidate.second;
169 float ry = edgePoint.first - centerCandidate.first;
170 float r2 = (rx * rx) + (ry * ry);
171 if ((r2 > rmin2) && (r2 < rmax2)) {
172 data.m_centerCandidate = centerCandidate;
173 data.m_edgePoint = edgePoint;
177 updateRadiusAccumulator(data, radiusAccumList, radiusActualValueList, votingPoints);
181#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
183 auto computeEffectiveRadius = [](
const float &votes,
const float &weigthedSumRadius) {
184 float r_effective = -1.f;
185 if (votes > std::numeric_limits<float>::epsilon()) {
186 r_effective = weigthedSumRadius / votes;
193 std::vector<float> v_r_effective;
194 std::vector<float> v_votes_effective;
195 std::vector<std::vector<std::pair<unsigned int, unsigned int> > > v_votingPoints_effective;
196 std::vector<bool> v_hasMerged_effective;
197 for (
int idBin = 0; idBin < nbBins; ++idBin) {
198 float r_effective = computeEffectiveRadius(radiusAccumList[idBin], radiusActualValueList[idBin]);
199 float votes_effective = radiusAccumList[idBin];
200 std::vector<std::pair<unsigned int, unsigned int> > votingPoints_effective = votingPoints[idBin];
201 bool is_r_effective_similar = (r_effective > 0.f);
204 int idCandidate = idBin + 1;
205 bool hasMerged =
false;
206 while ((idCandidate < nbBins) && is_r_effective_similar) {
207 float r_effective_candidate = computeEffectiveRadius(radiusAccumList[idCandidate], radiusActualValueList[idCandidate]);
208 if (std::abs(r_effective_candidate - r_effective) <
m_algoParams.m_mergingRadiusDiffThresh) {
209 r_effective = ((r_effective * votes_effective) + (r_effective_candidate * radiusAccumList[idCandidate])) / (votes_effective + radiusAccumList[idCandidate]);
210 votes_effective += radiusAccumList[idCandidate];
211 radiusAccumList[idCandidate] = -.1f;
212 radiusActualValueList[idCandidate] = -1.f;
213 is_r_effective_similar =
true;
217#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
218 votingPoints_effective.insert(
219 votingPoints_effective.end(),
220 std::make_move_iterator(votingPoints[idCandidate].begin()),
221 std::make_move_iterator(votingPoints[idCandidate].end())
224 votingPoints_effective.insert(
225 votingPoints_effective.end(),
226 votingPoints[idCandidate].begin(),
227 votingPoints[idCandidate].end()
234 is_r_effective_similar =
false;
239 if ((votes_effective >
m_algoParams.m_centerMinThresh) && (votes_effective >= (
m_algoParams.m_circleVisibilityRatioThresh * 2.f * M_PI_FLOAT * r_effective))) {
241 v_r_effective.push_back(r_effective);
242 v_votes_effective.push_back(votes_effective);
244 v_votingPoints_effective.push_back(votingPoints_effective);
245 v_hasMerged_effective.push_back(hasMerged);
250 unsigned int nbCandidates =
static_cast<unsigned int>(v_r_effective.size());
251 for (
unsigned int idBin = 0; idBin < nbCandidates; ++idBin) {
254 float r_effective = v_r_effective[idBin];
262 if (v_hasMerged_effective[idBin]) {
264 std::sort(v_votingPoints_effective[idBin].begin(), v_votingPoints_effective[idBin].end());
265 v_votingPoints_effective[idBin].erase(std::unique(v_votingPoints_effective[idBin].begin(), v_votingPoints_effective[idBin].end()), v_votingPoints_effective[idBin].end());
318 std::vector<float> &circleCandidatesProba, std::vector<std::vector<std::pair<unsigned int, unsigned int> > > &votingPoints)
320 size_t nbCandidates = circleCandidates.size();
322 while (i < nbCandidates) {
324 bool hasPerformedMerge =
false;
327 while (j < nbCandidates) {
332 bool areCirclesSimilar = ((distanceBetweenCenters <
m_algoParams.m_centerMinDist)
333 && (radiusDifference <
m_algoParams.m_mergingRadiusDiffThresh)
336 if (areCirclesSimilar) {
337 hasPerformedMerge =
true;
339 unsigned int totalVotes = circleCandidatesVotes[i] + circleCandidatesVotes[j];
340 float totalProba = circleCandidatesProba[i] + circleCandidatesProba[j];
341 float newProba = 0.5f * totalProba;
342 float newRadius = ((cic_i.
getRadius() * circleCandidatesProba[i]) + (cic_j.
getRadius() * circleCandidatesProba[j])) / totalProba;
345 circleCandidates[j] = circleCandidates[nbCandidates - 1];
346 const unsigned int var2 = 2;
347 circleCandidatesVotes[i] = totalVotes / var2;
348 circleCandidatesVotes[j] = circleCandidatesVotes[nbCandidates - 1];
349 circleCandidatesProba[i] = newProba;
350 circleCandidatesProba[j] = circleCandidatesProba[nbCandidates - 1];
352#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
353 votingPoints[i].insert(
354 votingPoints[i].end(),
355 std::make_move_iterator(votingPoints[j].begin()),
356 std::make_move_iterator(votingPoints[j].end())
359 votingPoints[i].insert(
360 votingPoints[i].end(),
361 votingPoints[j].begin(),
362 votingPoints[j].end()
365 votingPoints.pop_back();
367 circleCandidates.pop_back();
368 circleCandidatesVotes.pop_back();
369 circleCandidatesProba.pop_back();
379 circleCandidates[i] = cic_i;
380 if (hasPerformedMerge &&
m_algoParams.m_recordVotingPoints) {
382 std::sort(votingPoints[i].begin(), votingPoints[i].end());
383 votingPoints[i].erase(std::unique(votingPoints[i].begin(), votingPoints[i].end()), votingPoints[i].end());