7 #include "CmdMediator.h"
8 #include "CmdSettingsColorFilter.h"
9 #include "ColorFilter.h"
10 #include "ColorFilterHistogram.h"
11 #include "ColorConstants.h"
12 #include "DlgFilterThread.h"
13 #include "DlgSettingsColorFilter.h"
14 #include "EngaugeAssert.h"
16 #include "MainWindow.h"
19 #include <QGraphicsLineItem>
20 #include <QGraphicsScene>
21 #include <QGridLayout>
26 #include <QRadioButton>
28 #include "ViewPreview.h"
29 #include "ViewProfile.h"
30 #include "ViewProfileDivider.h"
31 #include "ViewProfileScale.h"
33 const int MINIMUM_DIALOG_WIDTH_COLOR_FILTER = 640;
34 const int MINIMUM_HEIGHT = 500;
38 "DlgSettingsColorFilter",
40 m_scenePreview (nullptr),
41 m_viewPreview (nullptr),
42 m_filterThread (nullptr),
43 m_modelColorFilterBefore (nullptr),
44 m_modelColorFilterAfter (nullptr)
46 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::DlgSettingsColorFilter";
50 MINIMUM_DIALOG_WIDTH_COLOR_FILTER);
53 DlgSettingsColorFilter::~DlgSettingsColorFilter()
55 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::~DlgSettingsColorFilter";
57 delete m_filterThread;
60 void DlgSettingsColorFilter::createControls (QGridLayout *layout,
int &row)
62 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createControls";
64 QLabel *labelCurve =
new QLabel (QString (
"%1:").arg (tr (
"Curve Name")));
65 layout->addWidget (labelCurve, row++, 1);
67 m_cmbCurveName =
new QComboBox ();
68 m_cmbCurveName->setWhatsThis (tr (
"Name of the curve that is currently selected for editing"));
69 connect (m_cmbCurveName, SIGNAL (activated (
const QString &)),
this, SLOT (slotCurveName (
const QString &)));
70 layout->addWidget (m_cmbCurveName, row++, 1);
72 QLabel *labelProfile =
new QLabel (QString (
"%1:").arg (tr (
"Filter mode")));
73 layout->addWidget (labelProfile, row++, 1);
75 m_btnIntensity =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_INTENSITY));
76 m_btnIntensity->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Intensity parameter, "
77 "to hide unimportant information and emphasize important information.\n\n"
78 "The Intensity value of a pixel is computed from the red, green "
79 "and blue components as I = squareroot (R * R + G * G + B * B)"));
80 connect (m_btnIntensity, SIGNAL (released ()),
this, SLOT (slotIntensity ()));
81 layout->addWidget (m_btnIntensity, row++, 1);
83 m_btnForeground =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_FOREGROUND));
84 m_btnForeground->setWhatsThis (tr (
"Filter the original image into black and white pixels by isolating the foreground from the background, "
85 "to hide unimportant information and emphasize important information.\n\n"
86 "The background color is shown on the left side of the scale bar.\n\n"
87 "The distance of any color (R, G, B) from the background color (Rb, Gb, Bb) is computed as "
88 "F = squareroot ((R - Rb) * (R - Rb) + (G - Gb) * (G - Gb) + (B - Bb)). On the left end of the "
89 "scale, the foreground distance value is zero, and it increases linearly to the maximum on the far right."));
90 connect (m_btnForeground, SIGNAL (released ()),
this, SLOT (slotForeground ()));
91 layout->addWidget (m_btnForeground, row++, 1);
93 m_btnHue =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_HUE));
94 m_btnHue->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Hue component of the "
95 "Hue, Saturation and Value (HSV) color components, "
96 "to hide unimportant information and emphasize important information."));
97 connect (m_btnHue, SIGNAL (released ()),
this, SLOT (slotHue ()));
98 layout->addWidget (m_btnHue, row++, 1);
100 m_btnSaturation =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_SATURATION));
101 m_btnSaturation->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Saturation component of the "
102 "Hue, Saturation and Value (HSV) color components, "
103 "to hide unimportant information and emphasize important information."));
104 connect (m_btnSaturation, SIGNAL (released ()),
this, SLOT (slotSaturation ()));
105 layout->addWidget (m_btnSaturation, row++, 1);
107 m_btnValue =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_VALUE));
108 m_btnValue->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Value component of the "
109 "Hue, Saturation and Value (HSV) color components, "
110 "to hide unimportant information and emphasize important information.\n\n"
111 "The Value component is also called the Lightness."));
112 connect (m_btnValue, SIGNAL (released ()),
this, SLOT (slotValue ()));
113 layout->addWidget (m_btnValue, row++, 1);
120 void DlgSettingsColorFilter::createPreview (QGridLayout *layout,
int &row)
122 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createPreview";
124 QLabel *labelPreview =
new QLabel (tr (
"Preview"));
125 layout->addWidget (labelPreview, row++, 0, 1, 5);
127 m_scenePreview =
new QGraphicsScene (
this);
129 ViewPreview::VIEW_ASPECT_RATIO_VARIABLE,
131 m_viewPreview->setWhatsThis (tr (
"Preview window that shows how current settings affect the filtering of the original image."));
132 m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
133 m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
135 m_viewPreview->setRenderHint(QPainter::Antialiasing);
137 layout->addWidget (m_viewPreview, row++, 0, 1, 5);
140 void DlgSettingsColorFilter::createProfileAndScale (QGridLayout *layout,
int &row)
142 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createProfileAndScale";
144 const int MINIMUM_VIEW_PROFILE_WIDTH = 70;
146 QLabel *labelProfile =
new QLabel (tr (
"Filter Parameter Histogram Profile"));
147 layout->addWidget (labelProfile, row++, 3);
149 m_sceneProfile =
new QGraphicsScene;
150 m_sceneProfile->setSceneRect(0, 0, PROFILE_SCENE_WIDTH (), PROFILE_SCENE_HEIGHT ());
153 MINIMUM_VIEW_PROFILE_WIDTH);
154 m_viewProfile->setWhatsThis (tr (
"Histogram profile of the selected filter parameter. The two Dividers can be moved back and forth to adjust "
155 "the range of filter parameter values that will be included in the filtered image. The clear portion will "
156 "be included, and the shaded portion will be excluded."));
157 layout->addWidget (m_viewProfile, row, 3, PROFILE_HEIGHT_IN_ROWS (), 1);
158 row += PROFILE_HEIGHT_IN_ROWS ();
161 m_scale->setWhatsThis (tr (
"This read-only box displays a graphical representation of the horizontal axis in the histogram profile above."));
162 m_scale->setAutoFillBackground(
true);
163 layout->addWidget (m_scale, row++, 3, 1, 1);
168 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createSubPanel";
170 const int EMPTY_COLUMN_WIDTH = 40;
172 QWidget *subPanel =
new QWidget ();
173 QGridLayout *layout =
new QGridLayout (subPanel);
174 subPanel->setLayout (layout);
176 layout->setColumnStretch(0, 0);
177 layout->setColumnMinimumWidth(0, EMPTY_COLUMN_WIDTH);
178 layout->setColumnStretch(1, 0);
179 layout->setColumnMinimumWidth(1, 210);
180 layout->setColumnStretch(2, 0);
181 layout->setColumnMinimumWidth(2, 15);
182 layout->setColumnStretch(3, 1);
183 layout->setColumnMinimumWidth(4, EMPTY_COLUMN_WIDTH);
184 layout->setColumnStretch(4, 0);
186 int rowLeft = 0, rowRight = 0;
187 createControls (layout, rowLeft);
188 createProfileAndScale (layout, rowRight);
190 int row = qMax (rowLeft, rowRight);
191 createPreview (layout, row);
196 QRgb DlgSettingsColorFilter::createThread ()
198 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createThread";
206 if (m_filterThread ==
nullptr) {
211 m_filterThread->start();
214 return rgbBackground;
219 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::handleOk";
223 *m_modelColorFilterBefore,
224 *m_modelColorFilterAfter);
232 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::load";
237 delete m_modelColorFilterBefore;
238 delete m_modelColorFilterAfter;
245 m_cmbCurveName->clear ();
246 m_cmbCurveName->addItem (AXIS_CURVE_NAME);
248 QStringList::const_iterator itr;
249 for (itr = curveNames.begin (); itr != curveNames.end (); itr++) {
251 QString curveName = *itr;
252 m_cmbCurveName->addItem (curveName);
256 m_cmbCurveName->setCurrentText (
mainWindow().selectedGraphCurve());
262 void DlgSettingsColorFilter::loadForCurveName()
264 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::loadForCurveName";
267 QString curveName = m_cmbCurveName->currentText();
270 if (!curveName.isEmpty () && m_modelColorFilterAfter !=
nullptr) {
273 ColorFilterMode colorFilterMode = m_modelColorFilterAfter->
colorFilterMode(curveName);
274 m_btnIntensity->setChecked (colorFilterMode == COLOR_FILTER_MODE_INTENSITY);
275 m_btnForeground->setChecked (colorFilterMode == COLOR_FILTER_MODE_FOREGROUND);
276 m_btnHue->setChecked (colorFilterMode == COLOR_FILTER_MODE_HUE);
277 m_btnSaturation->setChecked (colorFilterMode == COLOR_FILTER_MODE_SATURATION);
278 m_btnValue->setChecked (colorFilterMode == COLOR_FILTER_MODE_VALUE);
280 m_scenePreview->clear();
282 m_scenePreview->addPixmap (QPixmap::fromImage (m_imagePreview));
284 QRgb rgbBackground = createThread ();
295 setMinimumHeight (MINIMUM_HEIGHT);
299 void DlgSettingsColorFilter::slotCurveName(
const QString & )
301 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotCurveName";
306 void DlgSettingsColorFilter::slotDividerHigh (
double xCenter)
308 m_modelColorFilterAfter->
setHigh (m_cmbCurveName->currentText(),
309 xCenter / double (PROFILE_SCENE_WIDTH ()));
313 void DlgSettingsColorFilter::slotDividerLow (
double xCenter)
315 m_modelColorFilterAfter->
setLow (m_cmbCurveName->currentText(),
316 xCenter / double (PROFILE_SCENE_WIDTH ()));
320 void DlgSettingsColorFilter::slotForeground ()
322 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotForeground";
325 COLOR_FILTER_MODE_FOREGROUND);
330 void DlgSettingsColorFilter::slotHue ()
332 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotHue";
335 COLOR_FILTER_MODE_HUE);
340 void DlgSettingsColorFilter::slotIntensity ()
342 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotIntensity";
345 COLOR_FILTER_MODE_INTENSITY);
350 void DlgSettingsColorFilter::slotSaturation ()
352 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotSaturation";
355 COLOR_FILTER_MODE_SATURATION);
368 for (
int xFrom = 0, xTo = xLeft; xFrom < image.width(); xFrom++, xTo++) {
369 for (
int y = 0; y < image.height (); y++) {
371 QColor pixel = image.pixel (xFrom, y);
372 m_imagePreview.setPixel (xTo, y, pixel.rgb());
377 QGraphicsItem *itemPixmap = m_scenePreview->items().at(0);
378 m_scenePreview->removeItem (itemPixmap);
382 m_scenePreview->addPixmap (QPixmap::fromImage (m_imagePreview));
385 void DlgSettingsColorFilter::slotValue ()
387 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotValue";
390 COLOR_FILTER_MODE_VALUE);
395 void DlgSettingsColorFilter::updateHistogram()
397 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::updateHistogram";
401 const double PEN_WIDTH = 0.0;
403 QString curveName = m_cmbCurveName->currentText();
405 m_sceneProfile->clear();
425 double logMaxBinCount = qLn (maxBinCount);
426 if (qAbs (logMaxBinCount) > 0) {
432 double count0 = 1.0 + histogramBins [bin - 1];
433 double y0 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count0) / logMaxBinCount);
438 double count1 = 1.0 + histogramBins [bin];
439 double y1 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count1) / logMaxBinCount);
441 QGraphicsLineItem *line =
new QGraphicsLineItem (x0, y0, x1, y1);
442 line->setPen (QPen (QBrush (Qt::black), PEN_WIDTH));
443 m_sceneProfile->addItem (line);
450 PROFILE_SCENE_WIDTH (),
451 PROFILE_SCENE_HEIGHT (),
452 qFloor (PROFILE_SCENE_HEIGHT () * 2.0 / 3.0),
456 PROFILE_SCENE_HEIGHT (),
457 PROFILE_SCENE_WIDTH (),
458 qFloor (PROFILE_SCENE_HEIGHT () / 3.0),
463 connect (m_dividerLow, SIGNAL (signalMovedLow (
double)), m_dividerHigh, SLOT (slotOtherMoved(
double)));
464 connect (m_dividerHigh, SIGNAL (signalMovedHigh (
double)), m_dividerLow, SLOT (slotOtherMoved(
double)));
467 connect (m_dividerLow, SIGNAL (signalMovedLow (
double)),
this, SLOT (slotDividerLow (
double)));
468 connect (m_dividerHigh, SIGNAL(signalMovedHigh (
double)),
this, SLOT (slotDividerHigh (
double)));
470 if (m_btnForeground->isChecked()) {
473 m_dividerLow->
setX (m_modelColorFilterAfter->
foregroundLow(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
474 m_dividerHigh->
setX (m_modelColorFilterAfter->
foregroundHigh(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
476 }
else if (m_btnIntensity->isChecked()) {
479 m_dividerLow->
setX (m_modelColorFilterAfter->
intensityLow(curveName), INTENSITY_MIN, INTENSITY_MAX);
480 m_dividerHigh->
setX (m_modelColorFilterAfter->
intensityHigh(curveName), INTENSITY_MIN, INTENSITY_MAX);
482 }
else if (m_btnHue->isChecked()) {
485 m_dividerLow->
setX (m_modelColorFilterAfter->
hueLow(curveName), HUE_MIN, HUE_MAX);
486 m_dividerHigh->
setX (m_modelColorFilterAfter->
hueHigh(curveName), HUE_MIN, HUE_MAX);
488 }
else if (m_btnSaturation->isChecked()) {
491 m_dividerLow->
setX (m_modelColorFilterAfter->
saturationLow(curveName), SATURATION_MIN, SATURATION_MAX);
492 m_dividerHigh->
setX (m_modelColorFilterAfter->
saturationHigh(curveName), SATURATION_MIN, SATURATION_MAX);
494 }
else if (m_btnValue->isChecked()) {
497 m_dividerLow->
setX (m_modelColorFilterAfter->
valueLow(curveName), VALUE_MIN, VALUE_MAX);
498 m_dividerHigh->
setX (m_modelColorFilterAfter->
valueHigh(curveName), VALUE_MIN, VALUE_MAX);
502 ENGAUGE_ASSERT (
false);
506 delete[] histogramBins;
509 void DlgSettingsColorFilter::updatePreview ()
511 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettings::updatePreview";
516 QString curveName = m_cmbCurveName->currentText();
518 m_modelColorFilterAfter->
low(curveName),
519 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.
DocumentModelColorFilter modelColorFilter() const
Get method for DocumentModelColorFilter.
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().
void finishPanel(QWidget *subPanel, int minimumWidth=MINIMUM_DIALOG_WIDTH, int minimumHeightOrZero=0)
Add Ok and Cancel buttons to subpanel to get the whole dialog.
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 setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
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.
virtual void createOptionalSaveDefault(QHBoxLayout *layout)
Let subclass define an optional Save As Default button.
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.