ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
qManualSeg.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 "qManualSeg.h"
9 
10 #include <pcl/kdtree/kdtree_flann.h>
11 #include <pcl/point_cloud.h>
12 
13 // Local
14 #include "profileImportDlg.h"
15 
16 // Qt
17 #include <QFile>
18 #include <QFileInfo>
19 #include <QMainWindow>
20 #include <QMessageBox>
21 #include <QSettings>
22 #include <QtGui>
23 
24 // CV_DB_LIB
25 #include <ecvCone.h>
26 #include <ecvDisplayTools.h>
27 #include <ecvFileUtils.h>
28 #include <ecvGenericPointCloud.h>
29 #include <ecvHObjectCaster.h>
30 #include <ecvMesh.h>
31 #include <ecvPointCloud.h>
32 #include <ecvPolyline.h>
33 #include <ecvProgressDialog.h>
34 #include <ecvScalarField.h>
35 
36 // CVCoreLib
37 #include <CVConst.h>
38 #include <CVKdTree.h>
39 #include <CVTools.h>
40 #include <CloudSamplingTools.h>
42 #include <SquareMatrix.h>
43 #include <math.h>
44 
45 #include <algorithm>
46 #include <fstream>
47 #include <iostream>
48 #include <opencv2/highgui/highgui.hpp>
49 #include <opencv2/imgproc/imgproc.hpp>
50 #include <opencv2/opencv.hpp>
51 #include <random>
52 using namespace std;
53 using namespace cv;
54 
55 ccManualSeg::ccManualSeg(QObject* parent)
56  : QObject(parent),
57  ccStdPluginInterface(":/CC/plugin/qManualSeg/info.json"),
58  m_action(0),
59  m_segmentationPoly(0),
60  m_polyVertices(0) {
61  m_polyVertices = new ccPointCloud("vertices");
62  m_segmentationPoly = new ccPolyline(m_polyVertices);
63  m_segmentationPoly->setForeground(true);
64  m_segmentationPoly->setColor(ecvColor::green);
65  m_segmentationPoly->showColors(true);
66  m_segmentationPoly->set2DMode(true);
67 }
68 
69 void ccManualSeg::onNewSelection(const ccHObject::Container& selectedEntities) {
70  if (m_action) {
71  }
72 }
73 
74 QList<QAction*> ccManualSeg::getActions() {
75  if (!m_action) {
76  m_action = new QAction(getName(), this);
77  m_action->setToolTip(getDescription());
78  m_action->setIcon(QIcon(QString::fromUtf8(
79  ":/CC/plugin/qManualSeg/cyberbuildIcon.png")));
80 
81  // Connect appropriate signal
82  connect(m_action, &QAction::triggered, this, &ccManualSeg::doAction);
83  }
84 
85  return QList<QAction*>{
86  m_action,
87  };
88 }
89 
90 // Returns indexes of points inside a polyline from a point cloud
91 vector<int> ccManualSeg::pointIdx(ccPointCloud* cloud, ccPolyline* poly) {
92  // Create pop-up window
94  vector<int> ptsIdx;
95  int cnt = 0;
96 
98  assert(gCloud);
99  gCloud->resetVisibilityArray();
100 
101  if (!poly) {
102  CVLog::Error("No polyline defined!");
103  }
104 
105  if (!poly->isClosed()) {
106  CVLog::Error(
107  "Define and/or close the segmentation polygon first! (right "
108  "click to close)");
109  }
110 
111  // viewing parameters
112  ccGLCameraParameters camera;
114 
118  poly->getAssociatedCloud();
119  bool mode3D = !poly->is2DMode();
120 
121  // duplicate polyline 'a minima' (only points and indexes + closed state)
122  if (m_polyVertices->reserve(vertices->size() +
123  (poly->isClosed() ? 0 : 1)) &&
124  m_segmentationPoly->reserve(poly->size() +
125  (poly->isClosed() ? 0 : 1))) {
126  for (unsigned i = 0; i < vertices->size(); ++i) {
127  CCVector3 P = *vertices->getPoint(i);
128  if (mode3D) {
129  CCVector3d Q2D;
130  camera.project(P, Q2D);
131 
132  P.x = static_cast<PointCoordinateType>(Q2D.x);
133  P.y = static_cast<PointCoordinateType>(Q2D.y);
134  P.z = 0;
135  }
137  }
138 
139  for (unsigned j = 0; j < poly->size(); ++j) {
141  }
142  }
143 
145 
146  ccGenericPointCloud::VisibilityTableType& visibilityArrayBase2 =
147  gCloud->getTheVisibilityArray();
148 
149  for (int j = 0; j < static_cast<int>(gCloud->size()); ++j) {
150  if (visibilityArrayBase2[j] == POINT_VISIBLE) {
151  const CCVector3* P3D = gCloud->getPoint(j);
152 
153  CCVector3d Q2D;
154  camera.project(*P3D, Q2D);
155 
156  CCVector2 P2D(static_cast<PointCoordinateType>(Q2D.x),
157  static_cast<PointCoordinateType>(Q2D.y));
158 
159  bool pointInside =
161  P2D, m_segmentationPoly);
162  // visibility values of 1 are points inside (with false in this
163  // line)
164  visibilityArrayBase2[j] =
165  (false != pointInside ? POINT_HIDDEN : POINT_VISIBLE);
166  cnt = cnt + visibilityArrayBase2[j];
167  if (visibilityArrayBase2[j] == 1) ptsIdx.push_back(j);
168  }
169  }
170 
171  return ptsIdx;
172 }
173 
174 // Returns a the contour as a polyline
176  std::vector<cloudViewer::PointProjectionTools::IndexedCCVector2> point;
177  std::list<cloudViewer::PointProjectionTools::IndexedCCVector2*> hullPoint2;
178 
179  for (unsigned i = 0; i < stone->size(); ++i)
180 
181  {
182  PointCoordinateType x = stone->getPoint(i)->x;
183  PointCoordinateType z = stone->getPoint(i)->z;
185 
186  point.push_back(P);
187  }
188 
190  0.0001);
191 
192  vector<unsigned> Vec;
193  for (int i = 0; i < (hullPoint2.size()); ++i) {
194  list<cloudViewer::PointProjectionTools::IndexedCCVector2*>::iterator
195  it = hullPoint2.begin();
196  std::advance(it, i);
198  int k = P2->index;
199  Vec.push_back(k);
200  }
201 
202  ccPointCloud* contour =
203  new ccPointCloud(stone->getName() + " - Contour Cloud");
204 
205  for (auto e : Vec) {
206  contour->reserveThePointsTable(1);
207  contour->reserveTheRGBTable();
208  CCVector3 p(stone->getPoint(e)->x, 0, stone->getPoint(e)->z);
209  contour->addPoint(p);
210 
211  const ecvColor::Rgb col = stone->getPointColor(e);
212  contour->addRGBColor(col);
213  }
214 
215  int cnt = Vec.size();
216 
217  ccPolyline* pContour = new ccPolyline(contour);
218  if (pContour->reserve(cnt)) {
219  pContour->addPointIndex(0, cnt);
220  pContour->setClosed(true);
221  pContour->setVisible(true);
222  pContour->setName(stone->getName() + " - Contour");
223  pContour->addChild(contour);
224  pContour->setColor(ecvColor::cyan);
225  pContour->showColors(true);
226  pContour->showVertices(true);
227  }
228  return pContour;
229 }
230 
231 // Returns stone indexes given points idexes
232 vector<int> ccManualSeg::stIdFromPtId(std::vector<int> pts,
233  std::vector<pair<int, int>> pairs) {
234  vector<int> v;
235 
236  for (auto e : pts)
237  if (!(find(v.begin(), v.end(), e) != v.end()))
238  v.push_back(pairs[e].second);
239 
240  sort(v.begin(), v.end());
241 
242  v.erase(unique(v.begin(), v.end()), v.end());
243 
244  return v;
245 }
246 
247 // Returns returns points indexes given stone indexes
248 vector<int> ccManualSeg::ptIdFromStId(std::vector<int> stIdx,
249  std::vector<pair<int, int>> pairs) {
250  vector<int> v;
251 
252  for (auto e : stIdx)
253  for (unsigned int i = 0; i < pairs.size(); i++)
254  if (pairs[i].second == e) v.push_back(pairs[i].first);
255 
256  return v;
257 }
258 
259 // Returns the centroid of a 2D point data set
260 pair<double, double> getCentroid(vector<pair<double, double>> V) {
261  double Sx = 0;
262  double Sz = 0;
263  int n = V.size();
264 
265  for (auto e : V) {
266  Sx += e.first;
267  Sz += e.second;
268  }
269 
270  return (make_pair(Sx / n, Sz / n));
271 }
272 
273 // Returns indexes of k (3 by default) nearest neighbors
274 vector<int> getKNN(pair<double, double> P,
275  vector<pair<double, double>> V,
276  int k = 3) {
277  if (k > V.size()) k = V.size();
278 
279  vector<pair<int, double>> distances;
280  double d;
281  vector<int> t(k);
282 
283  for (unsigned i = 0; i < V.size(); ++i) {
284  d = sqrt(pow((P.first - V[i].first), 2) +
285  pow((P.second - V[i].second), 2));
286  distances.push_back(make_pair(i, d));
287  }
288 
289  sort(distances.begin(), distances.end(),
290  [](auto& left, auto& right) { return left.second < right.second; });
291 
292  for (unsigned i = 0; i < k; ++i) {
293  t[i] = distances[i].first;
294  }
295 
296  return t;
297 }
298 
299 // Returns the number of common points within two data sets
300 int getNCommonPts(vector<pair<double, double>> tar,
301  vector<pair<double, double>> ref) {
302  int n = 0;
303  int n0 = 0;
304 
305  vector<pair<double, double>> allpts = tar;
306 
307  sort(allpts.begin(), allpts.end());
308  allpts.erase(unique(allpts.begin(), allpts.end()), allpts.end());
309 
310  allpts.insert(allpts.end(), ref.begin(), ref.end());
311  sort(allpts.begin(), allpts.end());
312 
313  n0 = allpts.size();
314 
315  allpts.erase(unique(allpts.begin(), allpts.end()), allpts.end());
316 
317  n = n0 - allpts.size();
318 
319  return n;
320 }
321 
322 // Returns the indexes of common points in two Point Clouds
323 vector<vector<int>> getCommonPtsIdx(ccPointCloud* Cl1, ccPointCloud* Cl2) {
324  vector<vector<int>> CommonPtsIdx(2);
325  vector<pair<float, float>> Pts1(Cl1->size());
326  vector<pair<float, float>> Pts2(Cl2->size());
327  vector<pair<float, float>> Pts1C;
328  vector<pair<float, float>> Pts2C;
329  vector<pair<float, float>> allPts;
330  vector<pair<float, float>> uniquePts;
331  vector<pair<float, float>> commonPts;
332 
333  for (unsigned i = 0; i < Cl1->size(); i++) {
334  Pts1[i] = make_pair(Cl1->getPoint(i)->x, Cl1->getPoint(i)->z);
335  }
336  for (unsigned i = 0; i < Cl2->size(); i++) {
337  Pts2[i] = make_pair(Cl2->getPoint(i)->x, Cl2->getPoint(i)->z);
338  }
339 
340  Pts1C = Pts1;
341  Pts2C = Pts2;
342 
343  sort(Pts1C.begin(), Pts1C.end());
344  sort(Pts2C.begin(), Pts2C.end());
345 
346  Pts1C.erase(unique(Pts1C.begin(), Pts1C.end()), Pts1C.end());
347  Pts2C.erase(unique(Pts2C.begin(), Pts2C.end()), Pts2C.end());
348 
349  allPts = Pts1C;
350  allPts.insert(allPts.end(), Pts2C.begin(), Pts2C.end());
351  sort(allPts.begin(), allPts.end());
352  uniquePts = allPts;
353 
354  uniquePts.erase(unique(uniquePts.begin(), uniquePts.end()),
355  uniquePts.end());
356  std::set_difference(allPts.begin(), allPts.end(), uniquePts.begin(),
357  uniquePts.end(),
358  std::inserter(commonPts, commonPts.end()));
359  sort(commonPts.begin(), commonPts.end());
360 
361  for (unsigned i = 0; i < Cl1->size(); i++) {
362  if (std::binary_search(commonPts.begin(), commonPts.end(), Pts1[i]))
363  CommonPtsIdx[0].push_back(i);
364  }
365 
366  for (unsigned i = 0; i < Cl2->size(); i++) {
367  if (std::binary_search(commonPts.begin(), commonPts.end(), Pts2[i]))
368  CommonPtsIdx[1].push_back(i);
369  }
370 
371  return CommonPtsIdx;
372 }
373 
375  Mat& corrMatS,
376  vector<Point>& idxPxS,
377  vector<int>& idxPx1DS,
378  Mat& imageBWS) {
379  // Correspondence 2D->1D. Each px has an index instead of two coords
380  int cntC = 0;
381  for (int y = 0; y < corrMatS.rows; y++) {
382  for (int x = 0; x < corrMatS.cols; x++) {
383  corrMatS.at<int>(y, x) = cntC;
384  cntC++;
385  }
386  }
387 
388  // Binary
389  int s = cloud->size();
390  const CCVector3* pointC0;
391  for (int i = 0; i < s; i++) {
392  // depth
393  pointC0 = cloud->getPoint(i);
394  int z = floor(pointC0->z);
395  int x = floor(pointC0->x);
396  imageBWS.at<uchar>(z, x) = 255;
397 
398  // idxPx per 3D point
399 
400  idxPxS.push_back(Point(z, x));
401  idxPx1DS.push_back(corrMatS.at<int>(z, x));
402  }
403 }
404 
405 // Extract Skeleton from Binary (CV_8U)
406 Mat skeleton(Mat I, bool flagInv) {
407  Mat toSkel;
408  if (flagInv) { // If black-white inversion is required
409  toSkel = 255 * cv::Mat::ones(I.rows, I.cols, CV_8U) - I;
410  } else {
411  toSkel = I;
412  }
413 
414  cv::Mat skel(toSkel.size(), CV_8U, cv::Scalar(0));
415  cv::Mat temp;
416  cv::Mat eroded;
417 
418  cv::Mat element =
419  cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(3, 3));
420  int iterations = 0;
421 
422  bool done;
423  do {
424  cv::erode(toSkel, eroded, element);
425  cv::dilate(eroded, temp, element);
426  cv::subtract(toSkel, temp, temp);
427  cv::bitwise_or(skel, temp, skel);
428  eroded.copyTo(toSkel);
429 
430  done = (cv::countNonZero(toSkel) == 0);
431  iterations++;
432  } while (!done && (iterations < 100));
433 
434  return skel;
435 }
436 
437 vector<int> setIntersectIdxPixs1D(vector<int> listNew, vector<int> listOld) {
438  vector<int> commonList;
439 
440  // Common
441  int cnt = 0;
442  for (auto& e : listNew) {
443  for (auto& ee : listOld) {
444  if (e == ee) {
445  commonList.push_back(cnt);
446  break;
447  }
448  }
449  cnt++;
450  }
451 
452  return commonList;
453 }
454 
455 ccPolyline* contourPoly2(ccPointCloud* cloud0, vector<int> V, QString name) {
456  std::vector<cloudViewer::PointProjectionTools::IndexedCCVector2> point;
457  std::list<cloudViewer::PointProjectionTools::IndexedCCVector2*> hullPoint2;
458 
459  for (unsigned i = 0; i < V.size(); ++i)
460 
461  {
462  PointCoordinateType x = cloud0->getPoint(V[i])->x;
463  PointCoordinateType z = cloud0->getPoint(V[i])->z;
465 
466  point.push_back(P);
467  }
468 
470  0.0001);
471 
472  vector<unsigned> Vec;
473  for (int i = 0; i < (hullPoint2.size()); ++i) {
474  list<cloudViewer::PointProjectionTools::IndexedCCVector2*>::iterator
475  it = hullPoint2.begin();
476  std::advance(it, i);
478  int k = P2->index;
479  Vec.push_back(k);
480  }
481 
482  ccPointCloud* contour = new ccPointCloud(name + " - Contour Cloud");
483 
484  for (auto e : Vec) {
485  contour->reserveThePointsTable(1);
486  contour->reserveTheRGBTable();
487  CCVector3 p(
488  cloud0->getPoint(V[e])->x, cloud0->getPoint(V[e])->y,
489  cloud0->getPoint(V[e])->z); // kike added "y" value (it was 0)
490  contour->addPoint(p);
491 
492  const ecvColor::Rgb col = cloud0->getPointColor(V[e]);
493  contour->addRGBColor(col);
494  }
495 
496  int cnt = Vec.size();
497 
498  ccPolyline* pContour = new ccPolyline(contour);
499 
500  if (pContour->reserve(cnt)) {
501  pContour->addPointIndex(0, cnt);
502  pContour->setClosed(true);
503  pContour->setVisible(true);
504  pContour->setName(name + " - Contour");
505  pContour->addChild(contour);
506  pContour->setColor(ecvColor::cyan);
507  pContour->showColors(true);
508  pContour->showVertices(true);
509  }
510 
511  return pContour;
512 }
513 
514 string dateStamp() {
515  time_t rawtime;
516  struct tm* timeinfo;
517  char buffer[80];
518 
519  time(&rawtime);
520  timeinfo = localtime(&rawtime);
521 
522  strftime(buffer, sizeof(buffer), "%H:%M:%S", timeinfo);
523  std::string str(buffer);
524 
525  string stamp("[");
526  stamp += str;
527  stamp += "]";
528 
529  return stamp;
530 }
531 
532 // Returns mortar maps (Depth and width)
534  ccPointCloud* f_cloudMortar) {
535  // Binary Mortar
536 
537  // Bringing clouds to the origin
538  CCVector3 minBox0;
539  minBox0 = CCVector3(0, 0, 0);
540  CCVector3 maxBox0;
541  maxBox0 = CCVector3(0, 0, 0);
542  f_cloudMortar->getBoundingBox(minBox0, maxBox0);
543  f_cloudMortar->Translate(-minBox0);
544  f_cloudStones->Translate(-minBox0);
545 
546  CCVector3 minBox;
547  minBox = CCVector3(0, 0, 0);
548  CCVector3 maxBox;
549  maxBox = CCVector3(0, 0, 0);
550  f_cloudMortar->scale(100, 1000, 100); // To cm mm cm
551  f_cloudMortar->getBoundingBox(minBox, maxBox);
552 
553  int rowsM = ceil(maxBox.z);
554  int colsM = ceil(maxBox.x);
555 
556  cv::Mat corrMatM = Mat::zeros(rowsM, colsM, CV_32F);
557  vector<Point> idxPxM;
558  vector<int> idxPxM1D;
559  cv::Mat imageBWS = Mat::zeros(rowsM, colsM, CV_8U);
560 
561  cloud2binary(f_cloudMortar, corrMatM, idxPxM, idxPxM1D, imageBWS);
562 
563  // Skeleton
564  Mat skel = skeleton(imageBWS, false);
565 
566  f_cloudMortar->scale(0.01, 0.001, 0.01); // Scale back
567 
568  // Skeleton 3D
569  vector<int> pixelsSkel;
570  for (int i = 0; i < skel.rows; i++) {
571  for (int j = 0; j < skel.cols; j++) {
572  unsigned char a = skel.at<char>(i, j);
573  if (a == 255) {
574  int idx = corrMatM.at<int>(i, j);
575  pixelsSkel.push_back(idx);
576  }
577  }
578  }
579 
580  vector<int> idxCloudMortarSkel =
581  setIntersectIdxPixs1D(idxPxM1D, pixelsSkel);
582  ccPointCloud* skelM = new ccPointCloud("Skeleton Mortar");
583  for (auto e : idxCloudMortarSkel) {
584  skelM->reserveThePointsTable(1);
585  skelM->reserveTheRGBTable();
586  CCVector3 p(f_cloudMortar->getPoint(e)->x,
587  f_cloudMortar->getPoint(e)->y,
588  f_cloudMortar->getPoint(e)->z);
589  skelM->addPoint(p);
590  const ecvColor::Rgb col = f_cloudMortar->getPointColor(e);
591  skelM->addRGBColor(col);
592  }
593 
595  false); // Subsample result
596  cloudViewer::ReferenceCloud* refCloud =
598  skelM, 0.01, modParams, 0, 0); // 1 point per cm^2
599 
600  ccPointCloud* f_skelMortar = skelM->partialClone(refCloud); // save output
601  delete refCloud;
602  delete skelM;
603  refCloud = 0;
604  skelM = 0;
605 
606  // Maps using PCL
607  // Mortar depth map
608  pcl::PointCloud<pcl::PointXYZ>::Ptr pcl_cloudStones(
609  new pcl::PointCloud<pcl::PointXYZ>);
610  pcl_cloudStones->width = f_cloudStones->size();
611  pcl_cloudStones->height = 1;
612  pcl_cloudStones->points.resize(pcl_cloudStones->width *
613  pcl_cloudStones->height);
614 
615  for (size_t i = 0; i < f_cloudStones->size(); ++i) {
616  pcl_cloudStones->points[i].x = f_cloudStones->getPoint(i)->x;
617  pcl_cloudStones->points[i].y = f_cloudStones->getPoint(i)->y;
618  pcl_cloudStones->points[i].z = f_cloudStones->getPoint(i)->z;
619  }
620 
621  pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
622 
623  kdtree.setInputCloud(pcl_cloudStones);
624 
625  unsigned int nnIdx;
626  vector<double> distStD, dist3St, distStD2;
627  vector<double> distStWidth;
628  vector<double> distStW;
629  for (int i = 0; i < f_skelMortar->size(); i++) {
630  pcl::PointXYZ searchPoint;
631 
632  searchPoint.x = f_skelMortar->getPoint(i)->x;
633  searchPoint.y = f_skelMortar->getPoint(i)->y;
634  searchPoint.z = f_skelMortar->getPoint(i)->z;
635 
636  std::vector<int> pointIdxRadiusSearch;
637  std::vector<float> pointRadiusSquaredDistance;
638 
639  float radius = 0.1; // 10cm
640  pcl::PointXYZ nnPoint;
641 
642  if (kdtree.radiusSearch(searchPoint, radius, pointIdxRadiusSearch,
643  pointRadiusSquaredDistance) > 0) {
644  nnPoint.x = pcl_cloudStones->points[pointIdxRadiusSearch[0]].x;
645  nnPoint.y = pcl_cloudStones->points[pointIdxRadiusSearch[0]].y;
646  nnPoint.z = pcl_cloudStones->points[pointIdxRadiusSearch[0]].z;
647 
648  double disty = abs(searchPoint.y - nnPoint.y); // Depth
649  double distx = abs(searchPoint.x - nnPoint.x);
650  double distz = abs(searchPoint.z - nnPoint.z);
651  double dist3 = sqrt(distx * distx +
652  distz * distz); // 2D distance (XZ) will be
653  // used as a reference for the
654  // creation of mortar width map
655 
656  distStD.push_back(disty * 1000); // depth (y axis) in mm
657  dist3St.push_back(dist3);
658 
659  double dist1 = 1000;
660  double dist2 = 1000;
661  double dist1y = 1000;
662  double dist2y = 1000;
663  int idx1 = -1;
664  int idx2 = -1;
665  for (size_t j = 0; j < pointIdxRadiusSearch.size(); ++j) {
666  double distx =
667  abs(searchPoint.x -
668  pcl_cloudStones->points[pointIdxRadiusSearch[j]]
669  .x); // 2D distance
670  double distz =
671  abs(searchPoint.z -
672  pcl_cloudStones->points[pointIdxRadiusSearch[j]].z);
673  double disty =
674  abs(searchPoint.y -
675  pcl_cloudStones->points[pointIdxRadiusSearch[j]].y);
676  double dist3 =
677  sqrt(abs(distx) * abs(distx) + abs(distz) * abs(distz));
678 
679  int idxSt = f_cloudStones->getPointScalarValue(
680  pointIdxRadiusSearch[j]);
681 
682  if (j == 0) { // Initialise NN stone 1
683  dist1 = dist3;
684  dist1y = disty;
685  idx1 = idxSt;
686  } else {
687  if (idxSt == idx1) { // If point belongs to stone 1
688  if (dist3 < dist1) dist1 = dist3;
689  dist1y = disty;
690  }
691  if (idxSt != idx1 & idx2 == -1) { // Initialise stone 2
692  idx2 = idxSt;
693  dist2 = dist3;
694  dist2y = disty;
695  }
696  if (idxSt == idx2) { // If point belongs to stone 2
697  if (dist3 < dist2) dist2 = dist3;
698  dist2y = disty;
699  }
700  }
701 
702  } // Points are ordered by radius. Idx 0 is the nearest neighbour
703 
704  // For each point, there is dist1 or dist1 and dist2
705  if (idx1 > -1 & idx2 == -1 &
706  dist1 < 1000) { // Only one stone (boundaries of wall)
707  distStW.push_back(dist1 * 1000);
708  distStD2.push_back(dist1y * 1000);
709  } else if (idx1 > -1 & idx2 > -1) {
710  distStW.push_back((dist1 + dist2) * 1000);
711  distStD2.push_back((dist1y + dist2y) / 2 * 1000);
712  }
713 
714  } else {
715  distStD.push_back(
716  100); // Add high values for non-calculated values (no
717  // neighbours available). These values can be
718  // modified according to the needs
719  distStD2.push_back(100);
720  dist3St.push_back(200);
721 
722  distStW.push_back(200);
723  }
724  }
725 
726  cloudViewer::ScalarField* depthSF =
727  nullptr; // Add depth as a scalarField to f_skelMortar
728 
729  int sfIdxD = f_skelMortar->getScalarFieldIndexByName(
730  "Mortar relative depth (mm)");
731  if (sfIdxD < 0) {
732  sfIdxD = f_skelMortar->addScalarField("Mortar relative depth (mm)");
733  }
734  if (sfIdxD < 0) {
735  return nullptr;
736  }
737 
738  depthSF = f_skelMortar->getScalarField(sfIdxD);
739 
740  for (unsigned int i = 0; i < distStD2.size(); i++) {
741  double index = static_cast<double>(distStD2.at(i));
742  depthSF->setValue(i, index);
743  }
744 
745  f_skelMortar->setCurrentDisplayedScalarField(sfIdxD);
746 
747  depthSF->computeMinAndMax();
748 
749  cloudViewer::ScalarField* widthSF =
750  nullptr; // Add width as a scalarField to f_skelMortar
751 
752  int sfIdxW = f_skelMortar->getScalarFieldIndexByName(
753  "Mortar relative width (mm)");
754  if (sfIdxW < 0) {
755  sfIdxW = f_skelMortar->addScalarField("Mortar relative width (mm)");
756  }
757  if (sfIdxW < 0) {
758  return nullptr;
759  }
760 
761  widthSF = f_skelMortar->getScalarField(sfIdxW);
762 
763  for (unsigned int i = 0; i < distStW.size(); i++) {
764  double index = static_cast<double>(distStW.at(i));
765  widthSF->setValue(i, index);
766  }
767 
768  f_skelMortar->setCurrentDisplayedScalarField(sfIdxW);
769 
770  f_cloudMortar->Translate(minBox0);
771  f_cloudStones->Translate(minBox0);
772  f_skelMortar->Translate(minBox0);
773  widthSF->computeMinAndMax();
774  f_skelMortar->setPointSize(10);
775  f_skelMortar->showSF(true);
776  f_skelMortar->setName("Mortar Maps");
777  return f_skelMortar;
778 }
779 
780 void ccManualSeg::doAction() {
781  // Create log file
782 
783  time_t rawtime;
784  struct tm* timeinfo;
785  char buffer[80];
786 
787  time(&rawtime);
788  timeinfo = localtime(&rawtime);
789 
790  strftime(buffer, sizeof(buffer), "%Y%m%d_%H%M%S", timeinfo);
791  std::string str(buffer);
792 
793  string filename("MSP_log_");
794  filename += str;
795  filename += ".txt";
796  ofstream auto_seg_log;
797 
798  string stamp;
799 
800  time_t my_time = time(NULL);
801 
802  if (m_app == nullptr) {
803  // m_app should have already been initialized by CC when plugin is
804  // loaded
805  Q_ASSERT(false);
806 
807  return;
808  }
809 
811 
812  int cnt = 0;
813  int cnt2 = 0;
814 
815  // Dialog showing message. 31/10/2018
817 
818  // Check loaded point clouds (there should be 2: base and segmented)
819  ccHObject* root = m_app->dbRootObject();
820  ccPointCloud* segmentCloud;
821 
822  std::vector<int> idxPoly;
823  int idxStone = -1;
824  int idxMortar = -1;
825  int refStone = -1;
826  int refMortar = -1;
827 
829  ccHObject::Container polys;
830  ccHObject::Container contourfolder;
831  ccHObject::Container oldMortarMaps;
832 
833  bool bench = false;
834 
835  // removing old contours and mortar maps from DB
836  if (root) {
837  root->filterChildren(contourfolder, true, CV_TYPES::HIERARCHY_OBJECT);
838  root->filterChildren(oldMortarMaps, true, CV_TYPES::POINT_CLOUD);
839 
840  if (contourfolder.size() >= 0) {
841  for (int i = 0; i < contourfolder.size(); ++i) {
842  ccHObject* ContoursContainer = contourfolder[i];
843 
844  QString s = ContoursContainer->getName();
845  string s0 = s.toStdString();
846  string s1 = "tone contours";
847 
848  if (s0.find(s1) != std::string::npos) {
849  m_app->removeFromDB(ContoursContainer, false);
850  }
851  }
852  }
853 
854  if (oldMortarMaps.size() >= 0) {
855  for (int i = 0; i < contourfolder.size(); ++i) {
856  ccHObject* Maps = contourfolder[i];
857 
858  QString s = Maps->getName();
859  string s0 = s.toStdString();
860  string s1 = "Mortar Maps";
861 
862  if (s0.find(s1) != std::string::npos) {
863  m_app->removeFromDB(Maps, false);
864  }
865  }
866  }
867  }
868 
869  ccPointCloud* cloudStone = new ccPointCloud("cloudStone");
870  ccPointCloud* cloudMortar = new ccPointCloud("cloudMortar");
871  ccPointCloud* refStoneCloud = new ccPointCloud("refStoneCloud");
872  ccPointCloud* refMortarCloud = new ccPointCloud("refMortarCloud");
873 
874  CCVector3 minBox0;
875  minBox0 = CCVector3(0, 0, 0);
876  CCVector3 maxBox0;
877  maxBox0 = CCVector3(0, 0, 0);
878 
879  if (root) {
880  int sizeClouds = 1000000000;
881  root->filterChildren(pcs, true, CV_TYPES::POINT_CLOUD);
882  root->filterChildren(polys, true, CV_TYPES::POLY_LINE);
883 
884  int t = pcs.size();
885  int n = polys.size();
886 
887  if (t >= 2) {
888  QFileInfo fileInfo(pcs.front()->getFullPath());
889  QDir dir(fileInfo.absolutePath());
890  QString autoSegLogFile = dir.absoluteFilePath(filename.c_str());
891  filename = CVTools::FromQString(autoSegLogFile);
892  auto_seg_log.open(filename);
893  for (int i = 0; i < pcs.size(); ++i) {
894  ccPointCloud* cl = static_cast<ccPointCloud*>(pcs.at(i));
895  QString s = cl->getName();
896  string s0 = s.toStdString();
897  string s1 = "tone";
898  string s2 = "ortar";
899  string s3 = "ref";
900 
901  if ((s0.find(s3) != std::string::npos) &&
902  (s0.find(s1) != std::string::npos)) {
903  refStone = i;
904  string cComment = "reference stone cloud found!";
905  QString qComment = QString::fromUtf8(cComment.c_str());
908 
909  stamp = dateStamp();
910  auto_seg_log << stamp << " Reference stone cloud found"
911  << endl;
912  }
913 
914  if ((s0.find(s3) != std::string::npos) &&
915  (s0.find(s2) != std::string::npos)) {
916  refMortar = i;
917  string cComment = "reference mortar cloud found!";
918  QString qComment = QString::fromUtf8(cComment.c_str());
921 
922  stamp = dateStamp();
923  auto_seg_log << stamp << " Reference mortar cloud found"
924  << endl;
925  }
926 
927  if (!(s0.find(s3) != std::string::npos) &&
928  (s0.find(s1) != std::string::npos)) {
929  idxStone = i;
930  string cComment = "Stone cloud found!";
931  QString qComment = QString::fromUtf8(cComment.c_str());
934 
935  stamp = dateStamp();
936  auto_seg_log << stamp << " Stone cloud found" << endl;
937  }
938 
939  if (!(s0.find(s3) != std::string::npos) &&
940  (s0.find(s2) != std::string::npos)) {
941  idxMortar = i;
942  string cComment = "Mortar cloud found!";
943  QString qComment = QString::fromUtf8(cComment.c_str());
946 
947  stamp = dateStamp();
948  auto_seg_log << stamp << " Mortar cloud found" << endl;
949  }
950 
951  // For Bench
952 
953  if (n == 0 && refStone != -1 && idxStone != -1 &&
954  refMortar != -1 && idxMortar != -1) {
955  bench = true;
956 
957  refStoneCloud =
958  static_cast<ccPointCloud*>(pcs.at(refStone));
959  refMortarCloud =
960  static_cast<ccPointCloud*>(pcs.at(refMortar));
961  cloudStone = static_cast<ccPointCloud*>(pcs.at(idxStone));
962  cloudMortar = static_cast<ccPointCloud*>(pcs.at(idxMortar));
963  }
964  }
965 
966  } else {
968  "At least one cloud and a polyline are required",
970  return;
971  }
972 
973  if (!bench) {
974  if (idxMortar != -1 && idxStone != -1) {
975  cloudStone = static_cast<ccPointCloud*>(pcs.at(idxStone));
976  cloudMortar = static_cast<ccPointCloud*>(pcs.at(idxMortar));
977  } else {
978  if (idxMortar == -1 && idxStone == -1) {
979  int cnt = 0;
980 
981  for (int i = 0; i < pcs.size(); ++i) {
982  ccPointCloud* cl =
983  static_cast<ccPointCloud*>(pcs.at(i));
984 
985  if (cl->size() > 100) {
986  idxMortar = i;
987  cnt++;
988  }
989  }
990 
991  if (cnt > 1) {
993  "For manual segmentation leave only one cloud "
994  "in DB",
996  return;
997  }
998 
999  cloudMortar = static_cast<ccPointCloud*>(pcs.at(idxMortar));
1000 
1001  cloudMortar->getBoundingBox(minBox0, maxBox0);
1002 
1003  }
1004 
1005  else {
1007  "Only one cloud has been foud",
1009 
1011  "for manual segmentation please change it's name "
1012  "so that it doesn't contain the sequence 'stone' "
1013  "or 'mortar'",
1015 
1016  return;
1017  }
1018  }
1019  }
1020  } else {
1021  return;
1022  }
1023 
1024  if (!bench) {
1025  // saving point size
1026  unsigned pointSizeMortar = cloudMortar->getPointSize();
1027 
1028  std::vector<int> recIdx;
1029  std::vector<int> polyIdx;
1030 
1031  // Make the distinction between rectangles and non rectangular polylines
1032  for (unsigned int i = 0; i < polys.size(); i++) {
1033  ccPolyline* poly = static_cast<ccPolyline*>(polys.at(i));
1034  // poly->point
1035  int j = poly->size();
1036 
1037  const CCVector3* Pt0 = poly->getPoint(0);
1038  float x0 = poly->getPoint(0)->x;
1039  float x1 = poly->getPoint(1)->x;
1040  float x2 = poly->getPoint(2)->x;
1041  float x3 = poly->getPoint(3)->x;
1042  float dx1 = x1 - x0;
1043  float dx2 = x3 - x2;
1044  bool a = false;
1045 
1046  if (poly->size() == 4 && dx1 == dx2) {
1047  recIdx.push_back(i);
1048  } else {
1049  polyIdx.push_back(i);
1050  }
1051  }
1052 
1053  // Creating vectors
1054 
1055  vector<vector<pair<int, int>>> stonePairs(2);
1056  vector<vector<int>> mortarPoints(2);
1057  vector<int> allStIdx;
1058 
1059  int sfindex = cloudStone->getScalarFieldIndexByName("Stone Index");
1060  cloudViewer::ScalarField* stIdSF = cloudStone->getScalarField(sfindex);
1061 
1062  for (unsigned int i = 0; i < cloudMortar->size(); i++)
1063  mortarPoints[0].push_back(i);
1064 
1065  int maxId = 0;
1066 
1067  if (cloudStone->size() > 0) {
1068  for (unsigned int i = 0; i < cloudStone->size(); i++) {
1069  stonePairs[0].push_back(make_pair(i, stIdSF->getValue(i)));
1070  allStIdx.push_back(stIdSF->getValue(i));
1071  }
1072 
1073  sort(allStIdx.begin(), allStIdx.end());
1074 
1075  int n = allStIdx.size();
1076  maxId = allStIdx[n - 1];
1077  }
1078 
1079  stamp = dateStamp();
1080  auto_seg_log << " Evaluating polylines ("
1081  << polyIdx.size() + recIdx.size() << ")..." << endl;
1082 
1083  // rectangular polyline
1084  if (recIdx.size() != 0) {
1085  stamp = dateStamp();
1086  auto_seg_log << " Deleting incorrectly identified stones ("
1087  << recIdx.size() << ")..." << endl;
1088  int cntRect = 0;
1089  for (auto i : recIdx) {
1090  cntRect++;
1091  stamp = dateStamp();
1092  auto_seg_log << stamp << " Polyline " << cntRect << "/"
1093  << recIdx.size() << endl;
1094 
1095  vector<int> v;
1096  vector<int> stId;
1097 
1098  ccPolyline* poly = static_cast<ccPolyline*>(polys.at(i));
1099 
1100  v = pointIdx(cloudStone, poly);
1101  stId = stIdFromPtId(v, stonePairs[0]);
1102 
1103  for (auto e : stId)
1104  for (unsigned int i = 0; i < stonePairs[0].size(); ++i) {
1105  if (stonePairs[0][i].second == e) {
1106  stonePairs[0][i].second = -1;
1107  mortarPoints[1].push_back(stonePairs[0][i].first);
1108  }
1109  }
1110  m_app->removeFromDB(poly, false);
1111  }
1112  }
1113 
1114  // Polylines
1115  if (polyIdx.size() != 0) {
1116  stamp = dateStamp();
1117  auto_seg_log << " Correcting boundaries of stones ("
1118  << polyIdx.size() << ")..." << endl;
1119  int cntPoly = 0;
1120  for (auto i : polyIdx) {
1121  cntPoly++;
1122  stamp = dateStamp();
1123  auto_seg_log << stamp << " Polyline " << cntPoly << "/"
1124  << polyIdx.size() << endl;
1125  ccPolyline* poly = static_cast<ccPolyline*>(polys.at(i));
1126 
1127  vector<int> vs;
1128  vector<int> vm;
1129  vector<int> stId;
1130 
1131  vs = pointIdx(cloudStone, poly);
1132  vm = pointIdx(cloudMortar, poly);
1133 
1134  int k;
1135  string kLabel;
1136 
1137  if (vm.size() == 0 &&
1138  vs.size() != 0) { // values can be test for higher than
1139  // zero just in case noise
1140  k = 1;
1141  kLabel = " (Removing stone)";
1142  }
1143  if (vs.size() == 0 && vm.size() != 0) {
1144  k = 2;
1145  kLabel = " (Adding new stone)";
1146  }
1147  if (vs.size() != 0 && vm.size() != 0) {
1148  k = 3;
1149  kLabel = " (Correcting previously segmented stone)";
1150  }
1151 
1152  stamp = dateStamp();
1153  auto_seg_log << stamp << " Case " << k << kLabel << endl;
1154 
1155  switch (k) {
1156  case 1: {
1157  vector<int> vr;
1158  vector<int> vall;
1159 
1160  stId = stIdFromPtId(vs, stonePairs[0]);
1161 
1162  if (stId.size() == 1 && stId[0] == -1) {
1163  maxId++;
1164  for (auto e : vs) {
1165  stonePairs[0][e].second = maxId;
1166  }
1167 
1168  vector<int> tempMortar = mortarPoints[1];
1169  vector<int> resMortar;
1170  sort(tempMortar.begin(), tempMortar.end());
1171  std::set_difference(
1172  tempMortar.begin(), tempMortar.end(),
1173  vs.begin(), vs.end(),
1174  std::inserter(resMortar, resMortar.end()));
1175 
1176  mortarPoints[1] = resMortar;
1177 
1178  }
1179 
1180  else {
1181  vall = ptIdFromStId(stId, stonePairs[0]);
1182 
1183  std::set_difference(vall.begin(), vall.end(),
1184  vs.begin(), vs.end(),
1185  std::inserter(vr, vr.end()));
1186 
1187  for (auto e : vr) {
1188  mortarPoints[1].push_back(e);
1189  stonePairs[0][e].second = -1;
1190  }
1191  }
1192 
1193  break;
1194  }
1195  case 2: {
1196  maxId++;
1197  for (auto e : vm) {
1198  stonePairs[1].push_back(make_pair(e, maxId));
1199  (mortarPoints[0])[e] = -1;
1200  }
1201  break;
1202  }
1203  case 3: {
1204  int minId;
1205  vector<int> vr;
1206  vector<int> vall;
1207 
1208  stId = stIdFromPtId(
1209  vs, stonePairs[0]); // Extract stone indices
1210  // from selection
1211 
1212  minId = stId[0]; // Select minId from indices
1213 
1214  for (auto e : stId) {
1215  if (e < minId) minId = e;
1216  }
1217 
1218  if (minId == -1) // If there is stone labelled as -1
1219  // inside (not belonging to any stone)
1220  {
1221  maxId++;
1222  minId = maxId; // Create a new label (?). This
1223  // should be done only if there is
1224  // no other stone in the selection
1225  }
1226 
1227  for (auto e : vm) // for each point from mortar cloud
1228  // in the selection
1229  {
1230  stonePairs[1].push_back(make_pair(
1231  e, minId)); // Add to stone vector. Note
1232  // that stonePairs[1] contains
1233  // points from the stone cloud
1234  // to be added as mortar
1235  mortarPoints[0][e] =
1236  -1; // Remove from mortar (idx to -1)
1237  }
1238 
1239  vall = ptIdFromStId(
1240  stId, stonePairs[0]); // All the points with
1241  // idx similar to the
1242  // ones in the selection
1243 
1244  for (auto e : vall) {
1245  stonePairs[0][e].second =
1246  minId; // Relabel all those points with
1247  // minId
1248  }
1249 
1250  sort(vs.begin(), vs.end());
1251  sort(vall.begin(), vall.end());
1252  std::set_difference(
1253  vall.begin(), vall.end(), vs.begin(), vs.end(),
1254  std::inserter(
1255  vr,
1256  vr.end())); // Difference between vall
1257  // and vs > Extract to vr
1258 
1259  if (vr.size() > 0) {
1260  for (auto e :
1261  vr) // Label these as mortar. Some points can
1262  // be duplicates (e.g. stone divided in
1263  // several chunks and outliers assigned to
1264  // mortar several times), so this is
1265  // checked below
1266  {
1267  mortarPoints[1].push_back(e);
1268  stonePairs[0][e].second =
1269  -1; // remove from stone (label -1)
1270  }
1271  }
1272 
1273  // Remove duplicates
1274  sort(mortarPoints[1].begin(), mortarPoints[1].end());
1275  mortarPoints[1].erase(unique(mortarPoints[1].begin(),
1276  mortarPoints[1].end()),
1277  mortarPoints[1].end());
1278 
1279  if (stId[0] == -1) {
1280  vector<int> tempMortar = mortarPoints[1];
1281  vector<int> resMortar;
1282  sort(tempMortar.begin(), tempMortar.end());
1283  std::set_difference(
1284  tempMortar.begin(), tempMortar.end(),
1285  vs.begin(), vs.end(),
1286  std::inserter(resMortar, resMortar.end()));
1287 
1288  mortarPoints[1] = resMortar;
1289  }
1290 
1291  break;
1292  }
1293  }
1294 
1295  m_app->removeFromDB(poly, false);
1296  }
1297  }
1298 
1299  m_app->refreshAll(true, true);
1300 
1301  int m = 5;
1302 
1303  ecvColor::Rgb col;
1304  const CCVector3* pt;
1305 
1307  ccPointCloud* new_CloudGlobal = new ccPointCloud("global");
1308  for (unsigned int i = 0; i < cloudStone->size(); ++i) {
1309  new_CloudGlobal->reserveThePointsTable(1);
1310  new_CloudGlobal->reserveTheRGBTable();
1311 
1312  col = cloudStone->getPointColor(i);
1313  pt = cloudStone->getPoint(i);
1314 
1315  new_CloudGlobal->addPoint(*pt);
1316  new_CloudGlobal->addRGBColor(col);
1317  }
1318 
1319  for (unsigned int i = 0; i < cloudMortar->size(); ++i) {
1320  new_CloudGlobal->reserveThePointsTable(1);
1321  new_CloudGlobal->reserveTheRGBTable();
1322 
1323  col = cloudMortar->getPointColor(i);
1324  pt = cloudMortar->getPoint(i);
1325 
1326  new_CloudGlobal->addPoint(*pt);
1327  new_CloudGlobal->addRGBColor(col);
1328  }
1329 
1330  // adding points to each point cloud
1331  ccPointCloud* new_CloudStone = new ccPointCloud("Stone - cloud");
1332  ccPointCloud* new_CloudMortar = new ccPointCloud("Mortar - cloud");
1333 
1334  // Adding points to the final Stone cloud
1335  vector<pair<int, int>> rStPairs;
1336 
1337  // removing points that are going to the mortar cloud (with index -1)
1338  for (auto e : stonePairs[0]) {
1339  if (e.second != -1) rStPairs.push_back(e);
1340  }
1341 
1342  for (unsigned int i = 0; i < rStPairs.size(); ++i) {
1343  new_CloudStone->reserveThePointsTable(1);
1344  new_CloudStone->reserveTheRGBTable();
1345 
1346  col = cloudStone->getPointColor(rStPairs[i].first);
1347  pt = cloudStone->getPoint(rStPairs[i].first);
1348 
1349  new_CloudStone->addPoint(*pt);
1350  new_CloudStone->addRGBColor(col);
1351  }
1352 
1353  // adding points coming from mortar
1354  if (stonePairs[1].size() != 0) {
1355  for (auto i = 0; i < stonePairs[1].size(); ++i) {
1356  new_CloudStone->reserveThePointsTable(1);
1357  new_CloudStone->reserveTheRGBTable();
1358 
1359  col = cloudMortar->getPointColor(stonePairs[1][i].first);
1360  pt = cloudMortar->getPoint(stonePairs[1][i].first);
1361 
1362  new_CloudStone->addPoint(*pt);
1363  new_CloudStone->addRGBColor(col);
1364  }
1365  }
1366 
1367  // Adding scalrfield to the stone cloud
1368  cloudViewer::ScalarField* new_stIdSF = nullptr;
1369 
1370  int nsfIdx = new_CloudStone->getScalarFieldIndexByName("Stone Index");
1371  if (nsfIdx < 0) {
1372  nsfIdx = new_CloudStone->addScalarField("Stone Index");
1373  }
1374  if (nsfIdx < 0) {
1375  return;
1376  }
1377 
1378  new_stIdSF = new_CloudStone->getScalarField(nsfIdx);
1379 
1380  for (unsigned int i = 0; i < rStPairs.size(); ++i) {
1381  int index = static_cast<int>(rStPairs[i].second);
1382  new_stIdSF->setValue(i, index);
1383  }
1384 
1385  // adding points coming from mortar
1386  if (stonePairs[1].size() != 0) {
1387  for (auto i = 0; i < stonePairs[1].size(); ++i) {
1388  int index = static_cast<int>(stonePairs[1][i].second);
1389  new_stIdSF->setValue(rStPairs.size() + i, index);
1390  }
1391  }
1392 
1393  new_CloudStone->setCurrentDisplayedScalarField(nsfIdx);
1394 
1395  new_stIdSF->computeMinAndMax();
1396  new_CloudStone->showColors(true);
1397  new_CloudMortar->showColors(true);
1398 
1399  for (auto e : mortarPoints[0]) {
1400  if (e != -1) {
1401  new_CloudMortar->reserveThePointsTable(1);
1402  new_CloudMortar->reserveTheRGBTable();
1403 
1404  col = cloudMortar->getPointColor(e);
1405  pt = cloudMortar->getPoint(e);
1406 
1407  new_CloudMortar->addPoint(*pt);
1408  new_CloudMortar->addRGBColor(col);
1409  }
1410  }
1411 
1412  // points coming from stone cloud
1413  if (mortarPoints[1].size() != 0) {
1414  for (auto e : mortarPoints[1]) {
1415  if (e != -1) {
1416  new_CloudMortar->reserveThePointsTable(1);
1417  new_CloudMortar->reserveTheRGBTable();
1418 
1419  col = cloudStone->getPointColor(e);
1420  pt = cloudStone->getPoint(e);
1421 
1422  new_CloudMortar->addPoint(*pt);
1423  new_CloudMortar->addRGBColor(col);
1424  }
1425  }
1426  }
1427 
1428  // moving the clouds to center in case they were not
1429  if (idxStone == -1) {
1430  new_CloudStone->Translate(-minBox0);
1431  new_CloudMortar->Translate(-minBox0);
1432  }
1433 
1434  // Creating new vectors
1435  int nbpts = new_CloudStone->size();
1436  vector<pair<int, int>> nstonePairs;
1437  vector<int> nallStIdx;
1438 
1439  int nsfindex = new_CloudStone->getScalarFieldIndexByName("Stone Index");
1440  cloudViewer::ScalarField* nstIdSF =
1441  new_CloudStone->getScalarField(nsfindex);
1442 
1443  if (nbpts > 0) {
1444  for (unsigned int i = 0; i < nbpts; i++) {
1445  nstonePairs.push_back(make_pair(i, nstIdSF->getValue(i)));
1446  nallStIdx.push_back(nstIdSF->getValue(i));
1447  }
1448  }
1449 
1450  sort(nallStIdx.begin(), nallStIdx.end());
1451  nallStIdx.erase(unique(nallStIdx.begin(), nallStIdx.end()),
1452  nallStIdx.end());
1453 
1454  // correcting indexes
1455  vector<vector<int>> vecStones(nallStIdx.size());
1456 
1457  sort(nstonePairs.begin(), nstonePairs.end(),
1458  [](auto& left, auto& right) {
1459  return left.second < right.second;
1460  });
1461 
1462  int old_idx = nstonePairs[0].second;
1463  int new_idx = 0;
1464 
1465  for (unsigned i = 0; i < nstonePairs.size(); i++) {
1466  if (nstonePairs[i].second == old_idx) {
1467  nstonePairs[i].second = new_idx;
1468  vecStones[new_idx].push_back(nstonePairs[i].first);
1469 
1470  } else {
1471  new_idx++;
1472  old_idx = nstonePairs[i].second;
1473  nstonePairs[i].second = new_idx;
1474  vecStones[new_idx].push_back(nstonePairs[i].first);
1475  }
1476  }
1477 
1478  sort(nstonePairs.begin(), nstonePairs.end(),
1479  [](auto& left, auto& right) { return left.first < right.first; });
1480 
1481  // shuffling scalar field for better visuals
1482  vector<int> stIdShuffle;
1483  for (auto e : nstonePairs) {
1484  stIdShuffle.push_back(e.second);
1485  }
1486 
1487  sort(stIdShuffle.begin(), stIdShuffle.end());
1488 
1489  stIdShuffle.erase(unique(stIdShuffle.begin(), stIdShuffle.end()),
1490  stIdShuffle.end());
1491 
1492  auto rng = std::default_random_engine{};
1493  std::shuffle(stIdShuffle.begin(), stIdShuffle.end(), rng);
1494 
1495  if (nbpts > 0) {
1496  for (unsigned int i = 0; i < nbpts; i++) {
1497  int index =
1498  static_cast<int>(stIdShuffle[nstonePairs[i].second]);
1499  nstIdSF->setValue(i, index);
1500  }
1501  }
1502 
1503  // Mortar maps
1504  auto_seg_log << " Starting mortar maps generation..." << endl;
1505  ccPointCloud* mortarMaps =
1506  getMortarMaps(new_CloudStone, new_CloudMortar);
1507 
1508  stamp = dateStamp();
1509  auto_seg_log << stamp << " Mortar maps OK" << endl;
1510 
1511  // Move all the clouds back
1512  new_CloudStone->Translate(minBox0);
1513  new_CloudMortar->Translate(minBox0);
1514  mortarMaps->Translate(minBox0);
1515 
1516  // generating contour polylines
1517 
1518  ccHObject* nContoursContainer = new ccHObject("Stone contours");
1519 
1520  int cntSt = 0;
1521  stamp = dateStamp();
1522  auto_seg_log << " Starting contours regeneration" << endl;
1523 
1524  // contours in an alternative way using stone indexes and original cloud
1525 
1526  if (vecStones.size() > 0) {
1527  for (auto ve : vecStones) {
1528  string s_name = "stone " + to_string(cntSt);
1529  QString qs_name = QString::fromUtf8(s_name.c_str());
1530  ccPolyline* contour = nullptr;
1531 
1532  stamp = dateStamp();
1533  auto_seg_log << stamp << " Polyline " << cntSt << "/"
1534  << vecStones.size() - 1 << endl;
1535 
1536  if (ve.size() > 0) {
1537  contour = contourPoly2(new_CloudStone, ve, qs_name);
1538  nContoursContainer->addChild(contour);
1539  cntSt++;
1540  }
1541  }
1542  }
1543  stamp = dateStamp();
1544  auto_seg_log << stamp << " Contours regeneration done" << endl;
1545 
1546  new_CloudMortar->setPointSize(pointSizeMortar);
1547  new_CloudStone->setPointSize(pointSizeMortar);
1548 
1549  m_app->addToDB(new_CloudStone, true, true, false, true);
1550  m_app->addToDB(new_CloudMortar, true, true, false, true);
1551  m_app->addToDB(nContoursContainer, true, true, false, true);
1552  m_app->addToDB(mortarMaps, true, true, false, true);
1553 
1555  }
1556 }
constexpr unsigned char POINT_VISIBLE
Definition: CVConst.h:92
constexpr unsigned char POINT_HIDDEN
Definition: CVConst.h:94
@ CC_FRONT_VIEW
Definition: CVConst.h:105
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
Definition: CVGeom.h:798
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
std::string filename
int size
std::string name
#define NULL
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
static std::string FromQString(const QString &qs)
Definition: CVTools.cpp:100
Dialog for importing a 2D revolution profile (qSRA plugin)
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
virtual QString getName() const override
Returns (short) name (for menu entry, etc.)
virtual QString getDescription() const override
Returns long name/description (for tooltip, etc.)
virtual void setVisible(bool state)
Sets entity visibility.
virtual void showColors(bool state)
Sets colors visibility.
virtual void showSF(bool state)
Sets active scalarfield visibility.
A 3D cloud interface with associated features (color, normals, octree, etc.)
unsigned char getPointSize() const
Returns current point size.
void setPointSize(unsigned size=0)
Sets point size.
virtual VisibilityTableType & getTheVisibilityArray()
Returns associated visibility array.
virtual bool resetVisibilityArray()
Resets the associated visibility array.
std::vector< unsigned char > VisibilityTableType
Array of "visibility" information for each point.
static ccGenericPointCloud * ToGenericPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccGenericPointCloud.
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
unsigned filterChildren(Container &filteredChildren, bool recursive=false, CV_CLASS_ENUM filter=CV_TYPES::OBJECT, bool strict=false) const
Collects the children corresponding to a certain pattern.
std::vector< ccHObject * > Container
Standard instances container (for children, etc.)
Definition: ecvHObject.h:337
ccPointCloud * m_polyVertices
Segmentation polyline vertices.
Definition: qManualSeg.h:60
ccPolyline * m_segmentationPoly
Segmentation polyline.
Definition: qManualSeg.h:58
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
virtual void setName(const QString &name)
Sets object name.
Definition: ecvObject.h:75
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void setCurrentDisplayedScalarField(int index)
Sets the currently displayed scalar field.
virtual void scale(PointCoordinateType fx, PointCoordinateType fy, PointCoordinateType fz, CCVector3 center=CCVector3(0, 0, 0)) override
Multiplies all coordinates by constant factors (one per dimension)
int addScalarField(const char *uniqueName) override
Creates a new scalar field and registers it.
bool reserve(unsigned numberOfPoints) override
Reserves memory for all the active features.
bool reserveTheRGBTable()
Reserves memory to store the RGB colors.
void clear() override
Clears the entity from all its points and features.
virtual ccPointCloud & Translate(const Eigen::Vector3d &translation, bool relative=true) override
Apply translation to the geometry coordinates.
const ecvColor::Rgb & getPointColor(unsigned pointIndex) const override
Returns color corresponding to a given point.
void addRGBColor(const ecvColor::Rgb &C)
Pushes an RGB color on stack.
ccPointCloud * partialClone(const cloudViewer::ReferenceCloud *selection, int *warnings=nullptr, bool withChildEntities=true) const
Creates a new point cloud object from a ReferenceCloud (selection)
bool reserveThePointsTable(unsigned _numberOfPoints)
Reserves memory to store the points coordinates.
Colored polyline.
Definition: ecvPolyline.h:24
bool is2DMode() const
Returns whether the polyline is considered as 2D or 3D.
Definition: ecvPolyline.h:63
void showVertices(bool state)
Sets whether to display or hide the polyline vertices.
Definition: ecvPolyline.h:129
void setColor(const ecvColor::Rgb &col)
Sets the polyline color.
Definition: ecvPolyline.h:81
Standard ECV plugin interface.
ecvMainAppInterface * m_app
Main application interface.
static ReferenceCloud * resampleCloudSpatially(GenericIndexedCloudPersist *cloud, PointCoordinateType minDistance, const SFModulationParams &modParams, DgmOctree *octree=nullptr, GenericProgressCallback *progressCb=nullptr)
Resamples a point cloud (process based on inter point distance)
virtual unsigned size() const =0
Returns the number of points.
A generic 3D point cloud with index-based and presistent access to points.
virtual const CCVector3 * getPoint(unsigned index) const =0
Returns the ith point.
static bool isPointInsidePoly(const CCVector2 &P, const GenericIndexedCloud *polyVertices)
Tests if a point is inside a polygon (2D)
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.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
void getBoundingBox(CCVector3 &bbMin, CCVector3 &bbMax) override
Definition: PointCloudTpl.h:57
unsigned size() const override
Definition: PointCloudTpl.h:38
ScalarType getPointScalarValue(unsigned pointIndex) const override
const CCVector3 * getPoint(unsigned index) const override
static bool extractConcaveHull2D(std::vector< IndexedCCVector2 > &points, std::list< IndexedCCVector2 * > &hullPoints, PointCoordinateType maxSquareLength=0)
Determines the 'concave' hull of a set of points.
void setClosed(bool state)
Sets whether the polyline is closed or not.
Definition: Polyline.h:29
void clear(bool unusedParam=true) override
Clears the cloud.
Definition: Polyline.cpp:15
bool isClosed() const
Returns whether the polyline is closed or not.
Definition: Polyline.h:26
A very simple point cloud (no point duplication)
virtual bool addPointIndex(unsigned globalIndex)
Point global index insertion mechanism.
virtual GenericIndexedCloudPersist * getAssociatedCloud()
Returns the associated (source) cloud.
unsigned size() const override
Returns the number of points.
virtual unsigned getPointGlobalIndex(unsigned localIndex) const
virtual bool reserve(unsigned n)
Reserves some memory for hosting the point references.
const CCVector3 * getPoint(unsigned index) const override
Returns the ith point.
A simple scalar field (to be associated to a point cloud)
Definition: ScalarField.h:25
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
RGB color structure.
Definition: ecvColorTypes.h:49
static void GetGLCameraParameters(ccGLCameraParameters &params)
Returns the current OpenGL camera parameters.
virtual ccHObject * dbRootObject()=0
Returns DB root (as a ccHObject)
virtual QMainWindow * getMainWindow()=0
Returns main window.
virtual void setView(CC_VIEW_ORIENTATION view)=0
virtual void refreshAll(bool only2D=false, bool forceRedraw=true)=0
Redraws all GL windows that have the 'refresh' flag on.
virtual void addToDB(ccHObject *obj, bool updateZoom=false, bool autoExpandDBTree=true, bool checkDimensions=false, bool autoRedraw=true)=0
virtual void dispToConsole(QString message, ConsoleMessageLevel level=STD_CONSOLE_MESSAGE)=0
virtual void removeFromDB(ccHObject *obj, bool autoDelete=true)=0
Removes an entity from main db tree.
__host__ __device__ int2 abs(int2 v)
Definition: cutil_math.h:1267
@ HIERARCHY_OBJECT
Definition: CVTypes.h:103
@ POINT_CLOUD
Definition: CVTypes.h:104
@ POLY_LINE
Definition: CVTypes.h:112
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
CLOUDVIEWER_HOST_DEVICE Pair< First, Second > make_pair(const First &_first, const Second &_second)
Definition: SlabTraits.h:49
MiniVec< float, N > floor(const MiniVec< float, N > &a)
Definition: MiniVec.h:75
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
Definition: MiniVec.h:89
constexpr Rgb cyan(0, MAX, MAX)
constexpr Rgb green(0, MAX, 0)
unsigned char uchar
Definition: matrix.h:41
std::string to_string(const T &n)
Definition: Common.h:20
Definition: Eigen.h:85
ccPolyline * contourPoly(ccPointCloud *stone)
Definition: qManualSeg.cpp:175
vector< int > setIntersectIdxPixs1D(vector< int > listNew, vector< int > listOld)
Definition: qManualSeg.cpp:437
ccPolyline * contourPoly2(ccPointCloud *cloud0, vector< int > V, QString name)
Definition: qManualSeg.cpp:455
ccPointCloud * getMortarMaps(ccPointCloud *f_cloudStones, ccPointCloud *f_cloudMortar)
Definition: qManualSeg.cpp:533
Mat skeleton(Mat I, bool flagInv)
Definition: qManualSeg.cpp:406
void cloud2binary(ccPointCloud *cloud, Mat &corrMatS, vector< Point > &idxPxS, vector< int > &idxPx1DS, Mat &imageBWS)
Definition: qManualSeg.cpp:374
vector< vector< int > > getCommonPtsIdx(ccPointCloud *Cl1, ccPointCloud *Cl2)
Definition: qManualSeg.cpp:323
pair< double, double > getCentroid(vector< pair< double, double >> V)
Definition: qManualSeg.cpp:260
int getNCommonPts(vector< pair< double, double >> tar, vector< pair< double, double >> ref)
Definition: qManualSeg.cpp:300
vector< int > getKNN(pair< double, double > P, vector< pair< double, double >> V, int k=3)
Definition: qManualSeg.cpp:274
string dateStamp()
Definition: qManualSeg.cpp:514
OpenGL camera parameters.
bool project(const CCVector3d &input3D, CCVector3d &output2D, bool *inFrustum=nullptr) const
Projects a 3D point in 2D (+ normalized 'z' coordinate)
Parameters for the scalar-field based modulation of a parameter.
Definition: lsd.c:149