From ae93995a5d2b1487f468cb12c1b15d860d3880a6 Mon Sep 17 00:00:00 2001 From: valorun Date: Wed, 29 Apr 2020 19:19:46 +0200 Subject: [PATCH] Filter scalar function --- ColorimetricSegmenter.cpp | 100 +++++++++- ColorimetricSegmenter.h | 9 +- ScalarDialog.cpp | 155 +++++++++++++++ ScalarDialog.h | 62 ++++++ ScalarDialog.ui | 389 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 709 insertions(+), 6 deletions(-) create mode 100644 ScalarDialog.cpp create mode 100644 ScalarDialog.h create mode 100644 ScalarDialog.ui diff --git a/ColorimetricSegmenter.cpp b/ColorimetricSegmenter.cpp index d709f09..d7e60d3 100644 --- a/ColorimetricSegmenter.cpp +++ b/ColorimetricSegmenter.cpp @@ -45,7 +45,8 @@ ColorimetricSegmenter::ColorimetricSegmenter( QObject *parent ) , ccStdPluginInterface( ":/CC/plugin/ColorimetricSegmenter/info.json" ) , m_action_filterRgb( nullptr ) , m_action_filterRgbWithSegmentation(nullptr) - , m_action_filterHSV( nullptr ) + , m_action_filterHSV( nullptr ) + , m_action_filterScalar( nullptr ) { } @@ -88,6 +89,11 @@ void ColorimetricSegmenter::onNewSelection( const ccHObject::Container &selected return; } + if (m_action_filterScalar == nullptr) + { + return; + } + // If you need to check for a specific type of object, you can use the methods // in ccHObjectCaster.h or loop and check the objects' classIDs like this: // @@ -119,12 +125,14 @@ void ColorimetricSegmenter::onNewSelection( const ccHObject::Container &selected m_action_filterRgb->setEnabled(false); m_action_filterHSV->setEnabled(false); m_action_filterRgbWithSegmentation->setEnabled(false); + m_action_filterScalar->setEnabled(false); //Activate only if only one of them is activated if ((activateColorFilters != activateScalarFilter) && !selectedEntities.empty()) { m_action_filterRgb->setEnabled(activateColorFilters); m_action_filterHSV->setEnabled(activateColorFilters); m_action_filterRgbWithSegmentation->setEnabled(activateColorFilters); + m_action_filterScalar->setEnabled(activateScalarFilter); } } @@ -179,9 +187,24 @@ QList ColorimetricSegmenter::getActions() connect(m_action_filterHSV, SIGNAL(entityHasChanged(ccHObject*)), this, SLOT(handleEntityChange(ccHObject*))); connect(m_action_filterHSV, SIGNAL(newErrorMessage(QString)), this, SLOT(handleErrorMessage(QString))); - } + } - return { m_action_filterRgb, m_action_filterHSV, m_action_filterRgbWithSegmentation }; + // Scalar filter + if (!m_action_filterScalar) + { + m_action_filterScalar = new QAction("Filter scalar", this); + m_action_filterScalar->setToolTip("Filter the points on the selected cloud using scalar field"); + m_action_filterScalar->setIcon(getIcon()); + + // Connect appropriate signal + connect(m_action_filterScalar, &QAction::triggered, this, &ColorimetricSegmenter::filterScalar); + + connect(m_action_filterScalar, SIGNAL(newEntity(ccHObject*)), this, SLOT(handleNewEntity(ccHObject*))); + connect(m_action_filterScalar, SIGNAL(entityHasChanged(ccHObject*)), this, SLOT(handleEntityChange(ccHObject*))); + connect(m_action_filterScalar, SIGNAL(newErrorMessage(QString)), this, SLOT(handleErrorMessage(QString))); + + } + return { m_action_filterRgb, m_action_filterHSV, m_action_filterRgbWithSegmentation, m_action_filterScalar }; } // Get all point clouds that are selected in CC @@ -283,7 +306,76 @@ void ColorimetricSegmenter::filterRgb() m_app->dispToConsole("[ColorimetricSegmenter] Cloud successfully filtered ! ", ccMainAppInterface::STD_CONSOLE_MESSAGE); } - } + } + // Stop timer + auto stop = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(stop - start).count(); + QString s = QString::number(duration); + + //Print time of execution + ccLog::Print("Time to execute : " + s + " milliseconds."); +} + + +void ColorimetricSegmenter::filterScalar() +{ + if ( m_app == nullptr ) + { + // m_app should have already been initialized by CC when plugin is loaded + Q_ASSERT( false ); + + return; + } + + //check valid window + if (!m_app->getActiveGLWindow()) + { + m_app->dispToConsole("[ccCompass] Could not find valid 3D window.", ccMainAppInterface::ERR_CONSOLE_MESSAGE); + return; + } + + // Retrieve parameters from dialog + if (m_app->pickingHub()) { + m_pickingHub = m_app->pickingHub(); + } + + scalarDlg = new ScalarDialog(m_pickingHub,(QWidget*)m_app->getMainWindow()); + scalarDlg->show(); + + auto start = std::chrono::high_resolution_clock::now(); + + double marginError = static_cast(rgbDlg->margin->value()) / 100.0; + ScalarType first = scalarDlg->first->value() - (marginError * scalarDlg->first ->value()); + ScalarType second = scalarDlg->second->value() - (marginError * scalarDlg->second ->value()); + + std::vector clouds = getSelectedPointClouds(); + for (ccPointCloud* cloud : clouds) { + const ScalarType min = std::min(first, second); + const ScalarType max = std::max(first, second); + + // Use only references for speed reasons + CCLib::ReferenceCloud* filteredCloudInside = new CCLib::ReferenceCloud(cloud); + CCLib::ReferenceCloud* filteredCloudOutside = new CCLib::ReferenceCloud(cloud); + + for (unsigned j = 0; j < cloud->size(); ++j) + { + const ScalarType val = cloud->getPointScalarValue(j); + (val > min && val < max) + ? addPoint(filteredCloudInside, j) : addPoint(filteredCloudOutside, j); + } + std::string name = "min:" + std::to_string(min) + "/max:" + std::to_string(max); + + createClouds(scalarDlg, cloud, filteredCloudInside, filteredCloudOutside, name); + + m_app->dispToConsole("[ColorimetricSegmenter] Cloud successfully filtered ! ", ccMainAppInterface::STD_CONSOLE_MESSAGE); + } + // Stop timer + auto stop = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(stop - start).count(); + QString s = QString::number(duration); + + //Print time of execution + ccLog::Print("Time to execute : " + s + " milliseconds."); } /** diff --git a/ColorimetricSegmenter.h b/ColorimetricSegmenter.h index f66128a..60ea5d0 100644 --- a/ColorimetricSegmenter.h +++ b/ColorimetricSegmenter.h @@ -31,6 +31,7 @@ #include "RgbDialog.h" #include "HSVDialog.h" +#include "ScalarDialog.h" //! Example qCC plugin /** Replace 'ExamplePlugin' by your own plugin class name throughout and then @@ -98,7 +99,9 @@ private: //! Filter a cloud with RGB color void filterRgb(); - void filterHSV(); + void filterHSV(); + + void filterScalar(); void addPoint(CCLib::ReferenceCloud* filteredCloud, unsigned int j); @@ -146,12 +149,14 @@ private: QAction* m_action_filterRgb; QAction* m_action_filterRgbWithSegmentation; QAction* m_action_filterHSV; + QAction* m_action_filterScalar; //! Picking hub ccPickingHub* m_pickingHub = nullptr; RgbDialog* rgbDlg; - HSVDialog* hsvDlg; + HSVDialog* hsvDlg; + ScalarDialog* scalarDlg; //link to application windows //ccGLWindow* m_window; diff --git a/ScalarDialog.cpp b/ScalarDialog.cpp new file mode 100644 index 0000000..a1f2cab --- /dev/null +++ b/ScalarDialog.cpp @@ -0,0 +1,155 @@ +//########################################################################## +//# # +//# CLOUDCOMPARE PLUGIN: ColorimetricSegmenter # +//# # +//# This program is free software; you can redistribute it and/or modify # +//# it under the terms of the GNU General Public License as published by # +//# the Free Software Foundation; version 2 of the License. # +//# # +//# This program is distributed in the hope that it will be useful, # +//# but WITHOUT ANY WARRANTY; without even the implied warranty of # +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +//# GNU General Public License for more details. # +//# # +//# COPYRIGHT: Tri-Thien TRUONG, Ronan COLLIER, Mathieu LETRONE # +//# # +//########################################################################## +#include "ScalarDialog.h" + +//local +#include "mainwindow.h" + +//Qt +#include +#include +#include +#include +#include +#include +#include + +//common +#include + +#include +#include + +//qCC_gl +#include +#include + +/* + Constructor +*/ +ScalarDialog::ScalarDialog(ccPickingHub* pickingHub, QWidget* parent) + : QDialog(parent) + , Ui::ScalarDialog() + , m_pickingWin(0) + , m_pickingHub(pickingHub) +{ + assert(pickingHub); + + setModal(false); + setupUi(this); + + //Link between Ui and actions + connect(pointPickingButton_first, &QCheckBox::toggled, this, &ScalarDialog::pickPoint_first); + connect(pointPickingButton_second, &QCheckBox::toggled, this, &ScalarDialog::pickPoint_second); + + + //auto disable picking mode on quit + connect(this, &QDialog::finished, [&]() + { + if (pointPickingButton_first->isChecked()) pointPickingButton_first->setChecked(false); + if (pointPickingButton_second->isChecked()) pointPickingButton_second->setChecked(false); + } + ); +} + +/* + Method for the first picking point functionnality +*/ +void ScalarDialog::pickPoint_first(bool state) +{ + if (!m_pickingHub) + { + return; + } + if (state) + { + if (!m_pickingHub->addListener(this, true)) + { + ccLog::Error("Can't start the picking process (another tool is using it)"); + state = false; + } + } + else + { + m_pickingHub->removeListener(this); + } + pointPickingButton_first->blockSignals(true); + pointPickingButton_first->setChecked(state); + pointPickingButton_first->blockSignals(false); +} + +/* + Method for the second picking point functionnality +*/ +void ScalarDialog::pickPoint_second(bool state) +{ + if (!m_pickingHub) + { + return; + } + if (state) + { + if (!m_pickingHub->addListener(this, true)) + { + ccLog::Error("Can't start the picking process (another tool is using it)"); + state = false; + } + } + else + { + m_pickingHub->removeListener(this); + } + pointPickingButton_second->blockSignals(true); + pointPickingButton_second->setChecked(state); + pointPickingButton_second->blockSignals(false); +} + +/* + Method applied after a point is picked by picking point functionnality +*/ +void ScalarDialog::onItemPicked(const PickedItem& pi) +{ + assert(pi.entity); + m_pickingWin = m_pickingHub->activeWindow(); + + if (pi.entity->isKindOf(CC_TYPES::POINT_CLOUD)) + { + if (static_cast(pi.entity)->hasColors()) { + //Get RGB values of the picked point + ccGenericPointCloud* cloud = static_cast(pi.entity); + const ScalarType scalarValue = cloud->getPointScalarValue(pi.itemIndex); + if (pointPickingButton_first->isChecked()) { + ccLog::Print("Point picked from first point picker"); + + first->setValue(scalarValue); + + pointPickingButton_first->setChecked(false); + } + else { + ccLog::Print("Point picked from second point picker"); + + second->setValue(scalarValue); + + pointPickingButton_second->setChecked(false); + } + } + else { + ccLog::Print("The point cloud is not with RGB values."); + } + + } +} diff --git a/ScalarDialog.h b/ScalarDialog.h new file mode 100644 index 0000000..87af043 --- /dev/null +++ b/ScalarDialog.h @@ -0,0 +1,62 @@ +//########################################################################## +//# # +//# CLOUDCOMPARE PLUGIN: ColorimetricSegmenter # +//# # +//# This program is free software; you can redistribute it and/or modify # +//# it under the terms of the GNU General Public License as published by # +//# the Free Software Foundation; version 2 of the License. # +//# # +//# This program is distributed in the hope that it will be useful, # +//# but WITHOUT ANY WARRANTY; without even the implied warranty of # +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +//# GNU General Public License for more details. # +//# # +//# COPYRIGHT: Tri-Thien TRUONG, Ronan COLLIER, Mathieu LETRONE # +//# # +//########################################################################## + +#ifndef ScalarDialog_H +#define ScalarDialog_H + +#include +#include "ccPickingListener.h" + +//Qt +#include +#include +#include + +class ccGLWindow; +class ccPlane; +class ccHObject; +class ccPickingHub; + +/* + Get the values of the RGB interface, and interactions +*/ +class ScalarDialog : public QDialog, public ccPickingListener, public Ui::ScalarDialog +{ + Q_OBJECT +public: + explicit ScalarDialog(ccPickingHub* pickingHub, QWidget* parent = 0); + + //! Inherited from ccPickingListener + virtual void onItemPicked(const PickedItem& pi); + +public slots: + void pickPoint_first(bool); + void pickPoint_second(bool); + +protected: //members + + //! Picking window (if any) + ccGLWindow* m_pickingWin; + + //! Picking hub + ccPickingHub* m_pickingHub; +private: + static const int NULL_VALUE = 0; + +}; + +#endif // ScalarDialog_H diff --git a/ScalarDialog.ui b/ScalarDialog.ui new file mode 100644 index 0000000..97e1b74 --- /dev/null +++ b/ScalarDialog.ui @@ -0,0 +1,389 @@ + + + ScalarDialog + + + + 0 + 0 + 780 + 314 + + + + + 0 + 0 + + + + Scalar color setting + + + + + + + + + + Choose the lowest point + + + true + + + + + + Pick the plane center (click again to cancel) + + + + :/CC/images/ccPointPicking.png:/CC/images/ccPointPicking.png + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 10 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 10 + + + + + + + + (0-1) : + + + 0 + + + 0.000000000000000 + + + 1.000000000000000 + + + 0.010000000000000 + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + Choose the highest point + + + true + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 10 + + + + + + + + Pick the plane center (click again to cancel) + + + + :/CC/images/ccPointPicking.png:/CC/images/ccPointPicking.png + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 10 + + + + + + + + (0-1) : + + + 0 + + + 0.000000000000000 + + + 1.000000000000000 + + + 0.010000000000000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Choose which points to keep + + + + 6 + + + 5 + + + 5 + + + + + Retain + + + true + + + + + + + Exclude + + + + + + + Both + + + + + + + + + + + + Deviation from limit (%) : + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 20 + + + + + + + + 100 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + + + + + + buttonBox + accepted() + ScalarDialog + accept() + + + 218 + 114 + + + 157 + 118 + + + + + buttonBox + rejected() + ScalarDialog + reject() + + + 260 + 120 + + + 280 + 118 + + + + +