29 #include <QMainWindow>
32 const std::chrono::high_resolution_clock::time_point& startTime) {
33 auto stopTime = std::chrono::high_resolution_clock::now();
34 auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
39 CVLog::Print(
"Time to execute: " + QString::number(duration_ms) +
46 Q_ASSERT(lower <= upper);
47 return (value >= lower && value <= upper);
50 ColorimetricSegmenter::ColorimetricSegmenter(QObject* parent)
53 m_action_filterRgb(nullptr)
56 m_action_filterHSV(nullptr),
57 m_action_filterScalar(nullptr),
58 m_action_histogramClustering(nullptr),
59 m_action_kMeansClustering(nullptr),
60 m_addPointError(false) {}
62 void ColorimetricSegmenter::onNewSelection(
65 bool activateColorFilters =
false;
66 bool activateScalarFilter =
false;
67 for (
ccHObject* entity : selectedEntities) {
69 if (entity->hasColors()) {
70 activateColorFilters =
true;
71 }
else if (entity->hasDisplayedScalarField()) {
72 activateScalarFilter =
true;
78 if (activateColorFilters && activateScalarFilter) {
79 activateColorFilters = activateScalarFilter =
false;
82 if (m_action_filterRgb)
83 m_action_filterRgb->setEnabled(activateColorFilters);
84 if (m_action_filterHSV)
85 m_action_filterHSV->setEnabled(activateColorFilters);
88 if (m_action_filterScalar)
89 m_action_filterScalar->setEnabled(activateScalarFilter);
90 if (m_action_histogramClustering)
91 m_action_histogramClustering->setEnabled(activateColorFilters);
92 if (m_action_kMeansClustering)
93 m_action_kMeansClustering->setEnabled(activateColorFilters);
96 QList<QAction*> ColorimetricSegmenter::getActions() {
98 if (!m_action_filterRgb) {
99 m_action_filterRgb =
new QAction(
"Filter RGB",
this);
100 m_action_filterRgb->setToolTip(
101 "Filter the points of the selected cloud by RGB color");
102 m_action_filterRgb->setIcon(
103 QIcon(
":/CC/plugin/ColorimetricSegmenter/images/icon_rgb.png"));
106 connect(m_action_filterRgb, &QAction::triggered,
this,
107 &ColorimetricSegmenter::filterRgb);
125 if (!m_action_filterHSV) {
126 m_action_filterHSV =
new QAction(
"Filter HSV",
this);
127 m_action_filterHSV->setToolTip(
128 "Filter the points of the selected cloud by HSV color");
129 m_action_filterHSV->setIcon(
130 QIcon(
":/CC/plugin/ColorimetricSegmenter/images/icon_hsv.png"));
133 connect(m_action_filterHSV, &QAction::triggered,
this,
134 &ColorimetricSegmenter::filterHSV);
138 if (!m_action_filterScalar) {
139 m_action_filterScalar =
new QAction(
"Filter scalar",
this);
140 m_action_filterScalar->setToolTip(
141 "Filter the points of the selected cloud using scalar field");
142 m_action_filterScalar->setIcon(QIcon(
143 ":/CC/plugin/ColorimetricSegmenter/images/icon_scalar.png"));
146 connect(m_action_filterScalar, &QAction::triggered,
this,
147 &ColorimetricSegmenter::filterScalar);
150 if (!m_action_histogramClustering) {
151 m_action_histogramClustering =
152 new QAction(
"Histogram Clustering",
this);
153 m_action_histogramClustering->setToolTip(
154 "Quantify the number of colors using Histogram Clustering");
155 m_action_histogramClustering->setIcon(QIcon(
156 ":/CC/plugin/ColorimetricSegmenter/images/icon_quantif_h.png"));
159 connect(m_action_histogramClustering, &QAction::triggered,
this,
160 &ColorimetricSegmenter::HistogramClustering);
163 if (!m_action_kMeansClustering) {
166 m_action_kMeansClustering =
new QAction(
"Kmeans Clustering",
this);
167 m_action_kMeansClustering->setToolTip(
168 "Quantify the number of colors using Kmeans Clustering");
169 m_action_kMeansClustering->setIcon(QIcon(
170 ":/CC/plugin/ColorimetricSegmenter/images/icon_quantif_k.png"));
173 connect(m_action_kMeansClustering, &QAction::triggered,
this,
174 &ColorimetricSegmenter::KmeansClustering);
177 return {m_action_filterRgb, m_action_filterHSV,
179 m_action_filterScalar, m_action_histogramClustering,
180 m_action_kMeansClustering};
185 std::vector<ccPointCloud*> ColorimetricSegmenter::getSelectedPointClouds() {
186 if (
m_app ==
nullptr) {
190 return std::vector<ccPointCloud*>{};
194 std::vector<ccPointCloud*> clouds;
195 for (
size_t i = 0; i < selectedEntities.size(); ++i) {
197 clouds.push_back(
static_cast<ccPointCloud*
>(selectedEntities[i]));
207 void ColorimetricSegmenter::filterRgb() {
208 if (
m_app ==
nullptr) {
223 std::vector<ccPointCloud*> clouds = getSelectedPointClouds();
224 if (clouds.empty()) {
234 if (!rgbDlg.exec())
return;
237 auto startTime = std::chrono::high_resolution_clock::now();
240 int redInf =
static_cast<int>(
241 std::min(rgbDlg.red_first->value(), rgbDlg.red_second->value()));
242 int redSup =
static_cast<int>(
243 std::max(rgbDlg.red_first->value(), rgbDlg.red_second->value()));
244 int greenInf =
static_cast<int>(
std::min(rgbDlg.green_first->value(),
245 rgbDlg.green_second->value()));
246 int greenSup =
static_cast<int>(
std::max(rgbDlg.green_first->value(),
247 rgbDlg.green_second->value()));
248 int blueInf =
static_cast<int>(
249 std::min(rgbDlg.blue_first->value(), rgbDlg.blue_second->value()));
250 int blueSup =
static_cast<int>(
251 std::max(rgbDlg.blue_first->value(), rgbDlg.blue_second->value()));
253 if (rgbDlg.margin->value() > 0) {
256 static_cast<int>(rgbDlg.margin->value() * 2.56);
258 redInf -= marginError;
259 redSup += marginError;
260 greenInf -= marginError;
261 greenSup += marginError;
262 blueInf -= marginError;
263 blueSup += marginError;
278 if (cloud && cloud->hasColors()) {
283 for (
unsigned j = 0; j < cloud->size(); ++j) {
291 addPoint(filteredCloudInside, j);
293 addPoint(filteredCloudOutside, j);
296 if (m_addPointError) {
300 QString
name =
"Rmin:" + QString::number(redInf) +
301 "/Gmin:" + QString::number(greenInf) +
302 "/Bmin:" + QString::number(blueInf) +
303 "/Rmax:" + QString::number(redSup) +
304 "/Gmax:" + QString::number(greenSup) +
305 "/Bmax:" + QString::number(blueSup);
307 createClouds<const RgbDialog&>(rgbDlg, cloud, filteredCloudInside,
308 filteredCloudOutside,
name);
311 "[ColorimetricSegmenter] Cloud successfully filtered ! ",
319 void ColorimetricSegmenter::filterScalar() {
320 if (
m_app ==
nullptr) {
340 if (!scalarDlg.exec())
return;
343 auto startTime = std::chrono::high_resolution_clock::now();
345 ScalarType marginError = scalarDlg.margin->value() / 100.0f;
346 ScalarType minVal =
static_cast<ScalarType
>(
347 std::min(scalarDlg.first->value(), scalarDlg.second->value()));
348 ScalarType maxVal =
static_cast<ScalarType
>(
349 std::max(scalarDlg.first->value(), scalarDlg.second->value()));
351 minVal -= (marginError * minVal);
352 maxVal += (marginError * maxVal);
354 std::vector<ccPointCloud*> clouds = getSelectedPointClouds();
360 for (
unsigned j = 0; j < cloud->size(); ++j) {
361 const ScalarType val = cloud->getPointScalarValue(j);
362 addPoint(val >= minVal && val <= maxVal ? filteredCloudInside
363 : filteredCloudOutside,
366 if (m_addPointError) {
370 QString
name =
"min:" + QString::number(minVal) +
371 "/max:" + QString::number(maxVal);
373 createClouds<const ScalarDialog&>(scalarDlg, cloud, filteredCloudInside,
374 filteredCloudOutside,
name);
377 "[ColorimetricSegmenter] Cloud successfully filtered ! ",
384 typedef QSharedPointer<cloudViewer::ReferenceCloud>
_Region;
402 unsigned thresholdDistance) {
403 QScopedPointer<ccPointCloud> regionCloud(
412 params = cloudViewer::DistanceComputationTools::
413 Cloud2CloudDistancesComputationParams();
415 params.kNNForLocalModel = k;
416 params.maxSearchDist = thresholdDistance;
419 std::vector<double> distancesToCentralRegion;
420 distancesToCentralRegion.reserve(regions.size());
422 for (
const _Region& r : regions) {
423 QScopedPointer<ccPointCloud> neighbourCloud(
425 if (!neighbourCloud) {
434 regionCloud.data(),
params);
436 double meanDistance = 0.0;
437 for (
unsigned i = 0; i < neighbourCloud->size(); ++i) {
438 meanDistance +=
static_cast<double>(
439 neighbourCloud->getPointScalarValue(i));
441 meanDistance /= neighbourCloud->size();
443 distancesToCentralRegion.push_back(meanDistance);
449 regionCloud.reset(
nullptr);
452 std::vector<size_t> regionIndices(regions.size());
453 for (
size_t i = 0; i < regions.size(); ++i) regionIndices[i] = i;
455 std::sort(regionIndices.begin(), regionIndices.end(),
456 [&](
size_t a,
size_t b) {
457 return distancesToCentralRegion[a] <
458 distancesToCentralRegion[b];
462 for (
size_t regionIndex : regionIndices) {
463 if (neighbourRegions.size() < k) {
464 neighbourRegions.push_back(regions[regionIndex]);
481 int dr =
static_cast<int>(c1.
r) - c2.
r;
482 int dg =
static_cast<int>(c1.
g) - c2.
g;
483 int db =
static_cast<int>(c1.
b) - c2.
b;
484 return sqrt(
static_cast<double>(dr * dr + dg * dg + db * db));
495 if (!subset || subset->
size() == 0) {
503 }
else if (
count == 1) {
508 size_t redSum = 0, greenSum = 0, blueSum = 0;
509 for (
unsigned j = 0; j < subset->
size(); ++j) {
546 bool ColorimetricSegmenter::RegionGrowing(RegionSet& regions,
551 if (!pointCloud || pointCloud->
size() == 0) {
555 size_t pointCount = pointCloud->
size();
558 std::vector<unsigned> unlabeledPoints;
559 unlabeledPoints.resize(pointCount);
560 for (
unsigned j = 0; j < pointCount; ++j) {
561 unlabeledPoints.push_back(j);
564 std::vector<unsigned> pointIndices;
571 while (!unlabeledPoints.empty()) {
573 pointIndices.push_back(unlabeledPoints.back());
574 unlabeledPoints.pop_back();
578 rc->addPointIndex(unlabeledPoints.back());
581 while (!pointIndices.empty()) {
583 unsigned tPointIndex = pointIndices.back();
584 pointIndices.pop_back();
605 if (std::find(unlabeledPoints.begin(),
606 unlabeledPoints.end(),
607 p) != unlabeledPoints.end()) {
614 pointIndices.push_back(p);
615 rc->addPointIndex(p);
619 regions.push_back(rc);
621 }
catch (
const std::bad_alloc&) {
635 static int FindRegion(
const std::vector<_RegionSet>& container,
637 for (
size_t i = 0; i < container.size(); ++i) {
639 if (std::find(l.begin(), l.end(), region) != l.end()) {
640 return static_cast<int>(i);
646 bool ColorimetricSegmenter::RegionMergingAndRefinement(
647 RegionSet& mergedRegions,
649 const RegionSet& regions,
653 const unsigned Min) {
654 std::vector<_RegionSet> homogeneous;
657 for (
const Region& ri : regions) {
660 int riSetIndex =
FindRegion(homogeneous, ri.data());
661 if (riSetIndex == -1) {
663 homogeneous.resize(homogeneous.size() + 1);
664 riSet = &homogeneous.back();
665 riSet->push_back(ri);
667 riSet = &(homogeneous[riSetIndex]);
677 for (
const Region& rj : knnResult) {
682 int regionIndex =
FindRegion(homogeneous, rj.data());
683 if (regionIndex < 0) {
685 riSet->push_back(rj);
695 for (
const Region& li : l) {
696 if (li && !merged->add(*li)) {
701 mergedRegions.push_back(merged);
722 static const unsigned TNN = 1;
723 static const double TPP = 2.0;
724 static const double TD = 2.0;
725 static const double TRR = 2.0;
726 static const unsigned Min = 2;
728 void ColorimetricSegmenter::filterRgbWithSegmentation() {
729 if (
m_app ==
nullptr) {
737 std::vector<ccPointCloud*> clouds = getSelectedPointClouds();
738 if (clouds.empty()) {
748 if (!rgbDlg.exec())
return;
751 auto startTime = std::chrono::high_resolution_clock::now();
754 double marginError = rgbDlg.margin->value() / 100.0;
757 int redInf =
static_cast<int>(
758 rgbDlg.red_first->value() -
759 static_cast<int>(marginError * rgbDlg.red_first->value()));
760 int redSup =
static_cast<int>(
761 rgbDlg.red_second->value() +
762 static_cast<int>(marginError * rgbDlg.red_second->value()));
763 int greenInf =
static_cast<int>(
764 rgbDlg.green_first->value() -
765 static_cast<int>(marginError * rgbDlg.green_first->value()));
766 int greenSup =
static_cast<int>(
767 rgbDlg.green_second->value() +
768 static_cast<int>(marginError * rgbDlg.green_second->value()));
769 int blueInf =
static_cast<int>(
770 rgbDlg.blue_first->value() -
771 static_cast<int>(marginError * rgbDlg.blue_first->value()));
772 int blueSup =
static_cast<int>(
773 rgbDlg.blue_second->value() +
774 static_cast<int>(marginError * rgbDlg.blue_second->value()));
784 if (cloud->hasColors()) {
786 if (!RegionGrowing(regions, cloud,
TNN,
TPP,
TD)) {
791 RegionSet mergedRegions;
792 RegionMergingAndRefinement(mergedRegions, cloud, regions,
TNN,
TRR,
799 for (Region& r : mergedRegions) {
810 if (cloud->getParent()) {
811 cloud->getParent()->addChild(newCloud);
817 "[ColorimetricSegmenter] Cloud successfully "
818 "filtered with segmentation!",
836 void ColorimetricSegmenter::filterHSV() {
837 if (
m_app ==
nullptr) {
851 std::vector<ccPointCloud*> clouds = getSelectedPointClouds();
852 if (clouds.empty()) {
862 if (!hsvDlg.exec())
return;
865 auto startTime = std::chrono::high_resolution_clock::now();
869 hsv_first.
h =
static_cast<uint16_t
>(hsvDlg.hue_first->value());
870 hsv_first.
s =
static_cast<uint16_t
>(hsvDlg.sat_first->value());
871 hsv_first.
v =
static_cast<uint16_t
>(hsvDlg.val_first->value());
874 static const uint8_t LOW = 0;
875 static const uint8_t
MIDDLE = 1;
876 static const uint8_t HIGH = 2;
879 for (
unsigned i = 0; i <= 25; ++i) level[i] = LOW;
880 for (
unsigned i = 26; i <= 60; ++i) level[i] = MIDDLE;
881 for (
unsigned i = 61; i <= 100; ++i) level[i] = HIGH;
884 static const uint8_t RED = 0;
885 static const uint8_t YELLOW = 1;
886 static const uint8_t GREEN = 2;
887 static const uint8_t CYAN = 3;
888 static const uint8_t BLUE = 4;
889 static const uint8_t MAGENTA = 5;
890 uint8_t section[360];
892 for (
unsigned i = 0; i <= 30; ++i) section[i] = RED;
893 for (
unsigned i = 31; i <= 90; ++i) section[i] = YELLOW;
894 for (
unsigned i = 91; i <= 150; ++i) section[i] = GREEN;
895 for (
unsigned i = 151; i <= 210; ++i) section[i] = CYAN;
896 for (
unsigned i = 211; i <= 270; ++i) section[i] = BLUE;
897 for (
unsigned i = 271; i <= 330; ++i) section[i] = MAGENTA;
898 for (
unsigned i = 331; i <= 359; ++i) section[i] = RED;
902 if (cloud->hasColors()) {
908 for (
unsigned j = 0; j < cloud->size(); ++j) {
910 Hsv hsv_current(rgb);
911 assert(hsv_current.h <= 359);
912 assert(hsv_current.s <= 100);
913 assert(hsv_current.v <= 100);
915 if (level[hsv_first.
s] == LOW &&
916 level[hsv_current.s] == LOW)
920 addPoint(level[hsv_first.
v] == level[hsv_current.v]
921 ? filteredCloudInside
922 : filteredCloudOutside,
924 }
else if (level[hsv_first.
s] != LOW &&
925 level[hsv_current.s] !=
928 if (level[hsv_first.
v] == LOW &&
929 level[hsv_current.v] == LOW)
931 addPoint(filteredCloudInside, j);
932 }
else if (level[hsv_first.
v] != LOW &&
933 level[hsv_current.v] != LOW)
935 addPoint(section[hsv_first.
h] == section[hsv_current.h]
936 ? filteredCloudInside
937 : filteredCloudOutside,
940 addPoint(filteredCloudOutside, j);
943 addPoint(filteredCloudOutside, j);
946 if (m_addPointError) {
951 QString
name =
"h:" + QString::number(hsv_first.
h,
'f', 0) +
952 "/s:" + QString::number(hsv_first.
s,
'f', 0) +
953 "/v:" + QString::number(hsv_first.
v,
'f', 0);
954 createClouds<const HSVDialog&>(hsvDlg, cloud, filteredCloudInside,
955 filteredCloudOutside,
name);
958 "[ColorimetricSegmenter] Cloud successfully filtered ! ",
971 if (m_addPointError) {
976 return m_addPointError;
980 template <
typename T>
981 void ColorimetricSegmenter::createClouds(
987 if (dlg.retain->isChecked()) {
988 createCloud(cloud, filteredCloudInside,
name +
".inside");
989 }
else if (dlg.exclude->isChecked()) {
990 createCloud(cloud, filteredCloudOutside,
name +
".outside");
991 }
else if (dlg.both->isChecked()) {
992 createCloud(cloud, filteredCloudInside,
name +
".inside");
993 createCloud(cloud, filteredCloudOutside,
name +
".outside");
998 void ColorimetricSegmenter::createCloud(
1031 size_t clusterPerDim,
1036 for (
unsigned i = 0; i < cloud.
size(); i++) {
1039 size_t redCluster = (
static_cast<size_t>(rgb.
r) * clusterPerDim) >>
1041 size_t greenCluster =
1042 (
static_cast<size_t>(rgb.
g) * clusterPerDim) >>
1044 size_t blueCluster = (
static_cast<size_t>(rgb.
b) * clusterPerDim) >>
1048 redCluster + (greenCluster + blueCluster * clusterPerDim) *
1052 clusterMap[index].push_back(i);
1054 }
catch (
const std::bad_alloc&) {
1067 const std::vector<unsigned>& bucket) {
1068 size_t count = bucket.size();
1071 }
else if (
count == 1) {
1076 size_t redSum = 0, greenSum = 0, blueSum = 0;
1077 for (
unsigned pointIndex : bucket) {
1100 return (
static_cast<int>(c1.
r) - c2.
r) + (
static_cast<int>(c1.
b) - c2.
b) +
1101 (
static_cast<int>(c1.
g) - c2.
g);
1109 void ColorimetricSegmenter::HistogramClustering() {
1110 if (
m_app ==
nullptr) {
1118 std::vector<ccPointCloud*> clouds =
1119 ColorimetricSegmenter::getSelectedPointClouds();
1120 if (clouds.empty()) {
1127 if (!quantiDlg.exec())
return;
1130 auto startTime = std::chrono::high_resolution_clock::now();
1132 int nbClusterByComponent = quantiDlg.area_quanti->value();
1133 if (nbClusterByComponent < 0) {
1142 static_cast<size_t>(nbClusterByComponent),
1157 QString(
"HistogramClustering: Indice Q = %1 // colors = %2")
1158 .arg(nbClusterByComponent)
1159 .arg(nbClusterByComponent * nbClusterByComponent *
1160 nbClusterByComponent));
1162 for (
auto it = clusterMap.begin(); it != clusterMap.end(); it++) {
1166 for (
unsigned pointIndex : it->second) {
1167 (*histCloud).setPointColor(pointIndex, averageColor);
1179 "[ColorimetricSegmenter] Cloud successfully clustered!",
1195 int maxIterationCount) {
1197 if (!theCloud || K == 0) {
1202 unsigned pointCount = theCloud->
size();
1203 if (pointCount == 0)
return nullptr;
1205 if (K >= pointCount) {
1207 "Cloud %1 has less point than the expected number of classes.");
1214 std::vector<ecvColor::Rgb> clusterCenters;
1215 std::vector<std::size_t>
1218 clusterIndex.
resize(pointCount);
1219 clusterCenters.resize(K);
1222 double step =
static_cast<double>(pointCount) / K;
1223 for (
unsigned j = 0; j < K; ++j) {
1226 static_cast<unsigned>(
std::ceil(step * j)));
1231 for (; iteration < maxIterationCount; ++iteration) {
1232 bool meansHaveMoved =
false;
1235 for (
unsigned i = 0; i < pointCount; ++i) {
1238 std::size_t minK = 0;
1239 int minDistsToMean =
1243 for (
unsigned j = 1; j < K; ++j) {
1246 if (distToMean < minDistsToMean) {
1247 minDistsToMean = distToMean;
1252 clusterIndex[i] = minK;
1256 std::vector<std::vector<unsigned>> clusters;
1258 for (
unsigned i = 0; i < pointCount; ++i) {
1259 unsigned index =
static_cast<unsigned>(
1260 clusterIndex[
static_cast<std::size_t
>(i)]);
1261 clusters[index].push_back(i);
1264 CVLog::Print(
"Iteration " + QString::number(iteration));
1265 for (
unsigned j = 0; j < K; ++j) {
1266 const std::vector<unsigned>& cluster = clusters[j];
1267 if (cluster.empty()) {
1273 if (!meansHaveMoved &&
1275 meansHaveMoved =
true;
1278 clusterCenters[j] = newMean;
1281 if (!meansHaveMoved) {
1291 KCloud->
setName(
"Kmeans clustering: K = " + QString::number(K) +
1292 " / it = " + QString::number(iteration));
1295 for (
unsigned i = 0; i < pointCount; i++) {
1299 }
catch (
const std::bad_alloc&) {
1310 void ColorimetricSegmenter::KmeansClustering() {
1311 std::vector<ccPointCloud*> clouds =
1312 ColorimetricSegmenter::getSelectedPointClouds();
1313 if (clouds.empty()) {
1319 if (!kmeansDlg.exec())
return;
1321 assert(kmeansDlg.spinBox_k->value() >= 0);
1322 unsigned K =
static_cast<unsigned>(kmeansDlg.spinBox_k->value());
1323 int iterationCount = kmeansDlg.spinBox_it->value();
1326 auto startTime = std::chrono::high_resolution_clock::now();
1346 "[ColorimetricSegmenter] Cloud successfully clustered!",
cmdLineReadable * params[]
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Print(const char *format,...)
Prints out a formatted message in console.
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Hierarchical CLOUDVIEWER Object.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
ccHObject * getParent() const
Returns parent object.
std::vector< ccHObject * > Container
Standard instances container (for children, etc.)
virtual QString getName() const
Returns object name.
virtual void setName(const QString &name)
Sets object name.
virtual void setEnabled(bool state)
Sets the "enabled" property.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
ccPointCloud * cloneThis(ccPointCloud *destCloud=nullptr, bool ignoreChildren=false)
Clones this entity.
bool hasColors() const override
Returns whether colors are enabled or not.
bool resize(unsigned numberOfPoints) override
Resizes all the active features arrays.
void setPointColor(size_t pointIndex, const ecvColor::Rgb &col)
Sets a particular point color.
const ecvColor::Rgb & getPointColor(unsigned pointIndex) const override
Returns color corresponding to a given point.
ccPointCloud * partialClone(const cloudViewer::ReferenceCloud *selection, int *warnings=nullptr, bool withChildEntities=true) const
Creates a new point cloud object from a ReferenceCloud (selection)
Standard ECV plugin interface.
ecvMainAppInterface * m_app
Main application interface.
The octree structure used throughout the library.
void getCellPos(CellCode code, unsigned char level, Tuple3i &cellPos, bool isCodeTruncated) const
unsigned findNearestNeighborsStartingFromCell(NearestNeighboursSearchStruct &nNSS, bool getOnlyPointsWithValidScalar=false) const
void computeCellCenter(CellCode code, unsigned char level, CCVector3 ¢er, bool isCodeTruncated=false) const
int build(GenericProgressCallback *progressCb=nullptr)
Builds the structure.
const CellCode & getCellCode(unsigned index) const
Returns the ith cell code.
unsigned size() const override
const CCVector3 * getPoint(unsigned index) const override
A very simple point cloud (no point duplication)
virtual bool addPointIndex(unsigned globalIndex)
Point global index insertion mechanism.
unsigned size() const override
Returns the number of points.
virtual unsigned getPointGlobalIndex(unsigned localIndex) const
virtual QMainWindow * getMainWindow()=0
Returns main window.
virtual QWidget * getActiveWindow()=0
virtual const ccHObject::Container & getSelectedEntities() const =0
Returns currently selected entities ("read only")
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 ccPickingHub * pickingHub()
__host__ __device__ int2 abs(int2 v)
unsigned char ColorCompType
Default color components type (R,G and B)
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
constexpr Rgb white(MAX, MAX, MAX)
constexpr ColorCompType MAX
Max value of a single color component (default type)
std::map< size_t, std::vector< unsigned > > ClusterMap
static const unsigned Min
static ccPointCloud * ComputeKmeansClustering(ccPointCloud *theCloud, unsigned K, int maxIterationCount)
static double ColorimetricalDifference(ecvColor::Rgb c1, ecvColor::Rgb c2)
colorimetricalDifference Compute colorimetrical difference between two RGB color values.
static bool Inside(ColorCompType lower, ColorCompType value, ColorCompType upper)
std::vector< _RegionSet > SetOfRegionSet
static const unsigned TNN
QSharedPointer< cloudViewer::ReferenceCloud > _Region
static bool KNNRegions(ccPointCloud *basePointCloud, const _RegionSet ®ions, const _Region ®ion, unsigned k, _RegionSet &neighbourRegions, unsigned thresholdDistance)
KNNRegions Determines the neighboring regions of a region.
static int ColorDistance(const ecvColor::Rgb &c1, const ecvColor::Rgb &c2)
static int FindRegion(const std::vector< _RegionSet > &container, cloudViewer::ReferenceCloud *region)
findRegion Find a given region in a vector of reference clouds.
static ecvColor::Rgb ComputeAverageColor(const ccPointCloud &cloud, cloudViewer::ReferenceCloud *subset)
std::vector< _Region > _RegionSet
static void ShowDurationNow(const std::chrono::high_resolution_clock::time_point &startTime)
static bool GetKeyCluster(const ccPointCloud &cloud, size_t clusterPerDim, ClusterMap &clusterMap)