Ajout contenu branch ToonMapping

This commit is contained in:
Mathieu Letrone
2020-05-02 10:27:30 +02:00
parent 58371c57c9
commit a53bfa35d3
8 changed files with 742 additions and 21 deletions
+374 -14
View File
@@ -19,6 +19,7 @@
#include <QtGui>
#include <algorithm>
#include <map>
#include "ColorimetricSegmenter.h"
#include "ccLog.h"
@@ -29,12 +30,12 @@
// Default constructor:
// - pass the Qt resource path to the info.json file (from <yourPluginName>.qrc file)
// - pass the Qt resource path to the info.json file (from <yourPluginName>.qrc file)
// - constructor should mainly be used to initialize actions and other members
/*
/*
Default constructor:
- pass the Qt resource path to the info.json file (from <yourPluginName>.qrc file)
- pass the Qt resource path to the info.json file (from <yourPluginName>.qrc file)
- constructor should mainly be used to initialize actions and other members
*/
/*
@@ -47,6 +48,8 @@ ColorimetricSegmenter::ColorimetricSegmenter( QObject *parent )
, m_action_filterRgbWithSegmentation(nullptr)
, m_action_filterHSV( nullptr )
, m_action_filterScalar( nullptr )
, m_action_ToonMapping_Hist(nullptr)
, m_action_ToonMapping_KMeans(nullptr)
{
}
@@ -88,11 +91,20 @@ void ColorimetricSegmenter::onNewSelection( const ccHObject::Container &selected
{
return;
}
if (m_action_filterScalar == nullptr)
{
return;
}
if (m_action_ToonMapping_Hist == nullptr)
{
return;
}
if (m_action_ToonMapping_KMeans == 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:
@@ -104,7 +116,7 @@ void ColorimetricSegmenter::onNewSelection( const ccHObject::Container &selected
// // ... do something with the viewports
// }
// }
// For example - only enable our action if something is selected.
// Only enable our action if something is selected.
bool activateColorFilters = false;
@@ -126,6 +138,9 @@ void ColorimetricSegmenter::onNewSelection( const ccHObject::Container &selected
m_action_filterHSV->setEnabled(false);
m_action_filterRgbWithSegmentation->setEnabled(false);
m_action_filterScalar->setEnabled(false);
m_action_ToonMapping_Hist->setEnabled(false);
m_action_ToonMapping_KMeans->setEnabled(false);
//Activate only if only one of them is activated
if ((activateColorFilters != activateScalarFilter) && !selectedEntities.empty()) {
@@ -133,6 +148,9 @@ void ColorimetricSegmenter::onNewSelection( const ccHObject::Container &selected
m_action_filterHSV->setEnabled(activateColorFilters);
m_action_filterRgbWithSegmentation->setEnabled(activateColorFilters);
m_action_filterScalar->setEnabled(activateScalarFilter);
m_action_ToonMapping_Hist->setEnabled(activateColorFilters);
m_action_ToonMapping_KMeans->setEnabled(activateColorFilters);
}
}
@@ -204,7 +222,41 @@ QList<QAction*> ColorimetricSegmenter::getActions()
connect(m_action_filterScalar, SIGNAL(newErrorMessage(QString)), this, SLOT(handleErrorMessage(QString)));
}
return { m_action_filterRgb, m_action_filterHSV, m_action_filterRgbWithSegmentation, m_action_filterScalar };
if(!m_action_ToonMapping_Hist)
{
// Here we use the default plugin name, description, and icon,
// but each action should have its own.
m_action_ToonMapping_Hist = new QAction("Histogram Clustering", this);
m_action_ToonMapping_Hist->setToolTip("Quantified cloud generator");
m_action_ToonMapping_Hist->setIcon(getIcon());
// Connect appropriate signal
connect(m_action_ToonMapping_Hist, &QAction::triggered, this, &ColorimetricSegmenter::HistogramClustering);
connect(m_action_ToonMapping_Hist, SIGNAL(newEntity(ccHObject*)), this, SLOT(handleNewEntity(ccHObject*)));
connect(m_action_ToonMapping_Hist, SIGNAL(entityHasChanged(ccHObject*)), this, SLOT(handleEntityChange(ccHObject*)));
connect(m_action_ToonMapping_Hist, SIGNAL(newErrorMessage(QString)), this, SLOT(handleErrorMessage(QString)));
}
if (!m_action_ToonMapping_KMeans)
{
// Here we use the default plugin name, description, and icon,
// but each action should have its own.
m_action_ToonMapping_KMeans = new QAction("Kmeans Clustering", this);
m_action_ToonMapping_KMeans->setToolTip("Quantified cloud generator");
m_action_ToonMapping_KMeans->setIcon(getIcon());
// Connect appropriate signal
connect(m_action_ToonMapping_KMeans, &QAction::triggered, this, &ColorimetricSegmenter::KmeansClustering);
connect(m_action_ToonMapping_KMeans, SIGNAL(newEntity(ccHObject*)), this, SLOT(handleNewEntity(ccHObject*)));
connect(m_action_ToonMapping_KMeans, SIGNAL(entityHasChanged(ccHObject*)), this, SLOT(handleEntityChange(ccHObject*)));
connect(m_action_ToonMapping_KMeans, SIGNAL(newErrorMessage(QString)), this, SLOT(handleErrorMessage(QString)));
}
return { m_action_filterRgb, m_action_filterHSV, m_action_filterRgbWithSegmentation, m_action_filterScalar, ,m_action_ToonMapping_Hist, m_action_ToonMapping_KMeans };
}
// Get all point clouds that are selected in CC
@@ -234,12 +286,12 @@ std::vector<ccPointCloud*> ColorimetricSegmenter::getSelectedPointClouds()
// Algorithm for the RGB filter
// It uses a color range with RGB values, and keeps the points with a color within that range.
void ColorimetricSegmenter::filterRgb()
{
{
if ( m_app == nullptr )
{
// m_app should have already been initialized by CC when plugin is loaded
Q_ASSERT( false );
return;
}
@@ -254,7 +306,7 @@ void ColorimetricSegmenter::filterRgb()
if (m_app->pickingHub()) {
m_pickingHub = m_app->pickingHub();
}
rgbDlg = new RgbDialog(m_pickingHub,(QWidget*)m_app->getMainWindow());
rgbDlg->show();
@@ -751,7 +803,7 @@ void ColorimetricSegmenter::filterHSV()
{
const ccColor::Rgb& rgb = cloud->getPointColor(j);
hsv hsv_current = hsvDlg->rgb2hsv(rgb);
// Hue is useless here because the saturation is not high enough
if ( 0 <= hsv_first.s && hsv_first.s <= 25 && 0 <= hsv_current.s && hsv_current.s <= 25)
{
@@ -765,7 +817,7 @@ void ColorimetricSegmenter::filterHSV()
// We need to check value first
if (0 <= hsv_first.v && hsv_first.v <= 25 && 0 <= hsv_current.v && hsv_current.v <= 25) addPoint(filteredCloudInside, j); // black
// Then, we can check value
else if (hsv_first.v > 25 && hsv_first.v <= 100 && hsv_current.v > 25 && hsv_current.v <= 100)
else if (hsv_first.v > 25 && hsv_first.v <= 100 && hsv_current.v > 25 && hsv_current.v <= 100)
{
if (((hsv_first.h >= 0 && hsv_first.h <= 30) || (hsv_first.h >= 330 && hsv_first.h <= 360)) &&
((hsv_current.h >= 0 && hsv_current.h <= 30) || (hsv_current.h >= 330 && hsv_current.h <= 360))) addPoint(filteredCloudInside, j); // red
@@ -777,7 +829,7 @@ void ColorimetricSegmenter::filterHSV()
else addPoint(filteredCloudOutside, j);
}
else addPoint(filteredCloudOutside, j);
}
}
else addPoint(filteredCloudOutside, j);
}
@@ -815,7 +867,7 @@ void ColorimetricSegmenter::addPoint(CCLib::ReferenceCloud* filteredCloud, unsig
template <typename T>
void ColorimetricSegmenter::createClouds(T& dlg, ccPointCloud* cloud, CCLib::ReferenceCloud* filteredCloudInside, CCLib::ReferenceCloud* filteredCloudOutside, std::string name)
{
if (dlg->retain->isChecked()) {
createCloud(cloud, filteredCloudInside, name, true);
}
@@ -826,7 +878,7 @@ void ColorimetricSegmenter::createClouds(T& dlg, ccPointCloud* cloud, CCLib::Ref
createCloud(cloud, filteredCloudInside, name, true);
createCloud(cloud, filteredCloudOutside, name, false);
}
}
// Method to create a new cloud
@@ -847,3 +899,311 @@ void ColorimetricSegmenter::createCloud(ccPointCloud* cloud, CCLib::ReferenceClo
m_app->addToDB(newCloud, false, true, false, false);
}
/**
Generate nxnxn clusters of points according to their color value (RGB)
@param cloud : the cloud which we work with
@param clusterPerDim : coefficient uses to split each RGB component
Returns a map of nxnxn keys, for each key a vector of the points index in the partition
*/
std::map<int, std::vector<unsigned>> getKeyCluster(const ccPointCloud& cloud, int clusterPerDim) {
float clusterSize = 256 / clusterPerDim;
std::map<int, std::vector<unsigned>> keyMap;
std::map<int, std::vector<unsigned>>::iterator it;
for (unsigned i = 0; i < cloud.size(); i++) {
const ccColor::Rgb& rgb = cloud.getPointColor(i);
int redCluster = rgb.r / clusterSize;
int greenCluster = rgb.g / clusterSize;
int blueCluster = rgb.b / clusterSize;
int index = redCluster+greenCluster*10+blueCluster*100;
it = keyMap.find(index);
//check if the entry with this index already exists
if (it == keyMap.end()) {
//if no, we create it
std::vector<unsigned> points = { i };
keyMap.insert(std::pair<int, std::vector<unsigned>>(index, points));
}
else {
//else we add the point in the container
it->second.push_back(i);
}
}
return keyMap;
}
/**
Compute the average color (RGB)
@param cloud : cloud who contains the points
@param bucket : vector of indexes of points
Returns average color (RGB)
*/
ccColor::Rgb computeAverageColor(const ccPointCloud& cloud, std::vector<unsigned> bucket) {
unsigned red=0, green=0, blue=0;
unsigned length = bucket.size();
//other formula to compute the average can be used
for (unsigned point : bucket) {
const ccColor::Rgb rgb = cloud.getPointColor(point);
red += rgb.r ;
green += rgb.g;
blue += rgb.b;
}
red = floor(red / length);
blue = floor(blue / length);
green = floor(green / length);
ccColor::Rgb res;
res.r = static_cast<unsigned char>(red); res.b = static_cast<unsigned char>((blue)); res.g = static_cast<unsigned char>((green));
return res;
}
/**
Compute the distance between two colors
/!\ the formula can be modified, here it is simple to be as quick as possible
*/
double ColorDistance(ccColor::Rgb c1, ccColor::Rgb c2) {
return (c1.r-c2.r) + (c1.b - c2.b) + (c1.g - c2.g);
}
/**
Generate a pointcloud quantified using an histogram clustering
The purpose is to counter luminance variation due to the merge of different scans
*/
void ColorimetricSegmenter::HistogramClustering() {
if (m_app == nullptr)
{
// m_app should have already been initialized by CC when plugin is loaded
Q_ASSERT(false);
return;
}
// creation of the window
quantiDlg = new QuantiDlg((QWidget*)m_app->getMainWindow());
if (!quantiDlg.exec())
return;
// Start timer
auto start = std::chrono::high_resolution_clock::now();
int nbClusterByComponent = quantiDlg.area_quanti->value();
std::vector<ccPointCloud*> clouds = ColorimetricSegmenter::getSelectedPointClouds();
for (ccPointCloud* cloud : clouds) {
if (cloud->hasColors()) {
ccPointCloud* histCloud = cloud->cloneThis();
histCloud->setName(QString::fromStdString("HistogramClustering : Indice Q : "+std::to_string(nbClusterByComponent)+" //Couleurs : "+std::to_string(nbClusterByComponent* nbClusterByComponent * nbClusterByComponent)));
std::map<int, std::vector<unsigned>> clusterMap;
clusterMap =getKeyCluster(*histCloud, nbClusterByComponent);
for (std::map<int,std::vector<unsigned>>::iterator it = clusterMap.begin(), end = clusterMap.end(); it != end; it++)
{
ccColor::Rgb averageColor = computeAverageColor(*histCloud, it->second);
for (auto point : it->second) {
(*histCloud).setPointColor(point, averageColor);
}
}
cloud->setEnabled(false);
if (cloud->getParent()) {
cloud->getParent()->addChild(histCloud);
}
m_app->addToDB(histCloud, false, true, false, false);
m_app->dispToConsole("[ColorimetricSegmenter] Cloud successfully clustering ! ", ccMainAppInterface::STD_CONSOLE_MESSAGE);
}
}
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.");
}
/**
K-means algorithm
@param k : k clusters
@param it : limit of iterations before returns a result
Returns a cloud quantified
*/
ccPointCloud* computeKmeansClustering(ccPointCloud* theCloud,
unsigned char K, int it)
{
//valid parameters?
if (!theCloud || K == 0)
{
assert(false);
return false;
}
unsigned n = theCloud->size();
if (n == 0)
return false;
//on a besoin de memoire ici !
std::vector<ccColor::Rgb> theKMeans; //K clusters centers
std::vector<unsigned char> belongings; //index of the cluster the point belongs to
std::vector<double> minDistsToMean; //distance to the nearest cluster center
std::vector<unsigned> theKNums; //number of points per clusters
std::vector<unsigned> theOldKNums; //number of points per clusters (prior to iteration)
try
{
theKMeans.resize(n);
belongings.resize(n);
minDistsToMean.resize(n);
theKNums.resize(K);
theOldKNums.resize(K);
}
catch (const std::bad_alloc&)
{
//not enough memory
return false;
}
//init classes centers (regularly sampled
unsigned step = n / K;
for (unsigned char j = 0; j < K; ++j)
theKMeans[j] = theCloud->getPointColor(step*j);
//let's start
bool meansHaveMoved = false;
int iteration = 0;
do
{
meansHaveMoved = false;
++iteration;
//
std::map<unsigned char, std::vector<unsigned>> KGroups;
{
for (unsigned i = 0; i < n; ++i)
{
unsigned char minK = 0;
ccColor::Rgb color = theCloud->getPointColor(i);
minDistsToMean[i] = std::abs(ColorDistance(color, theKMeans[minK]));
//we look for the nearest cluster center
for (unsigned char j = 1; j < K; ++j)
{
double distToMean = std::abs(ColorDistance(color, theKMeans[j]));
if (distToMean < minDistsToMean[i])
{
minDistsToMean[i] = distToMean;
minK = j;
}
}
belongings[i] = minK;
//minDistsToMean[i] = V;
}
}
//compute the clusters centers
theOldKNums = theKNums;
std::fill(theKNums.begin(), theKNums.end(), static_cast<unsigned>(0));
for (unsigned i = 0; i < n; ++i)
{
auto it = KGroups.find(belongings[i]);
if (it == KGroups.end()) {
std::vector<unsigned> points = { i };
KGroups.insert(std::pair<unsigned char, std::vector<unsigned>>(belongings[i], points));
}
else {
it->second.push_back(i);
}
++theKNums[belongings[i]];
}
for (unsigned char j = 0; j < K; ++j)
{
ccColor::Rgb newMean = (KGroups[j].size() > 0 ? computeAverageColor(*theCloud, KGroups[j]) : theKMeans[j]);
if (theOldKNums[j] != theKNums[j]) {
meansHaveMoved = true;
}
theKMeans[j] = newMean;
}
} while (iteration < it);
ccPointCloud* KCloud = theCloud->cloneThis();
KCloud->setName(QString::fromStdString("Kmeans clustering : K : " + std::to_string(K)));
//set color for each cluster
for (unsigned i = 0; i < n; i++) {
(*KCloud).setPointColor(i, theKMeans[belongings[i]]);
}
return KCloud;
}
/**
Algorithm based on k-means for clustering points cloud by its colors
*/
void ColorimetricSegmenter::KmeansClustering() {
kmeansDlg = new KmeansDlg((QWidget*)m_app->getMainWindow());
if (!kmeansDlg.exec())
return;
// Start timer
auto start = std::chrono::high_resolution_clock::now();
std::vector<ccPointCloud*> clouds = ColorimetricSegmenter::getSelectedPointClouds();
for (ccPointCloud* cloud : clouds)
{
std::cout << " nb iteration : " << kmeansDlg.spinBox_it->value() << std::endl << "nb k : " << kmeansDlg.spinBox_k->value() << std::endl;
ccPointCloud* kcloud = computeKmeansClustering(cloud, kmeansDlg.spinBox_k->value(), kmeansDlg.spinBox_it->value());
cloud->setEnabled(false);
if (cloud->getParent())
{
cloud->getParent()->addChild(kcloud);
}
m_app->addToDB(kcloud, false, true, false, false);
m_app->dispToConsole("[ColorimetricSegmenter] Cloud successfully clustering ! ", 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");
}
+19 -7
View File
@@ -32,21 +32,23 @@
#include "RgbDialog.h"
#include "HSVDialog.h"
#include "ScalarDialog.h"
#include "QuantiDialog.h"
#include "KmeansDlg.h"
//! Example qCC plugin
/** Replace 'ExamplePlugin' by your own plugin class name throughout and then
check 'ExamplePlugin.cpp' for more directions.
Each plugin requires an info.json file to provide information about itself -
the name, authors, maintainers, icon, etc..
The one method you are required to implement is 'getActions'. This should
return all actions (QAction objects) for the plugin. CloudCompare will
automatically add these with their icons in the plugin toolbar and to the
plugin menu. If your plugin returns several actions, CC will create a
dedicated toolbar and a sub-menu for your plugin. You are responsible for
connecting these actions to methods in your plugin.
Use the ccStdPluginInterface::m_app variable for access to most of the CC
components (database, 3D views, console, etc.) - see the ccMainAppInterface
class in ccMainAppInterface.h.
@@ -58,16 +60,16 @@ class ColorimetricSegmenter : public QObject, public ccStdPluginInterface
{
Q_OBJECT
Q_INTERFACES(ccStdPluginInterface)
// Replace "Example" by your plugin name (IID should be unique - let's hope your plugin name is unique ;)
// The info.json file provides information about the plugin to the loading system and
// it is displayed in the plugin information dialog.
Q_PLUGIN_METADATA(IID "cccorp.cloudcompare.plugin.ColorimetricSegmenter" FILE "info.json")
public:
explicit ColorimetricSegmenter( QObject *parent = nullptr );
~ColorimetricSegmenter() override = default;
// inherited from ccStdPluginInterface
void onNewSelection( const ccHObject::Container &selectedEntities ) override;
QList<QAction *> getActions() override;
@@ -103,6 +105,10 @@ private:
void filterScalar();
void HistogramClustering();
void KmeansClustering();
void addPoint(CCLib::ReferenceCloud* filteredCloud, unsigned int j);
template <typename T>
@@ -113,7 +119,7 @@ private:
//picked point callbacks
//void pointPicked(ccHObject* entity, unsigned itemIdx, int x, int y, const CCVector3& P);
//virtual void onItemPicked(const ccPickingListener::PickedItem& pi); //inherited from ccPickingListener
//! Segment a cloud with RGB color
void filterRgbWithSegmentation();
@@ -150,6 +156,9 @@ private:
QAction* m_action_filterRgbWithSegmentation;
QAction* m_action_filterHSV;
QAction* m_action_filterScalar;
QAction* m_action_ToonMapping_Hist;
QAction* m_action_ToonMapping_KMeans;
//! Picking hub
ccPickingHub* m_pickingHub = nullptr;
@@ -157,6 +166,9 @@ private:
RgbDialog* rgbDlg;
HSVDialog* hsvDlg;
ScalarDialog* scalarDlg;
QuantiDialog* quantiDlg;
KmeansDlg* kmeansDlg;
//link to application windows
//ccGLWindow* m_window;
+12
View File
@@ -0,0 +1,12 @@
#include "KmeansDlg.h"
#include <QVariant>
KmeansDlg::KmeansDlg(QWidget* parent)
: QDialog(parent)
, Ui::KmeansDialog()
{
setupUi(this);
}
+18
View File
@@ -0,0 +1,18 @@
#ifndef KMEANSDIALOG_H
#define KMEANSDIALOG_H
#include <ui_KmeansDlg.h>
//Qt
#include <QDialog>
class KmeansDlg : public QDialog, public Ui::KmeansDialog
{
Q_OBJECT
public:
explicit KmeansDlg(QWidget* parent = 0);
};
#endif
+114
View File
@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KmeansDialog</class>
<widget class="QDialog" name="KmeansDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>391</width>
<height>230</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>-50</x>
<y>180</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QWidget" name="gridLayoutWidget">
<property name="geometry">
<rect>
<x>20</x>
<y>40</y>
<width>351</width>
<height>111</height>
</rect>
</property>
<layout class="QGridLayout">
<item row="1" column="1">
<widget class="QSpinBox" name="spinBox_it">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_color">
<property name="text">
<string>Nombre couleurs</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinBox_k">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_It">
<property name="text">
<string>Nombre itération</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>KmeansDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>KmeansDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
+18
View File
@@ -0,0 +1,18 @@
#include "QuantiDialog.h"
#include <QVariant>
QuantiDialog::QuantiDialog(QWidget* parent)
: QDialog(parent)
, Ui::QuantiDialog()
{
setupUi(this);
//connect(area_quanti, static_cast<void(QSpinBox::*)(double)>(&QSpinBox::valueChanged), this, SLOT(QuantiDialog::updateLabe()));
//connect(area_quanti, SIGNAL(valueChanged(int)), this, &QuantiDialog::updateLabelValue);
//connect(area_quanti, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &QuantiDialog::updateLabelValue);
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef QUANTIDIALOG_H
#define QUANTIDIALOG_H
#include <ui_QuantiDialog.h>
//Qt
#include <QDialog>
class QuantiDialog : public QDialog, public Ui::QuantiDialog
{
Q_OBJECT
public:
explicit QuantiDialog(QWidget* parent = 0);
public slots:
void updateLabelValue(double value) {
nb_color_label->setText(QString::fromStdString(std::to_string(value * value)));
}
};
#endif
+164
View File
@@ -0,0 +1,164 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QuantiDialog</class>
<widget class="QDialog" name="QuantiDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>401</width>
<height>204</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>-40</x>
<y>150</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QWidget" name="layoutWidget_2">
<property name="geometry">
<rect>
<x>10</x>
<y>40</y>
<width>384</width>
<height>30</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_bottom">
<item>
<widget class="QLabel" name="quanti_label">
<property name="text">
<string>Indice de Quantification</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="area_quanti">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>149</x>
<y>310</y>
<width>384</width>
<height>28</height>
</rect>
</property>
<property name="cursor">
<cursorShape>ArrowCursor</cursorShape>
</property>
<property name="text">
<string>Use PointPicking</string>
</property>
</widget>
<widget class="QLabel" name="quanti_label_2">
<property name="geometry">
<rect>
<x>120</x>
<y>90</y>
<width>174</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QWidget" name="layoutWidget_4">
<property name="geometry">
<rect>
<x>10</x>
<y>90</y>
<width>384</width>
<height>30</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_bottom_4">
<item>
<widget class="QLabel" name="quanti_label_5">
<property name="text">
<string>Couleurs possibles :</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="nb_color_label">
<property name="text">
<string>1</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QuantiDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QuantiDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>