1 #include "CmdMediator.h"
2 #include "CmdSettingsColorFilter.h"
3 #include "ColorFilter.h"
4 #include "ColorFilterHistogram.h"
5 #include "ColorConstants.h"
6 #include "DlgFilterThread.h"
7 #include "DlgSettingsColorFilter.h"
8 #include "EngaugeAssert.h"
10 #include "MainWindow.h"
13 #include <QGraphicsLineItem>
14 #include <QGraphicsScene>
15 #include <QGridLayout>
20 #include <QRadioButton>
22 #include "ViewPreview.h"
23 #include "ViewProfile.h"
24 #include "ViewProfileDivider.h"
25 #include "ViewProfileScale.h"
29 "DlgSettingsColorFilter",
34 m_modelColorFilterBefore (0),
35 m_modelColorFilterAfter (0)
37 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::DlgSettingsColorFilter";
43 DlgSettingsColorFilter::~DlgSettingsColorFilter()
45 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::~DlgSettingsColorFilter";
48 void DlgSettingsColorFilter::createControls (QGridLayout *layout,
int &row)
50 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createControls";
52 QLabel *labelCurve =
new QLabel (
"Curve Name:");
53 layout->addWidget (labelCurve, row++, 1);
55 m_cmbCurveName =
new QComboBox ();
56 m_cmbCurveName->setWhatsThis (tr (
"Name of the curve that is currently selected for editing"));
57 connect (m_cmbCurveName, SIGNAL (activated (
const QString &)),
this, SLOT (slotCurveName (
const QString &)));
58 layout->addWidget (m_cmbCurveName, row++, 1);
60 QLabel *labelProfile =
new QLabel (
"Filter mode:");
61 layout->addWidget (labelProfile, row++, 1);
63 m_btnIntensity =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_INTENSITY));
64 m_btnIntensity->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Intensity parameter, "
65 "to hide unimportant information and emphasize important information.\n\n"
66 "The Intensity value of a pixel is computed from the red, green "
67 "and blue components as I = squareroot (R * R + G * G + B * B)"));
68 connect (m_btnIntensity, SIGNAL (released ()),
this, SLOT (slotIntensity ()));
69 layout->addWidget (m_btnIntensity, row++, 1);
71 m_btnForeground =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_FOREGROUND));
72 m_btnForeground->setWhatsThis (tr (
"Filter the original image into black and white pixels by isolating the foreground from the background, "
73 "to hide unimportant information and emphasize important information.\n\n"
74 "The background color is shown on the left side of the scale bar.\n\n"
75 "The distance of any color (R, G, B) from the background color (Rb, Gb, Bb) is computed as "
76 "F = squareroot ((R - Rb) * (R - Rb) + (G - Gb) * (G - Gb) + (B - Bb)). On the left end of the "
77 "scale, the foreground distance value is zero, and it increases linearly to the maximum on the far right."));
78 connect (m_btnForeground, SIGNAL (released ()),
this, SLOT (slotForeground ()));
79 layout->addWidget (m_btnForeground, row++, 1);
81 m_btnHue =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_HUE));
82 m_btnHue->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Hue component of the "
83 "Hue, Saturation and Value (HSV) color components, "
84 "to hide unimportant information and emphasize important information."));
85 connect (m_btnHue, SIGNAL (released ()),
this, SLOT (slotHue ()));
86 layout->addWidget (m_btnHue, row++, 1);
88 m_btnSaturation =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_SATURATION));
89 m_btnSaturation->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Saturation component of the "
90 "Hue, Saturation and Value (HSV) color components, "
91 "to hide unimportant information and emphasize important information."));
92 connect (m_btnSaturation, SIGNAL (released ()),
this, SLOT (slotSaturation ()));
93 layout->addWidget (m_btnSaturation, row++, 1);
95 m_btnValue =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_VALUE));
96 m_btnValue->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Value component of the "
97 "Hue, Saturation and Value (HSV) color components, "
98 "to hide unimportant information and emphasize important information.\n\n"
99 "The Value component is also called the Lightness."));
100 connect (m_btnValue, SIGNAL (released ()),
this, SLOT (slotValue ()));
101 layout->addWidget (m_btnValue, row++, 1);
104 void DlgSettingsColorFilter::createPreview (QGridLayout *layout,
int &row)
106 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createPreview";
108 QLabel *labelPreview =
new QLabel (
"Preview");
109 layout->addWidget (labelPreview, row++, 0, 1, 5);
111 m_scenePreview =
new QGraphicsScene (
this);
112 m_viewPreview =
new ViewPreview (m_scenePreview,
this);
113 m_viewPreview->setWhatsThis (tr (
"Preview window that shows how current settings affect the filtering of the original image."));
114 m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
115 m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
117 m_viewPreview->setRenderHint(QPainter::Antialiasing);
119 layout->addWidget (m_viewPreview, row++, 0, 1, 5);
122 void DlgSettingsColorFilter::createProfileAndScale (QGridLayout *layout,
int &row)
124 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createProfileAndScale";
126 const int MINIMUM_VIEW_PROFILE_WIDTH = 70;
128 QLabel *labelProfile =
new QLabel (
"Filter Parameter Histogram Profile");
129 layout->addWidget (labelProfile, row++, 3);
131 m_sceneProfile =
new QGraphicsScene;
132 m_sceneProfile->setSceneRect(0, 0, PROFILE_SCENE_WIDTH (), PROFILE_SCENE_HEIGHT ());
135 MINIMUM_VIEW_PROFILE_WIDTH);
136 m_viewProfile->setWhatsThis (tr (
"Histogram profile of the selected filter parameter. The two Dividers can be moved back and forth to adjust "
137 "the range of filter parameter values that will be included in the filtered image. The clear portion will "
138 "be included, and the shaded portion will be excluded."));
139 layout->addWidget (m_viewProfile, row, 3, PROFILE_HEIGHT_IN_ROWS (), 1);
140 row += PROFILE_HEIGHT_IN_ROWS ();
143 m_scale->setWhatsThis (tr (
"This read-only box displays a graphical representation of the horizontal axis in the histogram profile above."));
144 m_scale->setAutoFillBackground(
true);
145 layout->addWidget (m_scale, row++, 3, 1, 1);
150 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createSubPanel";
152 const int EMPTY_COLUMN_WIDTH = 40;
154 QWidget *subPanel =
new QWidget ();
155 QGridLayout *layout =
new QGridLayout (subPanel);
156 subPanel->setLayout (layout);
158 layout->setColumnStretch(0, 0);
159 layout->setColumnMinimumWidth(0, EMPTY_COLUMN_WIDTH);
160 layout->setColumnStretch(1, 0);
161 layout->setColumnMinimumWidth(1, 210);
162 layout->setColumnStretch(2, 0);
163 layout->setColumnMinimumWidth(2, 15);
164 layout->setColumnStretch(3, 1);
165 layout->setColumnMinimumWidth(4, EMPTY_COLUMN_WIDTH);
166 layout->setColumnStretch(4, 0);
168 int rowLeft = 0, rowRight = 0;
169 createControls (layout, rowLeft);
170 createProfileAndScale (layout, rowRight);
172 int row = qMax (rowLeft, rowRight);
173 createPreview (layout, row);
178 QRgb DlgSettingsColorFilter::createThread ()
180 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createThread";
188 if (m_filterThread == 0) {
193 m_filterThread->start();
196 return rgbBackground;
201 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::handleOk";
205 *m_modelColorFilterBefore,
206 *m_modelColorFilterAfter);
214 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::load";
219 if (m_modelColorFilterBefore != 0) {
220 delete m_modelColorFilterBefore;
222 if (m_modelColorFilterAfter != 0) {
223 delete m_modelColorFilterAfter;
231 m_cmbCurveName->clear ();
232 m_cmbCurveName->addItem (AXIS_CURVE_NAME);
234 QStringList::const_iterator itr;
235 for (itr = curveNames.begin (); itr != curveNames.end (); itr++) {
237 QString curveName = *itr;
238 m_cmbCurveName->addItem (curveName);
242 m_cmbCurveName->setCurrentText (
mainWindow().selectedGraphCurve());
248 void DlgSettingsColorFilter::loadForCurveName()
250 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::loadForCurveName";
253 QString curveName = m_cmbCurveName->currentText();
256 if (!curveName.isEmpty () && m_modelColorFilterAfter != 0) {
259 ColorFilterMode colorFilterMode = m_modelColorFilterAfter->
colorFilterMode(curveName);
260 m_btnIntensity->setChecked (colorFilterMode == COLOR_FILTER_MODE_INTENSITY);
261 m_btnForeground->setChecked (colorFilterMode == COLOR_FILTER_MODE_FOREGROUND);
262 m_btnHue->setChecked (colorFilterMode == COLOR_FILTER_MODE_HUE);
263 m_btnSaturation->setChecked (colorFilterMode == COLOR_FILTER_MODE_SATURATION);
264 m_btnValue->setChecked (colorFilterMode == COLOR_FILTER_MODE_VALUE);
266 m_scenePreview->clear();
268 m_scenePreview->addPixmap (QPixmap::fromImage (m_imagePreview));
270 QRgb rgbBackground = createThread ();
278 void DlgSettingsColorFilter::slotCurveName(
const QString & )
280 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotCurveName";
285 void DlgSettingsColorFilter::slotDividerHigh (
double xCenter)
287 m_modelColorFilterAfter->
setHigh (m_cmbCurveName->currentText(),
288 xCenter / (double) PROFILE_SCENE_WIDTH ());
292 void DlgSettingsColorFilter::slotDividerLow (
double xCenter)
294 m_modelColorFilterAfter->
setLow (m_cmbCurveName->currentText(),
295 xCenter / (double) PROFILE_SCENE_WIDTH ());
299 void DlgSettingsColorFilter::slotForeground ()
301 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotForeground";
304 COLOR_FILTER_MODE_FOREGROUND);
309 void DlgSettingsColorFilter::slotHue ()
311 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotHue";
314 COLOR_FILTER_MODE_HUE);
319 void DlgSettingsColorFilter::slotIntensity ()
321 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotIntensity";
324 COLOR_FILTER_MODE_INTENSITY);
329 void DlgSettingsColorFilter::slotSaturation ()
331 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotSaturation";
334 COLOR_FILTER_MODE_SATURATION);
347 for (
int xFrom = 0, xTo = xLeft; xFrom < image.width(); xFrom++, xTo++) {
348 for (
int y = 0; y < image.height (); y++) {
350 QColor pixel = image.pixel (xFrom, y);
351 m_imagePreview.setPixel (xTo, y, pixel.rgb());
356 QGraphicsItem *itemPixmap = m_scenePreview->items().at(0);
357 m_scenePreview->removeItem (itemPixmap);
361 m_scenePreview->addPixmap (QPixmap::fromImage (m_imagePreview));
364 void DlgSettingsColorFilter::slotValue ()
366 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotValue";
369 COLOR_FILTER_MODE_VALUE);
374 void DlgSettingsColorFilter::updateHistogram()
376 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::updateHistogram";
380 const double PEN_WIDTH = 0.0;
382 QString curveName = m_cmbCurveName->currentText();
384 m_sceneProfile->clear();
404 double logMaxBinCount = qLn (maxBinCount);
410 double count0 = 1.0 + histogramBins [bin - 1];
411 double y0 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count0) / logMaxBinCount);
416 double count1 = 1.0 + histogramBins [bin];
417 double y1 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count1) / logMaxBinCount);
419 QGraphicsLineItem *line =
new QGraphicsLineItem (x0, y0, x1, y1);
420 line->setPen (QPen (QBrush (Qt::black), PEN_WIDTH));
421 m_sceneProfile->addItem (line);
427 PROFILE_SCENE_WIDTH (),
428 PROFILE_SCENE_HEIGHT (),
429 PROFILE_SCENE_HEIGHT () * 2.0 / 3.0,
433 PROFILE_SCENE_HEIGHT (),
434 PROFILE_SCENE_WIDTH (),
435 PROFILE_SCENE_HEIGHT () / 3.0,
440 connect (m_dividerLow, SIGNAL (signalMovedLow (
double)), m_dividerHigh, SLOT (slotOtherMoved(
double)));
441 connect (m_dividerHigh, SIGNAL (signalMovedHigh (
double)), m_dividerLow, SLOT (slotOtherMoved(
double)));
444 connect (m_dividerLow, SIGNAL (signalMovedLow (
double)),
this, SLOT (slotDividerLow (
double)));
445 connect (m_dividerHigh, SIGNAL(signalMovedHigh (
double)),
this, SLOT (slotDividerHigh (
double)));
447 if (m_btnForeground->isChecked()) {
450 m_dividerLow->
setX (m_modelColorFilterAfter->
foregroundLow(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
451 m_dividerHigh->
setX (m_modelColorFilterAfter->
foregroundHigh(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
453 }
else if (m_btnIntensity->isChecked()) {
456 m_dividerLow->
setX (m_modelColorFilterAfter->
intensityLow(curveName), INTENSITY_MIN, INTENSITY_MAX);
457 m_dividerHigh->
setX (m_modelColorFilterAfter->
intensityHigh(curveName), INTENSITY_MIN, INTENSITY_MAX);
459 }
else if (m_btnHue->isChecked()) {
462 m_dividerLow->
setX (m_modelColorFilterAfter->
hueLow(curveName), HUE_MIN, HUE_MAX);
463 m_dividerHigh->
setX (m_modelColorFilterAfter->
hueHigh(curveName), HUE_MIN, HUE_MAX);
465 }
else if (m_btnSaturation->isChecked()) {
468 m_dividerLow->
setX (m_modelColorFilterAfter->
saturationLow(curveName), SATURATION_MIN, SATURATION_MAX);
469 m_dividerHigh->
setX (m_modelColorFilterAfter->
saturationHigh(curveName), SATURATION_MIN, SATURATION_MAX);
471 }
else if (m_btnValue->isChecked()) {
474 m_dividerLow->
setX (m_modelColorFilterAfter->
valueLow(curveName), VALUE_MIN, VALUE_MAX);
475 m_dividerHigh->
setX (m_modelColorFilterAfter->
valueHigh(curveName), VALUE_MIN, VALUE_MAX);
479 ENGAUGE_ASSERT (
false);
484 void DlgSettingsColorFilter::updatePreview ()
486 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettings::updatePreview";
491 QString curveName = m_cmbCurveName->currentText();
493 m_modelColorFilterAfter->
low(curveName),
494 m_modelColorFilterAfter->
high(curveName));
void setBackgroundColor(QRgb rgbBackground)
Save the background color for foreground calculations.
int valueHigh(const QString &curveName) const
Get method for value high.
void generate(const ColorFilter &filter, double histogramBins[], ColorFilterMode colorFilterMode, const QImage &image, int &maxBinCount) const
Generate the histogram.
void setColorFilterMode(const QString &curveName, ColorFilterMode colorFilterMode)
Set method for filter mode.
int saturationLow(const QString &curveName) const
Get method for saturation lower bound.
void setX(double x, double xLow, double xHigh)
Set the position by specifying the new x coordinate.
void setCmdMediator(CmdMediator &cmdMediator)
Store CmdMediator for easy access by the leaf class.
int valueLow(const QString &curveName) const
Get method for value low.
QPixmap pixmap() const
Return the image that is being digitized.
Class for filtering image to remove unimportant information.
void slotTransferPiece(int xLeft, QImage image)
Receive processed piece of preview image, to be inserted at xLeft to xLeft+pixmap.width().
virtual void handleOk()
Process slotOk.
int foregroundLow(const QString &curveName) const
Get method for foreground lower bound.
int intensityLow(const QString &curveName) const
Get method for intensity lower bound.
void signalApplyFilter(ColorFilterMode colorFilterMode, double low, double high)
Send filter parameters to DlgFilterThread and DlgFilterWorker for processing.
double low(const QString &curveName) const
Low value of foreground, hue, intensity, saturation or value according to current filter mode normali...
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void setHigh(const QString &curveName, double s0To1)
Set the high value for the current filter mode.
Class that modifies QGraphicsView to automatically expand/shrink the view to fit the window...
Model for DlgSettingsColorFilter and CmdSettingsColorFilter.
int hueLow(const QString &curveName) const
Get method for hue lower bound.
Linear horizontal scale, with the spectrum reflecting the active filter parameter.
double high(const QString &curveName) const
High value of foreground, hue, intensity, saturation or value according to current filter mode...
QRgb marginColor(const QImage *image) const
Identify the margin color of the image, which is defined as the most common color in the four margins...
int hueHigh(const QString &curveName) const
Get method for hue higher bound.
void setColorFilterMode(ColorFilterMode colorFilterMode)
Change the gradient type.
int foregroundHigh(const QString &curveName) const
Get method for foreground higher bound.
Divider that can be dragged, in a dialog QGraphicsView.
ColorFilterMode colorFilterMode(const QString &curveName) const
Get method for filter mode.
Class for processing new filter settings. This is based on http://blog.debao.me/2013/08/how-to-use-qt...
void setLow(const QString &curveName, double s0To1)
Set the low value for the current filter mode.
Command for DlgSettingsColorFilter.
void finishPanel(QWidget *subPanel)
Add Ok and Cancel buttons to subpanel to get the whole dialog.
virtual QWidget * createSubPanel()
Create dialog-specific panel to which base class will add Ok and Cancel buttons.
static int MINIMUM_PREVIEW_HEIGHT
Dialog layout constant that guarantees preview has sufficent room.
void enableOk(bool enable)
Let leaf subclass control the Ok button.
DlgSettingsColorFilter(MainWindow &mainWindow)
Single constructor.
Abstract base class for all Settings dialogs.
int intensityHigh(const QString &curveName) const
Get method for intensity higher bound.
Class that generates a histogram according to the current filter.
Class that modifies QGraphicsView to present a two-dimensional profile, with movable dividers for sel...
static int HISTOGRAM_BINS()
Number of histogram bins.
MainWindow & mainWindow()
Get method for MainWindow.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
int saturationHigh(const QString &curveName) const
Get method for saturation higher bound.
CmdMediator & cmdMediator()
Provide access to Document information wrapped inside CmdMediator.