ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvColorLevelsDlg.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "ecvColorLevelsDlg.h"
9 
10 // local
11 #include "ecvGenericPointCloud.h"
12 #include "ecvHistogramWindow.h"
13 
14 // CV_DB_LIB
15 #include <ecvDisplayTools.h>
16 #include <ecvHObjectCaster.h>
17 #include <ecvPointCloud.h>
18 
19 // Qt
20 #include <QPushButton>
21 
22 // system
23 #include <assert.h>
24 #include <string.h>
25 
26 // persistent parameters
27 static int s_inputLevels[2] = {0, 255};
28 static int s_outputLevels[2] = {0, 255};
29 static bool s_outputLevelsEnabled = false;
30 
32  ccGenericPointCloud* pointCloud)
33  : QDialog(parent, Qt::Tool),
34  Ui::ColorLevelsDialog(),
35  m_histogram(0),
36  m_cloud(pointCloud) {
37  setupUi(this);
38 
39  // connect GUI elements
40  connect(channelComboBox,
41  static_cast<void (QComboBox::*)(int)>(
42  &QComboBox::currentIndexChanged),
44  connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked,
46 
47  // create histogram view
48  m_histogram = new ccHistogramWindow(this);
49  {
52  // add view
53  histoFrame->setLayout(new QHBoxLayout());
54  histoFrame->layout()->addWidget(m_histogram);
55  }
56 
57  // restore previous parameters
58  minInputSpinBox->setValue(s_inputLevels[0]);
59  maxInputSpinBox->setValue(s_inputLevels[1]);
60  minOutputSpinBox->setValue(s_outputLevels[0]);
61  maxOutputSpinBox->setValue(s_outputLevels[1]);
62  outputLevelsCheckBox->setChecked(s_outputLevelsEnabled);
63 
65 }
66 
68  if (m_histogram) {
69  unsigned pointCount = (m_cloud ? m_cloud->size() : 0);
70  if (pointCount == 0) {
71  // nothing to do
72  m_histogram->clear();
73  return;
74  }
75 
76  std::vector<unsigned> histoValues[3];
77  try {
78  for (int i = 0; i < 3; ++i) {
79  if (channelComboBox->currentIndex() == RGB ||
80  channelComboBox->currentIndex() == i + 1) {
81  histoValues[i].resize(1 << (sizeof(ColorCompType) * 8), 0);
82  }
83  }
84  } catch (const std::bad_alloc&) {
85  // not enough memory
86  m_histogram->clear();
87  return;
88  }
89 
90  std::vector<unsigned>* histoValuesR =
91  (histoValues[0].empty() ? 0 : histoValues);
92  std::vector<unsigned>* histoValuesG =
93  (histoValues[1].empty() ? 0 : histoValues + 1);
94  std::vector<unsigned>* histoValuesB =
95  (histoValues[2].empty() ? 0 : histoValues + 2);
96 
97  switch (channelComboBox->currentIndex()) {
98  case RGB:
100  m_histogram->setAxisLabels("R,G,B", "");
101  // test: for now we send all data into the same histogram!
102  histoValuesG = histoValuesR;
103  histoValuesB = histoValuesR;
104  break;
105  case RED:
107  m_histogram->setAxisLabels("Red", "");
108  break;
109  case GREEN:
111  m_histogram->setAxisLabels("Green", "");
112  break;
113  case BLUE:
115  m_histogram->setAxisLabels("Blue", "");
116  break;
117  }
118 
119  // project points
120  {
121  for (unsigned i = 0; i < pointCount; ++i) {
122  const ecvColor::Rgb& rgb = m_cloud->getPointColor(i);
123  if (histoValuesR) histoValuesR->at(rgb.r)++;
124  if (histoValuesG) histoValuesG->at(rgb.g)++;
125  if (histoValuesB) histoValuesB->at(rgb.b)++;
126  }
127  }
128 
129  for (int i = 0; i < 3; ++i) {
130  if (channelComboBox->currentIndex() == RGB ||
131  channelComboBox->currentIndex() == i + 1) {
132  m_histogram->fromBinArray(histoValues[i], 0.0, 256.0);
133  break;
134  }
135  }
136  m_histogram->refresh();
137  }
138 }
139 
141 
143  // save parameters
144  s_inputLevels[0] = minInputSpinBox->value();
145  s_inputLevels[1] = maxInputSpinBox->value();
146  s_outputLevels[0] = minOutputSpinBox->value();
147  s_outputLevels[1] = maxOutputSpinBox->value();
148  s_outputLevelsEnabled = outputLevelsCheckBox->isChecked();
149 
150  if (m_cloud &&
151  (minInputSpinBox->value() != 0 || maxInputSpinBox->value() != 255 ||
152  minOutputSpinBox->value() != 0 || maxOutputSpinBox->value() != 255)) {
153  bool applyRGB[3] = {channelComboBox->currentIndex() == RGB ||
154  channelComboBox->currentIndex() == RED,
155  channelComboBox->currentIndex() == RGB ||
156  channelComboBox->currentIndex() == GREEN,
157  channelComboBox->currentIndex() == RGB ||
158  channelComboBox->currentIndex() == BLUE};
159 
160  // update display
162 
163  unsigned pointCount = m_cloud->size();
164  int qIn = s_inputLevels[1] - s_inputLevels[0];
165  int pOut = s_outputLevels[1] - s_outputLevels[0];
166  for (unsigned i = 0; i < pointCount; ++i) {
167  const ecvColor::Rgb& rgb = m_cloud->getPointColor(i);
168  ecvColor::Rgb newRgb;
169  for (unsigned c = 0; c < 3; ++c) {
170  if (applyRGB[c]) {
171  double newC = s_outputLevels[0];
172  if (qIn) {
173  double u = (static_cast<double>(rgb.rgb[c]) -
174  s_inputLevels[0]) /
175  qIn;
176  newC = s_outputLevels[0] + u * pOut;
177  }
178  newRgb.rgb[c] = static_cast<ColorCompType>(std::max<double>(
179  std::min<double>(newC, ecvColor::MAX), 0.0));
180  } else {
181  newRgb.rgb[c] = rgb.rgb[c];
182  }
183  }
184 
185  // set the new color
186  if (pc) {
187  pc->setPointColor(i, newRgb);
188  } else {
189  // DGM FIXME: dirty!
190  const_cast<ecvColor::Rgb&>(rgb) = newRgb;
191  }
192  }
193 
194  // update display
196 
197  // update histogram
198  onChannelChanged(channelComboBox->currentIndex());
199  }
200 
201  // after applying the filter we reset the boundaries to (0,255)
202  // in case the user clicks multiple times on the "Apply" button!
203  minInputSpinBox->setValue(0);
204  maxInputSpinBox->setValue(255);
205  minOutputSpinBox->setValue(0);
206  maxOutputSpinBox->setValue(255);
207 }
ccHistogramWindow * m_histogram
Associated histogram view.
ccColorLevelsDlg(QWidget *parent, ccGenericPointCloud *pointCloud)
Default constructor.
void updateHistogram()
Updates histogram.
ccGenericPointCloud * m_cloud
Associated point cloud (color source)
A 3D cloud interface with associated features (color, normals, octree, etc.)
virtual const ecvColor::Rgb & getPointColor(unsigned pointIndex) const =0
Returns color corresponding to a given point.
static ccPointCloud * ToPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccPointCloud.
Histogram widget.
void refresh()
Updates the display.
void setColorScheme(HISTOGRAM_COLOR_SCHEME scheme)
Sets how the gradient bars should be colored.
void fromBinArray(const std::vector< unsigned > &histoValues, double minVal, double maxVal)
void setSolidColor(QColor color)
Sets solid color.
void clear()
Clears the display.
void setAxisLabels(const QString &xLabel, const QString &yLabel)
Sets axis labels.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void setPointColor(size_t pointIndex, const ecvColor::Rgb &col)
Sets a particular point color.
virtual unsigned size() const =0
Returns the number of points.
RGB color structure.
Definition: ecvColorTypes.h:49
static void RedrawDisplay(bool only2D=false, bool forceRedraw=true)
static int s_inputLevels[2]
static bool s_outputLevelsEnabled
static int s_outputLevels[2]
unsigned char ColorCompType
Default color components type (R,G and B)
Definition: ecvColorTypes.h:29
constexpr Rgb black(0, 0, 0)
constexpr ColorCompType MAX
Max value of a single color component (default type)
Definition: ecvColorTypes.h:34
constexpr Rgb red(MAX, 0, 0)
constexpr Rgb blue(0, 0, MAX)
constexpr Rgb green(0, MAX, 0)