11 #include <QHeaderView>
12 #include <QMessageBox>
36 #include <QElapsedTimer>
37 #include <QThreadPool>
49 : QDialog(parent, Qt::Tool),
50 Ui::ComparisonDialog(),
51 m_compEnt(compEntity),
53 m_compOctree(nullptr),
54 m_compOctreeIsPartial(false),
55 m_compSFVisibility(false),
60 m_refOctreeIsPartial(false),
61 m_refVisibility(false),
63 m_noDisplay(noDisplay),
64 m_bestOctreeLevel(0) {
67 int maxThreadCount = QThread::idealThreadCount();
68 maxThreadCountSpinBox->setRange(1, maxThreadCount);
69 maxThreadCountSpinBox->setSuffix(QString(
" / %1").arg(maxThreadCount));
70 maxThreadCountSpinBox->setValue(
71 QThreadPool::globalInstance()->maxThreadCount());
76 octreeLevelComboBox->addItem(
"AUTO");
78 octreeLevelComboBox->addItem(QString::number(i));
81 localModelComboBox->addItem(
"NONE");
82 localModelComboBox->addItem(
"Least Square Plane");
83 localModelComboBox->addItem(
"2D1/2 Triangulation");
84 localModelComboBox->addItem(
"Quadric");
85 localModelComboBox->setCurrentIndex(0);
88 signedDistCheckBox->setChecked(
false);
89 split3DCheckBox->setEnabled(
false);
90 okButton->setEnabled(
false);
94 preciseResultsTabWidget->setCurrentIndex(0);
103 maxSearchDistSpinBox->setValue(compEntBBox.
getDiagNorm());
107 signedDistCheckBox->setEnabled(
true);
108 signedDistCheckBox->setChecked(
true);
109 filterVisibilityCheckBox->setEnabled(
false);
110 filterVisibilityCheckBox->setVisible(
false);
112 signedDistCheckBox->setEnabled(
false);
113 split3DCheckBox->setEnabled(
true);
114 lmRadiusDoubleSpinBox->setValue(compEntBBox.
getDiagNorm() / 200.0);
115 filterVisibilityCheckBox->setEnabled(
120 connect(cancelButton, &QPushButton::clicked,
this,
122 connect(okButton, &QPushButton::clicked,
this,
124 connect(computeButton, &QPushButton::clicked,
this,
126 connect(histoButton, &QPushButton::clicked,
this,
128 connect(maxDistCheckBox, &QCheckBox::toggled,
this,
130 connect(localModelComboBox,
131 static_cast<void (QComboBox::*)(
int)
>(
132 &QComboBox::currentIndexChanged),
134 connect(maxSearchDistSpinBox,
135 static_cast<void (QDoubleSpinBox::*)(
double)
>(
136 &QDoubleSpinBox::valueChanged),
143 QCoreApplication::processEvents();
162 CVLog::Error(
"Dialog initialization error! (bad entity type)");
170 "Dialog initialization error! (bad entity type - works "
171 "only with real point clouds [todo])");
196 CVLog::Error(
"Dialog initialization error! (bad entity type)");
228 (maxDistCheckBox->isChecked() ? maxSearchDistSpinBox->value()
232 if (bestOctreeLevel <= 0) {
234 "Can't evaluate best octree level! Try to set it manually "
246 localModelParamsFrame->setEnabled(index != 0);
250 lmKNNSpinBox->setMinimum(minKNN);
287 CVLog::Error(
"Dialog initialization error! (void entity)");
295 histoButton->setEnabled(
false);
296 preciseResultsTabWidget->widget(2)->setEnabled(
false);
308 "Failed to allocate a new scalar field for computing "
309 "approx. distances! Try to free some memory ...");
319 QScopedPointer<ecvProgressDialog> progressDlg;
320 if (parentWidget()) {
325 int approxResult = -1;
326 QElapsedTimer eTimer;
340 cloudViewer::DistanceComputationTools::
341 Cloud2MeshDistancesComputationParams c2mParams;
352 c2mParams, progressDlg.data(),
360 qint64 elapsedTime_ms = eTimer.elapsed();
367 if (approxResult < 0) {
369 "[computeApproxDistances] Computation failed (error code %i)",
375 elapsedTime_ms / 1.0e3);
378 ScalarType mean, variance;
382 approxStats->setColumnCount(2);
383 approxStats->setRowCount(5);
384 approxStats->setColumnWidth(1, 200);
385 approxStats->horizontalHeader()->hide();
389 approxStats->setItem(curRow, 0,
new QTableWidgetItem(
"Min dist."));
390 approxStats->setItem(
392 new QTableWidgetItem(QString(
"%1").arg(sf->
getMin())));
395 approxStats->setItem(curRow, 0,
new QTableWidgetItem(
"Max dist."));
396 approxStats->setItem(
398 new QTableWidgetItem(QString(
"%1").arg(sf->
getMax())));
401 approxStats->setItem(curRow, 0,
new QTableWidgetItem(
"Avg dist."));
402 approxStats->setItem(curRow++, 1,
403 new QTableWidgetItem(QString(
"%1").arg(mean)));
406 approxStats->setItem(curRow, 0,
new QTableWidgetItem(
"Sigma"));
407 approxStats->setItem(
409 new QTableWidgetItem(QString(
"%1").arg(
410 variance >= 0.0 ? sqrt(variance) : variance)));
416 approxStats->setItem(curRow, 0,
new QTableWidgetItem(
"Max error"));
417 approxStats->setItem(curRow++, 1,
418 new QTableWidgetItem(QString(
"%1").arg(e)));
420 for (
int i = 0; i < curRow; ++i) {
421 approxStats->setRowHeight(i, 20);
424 approxStats->setEditTriggers(QAbstractItemView::NoEditTriggers);
427 preciseResultsTabWidget->widget(2)->setEnabled(
true);
428 histoButton->setEnabled(
true);
431 maxSearchDistSpinBox->setValue(sf->
getMax());
438 computeButton->setEnabled(
true);
439 preciseGroupBox->setEnabled(
true);
441 okButton->setEnabled(
false);
468 if (!approxDistances) {
474 const int MAX_OCTREE_LEVEL =
481 std::vector<double> timings;
483 timings.resize(MAX_OCTREE_LEVEL, 0);
484 }
catch (
const std::bad_alloc&) {
485 CVLog::Warning(
"Can't determine best octree level: not enough memory!");
490 double meanTriangleSurface = 1.0;
494 CVLog::Error(
"Internal error: reference entity should be a mesh!");
498 if (!mesh || mesh->
size() == 0) {
499 CVLog::Warning(
"Can't determine best octree level: mesh is empty!");
506 if (meshSurface > 0) {
507 meanTriangleSurface = meshSurface / mesh->
size();
513 static const int s_minOctreeLevel = 6;
514 int theBestOctreeLevel = s_minOctreeLevel;
517 QScopedPointer<ecvProgressDialog> progressDlg;
518 if (parentWidget()) {
520 progressDlg->setMethodTitle(tr(
"Determining optimal octree level"));
521 progressDlg->setInfo(tr(
"Testing %1 levels...")
522 .arg(MAX_OCTREE_LEVEL));
523 progressDlg->start();
526 MAX_OCTREE_LEVEL - 2);
527 QApplication::processEvents();
529 bool maxDistanceDefined = maxDistCheckBox->isChecked();
531 maxDistanceDefined ? maxSearchDistSpinBox->value() : 0);
534 for (
int level = s_minOctreeLevel; level < MAX_OCTREE_LEVEL; ++level) {
535 const unsigned char bitDec =
537 unsigned numberOfPointsInCell = 0;
539 double cellDist = -1;
546 m_compOctree->getCellSize(
static_cast<unsigned char>(level));
550 double refListDensity = 1.0;
552 refListDensity =
m_refOctree->computeMeanOctreeDensity(
553 static_cast<unsigned char>(level));
561 for (cloudViewer::DgmOctree::cellsContainer::const_iterator c =
563 c != compCodes.end(); ++c) {
565 (c->theCode >> bitDec);
568 if (truncatedCode != tempCode) {
570 if (numberOfPointsInCell != 0) {
574 if (maxSearchDist <= 0 || cellDist <= maxSearchDist) {
576 cellDist /= cellSize;
579 double neighbourSize = 2.0 * cellDist + 1.0;
585 int nCell =
static_cast<int>(
ceil(cellDist));
588 double crossingMeshSurface =
589 (2.0 * nCell + 1.0) * cellSize;
591 crossingMeshSurface *= crossingMeshSurface;
594 double neighbourSize3 = neighbourSize *
600 timings[level] += neighbourSize3 +
601 0.5 * numberOfPointsInCell *
602 crossingMeshSurface /
606 neighbourSize -= 1.0;
608 double neighbourSize3 = neighbourSize *
614 double lastSliceCellNumber =
616 ? cellDist * cellDist * 24.0 + 2.0
624 0.1 * numberOfPointsInCell *
625 sqrt(lastSliceCellNumber) *
635 numberOfPointsInCell = 0;
637 tempCode = truncatedCode;
640 ScalarType pointDist = approxDistances->
getValue(index);
641 if (maxDistanceDefined && pointDist > maxDistance) {
642 pointDist = maxDistance;
646 cellDist = std::max<double>(cellDist, pointDist);
648 ++numberOfPointsInCell;
665 if (timings[level] < timings[theBestOctreeLevel]) {
666 theBestOctreeLevel = level;
673 theBestOctreeLevel, maxSearchDist);
675 return theBestOctreeLevel;
681 int octreeLevel = octreeLevelComboBox->currentIndex();
691 CVLog::Print(QString(
"[Distances] Octree level (auto): %1")
696 bool signedDistances =
697 signedDistCheckBox->isEnabled() && signedDistCheckBox->isChecked();
699 (signedDistances ? flipNormalsCheckBox->isChecked() :
false);
700 bool split3D = split3DCheckBox->isEnabled() && split3DCheckBox->isChecked();
710 "Couldn't allocate a new scalar field for computing "
711 "distances! Try to free some memory ...");
721 ScalarType maxSearchDist =
static_cast<ScalarType
>(
722 maxDistCheckBox->isChecked() ? maxSearchDistSpinBox->value() : 0);
724 bool multiThread = multiThreadedCheckBox->isChecked();
731 maxThreadCountSpinBox->value();
734 QScopedPointer<ecvProgressDialog> progressDlg;
735 if (parentWidget()) {
739 QElapsedTimer eTimer;
749 for (
unsigned j = 0; j < 3; ++j) {
762 "[ComputeDistances] Not enough memory to generate "
765 for (
unsigned j = 0; j < 3; ++j) {
778 bool filterVisibility = filterVisibilityCheckBox->
isEnabled() &&
779 filterVisibilityCheckBox->isChecked();
780 if (filterVisibility) {
812 filterVisibilityCheckBox->setChecked(
false);
813 if (QMessageBox::warning(
815 "Failed to find/init the depth buffer(s) "
816 "on the associated sensor! Do you want to "
819 QMessageBox::No) == QMessageBox::No) {
822 filterVisibility =
false;
831 if (localModelingTab->isEnabled()) {
834 localModelComboBox->currentIndex();
837 lmRadiusRadioButton->isChecked();
839 std::max(0, lmKNNSpinBox->value()));
841 lmRadiusDoubleSpinBox->value());
843 lmOptimizeCheckBox->isChecked();
853 c2cParams, progressDlg.data(),
860 if (multiThread && maxDistCheckBox->isChecked()) {
862 "[Cloud/Mesh comparison] Max search distance is not "
863 "supported in multi-thread mode! Switching to single "
879 c2mParams, progressDlg.data(),
883 qint64 elapsedTime_ms = eTimer.elapsed();
891 static_cast<double>(elapsedTime_ms) / 1.0e3);
894 ScalarType mean, variance;
898 "[ComputeDistances] Mean distance = %f / std deviation = %f",
899 mean, sqrt(variance));
905 okButton->setEnabled(
true);
921 m_sfName += QString(
"[%1]").arg(localModelComboBox->currentText());
935 if (maxSearchDist > 0) {
936 m_sfName += QString(
"[<%1]").arg(maxSearchDist);
941 static const QChar charDim[3] = {
'X',
'Y',
'Z'};
942 for (
unsigned j = 0; j < 3; ++j) {
946 QString(
" (%1)").arg(charDim[j])));
954 assert(sfEnter >= 0);
958 "[ComputeDistances] Result has been split along each "
959 "dimension (check the 3 other scalar fields with '_X', "
960 "'_Y' and '_Z' suffix!)");
970 for (
unsigned j = 0; j < 3; ++j) {
993 histogram->
setTitle(QString(
"Approximate distances (%1 values)")
995 histogram->
fromSF(sf, 8,
false);
998 hDlg->resize(400, 300);
1010 if (tmpSfIdx >= 0) {
1063 if (tmpSfIdx >= 0) {
constexpr unsigned CV_LOCAL_MODEL_MIN_SIZE[]
Min number of points to compute local models (see CV_LOCAL_MODEL_TYPES)
float PointCoordinateType
Type of the coordinates of a (N-D) point.
virtual void link()
Increase counter.
virtual void release()
Decrease counter and deletes object when 0.
static bool PrintDebug(const char *format,...)
Same as Print, but works only in Debug mode.
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.
static void UpdateUI()
Static shortcut to MainWindow::updateUI.
ccGenericPointCloud * m_refCloud
Reference entity equivalent cloud (if any)
void locaModelChanged(int)
QString m_sfName
last computed scalar field name
ccOctree::Shared m_refOctree
Reference entity's octree.
int determineBestOctreeLevel(double)
bool m_noDisplay
Whether a display is active (and should be refreshed) or not.
ccGenericMesh * m_refMesh
Reference entity equivalent mesh (if any)
CC_COMPARISON_TYPE
Comparison type.
ccHObject * m_refEnt
Reference entity.
bool m_refVisibility
Initial reference entity visibility.
ccOctree::Shared m_compOctree
Compared entity's octree.
ccComparisonDlg(ccHObject *compEntity, ccHObject *refEntity, CC_COMPARISON_TYPE cpType, QWidget *parent=nullptr, bool noDisplay=false)
Default constructor.
void updateDisplay(bool showSF, bool hideRef)
CC_COMPARISON_TYPE m_compType
Comparison type.
bool prepareEntitiesForComparison()
bool m_refOctreeIsPartial
Whether the reference entity octree is partial or not.
ccPointCloud * m_compCloud
Compared entity equivalent cloud.
bool m_compSFVisibility
Initial compared entity visibility.
bool m_compOctreeIsPartial
Whether the compared entity octree is partial or not.
int m_bestOctreeLevel
Best octree level (or 0 if none has been guessed already)
~ccComparisonDlg()
Default destructor.
bool computeApproxDistances()
ccHObject * m_compEnt
Compared entity.
QString m_oldSfName
Initial SF name enabled on the compared entity.
std::vector< PointCoordinateType > zBuff
Z-Buffer grid.
virtual bool isVisible() const
Returns whether entity is visible or not.
virtual void setVisible(bool state)
Sets entity visibility.
virtual bool sfShown() const
Returns whether active scalar field is visible.
virtual void showSF(bool state)
Sets active scalarfield visibility.
Ground-based Laser sensor.
bool computeDepthBuffer(cloudViewer::GenericCloud *cloud, int &errorCode, ccPointCloud *projectedCloud=nullptr)
static QString GetErrorString(int errorCode)
Returns the error string corresponding to an error code.
const ccDepthBuffer & getDepthBuffer() const
Returns the associated depth buffer.
virtual ccGenericPointCloud * getAssociatedCloud() const =0
Returns the vertices cloud.
virtual ccOctree::Shared getOctree() const
Returns the associated octree (if any)
static ccGenericPointCloud * ToGenericPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccGenericPointCloud.
static ccGenericMesh * ToGenericMesh(ccHObject *obj)
Converts current object to ccGenericMesh (if possible)
Hierarchical CLOUDVIEWER Object.
virtual ccBBox getOwnBB(bool withGLFeatures=false)
Returns the entity's own bounding-box.
unsigned getChildrenNumber() const
Returns the number of children.
void setRedrawFlagRecursive(bool redraw=false)
ccHObject * getChild(unsigned childPos) const
Returns the ith child.
Encapsulating dialog for ccHistogramWindow.
ccHistogramWindow * window()
Returns encapsulated ccHistogramWindow.
void setTitle(const QString &str)
Sets title.
void fromSF(ccScalarField *sf, unsigned initialNumberOfClasses=0, bool numberOfClassesCanBeChanged=true, bool showNaNValuesInGrey=true)
Computes histogram from a scalar field.
void setAxisLabels(const QString &xLabel, const QString &yLabel)
Sets axis labels.
virtual QString getName() const
Returns object name.
bool isA(CV_CLASS_ENUM type) const
virtual void setEnabled(bool state)
Sets the "enabled" property.
virtual bool isEnabled() const
Returns whether the object is enabled or not.
bool isKindOf(CV_CLASS_ENUM type) const
QSharedPointer< ccOctree > Shared
Shared pointer.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void enableVisibilityCheck(bool state)
void setCurrentDisplayedScalarField(int index)
Sets the currently displayed scalar field.
bool hasSensor() const
Returns whether the mesh as an associated sensor or not.
int addScalarField(const char *uniqueName) override
Creates a new scalar field and registers it.
int getCurrentDisplayedScalarFieldIndex() const
Returns the currently displayed scalar field index (or -1 if none)
void deleteScalarField(int index) override
Deletes a specific scalar field.
ccScalarField * getCurrentDisplayedScalarField() const
Returns the currently displayed scalar (or 0 if none)
A scalar field associated to display-related parameters.
T getDiagNorm() const
Returns diagonal length.
unsigned CellCode
Type of the code of an octree cell.
static const int MAX_OCTREE_LEVEL
Max octree subdivision level.
std::vector< IndexAndCode > cellsContainer
Container of 'IndexAndCode' structures.
static unsigned char GET_BIT_SHIFT(unsigned char level)
Returns the binary shift for a given level of subdivision.
A generic mesh with index-based vertex access.
virtual unsigned size() const =0
Returns the number of triangles.
bool oneStep()
Increments total progress value of a single unit.
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 setCurrentScalarField(int index)
Sets both the INPUT & OUTPUT scalar field.
unsigned size() const override
bool renameScalarField(int index, const char *newName)
Renames a specific scalar field.
const char * getScalarFieldName(int index) const
Returns the name of a specific scalar field.
ScalarField * getCurrentInScalarField() const
Returns the scalar field currently associated to the cloud input.
A simple scalar field (to be associated to a point cloud)
virtual void computeMinAndMax()
Determines the min and max values.
ScalarType getMin() const
Returns the minimum value.
ScalarType & getValue(std::size_t index)
void computeMeanAndVariance(ScalarType &mean, ScalarType *variance=nullptr) const
const char * getName() const
Returns scalar field name.
void setName(const char *name)
Sets scalar field name.
bool resizeSafe(std::size_t count, bool initNewElements=false, ScalarType valueForNewElements=0)
Resizes memory (no exception thrown)
ScalarType getMax() const
Returns the maximum value.
Graphical progress indicator (thread-safe)
#define CC_CLOUD2MESH_DISTANCES_DEFAULT_SF_NAME
#define CC_CLOUD2CLOUD_DISTANCES_DEFAULT_SF_NAME
#define CC_CLOUD2MESH_SIGNED_DISTANCES_DEFAULT_SF_NAME
#define CC_TEMP_DISTANCES_DEFAULT_SF_NAME
#define CC_TEMP_APPROX_DISTANCES_DEFAULT_SF_NAME
const unsigned char DEFAULT_OCTREE_LEVEL
MiniVec< float, N > ceil(const MiniVec< float, N > &a)