ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
TreeIso.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "TreeIso.h"
9 
10 #include "TreeIsoHelper.h"
11 
12 // CC
13 #include <ecvMainAppInterface.h>
14 #include <ecvQtHelpers.h>
15 
16 // qCC_db
17 #include <ecvPointCloud.h>
18 
19 // Qt
20 #include <QCoreApplication>
21 #include <QElapsedTimer>
22 #include <QProgressDialog>
23 
24 // system
25 #include <cmath>
26 #include <fstream>
27 #include <iomanip>
28 #include <iostream>
29 #include <sstream>
30 
31 // Boost
32 #include <boost/geometry.hpp>
33 #include <boost/geometry/geometries/point_xy.hpp>
34 #include <boost/geometry/geometries/polygon.hpp>
35 
36 typedef boost::geometry::model::d2::point_xy<double> point_xy;
37 typedef boost::geometry::model::polygon<point_xy> polygon;
38 typedef boost::geometry::model::multi_point<point_xy> multi_point;
39 typedef boost::geometry::model::multi_polygon<polygon> multi_polygon;
40 
41 typedef std::vector<float> Vec3d;
42 
43 // custom
44 using namespace CP;
45 
46 // scalar field names
47 static const char InitSegsSFName[] = "init_segs";
48 static const char IntermedSegsSFName[] = "intermediate_segs";
49 static const char FinalSegsSFName[] = "final_segs";
50 
51 template <class result_t = std::chrono::milliseconds,
52  class clock_t = std::chrono::steady_clock,
53  class duration_t = std::chrono::milliseconds>
54 static auto Since(std::chrono::time_point<clock_t, duration_t> const& start) {
55  return std::chrono::duration_cast<result_t>(clock_t::now() - start);
56 }
57 
59  const unsigned min_nn1,
60  const float regStrength1,
61  const float PR_DECIMATE_RES1,
62  QProgressDialog* progressDlg /*=nullptr*/) {
63  if (!pc) {
64  assert(false);
65  return false;
66  }
67 
68  if (progressDlg) {
69  progressDlg->setRange(0, 100);
70  }
71 
72  auto start = std::chrono::steady_clock::now(); // start timer
73 
74  const unsigned pointCount = pc->size();
75 
76  std::vector<Vec3d> pc_vec;
77  toTranslatedVector(pc, pc_vec);
78 
79  if (progressDlg) {
80  progressDlg->setValue(10);
81  QCoreApplication::processEvents();
82  }
83 
84  std::vector<size_t> ia, ic;
85  std::vector<Vec3d> pc_dec, pc_sub;
86  decimate_vec(pc_vec, PR_DECIMATE_RES1, pc_dec);
87  unique_index_by_rows(pc_dec, ia, ic);
88  get_subset(pc_vec, ia, pc_sub);
89 
90  if (progressDlg) {
91  progressDlg->setValue(30);
92  QCoreApplication::processEvents();
93  }
94 
95  const unsigned K = (min_nn1 - 1);
96  Vec3d edgeWeight;
97  std::vector<uint32_t> Eu;
98  std::vector<uint32_t> Ev;
99  std::vector<uint32_t> in_component;
100  std::vector<std::vector<uint32_t>> components;
101 
102  perform_cut_pursuit(K, regStrength1, pc_sub, edgeWeight, Eu, Ev,
103  in_component, components);
104 
105  if (progressDlg) {
106  progressDlg->setValue(90);
107  QCoreApplication::processEvents();
108  }
109 
110  // export segments as a new scalar field
111  int outSFIndex = pc->getScalarFieldIndexByName(InitSegsSFName);
112  if (outSFIndex < 0) {
113  outSFIndex = pc->addScalarField(InitSegsSFName);
114  if (outSFIndex < 0) {
115  CVLog::Error("[TreeIso] Not enough memory!");
116  return false;
117  }
118  }
119  cloudViewer::ScalarField* outSF = pc->getScalarField(outSFIndex);
120  outSF->fill(NAN_VALUE);
121 
122  std::vector<uint32_t> clusterIdx(pointCount);
123  for (unsigned i = 0; i < pointCount; ++i) {
124  clusterIdx[i] = in_component[ic[i]];
125  outSF->setValue(i, in_component[ic[i]]);
126  }
127  outSF->computeMinAndMax();
128  pc->colorsHaveChanged();
129  pc->setCurrentDisplayedScalarField(outSFIndex);
130  pc->showSF(true);
131 
132  auto elapsed = Since(start).count() / 1000;
133  CVLog::Print(QString("[TreeIso] Init segs took %1 seconds").arg(elapsed));
134 
135  if (progressDlg) {
136  progressDlg->setValue(100);
137  QCoreApplication::processEvents();
138  }
139 
140  return true;
141 }
142 
144  const unsigned PR_MIN_NN2,
145  const float PR_REG_STRENGTH2,
146  const float PR_DECIMATE_RES2,
147  const float PR_MAX_GAP,
148  QProgressDialog* progressDlg /*=nullptr*/) {
149  if (!pc) {
150  assert(false);
151  return false;
152  }
153 
154  if (progressDlg) {
155  progressDlg->setRange(0, 100);
156  }
157 
158  auto start = std::chrono::steady_clock::now();
159 
160  unsigned pointCount = pc->size();
161 
162  int initSFIndex = pc->getScalarFieldIndexByName(InitSegsSFName);
163  if (initSFIndex < 0) {
164  CVLog::Error("[TreeIso] Please run initial segmentation first!");
165  return false;
166  }
167  cloudViewer::ScalarField* initSF = pc->getScalarField(initSFIndex);
168 
169  std::vector<uint32_t> in_component;
170  try {
171  in_component.resize(pointCount);
172  } catch (const std::bad_alloc&) {
173  CVLog::Error("[TreeIso] Not enough memory");
174  return false;
175  }
176  for (unsigned i = 0; i < pointCount; ++i) {
177  in_component[i] = initSF->getValue(i);
178  }
179  std::vector<std::vector<uint32_t>> clusterVGroup;
180  unique_group(in_component, clusterVGroup);
181 
182  std::vector<Vec3d> pc_vec;
183  toTranslatedVector(pc, pc_vec);
184 
185  size_t n_clusters = clusterVGroup.size();
186 
187  std::vector<Vec3d> clusterCentroids(n_clusters);
188  std::vector<std::vector<Vec3d>> currentClusterDecs(n_clusters);
189  std::vector<std::vector<size_t>> currentClusterDecsICs(n_clusters);
190 
191  for (size_t i = 0; i < n_clusters; ++i) {
192  std::vector<Vec3d> currentClusterPos;
193  get_subset(pc_vec, clusterVGroup[i], currentClusterPos);
194 
195  if (currentClusterPos.size() > 1) {
196  std::vector<size_t> ia, ic;
197  std::vector<Vec3d> currentClusterPosDec;
198  decimate_vec(currentClusterPos, PR_DECIMATE_RES2,
199  currentClusterPosDec);
200  unique_index_by_rows(currentClusterPosDec, ia, ic);
201 
202  std::vector<Vec3d> currentClusterPosUnq;
203  get_subset(currentClusterPos, ia, currentClusterPosUnq);
204  currentClusterDecs[i] = currentClusterPosUnq;
205 
206  mean_col(currentClusterPos, clusterCentroids[i]);
207  currentClusterDecsICs[i] = ic;
208  } else {
209  currentClusterDecs[i] = currentClusterPos;
210  clusterCentroids[i] = currentClusterPos[0];
211  currentClusterDecsICs[i] = std::vector<size_t>(1, 0);
212  }
213  }
214 
215  if (progressDlg) {
216  progressDlg->setValue(10);
217  QCoreApplication::processEvents();
218  }
219 
220  std::vector<std::vector<uint32_t>> minIdxsC;
221  std::vector<Vec3d> minIdxsD;
222  knn_cpp_nearest_neighbors(clusterCentroids, PR_MIN_NN2, minIdxsC, minIdxsD,
223  8);
224 
225  if (progressDlg) {
226  progressDlg->setValue(15);
227  QCoreApplication::processEvents();
228  }
229 
230  size_t n_centroids = minIdxsC.size();
231  if (n_centroids == 0) {
232  assert(false);
233  return false;
234  }
235  size_t n_K = minIdxsC[0].size();
236  std::vector<Eigen::MatrixXf> currentClusterDecMats;
237  std::vector<
239  knn_kdtrees;
240  for (size_t i = 0; i < n_centroids; ++i) {
241  std::vector<Vec3d> currentClusterDec = currentClusterDecs[i];
242  Eigen::MatrixXf currentClusterDecMat(currentClusterDec[0].size(),
243  currentClusterDec.size());
244  for (size_t k = 0; k < currentClusterDec.size(); k++) {
245  currentClusterDecMat.col(k) = Eigen::VectorXf::Map(
246  &currentClusterDec[k][0], currentClusterDec[k].size());
247  }
248  currentClusterDecMats.push_back(currentClusterDecMat);
249  }
250 
251  if (progressDlg) {
252  progressDlg->setValue(20);
253  QCoreApplication::processEvents();
254  }
255 
256  std::vector<Vec3d> nnDists;
257  nnDists.resize(n_centroids, Vec3d(n_K));
258  for (size_t i = 0; i < n_centroids; ++i) {
260  knn_kdtree(currentClusterDecMats[minIdxsC[i][0]]);
261  knn_cpp_build(knn_kdtree);
262  for (size_t j = 1; j < n_K; ++j) {
263  if (minIdxsD[i][j] > 0) {
264  std::vector<std::vector<size_t>> min_c;
265  std::vector<Vec3d> min_D2;
266  float min_D = knn_cpp_query_min_d(
267  knn_kdtree, currentClusterDecMats[minIdxsC[i][j]], 1);
268  nnDists[i][j] = min_D;
269  }
270  }
271  }
272 
273  if (progressDlg) {
274  progressDlg->setValue(40);
275  QCoreApplication::processEvents();
276  }
277 
278  std::vector<Vec3d> currentClusterDecsFlat;
279  std::vector<size_t> currentClusterDecsFlatIndex;
280  std::vector<size_t> currentClusterDecsICsFlatIndex;
281  std::vector<uint32_t> currentClusterDecsIDs;
282 
283  for (auto& vec : clusterVGroup) {
284  currentClusterDecsIDs.insert(currentClusterDecsIDs.end(),
285  std::make_move_iterator(vec.begin()),
286  std::make_move_iterator(vec.end()));
287  }
288  for (auto& vec : currentClusterDecs) {
289  currentClusterDecsFlat.insert(currentClusterDecsFlat.end(),
290  std::make_move_iterator(vec.begin()),
291  std::make_move_iterator(vec.end()));
292  currentClusterDecsICsFlatIndex.insert(
293  currentClusterDecsICsFlatIndex.end(), vec.size());
294  }
295 
296  for (unsigned i = 0; i < currentClusterDecs.size(); i++) {
297  for (unsigned j = 0; j < currentClusterDecs[i].size(); ++j) {
298  currentClusterDecsFlatIndex.push_back(i);
299  }
300  }
301 
302  if (progressDlg) {
303  progressDlg->setValue(50);
304  QCoreApplication::processEvents();
305  }
306 
307  size_t nNodes = currentClusterDecsFlat.size();
308  unsigned nKs = PR_MIN_NN2;
309 
310  std::vector<std::vector<uint32_t>> minIdxs;
311  std::vector<Vec3d> Ds;
312  knn_cpp_nearest_neighbors(currentClusterDecsFlat, PR_MIN_NN2, minIdxs, Ds,
313  8);
314 
315  Vec3d edgeWeight;
316  std::vector<uint32_t> Eu;
317  std::vector<uint32_t> Ev;
318 
319  for (size_t i = 0; i < minIdxs.size(); i++) {
320  size_t currentNode = currentClusterDecsFlatIndex[i];
321  Vec3d currentDists = nnDists[currentNode];
322  for (size_t j = 1; j < minIdxs[0].size(); ++j) {
323  size_t nnNode = currentClusterDecsFlatIndex[minIdxs[i][j]];
324  const std::vector<uint32_t>& nnCand = minIdxsC[currentNode];
325  auto it = std::find(nnCand.begin(), nnCand.end(), nnNode);
326  if (it != nnCand.end()) {
327  float nnDist = currentDists[it - nnCand.begin()];
328  if (nnDist < PR_MAX_GAP) {
329  Eu.push_back(static_cast<uint32_t>(i));
330  Ev.push_back(minIdxs[i][j]);
331  edgeWeight.push_back(10 / ((nnDist + 0.1) / 0.01));
332  }
333  }
334  }
335  }
336 
337  if (progressDlg) {
338  progressDlg->setValue(55);
339  QCoreApplication::processEvents();
340  }
341 
342  std::vector<uint32_t> in_component2d;
343  perform_cut_pursuit2d(PR_MIN_NN2, PR_REG_STRENGTH2, currentClusterDecsFlat,
344  edgeWeight, Eu, Ev, in_component2d);
345 
346  if (progressDlg) {
347  progressDlg->setValue(80);
348  QCoreApplication::processEvents();
349  }
350 
351  std::vector<uint32_t> currentClusterDecsICsReverse;
352  std::vector<Vec3d> currentClusterDecsReverse;
353  size_t ia_counter = 0;
354  for (size_t i = 0; i < currentClusterDecs.size(); i++) {
355  size_t N = currentClusterDecsICs[i].size();
356  std::vector<uint32_t> v(in_component2d.begin() + ia_counter,
357  in_component2d.begin() + ia_counter +
358  currentClusterDecsICsFlatIndex[i]);
359  for (size_t j = 0; j < N; j++) {
360  currentClusterDecsICsReverse.push_back(
361  v[currentClusterDecsICs[i][j]]);
362  }
363  ia_counter += currentClusterDecsICsFlatIndex[i];
364  }
365 
366  std::vector<uint32_t> currentClusterDecsIDsSortedIdx;
367  std::vector<uint32_t> currentClusterDecsIDsSorted;
368 
369  sort_indexes(currentClusterDecsIDs, currentClusterDecsIDsSortedIdx,
370  currentClusterDecsIDsSorted);
371  std::vector<uint32_t> currentClusterDecsICsReverseSorted;
372  currentClusterDecsICsReverseSorted.reserve(
373  currentClusterDecsICsReverse.size());
374  std::transform(currentClusterDecsIDsSortedIdx.begin(),
375  currentClusterDecsIDsSortedIdx.end(),
376  std::back_inserter(currentClusterDecsICsReverseSorted),
377  [&](uint32_t i) { return currentClusterDecsICsReverse[i]; });
378 
379  // export segments as a new scalar field
380  int outSFIndex = pc->getScalarFieldIndexByName(IntermedSegsSFName);
381  if (outSFIndex < 0) {
382  outSFIndex = pc->addScalarField(IntermedSegsSFName);
383  if (outSFIndex < 0) {
384  CVLog::Error("[TreeIso] Not enough memory!");
385  return false;
386  }
387  }
388  cloudViewer::ScalarField* outSF = pc->getScalarField(outSFIndex);
389  outSF->fill(NAN_VALUE);
390 
391  std::vector<uint32_t> groupIdx(pointCount);
392  for (unsigned i = 0; i < pointCount; ++i) {
393  groupIdx[i] = currentClusterDecsICsReverseSorted[i];
394  outSF->setValue(i, currentClusterDecsICsReverseSorted[i]);
395  }
396  outSF->computeMinAndMax();
397  pc->colorsHaveChanged();
398  pc->setCurrentDisplayedScalarField(outSFIndex);
399  pc->showSF(true);
400 
401  if (progressDlg) {
402  progressDlg->setValue(100);
403  QCoreApplication::processEvents();
404  }
405 
406  auto elapsed = Since(start).count() / 1000;
407  CVLog::Print(QString("[TreeIso] Intermediate segs took %1 seconds")
408  .arg(elapsed));
409 
410  return true;
411 }
412 
414  const unsigned PR_MIN_NN3,
415  const float PR_REL_HEIGHT_LENGTH_RATIO,
416  const float PR_VERTICAL_WEIGHT,
417  QProgressDialog* progressDlg /*=nullptr*/) {
418  if (!pc) {
419  assert(false);
420  return false;
421  }
422 
423  if (progressDlg) {
424  progressDlg->setRange(0, 100);
425  }
426 
427  auto start = std::chrono::steady_clock::now();
428 
429  unsigned pointCount = pc->size();
430  std::vector<Vec3d> pc_vec;
431  toTranslatedVector(pc, pc_vec);
432 
433  int initIdx = pc->getScalarFieldIndexByName(InitSegsSFName);
434  if (initIdx < 0) {
435  CVLog::Error("[TreeIso] Please run initial segmentation first!");
436  return false;
437  }
438  int groupIdx = pc->getScalarFieldIndexByName(IntermedSegsSFName);
439  if (groupIdx < 0) {
440  CVLog::Error("[TreeIso] Please run intermeditate segmentation first!");
441  return false;
442  }
443 
444  cloudViewer::ScalarField* initSF = pc->getScalarField(initIdx);
445 
446  std::vector<uint32_t> segs_init_ids;
447  segs_init_ids.resize(pointCount);
448  for (unsigned i = 0; i < pointCount; ++i) {
449  segs_init_ids[i] = initSF->getValue(i);
450  }
451 
452  cloudViewer::ScalarField* groupSF = pc->getScalarField(groupIdx);
453  if (!groupSF) {
454  assert(false);
455  return false;
456  }
457 
458  std::vector<uint32_t> segs_group_ids;
459  segs_group_ids.resize(pointCount);
460 
461  for (unsigned i = 0; i < pointCount; ++i) {
462  segs_group_ids[i] = groupSF->getValue(i);
463  }
464 
465  std::vector<std::vector<uint32_t>> initVGroup;
466  std::vector<uint32_t> initU;
467  std::vector<uint32_t> initUI;
468  unique_group(segs_init_ids, initVGroup, initU, initUI);
469 
470  size_t n_init_clusters = initVGroup.size();
471  std::vector<Vec3d> clusterCentroids(n_init_clusters);
472 
473  for (size_t i = 0; i < n_init_clusters; ++i) {
474  std::vector<Vec3d> clusterPts;
475  get_subset(pc_vec, initVGroup[i], clusterPts);
476  Vec3d clusterCentroid;
477  mean_col(clusterPts, clusterCentroid);
478  clusterCentroids[i] = clusterCentroid;
479 
480  std::vector<uint32_t> segs_group_id;
481  get_subset(segs_group_ids, initVGroup[i], segs_group_id);
482  float seg_group_mode = mode_col(segs_group_id);
483  for (int j = 0; j < segs_group_id.size(); ++j) {
484  segs_group_ids[initVGroup[i][j]] = seg_group_mode;
485  }
486  }
487 
488  std::vector<uint32_t> cluster_ids;
489  get_subset(segs_group_ids, initUI, cluster_ids);
490 
491  std::vector<std::vector<uint32_t>> clusterVGroup;
492  std::vector<uint32_t> clusterU0;
493  unique_group(cluster_ids, clusterVGroup, clusterU0);
494 
495  if (clusterVGroup.size() > 1) {
496  auto start = std::chrono::steady_clock::now();
497  size_t n_clusters = clusterVGroup.size();
498 
499  std::vector<unsigned> mergedRemainIds;
500 
501  size_t n_to_merge_ids = 1;
502  int n_prev_merge_ids = -1;
503  size_t iter = 1;
504 
505  std::vector<std::vector<uint32_t>> groupVGroup;
506  std::vector<uint32_t> groupU;
507 
508  std::vector<std::vector<float>> centroid2DFeatures;
509  Eigen::MatrixXf groupCentroidsToMerge;
510  Eigen::MatrixXf groupCentroidsRemain;
511 
512  while ((n_to_merge_ids != 0) &&
513  (static_cast<int>(n_to_merge_ids) != n_prev_merge_ids)) {
514  if (iter > 1) {
515  n_prev_merge_ids = static_cast<int>(n_to_merge_ids);
516  }
517  unique_group(segs_group_ids, groupVGroup, groupU);
518  size_t nGroups = groupVGroup.size();
519  centroid2DFeatures.resize(nGroups, std::vector<float>(2));
520 
521  std::vector<float> zFeatures;
522  zFeatures.resize(nGroups);
523  std::vector<float> lenFeatures;
524  lenFeatures.resize(nGroups);
525 
526  std::vector<polygon> groupHulls;
527  for (size_t i = 0; i < nGroups; ++i) {
528  std::vector<Vec3d> groupPts;
529  get_subset(pc_vec, groupVGroup[i], groupPts);
530  Vec3d groupCentroids;
531  mean_col(groupPts, groupCentroids);
532  centroid2DFeatures[i][0] = groupCentroids[0];
533  centroid2DFeatures[i][1] = groupCentroids[1];
534 
535  std::vector<float> minPts;
536  min_col(groupPts, minPts);
537  zFeatures[i] = minPts[2];
538  std::vector<float> maxPts;
539  max_col(groupPts, maxPts);
540  lenFeatures[i] = maxPts[2] - minPts[2];
541 
542  polygon hull;
543  multi_point conv_points;
544  for (const auto& p : groupPts) {
545  conv_points.push_back(point_xy(p[0], p[1]));
546  }
547 
548  boost::geometry::convex_hull(conv_points, hull);
549  groupHulls.push_back(hull);
550  }
551 
552  size_t knncpp_nn =
553  (PR_MIN_NN3 < n_clusters ? PR_MIN_NN3 : n_clusters);
554  std::vector<std::vector<uint32_t>> groupNNIdxC;
555  std::vector<Vec3d> groupNNCDs;
556  knn_cpp_nearest_neighbors(centroid2DFeatures, knncpp_nn,
557  groupNNIdxC, groupNNCDs, 8);
558  Vec3d mds;
559  mean_col(groupNNCDs, mds);
560  float sigmaD = mds[1];
561 
562  std::vector<size_t> toMergeIds;
563  std::vector<size_t> toMergeCandidateIds;
564  Vec3d toMergeCandidateMetrics;
565  for (size_t i = 0; i < nGroups; ++i) {
566  const std::vector<uint32_t>& nnGroupId = groupNNIdxC[i];
567  Vec3d nnGroupZ(nnGroupId.size());
568  Vec3d nnGroupLen(nnGroupId.size());
569  for (size_t j = 0; j < nnGroupId.size(); ++j) {
570  nnGroupZ[j] = zFeatures[nnGroupId[j]];
571  nnGroupLen[j] = lenFeatures[nnGroupId[j]];
572  }
573  float minZ = min_col(nnGroupZ);
574  float minLen = min_col(nnGroupLen);
575 
576  float currentGroupRelHt =
577  (zFeatures[i] - minZ) / lenFeatures[i];
578 
579  if (abs(currentGroupRelHt) > PR_REL_HEIGHT_LENGTH_RATIO) {
580  if (iter == 1) {
581  float initialLenRatio =
582  lenFeatures[i] / median_col(lenFeatures);
583  if (initialLenRatio > 1.5) {
584  toMergeIds.push_back(i);
585  }
586  toMergeCandidateIds.push_back(i);
587  toMergeCandidateMetrics.push_back(initialLenRatio);
588  } else {
589  toMergeIds.push_back(i);
590  }
591  }
592  }
593  if ((iter == 1) && (toMergeCandidateMetrics.size() == 0)) {
594  break;
595  }
596  if ((iter == 1) && (toMergeIds.size() == 0)) {
597  size_t cand_ind = arg_max_col(toMergeCandidateMetrics);
598  toMergeIds.push_back(toMergeCandidateIds[cand_ind]);
599  }
600 
601  std::vector<size_t> remainIds;
602  std::vector<size_t> allIds(nGroups);
603  std::iota(std::begin(allIds), std::end(allIds), 0);
604  std::set_difference(allIds.begin(), allIds.end(),
605  toMergeIds.begin(), toMergeIds.end(),
606  std::inserter(remainIds, remainIds.begin()));
607 
608  get_subset(centroid2DFeatures, toMergeIds, groupCentroidsToMerge);
609  get_subset(centroid2DFeatures, remainIds, groupCentroidsRemain);
610  size_t knncpp_nn2 =
611  (PR_MIN_NN3 < remainIds.size() ? PR_MIN_NN3
612  : remainIds.size());
613 
615  knn_kdtree(groupCentroidsRemain);
616  knn_cpp_build(knn_kdtree);
617  std::vector<std::vector<size_t>> groupNNIdx;
618  std::vector<Vec3d> groupNNIdxDists;
619 
620  knn_cpp_query(knn_kdtree, groupCentroidsToMerge, knncpp_nn2,
621  groupNNIdx, groupNNIdxDists);
622 
623  size_t nToMergeIds = toMergeIds.size();
624  size_t nRemainIds = remainIds.size();
625  for (size_t i = 0; i < nToMergeIds; ++i) {
626  size_t toMergeId = toMergeIds[i];
627 
628  Eigen::MatrixXf currentClusterCentroids;
629  get_subset(clusterCentroids, clusterVGroup[toMergeId],
630  currentClusterCentroids);
631 
632  size_t nNNs = groupNNIdx.size();
633 
634  std::vector<float> scores;
635  std::vector<size_t> filteredRemainIds;
636  std::vector<float> min3DSpacings;
637 
638  for (size_t j = 0; j < nNNs; ++j) {
639  size_t remainId = remainIds[groupNNIdx[j][i]];
640 
641  float lineSegs2 = zFeatures[toMergeId] +
642  lenFeatures[toMergeId] -
643  zFeatures[remainId];
644  float lineSegs1 = zFeatures[remainId] +
645  lenFeatures[remainId] -
646  zFeatures[toMergeId];
647 
648  float verticalOverlapRatio =
649  (lineSegs2 > lineSegs1 ? lineSegs1 : lineSegs2) /
650  (lineSegs1 > lineSegs2 ? lineSegs1 : lineSegs2);
651  float horizontalOverlapRatio;
652  if ((boost::geometry::num_points(groupHulls[toMergeId]) >
653  3) &
654  (boost::geometry::num_points(groupHulls[remainId]) >
655  3)) {
656  multi_polygon intersection;
657  boost::geometry::intersection(groupHulls[toMergeId],
658  groupHulls[remainId],
659  intersection);
660  float intersect_area =
661  boost::geometry::area(intersection);
662  float area1 =
663  boost::geometry::area(groupHulls[toMergeId]);
664  float area2 =
665  boost::geometry::area(groupHulls[remainId]);
666  horizontalOverlapRatio =
667  intersect_area /
668  (area1 < area2 ? area1 : area2);
669  } else {
670  horizontalOverlapRatio = 0.0;
671  }
672 
673  Eigen::MatrixXf nnClusterCentroids;
674  get_subset(clusterCentroids, clusterVGroup[remainId],
675  nnClusterCentroids);
676 
679  knn_kdtree2(nnClusterCentroids);
680  knn_cpp_build(knn_kdtree2);
681  std::vector<std::vector<size_t>> min3D_idx;
682  std::vector<Vec3d> min3D_dists;
683 
684  knn_cpp_query(knn_kdtree2, currentClusterCentroids, 1,
685  min3D_idx, min3D_dists);
686  float min3DSpacing = min_col(min3D_dists[0]);
687  min3DSpacings.push_back(min3DSpacing);
688 
689  Eigen::MatrixXf nnClusterCentroids2D =
690  nnClusterCentroids.block(0, 0, 2,
691  nnClusterCentroids.cols());
692  Eigen::MatrixXf currentClusterCentroids2D =
693  currentClusterCentroids.block(
694  0, 0, 2, currentClusterCentroids.cols());
695  Eigen::VectorXf nnClusterCentroids2Dmean =
696  nnClusterCentroids2D.rowwise().mean();
697  Eigen::VectorXf currentClusterCentroids2Dmean =
698  currentClusterCentroids2D.rowwise().mean();
699  float min2DSpacing =
700  sqrt((nnClusterCentroids2Dmean[0] -
701  currentClusterCentroids2Dmean[0]) *
702  (nnClusterCentroids2Dmean[0] -
703  currentClusterCentroids2Dmean[0]) +
704  (nnClusterCentroids2Dmean[1] -
705  currentClusterCentroids2Dmean[1]) *
706  (nnClusterCentroids2Dmean[1] -
707  currentClusterCentroids2Dmean[1]));
708 
709  verticalOverlapRatio =
710  verticalOverlapRatio > 0 ? verticalOverlapRatio : 0;
711 
712  float score = exp(
713  -(1 - horizontalOverlapRatio) *
714  (1 - horizontalOverlapRatio) -
715  PR_VERTICAL_WEIGHT * (1 - verticalOverlapRatio) *
716  (1 - verticalOverlapRatio) -
717  ((min3DSpacing < min2DSpacing ? min3DSpacing
718  : min2DSpacing) /
719  sigmaD) *
720  ((min3DSpacing < min2DSpacing
721  ? min3DSpacing
722  : min2DSpacing) /
723  sigmaD));
724  scores.push_back(score);
725 
726  filteredRemainIds.push_back(remainId);
727  }
728 
729  std::vector<size_t> scoreSortI;
730  std::vector<float> scoreSort;
731 
732  sort_indexes<float, size_t>(scores, scoreSortI, scoreSort);
733  float score_highest = scoreSort[0];
734  if (score_highest == 0) {
735  continue;
736  }
737  std::vector<float> scoreSortRatio;
738 
739  scoreSortRatio.reserve(scoreSort.size());
740  std::transform(scoreSort.begin(), scoreSort.end(),
741  std::back_inserter(scoreSortRatio),
742  [score_highest](float value) {
743  return value / score_highest;
744  });
745 
746  std::vector<std::size_t> scoreSortCandidateIdx;
747  for (std::size_t i = 0; i < scoreSortRatio.size(); ++i) {
748  if (scoreSortRatio[i] > 0.7) {
749  scoreSortCandidateIdx.push_back(i);
750  }
751  }
752  size_t nScoreSortCandidateIdx = scoreSortCandidateIdx.size();
753  unsigned mergeNNId = 0;
754  if (nScoreSortCandidateIdx == 1) {
755  mergeNNId = groupU
756  [filteredRemainIds
757  [scoreSortI[scoreSortCandidateIdx[0]]]];
758 
759  } else if (nScoreSortCandidateIdx > 1) {
760  std::vector<float> min3DSpacingsFiltered;
761  std::vector<size_t> scoreSortIFiltered;
762  get_subset(scoreSortI, scoreSortCandidateIdx,
763  scoreSortIFiltered);
764  get_subset(min3DSpacings, scoreSortIFiltered,
765  min3DSpacingsFiltered);
766 
767  size_t filterMinSpacingIdx =
768  arg_min_col(min3DSpacingsFiltered);
769  mergeNNId =
770  groupU[filteredRemainIds
771  [scoreSortI[filterMinSpacingIdx]]];
772  } else {
773  continue;
774  }
775 
776  std::vector<uint32_t> currentVGroup =
777  groupVGroup[toMergeIds[i]];
778  for (unsigned k = 0; k < currentVGroup.size(); ++k) {
779  segs_group_ids[currentVGroup[k]] = mergeNNId;
780  }
781  mergedRemainIds.push_back(mergeNNId);
782  mergedRemainIds.push_back(groupU[toMergeIds[i]]);
783  }
784 
785  n_to_merge_ids = toMergeIds.size();
786  get_subset(segs_group_ids, initUI, cluster_ids);
787  unique_group(cluster_ids, clusterVGroup, clusterU0);
788  n_clusters = clusterVGroup.size();
789  ++iter;
790  }
791 
792  unique_group(segs_group_ids, groupVGroup, groupU);
793  for (unsigned j = 0; j < groupVGroup.size(); ++j) {
794  std::vector<uint32_t> currentVGroup = groupVGroup[j];
795  for (unsigned k = 0; k < currentVGroup.size(); ++k) {
796  segs_group_ids[currentVGroup[k]] = j + 1;
797  }
798  }
799 
800  // export segments as a new scalar field
801  int outSFIndex = pc->getScalarFieldIndexByName(FinalSegsSFName);
802  if (outSFIndex < 0) {
803  outSFIndex = pc->addScalarField(FinalSegsSFName);
804  if (outSFIndex < 0) {
805  CVLog::Error("[TreeIso] Not enough memory!");
806  return false;
807  }
808  }
809  cloudViewer::ScalarField* outSF = pc->getScalarField(outSFIndex);
810  outSF->fill(NAN_VALUE);
811 
812  std::vector<uint32_t> groupIdx(pointCount);
813  for (unsigned i = 0; i < pointCount; ++i) {
814  outSF->setValue(i, segs_group_ids[i]);
815  }
816  outSF->computeMinAndMax();
817  pc->colorsHaveChanged();
818  pc->setCurrentDisplayedScalarField(outSFIndex);
819  pc->showSF(true);
820 
821  if (progressDlg) {
822  progressDlg->setValue(100);
823  QCoreApplication::processEvents();
824  }
825 
826  auto elapsed = Since(start).count() / 1000;
827  CVLog::Print(QString("[TreeIso] Final segs took: %1 seconds !!!")
828  .arg(elapsed));
829  }
830 
831  return true;
832 }
833 
834 // 1. initial 3D segmentation
835 bool TreeIso::Init_seg(const unsigned min_nn1,
836  const float regStrength1,
837  const float PR_DECIMATE_RES1,
838  ecvMainAppInterface* app,
839  QProgressDialog* progressDlg) {
840  if (!app) {
841  assert(false);
842  return false;
843  }
844 
845  const ccHObject::Container& selectedEntities = app->getSelectedEntities();
846  if (selectedEntities.empty()) {
847  assert(false);
848  app->dispToConsole("[TreeIso] Select at least one cloud",
850  return false;
851  }
852  ccHObject* ent = selectedEntities[0];
853 
854  if (!ent || !ent->isA(CV_TYPES::POINT_CLOUD)) {
855  app->dispToConsole("[TreeIso] Not a point cloud",
857  return false;
858  }
859  ccPointCloud* pointCloud = static_cast<ccPointCloud*>(ent);
860 
861  if (Init_seg_pcd(pointCloud, min_nn1, regStrength1, PR_DECIMATE_RES1,
862  progressDlg)) {
863  ent->redrawDisplay();
864  return true;
865  } else {
866  return false;
867  }
868 }
869 
870 // 2. Bottom-up 2D segmentation
871 bool TreeIso::Intermediate_seg(const unsigned PR_MIN_NN2,
872  const float PR_REG_STRENGTH2,
873  const float PR_DECIMATE_RES2,
874  const float PR_MAX_GAP,
875  ecvMainAppInterface* app,
876  QProgressDialog* progressDlg) {
877  if (!app) {
878  assert(false);
879  return false;
880  }
881 
882  const ccHObject::Container& selectedEntities = app->getSelectedEntities();
883 
884  if (selectedEntities.empty()) {
885  assert(false);
886  app->dispToConsole("[TreeIso] Select at least one cloud",
888  return false;
889  }
890 
891  ccHObject* ent = selectedEntities[0];
892 
893  if (!ent || !ent->isA(CV_TYPES::POINT_CLOUD)) {
894  app->dispToConsole("[TreeIso] Not a point cloud",
896  return false;
897  }
898 
899  ccPointCloud* pointCloud = static_cast<ccPointCloud*>(ent);
900 
901  if (Intermediate_seg_pcd(pointCloud, PR_MIN_NN2, PR_REG_STRENGTH2,
902  PR_DECIMATE_RES2, PR_MAX_GAP, progressDlg)) {
903  ent->redrawDisplay();
904  return true;
905  } else {
906  return false;
907  }
908 }
909 
910 // 3. Global edge refinement
911 bool TreeIso::Final_seg(const unsigned PR_MIN_NN3,
912  const float PR_REL_HEIGHT_LENGTH_RATIO,
913  const float PR_VERTICAL_WEIGHT,
914  ecvMainAppInterface* app,
915  QProgressDialog* progressDlg) {
916  if (!app) {
917  assert(false);
918  return false;
919  }
920 
921  const ccHObject::Container& selectedEntities = app->getSelectedEntities();
922 
923  if (selectedEntities.empty()) {
924  assert(false);
925  app->dispToConsole("[TreeIso] Select at least one cloud",
927  return false;
928  }
929 
930  ccHObject* ent = selectedEntities[0];
931  if (!ent || !ent->isA(CV_TYPES::POINT_CLOUD)) {
932  app->dispToConsole("[TreeIso] Not a point cloud",
934  return false;
935  }
936  ccPointCloud* pointCloud = static_cast<ccPointCloud*>(ent);
937 
938  if (Final_seg_pcd(pointCloud, PR_MIN_NN3, PR_REL_HEIGHT_LENGTH_RATIO,
939  PR_VERTICAL_WEIGHT, progressDlg)) {
940  ent->redrawDisplay();
941  return true;
942  } else {
943  return false;
944  }
945 }
946 
949  kdtree,
950  unsigned n_thread /*=0*/) {
951  kdtree.setBucketSize(16);
952  kdtree.setSorted(true);
953  kdtree.setThreads(n_thread);
954  kdtree.build();
955 }
956 
959  kdtree,
960  Eigen::MatrixXf& query_points,
961  size_t k,
962  std::vector<std::vector<size_t>>& res_idx,
963  std::vector<Vec3d>& res_dists) {
964  res_idx.clear();
965  res_dists.clear();
966 
967  knncpp::Matrixi indices;
968  Eigen::MatrixXf distances;
969 
970  kdtree.query(query_points, k, indices, distances);
971  res_idx.resize(indices.rows(), std::vector<size_t>(indices.cols()));
972  for (Eigen::Index i = 0; i < indices.rows(); i++) {
973  res_idx[i] = std::vector<size_t>(
974  indices.row(i).data(), indices.row(i).data() + indices.cols());
975  }
976  res_dists.resize(distances.rows(), Vec3d(distances.cols()));
977  for (Eigen::Index i = 0; i < distances.rows(); i++) {
978  res_dists[i] = Vec3d(distances.row(i).data(),
979  distances.row(i).data() + distances.cols());
980  }
981 }
982 
985  kdtree,
986  Eigen::MatrixXf& query_points,
987  size_t k) {
988  knncpp::Matrixi indices;
989  Eigen::MatrixXf distances;
990 
991  kdtree.query(query_points, k, indices, distances);
992  return distances.minCoeff();
993 }
994 
995 void knn_cpp_nearest_neighbors(const std::vector<Vec3d>& dataset,
996  size_t k,
997  std::vector<std::vector<uint32_t>>& res_idx,
998  std::vector<Vec3d>& res_dists,
999  unsigned n_thread) {
1000  if (dataset.empty()) {
1001  assert(false);
1002  return;
1003  }
1004 
1005  Eigen::MatrixXf mat(dataset[0].size(), dataset.size());
1006  for (size_t i = 0; i < dataset.size(); i++) {
1007  mat.col(i) = Eigen::VectorXf::Map(&dataset[i][0], dataset[i].size());
1008  }
1009 
1011  mat);
1012  kdtree.setBucketSize(16);
1013  kdtree.setSorted(true);
1014  kdtree.setThreads(n_thread);
1015  kdtree.build();
1016  knncpp::Matrixi indices;
1017  Eigen::MatrixXf distances;
1018 
1019  kdtree.query(mat, k, indices, distances);
1020 
1021  res_idx.resize(indices.cols(), std::vector<uint32_t>(indices.rows()));
1022  for (Eigen::Index i = 0; i < indices.cols(); i++) {
1023  res_idx[i] = std::vector<uint32_t>(
1024  indices.col(i).data(), indices.col(i).data() + indices.rows());
1025  }
1026  res_dists.resize(distances.cols(), Vec3d(distances.rows()));
1027  for (Eigen::Index i = 0; i < distances.cols(); i++) {
1028  res_dists[i] = Vec3d(distances.col(i).data(),
1029  distances.col(i).data() + distances.rows());
1030  }
1031 }
1032 
1033 template <typename T>
1034 void unique_group(std::vector<T>& arr,
1035  std::vector<std::vector<T>>& u_group,
1036  std::vector<T>& arr_unq,
1037  std::vector<T>& ui) {
1038  arr_unq.clear();
1039  ui.clear();
1040  u_group.clear();
1041 
1042  if (arr.empty()) {
1043  assert(false);
1044  return;
1045  }
1046 
1047  std::vector<T> arr_sorted_idx;
1048  std::vector<T> arr_sorted;
1049  sort_indexes(arr, arr_sorted_idx, arr_sorted);
1050 
1051  const size_t n = arr.size();
1052 
1053  ui.push_back(arr_sorted_idx[0]);
1054  std::size_t counter = 0;
1055 
1056  std::vector<T> ut;
1057  ut.push_back(arr_sorted_idx[0]);
1058 
1059  // detect the location (before sorted) where a row in the sorted array is
1060  // different from the previous row (as ia), and add one for the reverse
1061  // index as ic
1062  for (std::size_t i = 1; i < n; ++i) {
1063  if (arr_sorted[i] != arr_sorted[i - 1]) {
1064  ui.push_back(arr_sorted_idx[i]);
1065  arr_unq.push_back(arr_sorted[i]);
1066 
1067  u_group.push_back(ut);
1068  ut.clear();
1069  ut.push_back(arr_sorted_idx[i]);
1070  counter++;
1071  } else {
1072  ut.push_back(arr_sorted_idx[i]);
1073  }
1074  }
1075  u_group.push_back(ut);
1076 }
1077 
1078 template <typename T>
1079 void unique_group(std::vector<T>& arr,
1080  std::vector<std::vector<T>>& u_group,
1081  std::vector<T>& arr_unq) {
1082  arr_unq.clear();
1083  u_group.clear();
1084 
1085  if (arr.empty()) {
1086  assert(false);
1087  return;
1088  }
1089 
1090  std::vector<T> arr_sorted_idx;
1091  std::vector<T> arr_sorted;
1092  sort_indexes(arr, arr_sorted_idx, arr_sorted);
1093 
1094  const size_t n = arr.size();
1095  arr_unq.push_back(arr_sorted[0]);
1096  std::size_t counter = 0;
1097 
1098  std::vector<T> ut;
1099  ut.push_back(arr_sorted_idx[0]);
1100 
1101  // detect the location (before sorted) where a row in the sorted array is
1102  // different from the previous row (as ia), and add one for the reverse
1103  // index as ic
1104  for (std::size_t i = 1; i < n; ++i) {
1105  if (arr_sorted[i] != arr_sorted[i - 1]) {
1106  arr_unq.push_back(arr_sorted[i]);
1107 
1108  u_group.push_back(ut);
1109  ut.clear();
1110  ut.push_back(arr_sorted_idx[i]);
1111  counter++;
1112  } else {
1113  ut.push_back(arr_sorted_idx[i]);
1114  }
1115  }
1116  u_group.push_back(ut);
1117 }
1118 
1119 template <typename T>
1120 void unique_group(std::vector<T>& arr, std::vector<std::vector<T>>& u_group) {
1121  u_group.clear();
1122 
1123  if (arr.empty()) {
1124  assert(false);
1125  return;
1126  }
1127 
1128  std::vector<T> arr_sorted_idx;
1129  std::vector<T> arr_sorted;
1130  sort_indexes(arr, arr_sorted_idx, arr_sorted);
1131 
1132  const size_t n = arr.size();
1133  std::size_t counter = 0;
1134 
1135  std::vector<T> ut;
1136  ut.push_back(arr_sorted_idx[0]);
1137 
1138  // detect the location (before sorted) where a row in the sorted array is
1139  // different from the previous row (as ia), and add one for the reverse
1140  // index as ic
1141  for (std::size_t i = 1; i < n; ++i) {
1142  if (arr_sorted[i] != arr_sorted[i - 1]) {
1143  u_group.push_back(ut);
1144  ut.clear();
1145  ut.push_back(arr_sorted_idx[i]);
1146  counter++;
1147  } else {
1148  ut.push_back(arr_sorted_idx[i]);
1149  }
1150  }
1151  u_group.push_back(ut);
1152 }
1153 
1154 template <typename T1, typename T2>
1155 void get_subset(std::vector<T1>& arr,
1156  std::vector<T2>& indices,
1157  std::vector<T1>& arr_sub) {
1158  arr_sub.clear();
1159  for (const auto& idx : indices) {
1160  arr_sub.push_back(arr[idx]);
1161  }
1162 }
1163 
1164 template <typename T1, typename T2>
1165 void get_subset(const std::vector<std::vector<T1>>& arr,
1166  const std::vector<T2>& indices,
1167  Eigen::MatrixXf& arr_sub) {
1168  arr_sub.setZero();
1169 
1170  if (arr.empty()) {
1171  assert(false);
1172  return;
1173  }
1174 
1175  arr_sub.resize(arr[0].size(), indices.size());
1176 
1177  for (size_t i = 0; i < indices.size(); ++i) {
1178  for (size_t j = 0; j < arr[0].size(); ++j) {
1179  arr_sub(j, i) = arr[indices[i]][j];
1180  }
1181  }
1182 }
1183 
1184 template <typename T1, typename T2>
1185 void get_subset(const std::vector<std::vector<T1>>& arr,
1186  const std::vector<T2>& indices,
1187  std::vector<std::vector<T1>>& arr_sub) {
1188  arr_sub.clear();
1189 
1190  if (arr.empty() || indices.empty()) {
1191  return;
1192  }
1193 
1194  arr_sub.resize(indices.size());
1195  for (size_t i = 0; i < indices.size(); ++i) {
1196  arr_sub[i] = arr[indices[i]];
1197  }
1198 }
1199 
1200 template <typename T1, typename T2>
1202  std::vector<T2>& indices,
1203  std::vector<std::vector<T1>>& arr_sub) {
1204  arr_sub.clear();
1205  arr_sub.resize(indices.size(), std::vector<T1>(3));
1206  for (size_t i = 0; i < indices.size(); ++i) {
1207  const CCVector3* vec = pcd->getPoint(indices[i]);
1208  arr_sub[i][0] = vec->x;
1209  arr_sub[i][1] = vec->y;
1210  arr_sub[i][2] = vec->z;
1211  }
1212  return true;
1213 }
1214 
1215 // convert ccPointCloud to a vector of points (centering the points about their
1216 // gravity center)
1217 template <typename T>
1219  std::vector<std::vector<T>>& y) {
1220  y.clear();
1221 
1222  const unsigned pointCount = pc->size();
1223  if (pointCount == 0) {
1224  assert(false);
1225  return;
1226  }
1227  y.resize(pointCount, std::vector<T>(3));
1228 
1229  for (unsigned i = 0; i < pointCount; ++i) {
1230  const CCVector3* pv = pc->getPoint(i);
1231  y[i] = {static_cast<float>(pv->x), static_cast<float>(pv->y),
1232  static_cast<float>(pv->z)};
1233  }
1234 
1235  std::vector<T> y_mean;
1236  mean_col(y, y_mean);
1237 
1238  for (unsigned i = 0; i < pointCount; ++i) {
1239  y[i][0] -= y_mean[0];
1240  y[i][1] -= y_mean[1];
1241  y[i][2] -= y_mean[2];
1242  }
1243 }
1244 
1245 bool perform_cut_pursuit(const uint32_t K,
1246  const float regStrength,
1247  const std::vector<Vec3d>& pc,
1248  std::vector<float>& edgeWeight,
1249  std::vector<uint32_t>& Eu,
1250  std::vector<uint32_t>& Ev,
1251  std::vector<uint32_t>& in_component,
1252  std::vector<std::vector<uint32_t>>& components) {
1253  const uint32_t pointCount = static_cast<uint32_t>(pc.size());
1254  if (pointCount == 0) {
1255  return false;
1256  }
1257 
1258  std::vector<std::vector<uint32_t>> nn_idx;
1259  std::vector<Vec3d> nn_D;
1260  knn_cpp_nearest_neighbors(pc, K + 1, nn_idx, nn_D, 8);
1261 
1262  const uint32_t nNod = pointCount;
1263  const uint32_t nObs = 3;
1264  const uint32_t nEdg = pointCount * K;
1265  const uint32_t cutoff = 0;
1266  const float mode = 1.0f;
1267  const float speed = 0;
1268  const float weight_decay = 0;
1269  const float verbose = 0;
1270 
1271  if (edgeWeight.size() == 0) {
1272  edgeWeight.resize(nEdg);
1273  std::fill(edgeWeight.begin(), edgeWeight.end(), 1.0);
1274  }
1275 
1276  // minus average
1277  std::vector<double> y_avg(nObs, 0.0);
1278 
1279  if (Eu.size() == 0) {
1280  Eu.resize(nEdg);
1281  Ev.resize(nEdg);
1282  for (unsigned i = 0; i < pointCount; ++i) {
1283  y_avg[0] += pc[i][0];
1284  y_avg[1] += pc[i][1];
1285  y_avg[2] += pc[i][2];
1286 
1287  for (unsigned j = 0; j < K; ++j) {
1288  Eu[i * K + j] = i;
1289  Ev[i * K + j] = nn_idx[i][j + 1];
1290  }
1291  }
1292  } else {
1293  for (unsigned i = 0; i < pointCount; ++i) {
1294  y_avg[0] += pc[i][0];
1295  y_avg[1] += pc[i][1];
1296  y_avg[2] += pc[i][2];
1297  }
1298  }
1299 
1300  y_avg[0] /= pointCount;
1301  y_avg[1] /= pointCount;
1302  y_avg[2] /= pointCount;
1303 
1304  std::vector<std::vector<float>> y = pc;
1305  for (unsigned i = 0; i < pointCount; ++i) {
1306  y[i][0] -= static_cast<float>(y_avg[0]);
1307  y[i][1] -= static_cast<float>(y_avg[1]);
1308  y[i][2] -= static_cast<float>(y_avg[2]);
1309  }
1310 
1311  std::vector<float> nodeWeight(pointCount, 1.0);
1312  std::vector<Vec3d> solution(pointCount, std::vector<float>(K));
1313  CP::cut_pursuit<float>(nNod, nEdg, nObs, y, Eu, Ev, edgeWeight, nodeWeight,
1314  solution, in_component, components, regStrength,
1315  cutoff, mode, speed, weight_decay, verbose);
1316  return true;
1317 }
1318 
1319 void perform_cut_pursuit2d(const uint32_t K,
1320  const float regStrength,
1321  const std::vector<Vec3d>& pc_vec,
1322  Vec3d& edgeWeight,
1323  std::vector<uint32_t>& Eu,
1324  std::vector<uint32_t>& Ev,
1325  std::vector<uint32_t>& in_component) {
1326  // build graph for cut-pursuit
1327  const uint32_t pointCount = static_cast<uint32_t>(pc_vec.size());
1328 
1329  const uint32_t nNod = pointCount;
1330  const uint32_t nObs = 2;
1331  const uint32_t nEdgMax = pointCount * K;
1332  const uint32_t cutoff = 0;
1333  const float mode = 1;
1334  const float speed = 0;
1335  const float weight_decay = 0;
1336  const float verbose = 0;
1337 
1338  if (edgeWeight.size() == 0) {
1339  edgeWeight.resize(nEdgMax);
1340  std::fill(edgeWeight.begin(), edgeWeight.end(), 1.0);
1341  }
1342  const uint32_t nEdg = static_cast<uint32_t>(edgeWeight.size());
1343 
1344  // minus average
1345  Vec3d y_avg(nObs, 0.0);
1346 
1347  if (Eu.size() == 0) {
1348  std::vector<std::vector<uint32_t>> nn_idx;
1349  std::vector<Vec3d> nn_D;
1350  knn_cpp_nearest_neighbors(pc_vec, K + 1, nn_idx, nn_D, 8);
1351  Eu.resize(nEdg);
1352  Ev.resize(nEdg);
1353  for (uint32_t i = 0; i < pointCount; ++i) {
1354  y_avg[0] += pc_vec[i][0];
1355  y_avg[1] += pc_vec[i][1];
1356  for (unsigned j = 0; j < K; ++j) {
1357  Eu[i * K + j] = i;
1358  Ev[i * K + j] = nn_idx[i][j + 1];
1359  }
1360  }
1361  } else {
1362  for (unsigned i = 0; i < pointCount; ++i) {
1363  y_avg[0] += pc_vec[i][0];
1364  y_avg[1] += pc_vec[i][1];
1365  }
1366  }
1367 
1368  y_avg[0] /= pointCount;
1369  y_avg[1] /= pointCount;
1370 
1371  std::vector<Vec3d> y = pc_vec;
1372  for (unsigned i = 0; i < pointCount; ++i) {
1373  y[i][0] -= static_cast<float>(y_avg[0]);
1374  y[i][1] -= static_cast<float>(y_avg[1]);
1375  }
1376 
1377  std::vector<float> nodeWeight(pointCount, 1.0);
1378  std::vector<std::vector<uint32_t>> components;
1379  std::vector<std::vector<float>> solution(pointCount, std::vector<float>(K));
1380  CP::cut_pursuit<float>(nNod, nEdg, nObs, y, Eu, Ev, edgeWeight, nodeWeight,
1381  solution, in_component, components, regStrength,
1382  cutoff, mode, speed, weight_decay, verbose);
1383 }
1384 
1385 template <typename T>
1386 size_t arg_min_col(std::vector<T>& arr) {
1387  auto min_element_it = std::min_element(arr.begin(), arr.end());
1388  std::size_t min_index = std::distance(arr.begin(), min_element_it);
1389  return min_index;
1390 }
1391 
1392 template <typename T>
1393 size_t arg_max_col(std::vector<T>& arr) {
1394  auto max_element_it = std::max_element(arr.begin(), arr.end());
1395  std::size_t max_index = std::distance(arr.begin(), max_element_it);
1396  return max_index;
1397 }
1398 
1399 template <typename T>
1400 void min_col(std::vector<std::vector<T>>& arr, std::vector<T>& min_vals) {
1401  min_vals.clear();
1402  if (arr.empty()) {
1403  return;
1404  }
1405 
1406  min_vals = arr[0];
1407  for (size_t j = 1; j < arr.size(); j++) {
1408  const auto& row = arr[j];
1409  for (size_t i = 0; i < row.size(); i++) {
1410  min_vals[i] = std::min(min_vals[i], row[i]);
1411  }
1412  }
1413 }
1414 
1415 template <typename T>
1416 T min_col(std::vector<T>& arr) {
1417  auto result_it = std::min_element(arr.begin(), arr.end());
1418  T result = *result_it;
1419  return result;
1420 }
1421 
1422 template <typename T>
1423 T mean_col(std::vector<T>& arr) {
1424  if (arr.empty()) {
1425  return std::numeric_limits<T>::quite_NaN();
1426  }
1427 
1428  double sum = 0.0;
1429  for (const T& value : arr) {
1430  sum += value;
1431  }
1432 
1433  return static_cast<T>(sum /= arr.size());
1434 }
1435 
1436 template <typename T>
1437 T median_col(std::vector<T>& arr) {
1438  size_t n = arr.size();
1439  if (n == 0) {
1440  return std::numeric_limits<T>::quiet_NaN();
1441  }
1442  // Sort the vector
1443  std::sort(arr.begin(), arr.end());
1444  // Calculate the median
1445  if (n % 2 == 0) {
1446  return (arr[n / 2 - 1] + arr[n / 2]) / 2;
1447  } else {
1448  return arr[n / 2];
1449  }
1450 }
1451 
1452 template <typename T>
1453 T mode_col(std::vector<T>& arr) {
1454  std::unordered_map<T, int> freq;
1455  for (const auto& val : arr) freq[val]++;
1456  return std::max_element(freq.begin(), freq.end(),
1457  [](const auto& a, const auto& b) {
1458  return a.second < b.second;
1459  })
1460  ->first;
1461 }
1462 
1463 template <typename T>
1464 void max_col(std::vector<std::vector<T>>& arr, std::vector<T>& max_vals) {
1465  max_vals.clear();
1466  if (arr.empty()) {
1467  return;
1468  }
1469 
1470  max_vals = arr[0];
1471  for (size_t j = 1; j < arr.size(); j++) {
1472  const auto& row = arr[j];
1473  for (size_t i = 0; i < row.size(); i++) {
1474  max_vals[i] = std::max(max_vals[i], row[i]);
1475  }
1476  }
1477 }
1478 
1479 template <typename T>
1480 void mean_col(std::vector<std::vector<T>>& arr, std::vector<T>& mean_vals) {
1481  mean_vals.clear();
1482  if (arr.empty()) {
1483  return;
1484  }
1485 
1486  std::vector<double> sums(arr[0].size(), 0.0);
1487 
1488  for (const std::vector<T>& element : arr) {
1489  for (size_t i = 0; i < arr[0].size(); i++) {
1490  sums[i] += element[i];
1491  }
1492  }
1493 
1494  mean_vals = std::vector<T>(arr[0].size());
1495  for (size_t i = 0; i < arr[0].size(); i++) {
1496  mean_vals[i] = static_cast<T>(sums[i] / arr.size());
1497  }
1498 }
1499 
1500 template <typename T>
1501 void decimate_vec(std::vector<std::vector<T>>& arr,
1502  T res,
1503  std::vector<std::vector<T>>& vec_dec) {
1504  vec_dec.clear();
1505 
1506  if (res == 0) {
1507  assert(false);
1508  return;
1509  }
1510 
1511  size_t num_rows = arr.size();
1512  if (num_rows == 0) {
1513  assert(false);
1514  return;
1515  }
1516  size_t num_cols = arr[0].size();
1517 
1518  std::vector<T> arr_min;
1519  min_col(arr, arr_min);
1520  vec_dec.resize(num_rows, std::vector<T>(num_cols));
1521 
1522  for (unsigned i = 0; i < num_rows; ++i) {
1523  for (unsigned j = 0; j < num_cols; ++j) {
1524  vec_dec[i][j] = std::floor((arr[i][j] - arr_min[j]) / res) + 1;
1525  }
1526  }
1527 }
1528 
1529 // return index
1530 template <typename T>
1531 void sort_indexes_by_row(std::vector<std::vector<T>>& v,
1532  std::vector<size_t>& idx,
1533  std::vector<std::vector<T>>& v_sorted) {
1534  idx.clear();
1535  v_sorted.clear();
1536 
1537  // initialize original index locations
1538  size_t m = v.size();
1539  if (m == 0) {
1540  return;
1541  }
1542  size_t n = v[0].size();
1543 
1544  idx.resize(m);
1545  std::iota(idx.begin(), idx.end(), 0);
1546 
1547  // std::vector<std::vector<T>> v_sorted;
1548  v_sorted.resize(m, std::vector<T>(n));
1549 
1550  // sort indexes based on comparing values in v
1551  // using std::stable_sort instead of std::sort
1552  // to avoid unnecessary index re-orderings
1553  // when v contains elements of equal values
1554  std::stable_sort(idx.begin(), idx.end(), [&v](size_t i1, size_t i2) {
1555  // bool vt = true;
1556  for (size_t k = 0; k < v[0].size(); ++k) {
1557  if (v[i1][k] == v[i2][k]) {
1558  continue;
1559  } else {
1560  return v[i1][k] < v[i2][k];
1561  }
1562  }
1563  return false;
1564  });
1565 
1566  for (size_t i = 0; i < idx.size(); ++i) {
1567  v_sorted[i].resize(n);
1568  for (size_t k = 0; k < n; ++k) {
1569  v_sorted[i][k] = v[idx[i]][k];
1570  }
1571  }
1572 }
1573 
1574 // return index
1575 template <typename ValueType, typename IndexType>
1576 void sort_indexes(std::vector<ValueType>& v,
1577  std::vector<IndexType>& idx,
1578  std::vector<ValueType>& v_sorted) {
1579  idx.clear();
1580  v_sorted.clear();
1581 
1582  size_t m = v.size();
1583  if (m == 0) {
1584  return;
1585  }
1586  idx.resize(m);
1587  std::iota(idx.begin(), idx.end(), 0);
1588 
1589  v_sorted.resize(m);
1590 
1591  std::stable_sort(idx.begin(), idx.end(), [&v](IndexType i1, IndexType i2) {
1592  return v[i1] < v[i2];
1593  });
1594 
1595  for (size_t i = 0; i < idx.size(); ++i) {
1596  v_sorted[i] = v[idx[i]];
1597  }
1598 }
1599 
1600 template <typename T>
1601 void unique_index_by_rows(std::vector<std::vector<T>>& arr,
1602  std::vector<size_t>& ia,
1603  std::vector<size_t>& ic) {
1604  ia.clear();
1605  ic.clear();
1606 
1607  std::vector<std::vector<T>> arr_sorted;
1608  arr_sorted.resize(arr.size());
1609  std::vector<size_t> sort_idx;
1610 
1611  // sort array first and get indices
1612  sort_indexes_by_row(arr, sort_idx, arr_sorted);
1613 
1614  const size_t num_rows = arr_sorted.size();
1615  const size_t num_cols = arr_sorted[0].size();
1616 
1617  ic.resize(num_rows);
1618  ia.push_back(sort_idx[0]);
1619  std::size_t counter = 0;
1620  ic[sort_idx[0]] = counter;
1621 
1622  // detect the location (before sorted) where a row in the sorted array is
1623  // different from the previous row (as ia), and add one for the reverse
1624  // index as ic
1625  for (std::size_t i = 1; i < num_rows; ++i) {
1626  bool diff = false;
1627  for (std::size_t k = 0; k < num_cols; ++k) {
1628  if (arr_sorted[i][k] != arr_sorted[i - 1][k]) {
1629  diff = true;
1630  break;
1631  }
1632  }
1633 
1634  if (diff) {
1635  ia.push_back(sort_idx[i]);
1636  counter++;
1637  }
1638  ic[sort_idx[i]] = counter;
1639  }
1640 }
constexpr ScalarType NAN_VALUE
NaN as a ScalarType value.
Definition: CVConst.h:76
int size
boost::geometry::model::multi_polygon< polygon > multi_polygon
Definition: TreeIso.cpp:39
void knn_cpp_build(knncpp::KDTreeMinkowskiX< float, knncpp::EuclideanDistance< float >> &kdtree, unsigned n_thread)
Definition: TreeIso.cpp:947
static const char FinalSegsSFName[]
Definition: TreeIso.cpp:49
void unique_index_by_rows(std::vector< std::vector< T >> &arr, std::vector< size_t > &ia, std::vector< size_t > &ic)
Definition: TreeIso.cpp:1601
void knn_cpp_query(knncpp::KDTreeMinkowskiX< float, knncpp::EuclideanDistance< float >> &kdtree, Eigen::MatrixXf &query_points, size_t k, std::vector< std::vector< size_t >> &res_idx, std::vector< Vec3d > &res_dists)
Definition: TreeIso.cpp:957
boost::geometry::model::d2::point_xy< double > point_xy
Definition: TreeIso.cpp:36
bool perform_cut_pursuit(const uint32_t K, const float regStrength, const std::vector< Vec3d > &pc, std::vector< float > &edgeWeight, std::vector< uint32_t > &Eu, std::vector< uint32_t > &Ev, std::vector< uint32_t > &in_component, std::vector< std::vector< uint32_t >> &components)
Definition: TreeIso.cpp:1245
void perform_cut_pursuit2d(const uint32_t K, const float regStrength, const std::vector< Vec3d > &pc_vec, Vec3d &edgeWeight, std::vector< uint32_t > &Eu, std::vector< uint32_t > &Ev, std::vector< uint32_t > &in_component)
Definition: TreeIso.cpp:1319
void max_col(std::vector< std::vector< T >> &arr, std::vector< T > &max_vals)
Definition: TreeIso.cpp:1464
void sort_indexes_by_row(std::vector< std::vector< T >> &v, std::vector< size_t > &idx, std::vector< std::vector< T >> &v_sorted)
Definition: TreeIso.cpp:1531
T mean_col(std::vector< T > &arr)
Definition: TreeIso.cpp:1423
T mode_col(std::vector< T > &arr)
Definition: TreeIso.cpp:1453
boost::geometry::model::polygon< point_xy > polygon
Definition: TreeIso.cpp:37
void sort_indexes(std::vector< ValueType > &v, std::vector< IndexType > &idx, std::vector< ValueType > &v_sorted)
Definition: TreeIso.cpp:1576
static auto Since(std::chrono::time_point< clock_t, duration_t > const &start)
Definition: TreeIso.cpp:54
float knn_cpp_query_min_d(knncpp::KDTreeMinkowskiX< float, knncpp::EuclideanDistance< float >> &kdtree, Eigen::MatrixXf &query_points, size_t k)
Definition: TreeIso.cpp:983
T median_col(std::vector< T > &arr)
Definition: TreeIso.cpp:1437
void min_col(std::vector< std::vector< T >> &arr, std::vector< T > &min_vals)
Definition: TreeIso.cpp:1400
void toTranslatedVector(const ccPointCloud *pc, std::vector< std::vector< T >> &y)
Definition: TreeIso.cpp:1218
size_t arg_max_col(std::vector< T > &arr)
Definition: TreeIso.cpp:1393
boost::geometry::model::multi_point< point_xy > multi_point
Definition: TreeIso.cpp:38
void decimate_vec(std::vector< std::vector< T >> &arr, T res, std::vector< std::vector< T >> &vec_dec)
Definition: TreeIso.cpp:1501
void knn_cpp_nearest_neighbors(const std::vector< Vec3d > &dataset, size_t k, std::vector< std::vector< uint32_t >> &res_idx, std::vector< Vec3d > &res_dists, unsigned n_thread)
Definition: TreeIso.cpp:995
std::vector< float > Vec3d
Definition: TreeIso.cpp:41
size_t arg_min_col(std::vector< T > &arr)
Definition: TreeIso.cpp:1386
static const char IntermedSegsSFName[]
Definition: TreeIso.cpp:48
static const char InitSegsSFName[]
Definition: TreeIso.cpp:47
void unique_group(std::vector< T > &arr, std::vector< std::vector< T >> &u_group, std::vector< T > &arr_unq, std::vector< T > &ui)
Definition: TreeIso.cpp:1034
void get_subset(std::vector< T1 > &arr, std::vector< T2 > &indices, std::vector< T1 > &arr_sub)
Definition: TreeIso.cpp:1155
core::Tensor result
Definition: VtkUtils.cpp:76
static bool Print(const char *format,...)
Prints out a formatted message in console.
Definition: CVLog.cpp:113
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
static bool Init_seg(const unsigned min_nn1, const float regStrength1, const float PR_DECIMATE_RES1, ecvMainAppInterface *app, QProgressDialog *progressDlg)
Definition: TreeIso.cpp:835
static bool Intermediate_seg_pcd(ccPointCloud *pc, const unsigned PR_MIN_NN2, const float PR_REG_STRENGTH2, const float PR_DECIMATE_RES2, const float PR_MAX_GAP, QProgressDialog *progressDlg=nullptr)
Definition: TreeIso.cpp:143
static bool Final_seg(const unsigned PR_MIN_NN3, const float PR_REL_HEIGHT_LENGTH_RATIO, const float PR_VERTICAL_WEIGHT, ecvMainAppInterface *app, QProgressDialog *progressDlg)
Definition: TreeIso.cpp:911
static bool Final_seg_pcd(ccPointCloud *pc, const unsigned PR_MIN_NN3, const float PR_REL_HEIGHT_LENGTH_RATIO, const float PR_VERTICAL_WEIGHT, QProgressDialog *progressDlg=nullptr)
Definition: TreeIso.cpp:413
static bool Init_seg_pcd(ccPointCloud *pc, const unsigned min_nn1, const float regStrength1, const float PR_DECIMATE_RES1, QProgressDialog *progressDlg=nullptr)
Definition: TreeIso.cpp:58
static bool Intermediate_seg(const unsigned PR_MIN_NN2, const float PR_REG_STRENGTH2, const float PR_DECIMATE_RES2, const float PR_MAX_GAP, ecvMainAppInterface *app, QProgressDialog *progressDlg)
Definition: TreeIso.cpp:871
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
virtual void showSF(bool state)
Sets active scalarfield visibility.
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
virtual void redrawDisplay(bool forceRedraw=true, bool only2D=false)
Redraws associated display.
std::vector< ccHObject * > Container
Standard instances container (for children, etc.)
Definition: ecvHObject.h:337
bool isA(CV_CLASS_ENUM type) const
Definition: ecvObject.h:131
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void setCurrentDisplayedScalarField(int index)
Sets the currently displayed scalar field.
int addScalarField(const char *uniqueName) override
Creates a new scalar field and registers it.
void colorsHaveChanged()
int getScalarFieldIndexByName(const char *name) const
Returns the index of a scalar field represented by its name.
ScalarField * getScalarField(int index) const
Returns a pointer to a specific scalar field.
unsigned size() const override
Definition: PointCloudTpl.h:38
const CCVector3 * getPoint(unsigned index) const override
A simple scalar field (to be associated to a point cloud)
Definition: ScalarField.h:25
void fill(ScalarType fillValue=0)
Fills the array with a particular value.
Definition: ScalarField.h:77
virtual void computeMinAndMax()
Determines the min and max values.
Definition: ScalarField.h:123
ScalarType & getValue(std::size_t index)
Definition: ScalarField.h:92
void setValue(std::size_t index, ScalarType value)
Definition: ScalarField.h:96
Main application interface (for plugins)
virtual const ccHObject::Container & getSelectedEntities() const =0
Returns currently selected entities ("read only")
virtual void dispToConsole(QString message, ConsoleMessageLevel level=STD_CONSOLE_MESSAGE)=0
void query(const Eigen::MatrixBase< Derived > &queryPoints, const size_t knn, Matrixi &indices, Matrix &distances) const
Definition: knncpp.h:1029
void setThreads(const unsigned int threads)
Definition: knncpp.h:962
void setBucketSize(const Index bucketSize)
Definition: knncpp.h:933
void setSorted(const bool sorted)
Definition: knncpp.h:938
int min(int a, int b)
Definition: cutil_math.h:53
__host__ __device__ int2 abs(int2 v)
Definition: cutil_math.h:1267
int max(int a, int b)
Definition: cutil_math.h:48
Definition: API.h:123
@ POINT_CLOUD
Definition: CVTypes.h:104
MiniVec< float, N > floor(const MiniVec< float, N > &a)
Definition: MiniVec.h:75
Eigen::Matrix< Index, Eigen::Dynamic, Eigen::Dynamic > Matrixi
Definition: knncpp.h:34
struct Index Index
Definition: sqlite3.c:14646