labplot  2.8.2
About: LabPlot is an application for plotting and analysis of 2D and 3D functions and data. It is a complete rewrite of LabPlot1 and lacks in the first release a lot of features available in the predecessor. On the other hand, the GUI and the usability is more superior.
  Fossies Dox: labplot-2.8.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

ImageEditor.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  File : ImageEditor.cpp
3  Project : LabPlot
4  Description : Edit Image on the basis of input color attributes
5  --------------------------------------------------------------------
6  Copyright : (C) 2015 by Ankit Wagadre (wagadre.ankit@gmail.com)
7  Copyright : (C) 2015-2016 Alexander Semke (alexander.semke@web.de)
8  ***************************************************************************/
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  * This program is distributed in the hope that it will be useful, *
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19  * GNU General Public License for more details. *
20  * *
21  * You should have received a copy of the GNU General Public License *
22  * along with this program; if not, write to the Free Software *
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
24  * Boston, MA 02110-1301 USA *
25  * *
26  ***************************************************************************/
27 
28 #include "ImageEditor.h"
29 #include <QThreadPool>
30 #include <QElapsedTimer>
31 #include <QMutex>
32 
33 extern "C" {
34 #include <gsl/gsl_math.h>
35 }
36 
37 static const QRgb white = QColor(Qt::white).rgb();
38 static const QRgb black = QColor(Qt::black).rgb();
39 static const double colorScale = gsl_hypot3(255, 255, 255);
40 
41 //Intensity, Foreground, Saturation and Value are from 0 to 100, Hue is from 0 to 360
42 static const int maxIntensity = 100;
43 static const int maxForeground = 100;
44 static const int maxHue = 360;
45 static const int maxSaturation = 100;
46 static const int maxValue = 100;
47 
48 QMutex mutex;
49 
50 class DiscretizeTask : public QRunnable {
51 public:
52  DiscretizeTask(int start, int end, QImage* plotImage, QImage* originalImage, const DatapickerImage::EditorSettings& settings, QColor background) :
53  m_start(start),
54  m_end(end),
55  m_plotImage(plotImage),
56  m_originalImage(originalImage),
57  m_settings(settings),
58  m_background(std::move(background))
59  {};
60 
61  void run() override {
62  for (int y = m_start; y < m_end; ++y) {
63  mutex.lock();
64  QRgb* line = reinterpret_cast<QRgb*>(m_plotImage->scanLine(y));
65  mutex.unlock();
66  for (int x = 0; x < m_plotImage->width(); ++x) {
69  continue;
70 
73  continue;
74 
77  continue;
78 
81  continue;
82 
85  continue;
86 
87  line[x] = black;
88  }
89  }
90  }
91 
92 private:
93  int m_start;
94  int m_end;
95  QImage* m_plotImage;
96  QImage* m_originalImage;
98  QColor m_background;
99 };
100 
101 /*!
102  *
103  */
104 void ImageEditor::discretize(QImage* plotImage, QImage* originalImage,
105  const DatapickerImage::EditorSettings& settings, QColor background) {
106  plotImage->fill(white);
107  QThreadPool* pool = QThreadPool::globalInstance();
108  int range = ceil(double(plotImage->height())/pool->maxThreadCount());
109  for (int i = 0; i < pool->maxThreadCount(); ++i) {
110  const int start = i*range;
111  int end = (i+1)*range;
112  if (end > plotImage->height()) end = plotImage->height();
113  auto* task = new DiscretizeTask(start, end, plotImage, originalImage, settings, background);
114  pool->start(task);
115  }
116  pool->waitForDone();
117 }
118 
119 bool ImageEditor::processedPixelIsOn(const QImage& plotImage, int x, int y) {
120  if ((x < 0) || (plotImage.width() <= x) || (y < 0) || (plotImage.height() <= y))
121  return false;
122 
123  // pixel is on if it is closer to black than white in gray scale. this test must be performed
124  // on little endian and big endian systems, with or without alpha bits (which are typically high bits)
125  const int BLACK_WHITE_THRESHOLD = 255 / 2; // put threshold in middle of range
126  int gray = qGray(plotImage.pixel(x, y));
127  return (gray < BLACK_WHITE_THRESHOLD);
128 }
129 
130 //##############################################################################
131 //##################### private helper functions #############################
132 //##############################################################################
133 QRgb ImageEditor::findBackgroundColor(const QImage* plotImage) {
134  ColorList::iterator itrC;
136  int x, y = 0;
137  for (x = 0; x < plotImage->width(); ++x) {
138  ColorEntry c;
139  c.color = plotImage->pixel(x,y);
140  c.count = 0;
141 
142  bool found = false;
143  for (itrC = colors.begin(); itrC != colors.end(); ++itrC) {
144  if (colorCompare(c.color.rgb(), (*itrC).color.rgb())) {
145  found = true;
146  ++(*itrC).count;
147  break;
148  }
149  }
150  if (!found)
151  colors.append(c);
152 
153  if (++y >= plotImage->height())
154  y = 0;
155  }
156 
157  ColorEntry cMax;
158  cMax.count = 0;
159  for (itrC = colors.begin(); itrC != colors.end(); ++itrC) {
160  if ((*itrC).count > cMax.count)
161  cMax = (*itrC);
162  }
163 
164  return cMax.color.rgb();
165 }
166 
167 void ImageEditor::uploadHistogram(int* bins, QImage* originalImage, QColor background, DatapickerImage::ColorAttributes type) {
168  //reset bin
169  for (int i = 0; i <= colorAttributeMax(type); ++i)
170  bins [i] = 0;
171 
172  for (int x = 0; x < originalImage->width(); ++x) {
173  for (int y = 0; y < originalImage->height(); ++y) {
174  int value = discretizeValueForeground(x, y, type, background, originalImage);
175  bins[value] += 1;
176  }
177  }
178 }
179 
181  //Intensity, Foreground, Saturation and Value are from 0 to 100
182  //Hue is from 0 to 360
183  switch (type) {
185  return 0;
187  return 100;
189  return 100;
191  return 360;
193  return 100;
195  default:
196  return 100;
197  }
198 }
199 
200 bool ImageEditor::colorCompare(QRgb color1, QRgb color2) {
201  const long MASK = 0xf0f0f0f0;
202  return (color1 & MASK) == (color2 & MASK);
203 }
204 
205 int ImageEditor::discretizeHue(int x, int y, const QImage* originalImage) {
206  const QColor color(originalImage->pixel(x,y));
207  const int h = color.hue();
208  int value = h * maxHue / 359;
209 
210  if (value < 0) //QColor::hue() can return -1
211  value = 0;
212  if (maxHue < value)
213  value = maxHue;
214 
215  return value;
216 }
217 
218 int ImageEditor::discretizeSaturation(int x, int y, const QImage* originalImage) {
219  const QColor color(originalImage->pixel(x,y));
220  const int s = color.saturation();
221  int value = s * maxSaturation / 255;
222 
223  if (maxSaturation < value)
224  value = maxSaturation;
225 
226  return value;
227 }
228 
229 int ImageEditor::discretizeValue(int x, int y, const QImage* originalImage) {
230  const QColor color(originalImage->pixel(x,y));
231  const int v = color.value();
232  int value = v * maxValue / 255;
233 
234  if (maxValue < value)
235  value = maxValue;
236 
237  return value;
238 }
239 
240 int ImageEditor::discretizeIntensity(int x, int y, const QImage* originalImage) {
241  const QRgb color = originalImage->pixel(x,y);
242  const int r = qRed(color);
243  const int g = qGreen(color);
244  const int b = qBlue(color);
245 
246  const double intensity = gsl_hypot3(r, g, b);
247  int value = (int) (intensity * maxIntensity / colorScale + 0.5);
248 
249  if (maxIntensity < value)
250  value = maxIntensity;
251 
252  return value;
253 }
254 
255 int ImageEditor::discretizeForeground(int x, int y, const QColor background, const QImage* originalImage) {
256  const QRgb color = originalImage->pixel(x,y);
257  const int r = qRed(color);
258  const int g = qGreen(color);
259  const int b = qBlue(color);
260  const int rBg = background.red();
261  const int gBg = background.green();
262  const int bBg = background.blue();
263  const double distance = gsl_hypot3(r - rBg, g - gBg, b - bBg);
264  int value = (int) (distance * maxForeground / colorScale + 0.5);
265 
266  if (maxForeground < value)
267  value = maxForeground;
268 
269  return value;
270 }
271 
273  const QColor background, const QImage* originalImage) {
274  const QColor color(originalImage->pixel(x,y));
275 
276  // convert hue from 0 to 359, saturation from 0 to 255, value from 0 to 255
277  int value = 0;
278  switch (type) {
280  break;
282  const int r = color.red();
283  const int g = color.green();
284  const int b = color.blue();
285  const double intensity = gsl_hypot3(r, g, b);
286  value = (int) (intensity * maxIntensity / colorScale + 0.5);
287  if (maxIntensity < value)
288  value = maxIntensity;
289  break;
290  }
292  const int r = color.red();
293  const int g = color.green();
294  const int b = color.blue();
295  const int rBg = background.red();
296  const int gBg = background.green();
297  const int bBg = background.blue();
298  const double distance = gsl_hypot3(r - rBg, g - gBg, b - bBg);
299  value = (int) (distance * maxForeground / colorScale + 0.5);
300  if (maxForeground < value)
301  value = maxForeground;
302  break;
303  }
305  const int h = color.hue();
306  value = h * maxHue / 359;
307  if (value < 0)
308  value = 0;
309  if (maxHue < value)
310  value = maxHue;
311  break;
312  }
314  const int s = color.saturation();
315  value = s * maxSaturation / 255;
316  if (maxSaturation < value)
317  value = maxSaturation;
318  break;
319  }
321  const int v = color.value();
322  value = v * maxValue / 255;
323  if (maxValue < value)
324  value = maxValue;
325  break;
326  }
327  }
328 
329  return value;
330 }
331 
332 bool ImageEditor::pixelIsOn(int value, int low, int high) {
333  if (low < high)
334  return ((low <= value) && (value <= high));
335  else
336  return ((low <= value) || (value <= high));
337 }
338 
340  switch (type) {
342  break;
344  return pixelIsOn(value, settings.intensityThresholdLow, settings.intensityThresholdHigh);
346  return pixelIsOn(value, settings.foregroundThresholdLow, settings.foregroundThresholdHigh);
348  return pixelIsOn(value, settings.hueThresholdLow, settings.hueThresholdHigh);
350  return pixelIsOn(value, settings.saturationThresholdLow, settings.saturationThresholdHigh);
352  return pixelIsOn(value, settings.valueThresholdLow, settings.valueThresholdHigh);
353  }
354 
355  return false;
356 }
static std::array< QColor, colorsCount > colors
Definition: GuiTools.cpp:42
static const int maxSaturation
Definition: ImageEditor.cpp:45
static const QRgb white
Definition: ImageEditor.cpp:37
static const QRgb black
Definition: ImageEditor.cpp:38
static const int maxForeground
Definition: ImageEditor.cpp:43
static const int maxValue
Definition: ImageEditor.cpp:46
static const double colorScale
Definition: ImageEditor.cpp:39
static const int maxHue
Definition: ImageEditor.cpp:44
static const int maxIntensity
Definition: ImageEditor.cpp:42
QMutex mutex
Definition: ImageEditor.cpp:48
QImage * m_originalImage
Definition: ImageEditor.cpp:96
DiscretizeTask(int start, int end, QImage *plotImage, QImage *originalImage, const DatapickerImage::EditorSettings &settings, QColor background)
Definition: ImageEditor.cpp:52
QImage * m_plotImage
Definition: ImageEditor.cpp:95
DatapickerImage::EditorSettings m_settings
Definition: ImageEditor.cpp:97
QColor m_background
Definition: ImageEditor.cpp:98
void run() override
Definition: ImageEditor.cpp:61
static bool processedPixelIsOn(const QImage &, int, int)
static bool pixelIsOn(int, DatapickerImage::ColorAttributes, const DatapickerImage::EditorSettings &)
static int discretizeValueForeground(int, int, DatapickerImage::ColorAttributes, const QColor, const QImage *)
static int discretizeHue(int, int, const QImage *)
static QRgb findBackgroundColor(const QImage *)
static int discretizeSaturation(int, int, const QImage *)
static int discretizeValue(int, int, const QImage *)
static void discretize(QImage *, QImage *, const DatapickerImage::EditorSettings &, QColor)
static int colorAttributeMax(DatapickerImage::ColorAttributes)
static int discretizeForeground(int, int, const QColor, const QImage *)
static int discretizeIntensity(int, int, const QImage *)
static void uploadHistogram(int *, QImage *, QColor, DatapickerImage::ColorAttributes)
static bool colorCompare(QRgb color1, QRgb color2)