Filter scalar function

This commit is contained in:
valorun
2020-04-29 19:19:46 +02:00
parent 6d850ccc54
commit ae93995a5d
5 changed files with 709 additions and 6 deletions
+96 -4
View File
@@ -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<QAction*> 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<std::chrono::milliseconds>(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<double>(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<ccPointCloud*> 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<ScalarDialog*>(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<std::chrono::milliseconds>(stop - start).count();
QString s = QString::number(duration);
//Print time of execution
ccLog::Print("Time to execute : " + s + " milliseconds.");
}
/**
+7 -2
View File
@@ -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;
+155
View File
@@ -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 <QVariant>
#include <QApplication>
#include <QClipboard>
#include <QFileDialog>
#include <QMenu>
#include <QMessageBox>
#include <QSettings>
//common
#include <ccPickingHub.h>
#include <ccGenericPointCloud.h>
#include <ccPointCloud.h>
//qCC_gl
#include <ccGLWidget.h>
#include <ccGLWindow.h>
/*
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<ccGenericPointCloud*>(pi.entity)->hasColors()) {
//Get RGB values of the picked point
ccGenericPointCloud* cloud = static_cast<ccGenericPointCloud*>(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.");
}
}
}
+62
View File
@@ -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 <ui_ScalarDialog.h>
#include "ccPickingListener.h"
//Qt
#include <ccHObject.h>
#include <QDialog>
#include <qcheckbox.h>
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
+389
View File
@@ -0,0 +1,389 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ScalarDialog</class>
<widget class="QDialog" name="ScalarDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>780</width>
<height>314</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Scalar color setting</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGroupBox" name="centerGroupBox">
<property name="title">
<string>Choose the lowest point</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="1">
<widget class="QToolButton" name="pointPickingButton_first">
<property name="toolTip">
<string>Pick the plane center (click again to cancel)</string>
</property>
<property name="icon">
<iconset resource="../../../qCC/icones.qrc">
<normaloff>:/CC/images/ccPointPicking.png</normaloff>:/CC/images/ccPointPicking.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="3">
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="3">
<widget class="QDoubleSpinBox" name="first">
<property name="prefix">
<string notr="true">(0-1) : </string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="centerGroupBox_2">
<property name="title">
<string>Choose the highest point </string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="2" column="3">
<spacer name="verticalSpacer_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QToolButton" name="pointPickingButton_second">
<property name="toolTip">
<string>Pick the plane center (click again to cancel)</string>
</property>
<property name="icon">
<iconset resource="../../../qCC/icones.qrc">
<normaloff>:/CC/images/ccPointPicking.png</normaloff>:/CC/images/ccPointPicking.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="3">
<widget class="QDoubleSpinBox" name="second">
<property name="prefix">
<string notr="true">(0-1) : </string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="horizontalGroupBox">
<property name="title">
<string>Choose which points to keep </string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>6</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item alignment="Qt::AlignHCenter">
<widget class="QRadioButton" name="retain">
<property name="text">
<string>Retain</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QRadioButton" name="exclude">
<property name="text">
<string>Exclude</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QRadioButton" name="both">
<property name="text">
<string>Both</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_bottom">
<item>
<widget class="QLabel" name="margin_label">
<property name="text">
<string>Deviation from limit (%) :</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QSpinBox" name="margin">
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../../../qCC/icones.qrc"/>
<include location="../../../qCC/icones.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ScalarDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>218</x>
<y>114</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>118</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ScalarDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>260</x>
<y>120</y>
</hint>
<hint type="destinationlabel">
<x>280</x>
<y>118</y>
</hint>
</hints>
</connection>
</connections>
</ui>