ccColorLevelsDlg.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. //##########################################################################
  2. //# #
  3. //# CLOUDCOMPARE #
  4. //# #
  5. //# This program is free software; you can redistribute it and/or modify #
  6. //# it under the terms of the GNU General Public License as published by #
  7. //# the Free Software Foundation; version 2 or later of the License. #
  8. //# #
  9. //# This program is distributed in the hope that it will be useful, #
  10. //# but WITHOUT ANY WARRANTY; without even the implied warranty of #
  11. //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
  12. //# GNU General Public License for more details. #
  13. //# #
  14. //# COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI) #
  15. //# #
  16. //##########################################################################
  17. #include "ccColorLevelsDlg.h"
  18. //local
  19. #include "ccHistogramWindow.h"
  20. #include "ccGenericPointCloud.h"
  21. //qCC_db
  22. #include <ccGenericGLDisplay.h>
  23. #include <ccPointCloud.h>
  24. #include <ccHObjectCaster.h>
  25. //Qt
  26. #include <QPushButton>
  27. //system
  28. #include <string.h>
  29. #include <assert.h>
  30. //persistent parameters
  31. static int s_inputLevels[2] = {0,255};
  32. static int s_outputLevels[2] = {0,255};
  33. static bool s_outputLevelsEnabled = false;
  34. ccColorLevelsDlg::ccColorLevelsDlg(QWidget* parent, ccGenericPointCloud* pointCloud)
  35. : QDialog(parent, Qt::Tool)
  36. , Ui::ColorLevelsDialog()
  37. , m_histogram(nullptr)
  38. , m_cloud(pointCloud)
  39. {
  40. setupUi(this);
  41. //connect GUI elements
  42. connect(channelComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this, &ccColorLevelsDlg::onChannelChanged);
  43. connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &ccColorLevelsDlg::onApply);
  44. //create histogram view
  45. m_histogram = new ccHistogramWindow(this);
  46. {
  47. m_histogram->setColorScheme(ccHistogramWindow::USE_SOLID_COLOR);
  48. m_histogram->setSolidColor(Qt::black);
  49. //add view
  50. histoFrame->setLayout(new QHBoxLayout());
  51. histoFrame->layout()->addWidget(m_histogram);
  52. }
  53. //restore previous parameters
  54. minInputSpinBox->setValue(s_inputLevels[0]);
  55. maxInputSpinBox->setValue(s_inputLevels[1]);
  56. minOutputSpinBox->setValue(s_outputLevels[0]);
  57. maxOutputSpinBox->setValue(s_outputLevels[1]);
  58. outputLevelsCheckBox->setChecked(s_outputLevelsEnabled);
  59. updateHistogram();
  60. }
  61. void ccColorLevelsDlg::updateHistogram()
  62. {
  63. if (m_histogram)
  64. {
  65. unsigned pointCount = (m_cloud ? m_cloud->size() : 0);
  66. if (pointCount == 0)
  67. {
  68. //nothing to do
  69. m_histogram->clear();
  70. return;
  71. }
  72. std::vector<unsigned> histoValues[3];
  73. try
  74. {
  75. for (int i = 0; i < 3; ++i)
  76. {
  77. if ( channelComboBox->currentIndex() == RGB
  78. || channelComboBox->currentIndex() == i + 1)
  79. {
  80. histoValues[i].resize(1 << (sizeof(ColorCompType) * 8), 0);
  81. }
  82. }
  83. }
  84. catch (const std::bad_alloc&)
  85. {
  86. //not enough memory
  87. m_histogram->clear();
  88. return;
  89. }
  90. std::vector<unsigned>* histoValuesR = (histoValues[0].empty() ? nullptr : histoValues);
  91. std::vector<unsigned>* histoValuesG = (histoValues[1].empty() ? nullptr : histoValues + 1);
  92. std::vector<unsigned>* histoValuesB = (histoValues[2].empty() ? nullptr : histoValues + 2);
  93. switch (channelComboBox->currentIndex())
  94. {
  95. case RGB:
  96. m_histogram->setSolidColor(Qt::black);
  97. m_histogram->setAxisLabels("R,G,B", QString());
  98. //test: for now we send all data into the same histogram!
  99. histoValuesG = histoValuesR;
  100. histoValuesB = histoValuesR;
  101. break;
  102. case RED:
  103. m_histogram->setSolidColor(Qt::red);
  104. m_histogram->setAxisLabels("Red", QString());
  105. break;
  106. case GREEN:
  107. m_histogram->setSolidColor(Qt::green);
  108. m_histogram->setAxisLabels("Green", QString());
  109. break;
  110. case BLUE:
  111. m_histogram->setSolidColor(Qt::blue);
  112. m_histogram->setAxisLabels("Blue", QString());
  113. break;
  114. }
  115. //project points
  116. {
  117. for (unsigned i = 0; i < pointCount; ++i)
  118. {
  119. const ccColor::Rgba& col = m_cloud->getPointColor(i);
  120. if (histoValuesR)
  121. histoValuesR->at(col.r)++;
  122. if (histoValuesG)
  123. histoValuesG->at(col.g)++;
  124. if (histoValuesB)
  125. histoValuesB->at(col.b)++;
  126. }
  127. }
  128. for (int i = 0; i < 3; ++i)
  129. {
  130. if (channelComboBox->currentIndex() == RGB || channelComboBox->currentIndex() == i + 1)
  131. {
  132. m_histogram->fromBinArray(histoValues[i], 0.0, 256.0);
  133. break;
  134. }
  135. }
  136. m_histogram->refresh();
  137. }
  138. }
  139. void ccColorLevelsDlg::onChannelChanged(int channel)
  140. {
  141. updateHistogram();
  142. }
  143. void ccColorLevelsDlg::onApply()
  144. {
  145. //save parameters
  146. s_inputLevels[0] = minInputSpinBox->value();
  147. s_inputLevels[1] = maxInputSpinBox->value();
  148. s_outputLevels[0] = minOutputSpinBox->value();
  149. s_outputLevels[1] = maxOutputSpinBox->value();
  150. s_outputLevelsEnabled = outputLevelsCheckBox->isChecked();
  151. if ( m_cloud
  152. && ( minInputSpinBox->value() != 0
  153. || maxInputSpinBox->value() != 255
  154. || minOutputSpinBox->value() != 0
  155. || maxOutputSpinBox->value() != 255
  156. ) )
  157. {
  158. bool applyRGB[3] = { channelComboBox->currentIndex() == RGB || channelComboBox->currentIndex() == RED,
  159. channelComboBox->currentIndex() == RGB || channelComboBox->currentIndex() == GREEN,
  160. channelComboBox->currentIndex() == RGB || channelComboBox->currentIndex() == BLUE };
  161. ScaleColorFields( m_cloud,
  162. s_inputLevels[0],
  163. s_inputLevels[1],
  164. s_outputLevels[0],
  165. s_outputLevels[1],
  166. applyRGB );
  167. //update display
  168. m_cloud->getDisplay()->redraw();
  169. //update histogram
  170. onChannelChanged(channelComboBox->currentIndex());
  171. }
  172. //after applying the filter we reset the boundaries to (0,255)
  173. //in case the user clicks multiple times on the "Apply" button!
  174. minInputSpinBox->setValue(0);
  175. maxInputSpinBox->setValue(255);
  176. minOutputSpinBox->setValue(0);
  177. maxOutputSpinBox->setValue(255);
  178. }
  179. bool ccColorLevelsDlg::ScaleColorFields(ccGenericPointCloud* cloud, int inputLevelMin, int inputLevelMax, int outputLevelMin, int outputLevelMax, const bool applyRGB[3])
  180. {
  181. if (!cloud)
  182. {
  183. assert(false);
  184. return false;
  185. }
  186. if (!cloud->hasColors())
  187. {
  188. ccLog::Warning("(ccColorLevelsDlg::ScaleColorFields] Cloud has no colors");
  189. return false;
  190. }
  191. ccPointCloud* pc = ccHObjectCaster::ToPointCloud(cloud);
  192. unsigned pointCount = cloud->size();
  193. int qIn = inputLevelMax - inputLevelMin;
  194. if (qIn == 0)
  195. {
  196. ccLog::Warning("(ccColorLevelsDlg::ScaleColorFields] Flat input range (input range can't be 0)");
  197. return false;
  198. }
  199. int pOut = outputLevelMax - outputLevelMin;
  200. double convRatio = pOut / static_cast<double>(qIn);
  201. for (unsigned i = 0; i < pointCount; ++i)
  202. {
  203. const ccColor::Rgba& col = cloud->getPointColor(i);
  204. ccColor::Rgba newRgb = col;
  205. for (unsigned c = 0; c < 3; ++c)
  206. {
  207. if (applyRGB[c])
  208. {
  209. double newC = outputLevelMin + (static_cast<int>(col.rgba[c]) - inputLevelMin) * convRatio;
  210. newRgb.rgba[c] = static_cast<ColorCompType>(std::max(std::min(newC, static_cast<double>(ccColor::MAX)), 0.0));
  211. }
  212. }
  213. //set the new color
  214. if (pc)
  215. {
  216. pc->setPointColor(i, newRgb);
  217. }
  218. else
  219. {
  220. //DGM FIXME: dirty!
  221. const_cast<ccColor::Rgba&>(col) = newRgb;
  222. }
  223. }
  224. return true;
  225. }