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;
37 "DlgSettingsColorFilter",
42 m_modelColorFilterBefore (0),
43 m_modelColorFilterAfter (0)
45 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::DlgSettingsColorFilter";
49 MINIMUM_DIALOG_WIDTH_COLOR_FILTER);
52 DlgSettingsColorFilter::~DlgSettingsColorFilter()
54 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::~DlgSettingsColorFilter";
57 void DlgSettingsColorFilter::createControls (QGridLayout *layout,
int &row)
59 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createControls";
61 QLabel *labelCurve =
new QLabel (tr (
"Curve Name:"));
62 layout->addWidget (labelCurve, row++, 1);
64 m_cmbCurveName =
new QComboBox ();
65 m_cmbCurveName->setWhatsThis (tr (
"Name of the curve that is currently selected for editing"));
66 connect (m_cmbCurveName, SIGNAL (activated (
const QString &)),
this, SLOT (slotCurveName (
const QString &)));
67 layout->addWidget (m_cmbCurveName, row++, 1);
69 QLabel *labelProfile =
new QLabel (tr (
"Filter mode:"));
70 layout->addWidget (labelProfile, row++, 1);
72 m_btnIntensity =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_INTENSITY));
73 m_btnIntensity->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Intensity parameter, "
74 "to hide unimportant information and emphasize important information.\n\n"
75 "The Intensity value of a pixel is computed from the red, green "
76 "and blue components as I = squareroot (R * R + G * G + B * B)"));
77 connect (m_btnIntensity, SIGNAL (released ()),
this, SLOT (slotIntensity ()));
78 layout->addWidget (m_btnIntensity, row++, 1);
80 m_btnForeground =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_FOREGROUND));
81 m_btnForeground->setWhatsThis (tr (
"Filter the original image into black and white pixels by isolating the foreground from the background, "
82 "to hide unimportant information and emphasize important information.\n\n"
83 "The background color is shown on the left side of the scale bar.\n\n"
84 "The distance of any color (R, G, B) from the background color (Rb, Gb, Bb) is computed as "
85 "F = squareroot ((R - Rb) * (R - Rb) + (G - Gb) * (G - Gb) + (B - Bb)). On the left end of the "
86 "scale, the foreground distance value is zero, and it increases linearly to the maximum on the far right."));
87 connect (m_btnForeground, SIGNAL (released ()),
this, SLOT (slotForeground ()));
88 layout->addWidget (m_btnForeground, row++, 1);
90 m_btnHue =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_HUE));
91 m_btnHue->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Hue component of the "
92 "Hue, Saturation and Value (HSV) color components, "
93 "to hide unimportant information and emphasize important information."));
94 connect (m_btnHue, SIGNAL (released ()),
this, SLOT (slotHue ()));
95 layout->addWidget (m_btnHue, row++, 1);
97 m_btnSaturation =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_SATURATION));
98 m_btnSaturation->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Saturation component of the "
99 "Hue, Saturation and Value (HSV) color components, "
100 "to hide unimportant information and emphasize important information."));
101 connect (m_btnSaturation, SIGNAL (released ()),
this, SLOT (slotSaturation ()));
102 layout->addWidget (m_btnSaturation, row++, 1);
104 m_btnValue =
new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_VALUE));
105 m_btnValue->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Value component of the "
106 "Hue, Saturation and Value (HSV) color components, "
107 "to hide unimportant information and emphasize important information.\n\n"
108 "The Value component is also called the Lightness."));
109 connect (m_btnValue, SIGNAL (released ()),
this, SLOT (slotValue ()));
110 layout->addWidget (m_btnValue, row++, 1);
117 void DlgSettingsColorFilter::createPreview (QGridLayout *layout,
int &row)
119 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createPreview";
121 QLabel *labelPreview =
new QLabel (tr (
"Preview"));
122 layout->addWidget (labelPreview, row++, 0, 1, 5);
124 m_scenePreview =
new QGraphicsScene (
this);
126 ViewPreview::VIEW_ASPECT_RATIO_VARIABLE,
128 m_viewPreview->setWhatsThis (tr (
"Preview window that shows how current settings affect the filtering of the original image."));
129 m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
130 m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
132 m_viewPreview->setRenderHint(QPainter::Antialiasing);
134 layout->addWidget (m_viewPreview, row++, 0, 1, 5);
137 void DlgSettingsColorFilter::createProfileAndScale (QGridLayout *layout,
int &row)
139 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createProfileAndScale";
141 const int MINIMUM_VIEW_PROFILE_WIDTH = 70;
143 QLabel *labelProfile =
new QLabel (tr (
"Filter Parameter Histogram Profile"));
144 layout->addWidget (labelProfile, row++, 3);
146 m_sceneProfile =
new QGraphicsScene;
147 m_sceneProfile->setSceneRect(0, 0, PROFILE_SCENE_WIDTH (), PROFILE_SCENE_HEIGHT ());
150 MINIMUM_VIEW_PROFILE_WIDTH);
151 m_viewProfile->setWhatsThis (tr (
"Histogram profile of the selected filter parameter. The two Dividers can be moved back and forth to adjust "
152 "the range of filter parameter values that will be included in the filtered image. The clear portion will "
153 "be included, and the shaded portion will be excluded."));
154 layout->addWidget (m_viewProfile, row, 3, PROFILE_HEIGHT_IN_ROWS (), 1);
155 row += PROFILE_HEIGHT_IN_ROWS ();
158 m_scale->setWhatsThis (tr (
"This read-only box displays a graphical representation of the horizontal axis in the histogram profile above."));
159 m_scale->setAutoFillBackground(
true);
160 layout->addWidget (m_scale, row++, 3, 1, 1);
165 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createSubPanel";
167 const int EMPTY_COLUMN_WIDTH = 40;
169 QWidget *subPanel =
new QWidget ();
170 QGridLayout *layout =
new QGridLayout (subPanel);
171 subPanel->setLayout (layout);
173 layout->setColumnStretch(0, 0);
174 layout->setColumnMinimumWidth(0, EMPTY_COLUMN_WIDTH);
175 layout->setColumnStretch(1, 0);
176 layout->setColumnMinimumWidth(1, 210);
177 layout->setColumnStretch(2, 0);
178 layout->setColumnMinimumWidth(2, 15);
179 layout->setColumnStretch(3, 1);
180 layout->setColumnMinimumWidth(4, EMPTY_COLUMN_WIDTH);
181 layout->setColumnStretch(4, 0);
183 int rowLeft = 0, rowRight = 0;
184 createControls (layout, rowLeft);
185 createProfileAndScale (layout, rowRight);
187 int row = qMax (rowLeft, rowRight);
188 createPreview (layout, row);
193 QRgb DlgSettingsColorFilter::createThread ()
195 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createThread";
203 if (m_filterThread == 0) {
208 m_filterThread->start();
211 return rgbBackground;
216 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::handleOk";
220 *m_modelColorFilterBefore,
221 *m_modelColorFilterAfter);
229 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::load";
234 if (m_modelColorFilterBefore != 0) {
235 delete m_modelColorFilterBefore;
237 if (m_modelColorFilterAfter != 0) {
238 delete m_modelColorFilterAfter;
246 m_cmbCurveName->clear ();
247 m_cmbCurveName->addItem (AXIS_CURVE_NAME);
249 QStringList::const_iterator itr;
250 for (itr = curveNames.begin (); itr != curveNames.end (); itr++) {
252 QString curveName = *itr;
253 m_cmbCurveName->addItem (curveName);
257 m_cmbCurveName->setCurrentText (
mainWindow().selectedGraphCurve());
263 void DlgSettingsColorFilter::loadForCurveName()
265 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::loadForCurveName";
268 QString curveName = m_cmbCurveName->currentText();
271 if (!curveName.isEmpty () && m_modelColorFilterAfter != 0) {
274 ColorFilterMode colorFilterMode = m_modelColorFilterAfter->
colorFilterMode(curveName);
275 m_btnIntensity->setChecked (colorFilterMode == COLOR_FILTER_MODE_INTENSITY);
276 m_btnForeground->setChecked (colorFilterMode == COLOR_FILTER_MODE_FOREGROUND);
277 m_btnHue->setChecked (colorFilterMode == COLOR_FILTER_MODE_HUE);
278 m_btnSaturation->setChecked (colorFilterMode == COLOR_FILTER_MODE_SATURATION);
279 m_btnValue->setChecked (colorFilterMode == COLOR_FILTER_MODE_VALUE);
281 m_scenePreview->clear();
283 m_scenePreview->addPixmap (QPixmap::fromImage (m_imagePreview));
285 QRgb rgbBackground = createThread ();
293 void DlgSettingsColorFilter::slotCurveName(
const QString & )
295 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotCurveName";
300 void DlgSettingsColorFilter::slotDividerHigh (
double xCenter)
302 m_modelColorFilterAfter->
setHigh (m_cmbCurveName->currentText(),
303 xCenter / (double) PROFILE_SCENE_WIDTH ());
307 void DlgSettingsColorFilter::slotDividerLow (
double xCenter)
309 m_modelColorFilterAfter->
setLow (m_cmbCurveName->currentText(),
310 xCenter / (double) PROFILE_SCENE_WIDTH ());
314 void DlgSettingsColorFilter::slotForeground ()
316 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotForeground";
319 COLOR_FILTER_MODE_FOREGROUND);
324 void DlgSettingsColorFilter::slotHue ()
326 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotHue";
329 COLOR_FILTER_MODE_HUE);
334 void DlgSettingsColorFilter::slotIntensity ()
336 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotIntensity";
339 COLOR_FILTER_MODE_INTENSITY);
344 void DlgSettingsColorFilter::slotSaturation ()
346 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotSaturation";
349 COLOR_FILTER_MODE_SATURATION);
362 for (
int xFrom = 0, xTo = xLeft; xFrom < image.width(); xFrom++, xTo++) {
363 for (
int y = 0; y < image.height (); y++) {
365 QColor pixel = image.pixel (xFrom, y);
366 m_imagePreview.setPixel (xTo, y, pixel.rgb());
371 QGraphicsItem *itemPixmap = m_scenePreview->items().at(0);
372 m_scenePreview->removeItem (itemPixmap);
376 m_scenePreview->addPixmap (QPixmap::fromImage (m_imagePreview));
379 void DlgSettingsColorFilter::slotValue ()
381 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotValue";
384 COLOR_FILTER_MODE_VALUE);
389 void DlgSettingsColorFilter::updateHistogram()
391 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::updateHistogram";
395 const double PEN_WIDTH = 0.0;
397 QString curveName = m_cmbCurveName->currentText();
399 m_sceneProfile->clear();
419 double logMaxBinCount = qLn (maxBinCount);
425 double count0 = 1.0 + histogramBins [bin - 1];
426 double y0 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count0) / logMaxBinCount);
431 double count1 = 1.0 + histogramBins [bin];
432 double y1 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count1) / logMaxBinCount);
434 QGraphicsLineItem *line =
new QGraphicsLineItem (x0, y0, x1, y1);
435 line->setPen (QPen (QBrush (Qt::black), PEN_WIDTH));
436 m_sceneProfile->addItem (line);
442 PROFILE_SCENE_WIDTH (),
443 PROFILE_SCENE_HEIGHT (),
444 PROFILE_SCENE_HEIGHT () * 2.0 / 3.0,
448 PROFILE_SCENE_HEIGHT (),
449 PROFILE_SCENE_WIDTH (),
450 PROFILE_SCENE_HEIGHT () / 3.0,
455 connect (m_dividerLow, SIGNAL (signalMovedLow (
double)), m_dividerHigh, SLOT (slotOtherMoved(
double)));
456 connect (m_dividerHigh, SIGNAL (signalMovedHigh (
double)), m_dividerLow, SLOT (slotOtherMoved(
double)));
459 connect (m_dividerLow, SIGNAL (signalMovedLow (
double)),
this, SLOT (slotDividerLow (
double)));
460 connect (m_dividerHigh, SIGNAL(signalMovedHigh (
double)),
this, SLOT (slotDividerHigh (
double)));
462 if (m_btnForeground->isChecked()) {
465 m_dividerLow->
setX (m_modelColorFilterAfter->
foregroundLow(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
466 m_dividerHigh->
setX (m_modelColorFilterAfter->
foregroundHigh(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
468 }
else if (m_btnIntensity->isChecked()) {
471 m_dividerLow->
setX (m_modelColorFilterAfter->
intensityLow(curveName), INTENSITY_MIN, INTENSITY_MAX);
472 m_dividerHigh->
setX (m_modelColorFilterAfter->
intensityHigh(curveName), INTENSITY_MIN, INTENSITY_MAX);
474 }
else if (m_btnHue->isChecked()) {
477 m_dividerLow->
setX (m_modelColorFilterAfter->
hueLow(curveName), HUE_MIN, HUE_MAX);
478 m_dividerHigh->
setX (m_modelColorFilterAfter->
hueHigh(curveName), HUE_MIN, HUE_MAX);
480 }
else if (m_btnSaturation->isChecked()) {
483 m_dividerLow->
setX (m_modelColorFilterAfter->
saturationLow(curveName), SATURATION_MIN, SATURATION_MAX);
484 m_dividerHigh->
setX (m_modelColorFilterAfter->
saturationHigh(curveName), SATURATION_MIN, SATURATION_MAX);
486 }
else if (m_btnValue->isChecked()) {
489 m_dividerLow->
setX (m_modelColorFilterAfter->
valueLow(curveName), VALUE_MIN, VALUE_MAX);
490 m_dividerHigh->
setX (m_modelColorFilterAfter->
valueHigh(curveName), VALUE_MIN, VALUE_MAX);
494 ENGAUGE_ASSERT (
false);
498 free (histogramBins);
501 void DlgSettingsColorFilter::updatePreview ()
503 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettings::updatePreview";
508 QString curveName = m_cmbCurveName->currentText();
510 m_modelColorFilterAfter->
low(curveName),
511 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().
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.
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.
void finishPanel(QWidget *subPanel, int minimumWidth=MINIMUM_DIALOG_WIDTH)
Add Ok and Cancel buttons to subpanel to get the whole dialog.
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.