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);
113 ViewPreview::VIEW_ASPECT_RATIO_VARIABLE,
115 m_viewPreview->setWhatsThis (tr (
"Preview window that shows how current settings affect the filtering of the original image."));
116 m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
117 m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
119 m_viewPreview->setRenderHint(QPainter::Antialiasing);
121 layout->addWidget (m_viewPreview, row++, 0, 1, 5);
124 void DlgSettingsColorFilter::createProfileAndScale (QGridLayout *layout,
int &row)
126 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createProfileAndScale";
128 const int MINIMUM_VIEW_PROFILE_WIDTH = 70;
130 QLabel *labelProfile =
new QLabel (
"Filter Parameter Histogram Profile");
131 layout->addWidget (labelProfile, row++, 3);
133 m_sceneProfile =
new QGraphicsScene;
134 m_sceneProfile->setSceneRect(0, 0, PROFILE_SCENE_WIDTH (), PROFILE_SCENE_HEIGHT ());
137 MINIMUM_VIEW_PROFILE_WIDTH);
138 m_viewProfile->setWhatsThis (tr (
"Histogram profile of the selected filter parameter. The two Dividers can be moved back and forth to adjust "
139 "the range of filter parameter values that will be included in the filtered image. The clear portion will "
140 "be included, and the shaded portion will be excluded."));
141 layout->addWidget (m_viewProfile, row, 3, PROFILE_HEIGHT_IN_ROWS (), 1);
142 row += PROFILE_HEIGHT_IN_ROWS ();
145 m_scale->setWhatsThis (tr (
"This read-only box displays a graphical representation of the horizontal axis in the histogram profile above."));
146 m_scale->setAutoFillBackground(
true);
147 layout->addWidget (m_scale, row++, 3, 1, 1);
152 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createSubPanel";
154 const int EMPTY_COLUMN_WIDTH = 40;
156 QWidget *subPanel =
new QWidget ();
157 QGridLayout *layout =
new QGridLayout (subPanel);
158 subPanel->setLayout (layout);
160 layout->setColumnStretch(0, 0);
161 layout->setColumnMinimumWidth(0, EMPTY_COLUMN_WIDTH);
162 layout->setColumnStretch(1, 0);
163 layout->setColumnMinimumWidth(1, 210);
164 layout->setColumnStretch(2, 0);
165 layout->setColumnMinimumWidth(2, 15);
166 layout->setColumnStretch(3, 1);
167 layout->setColumnMinimumWidth(4, EMPTY_COLUMN_WIDTH);
168 layout->setColumnStretch(4, 0);
170 int rowLeft = 0, rowRight = 0;
171 createControls (layout, rowLeft);
172 createProfileAndScale (layout, rowRight);
174 int row = qMax (rowLeft, rowRight);
175 createPreview (layout, row);
180 QRgb DlgSettingsColorFilter::createThread ()
182 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createThread";
190 if (m_filterThread == 0) {
195 m_filterThread->start();
198 return rgbBackground;
203 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::handleOk";
207 *m_modelColorFilterBefore,
208 *m_modelColorFilterAfter);
216 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::load";
221 if (m_modelColorFilterBefore != 0) {
222 delete m_modelColorFilterBefore;
224 if (m_modelColorFilterAfter != 0) {
225 delete m_modelColorFilterAfter;
233 m_cmbCurveName->clear ();
234 m_cmbCurveName->addItem (AXIS_CURVE_NAME);
236 QStringList::const_iterator itr;
237 for (itr = curveNames.begin (); itr != curveNames.end (); itr++) {
239 QString curveName = *itr;
240 m_cmbCurveName->addItem (curveName);
244 m_cmbCurveName->setCurrentText (
mainWindow().selectedGraphCurve());
250 void DlgSettingsColorFilter::loadForCurveName()
252 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::loadForCurveName";
255 QString curveName = m_cmbCurveName->currentText();
258 if (!curveName.isEmpty () && m_modelColorFilterAfter != 0) {
261 ColorFilterMode colorFilterMode = m_modelColorFilterAfter->
colorFilterMode(curveName);
262 m_btnIntensity->setChecked (colorFilterMode == COLOR_FILTER_MODE_INTENSITY);
263 m_btnForeground->setChecked (colorFilterMode == COLOR_FILTER_MODE_FOREGROUND);
264 m_btnHue->setChecked (colorFilterMode == COLOR_FILTER_MODE_HUE);
265 m_btnSaturation->setChecked (colorFilterMode == COLOR_FILTER_MODE_SATURATION);
266 m_btnValue->setChecked (colorFilterMode == COLOR_FILTER_MODE_VALUE);
268 m_scenePreview->clear();
270 m_scenePreview->addPixmap (QPixmap::fromImage (m_imagePreview));
272 QRgb rgbBackground = createThread ();
280 void DlgSettingsColorFilter::slotCurveName(
const QString & )
282 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotCurveName";
287 void DlgSettingsColorFilter::slotDividerHigh (
double xCenter)
289 m_modelColorFilterAfter->
setHigh (m_cmbCurveName->currentText(),
290 xCenter / (double) PROFILE_SCENE_WIDTH ());
294 void DlgSettingsColorFilter::slotDividerLow (
double xCenter)
296 m_modelColorFilterAfter->
setLow (m_cmbCurveName->currentText(),
297 xCenter / (double) PROFILE_SCENE_WIDTH ());
301 void DlgSettingsColorFilter::slotForeground ()
303 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotForeground";
306 COLOR_FILTER_MODE_FOREGROUND);
311 void DlgSettingsColorFilter::slotHue ()
313 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotHue";
316 COLOR_FILTER_MODE_HUE);
321 void DlgSettingsColorFilter::slotIntensity ()
323 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotIntensity";
326 COLOR_FILTER_MODE_INTENSITY);
331 void DlgSettingsColorFilter::slotSaturation ()
333 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotSaturation";
336 COLOR_FILTER_MODE_SATURATION);
349 for (
int xFrom = 0, xTo = xLeft; xFrom < image.width(); xFrom++, xTo++) {
350 for (
int y = 0; y < image.height (); y++) {
352 QColor pixel = image.pixel (xFrom, y);
353 m_imagePreview.setPixel (xTo, y, pixel.rgb());
358 QGraphicsItem *itemPixmap = m_scenePreview->items().at(0);
359 m_scenePreview->removeItem (itemPixmap);
363 m_scenePreview->addPixmap (QPixmap::fromImage (m_imagePreview));
366 void DlgSettingsColorFilter::slotValue ()
368 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotValue";
371 COLOR_FILTER_MODE_VALUE);
376 void DlgSettingsColorFilter::updateHistogram()
378 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::updateHistogram";
382 const double PEN_WIDTH = 0.0;
384 QString curveName = m_cmbCurveName->currentText();
386 m_sceneProfile->clear();
406 double logMaxBinCount = qLn (maxBinCount);
412 double count0 = 1.0 + histogramBins [bin - 1];
413 double y0 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count0) / logMaxBinCount);
418 double count1 = 1.0 + histogramBins [bin];
419 double y1 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count1) / logMaxBinCount);
421 QGraphicsLineItem *line =
new QGraphicsLineItem (x0, y0, x1, y1);
422 line->setPen (QPen (QBrush (Qt::black), PEN_WIDTH));
423 m_sceneProfile->addItem (line);
429 PROFILE_SCENE_WIDTH (),
430 PROFILE_SCENE_HEIGHT (),
431 PROFILE_SCENE_HEIGHT () * 2.0 / 3.0,
435 PROFILE_SCENE_HEIGHT (),
436 PROFILE_SCENE_WIDTH (),
437 PROFILE_SCENE_HEIGHT () / 3.0,
442 connect (m_dividerLow, SIGNAL (signalMovedLow (
double)), m_dividerHigh, SLOT (slotOtherMoved(
double)));
443 connect (m_dividerHigh, SIGNAL (signalMovedHigh (
double)), m_dividerLow, SLOT (slotOtherMoved(
double)));
446 connect (m_dividerLow, SIGNAL (signalMovedLow (
double)),
this, SLOT (slotDividerLow (
double)));
447 connect (m_dividerHigh, SIGNAL(signalMovedHigh (
double)),
this, SLOT (slotDividerHigh (
double)));
449 if (m_btnForeground->isChecked()) {
452 m_dividerLow->
setX (m_modelColorFilterAfter->
foregroundLow(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
453 m_dividerHigh->
setX (m_modelColorFilterAfter->
foregroundHigh(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
455 }
else if (m_btnIntensity->isChecked()) {
458 m_dividerLow->
setX (m_modelColorFilterAfter->
intensityLow(curveName), INTENSITY_MIN, INTENSITY_MAX);
459 m_dividerHigh->
setX (m_modelColorFilterAfter->
intensityHigh(curveName), INTENSITY_MIN, INTENSITY_MAX);
461 }
else if (m_btnHue->isChecked()) {
464 m_dividerLow->
setX (m_modelColorFilterAfter->
hueLow(curveName), HUE_MIN, HUE_MAX);
465 m_dividerHigh->
setX (m_modelColorFilterAfter->
hueHigh(curveName), HUE_MIN, HUE_MAX);
467 }
else if (m_btnSaturation->isChecked()) {
470 m_dividerLow->
setX (m_modelColorFilterAfter->
saturationLow(curveName), SATURATION_MIN, SATURATION_MAX);
471 m_dividerHigh->
setX (m_modelColorFilterAfter->
saturationHigh(curveName), SATURATION_MIN, SATURATION_MAX);
473 }
else if (m_btnValue->isChecked()) {
476 m_dividerLow->
setX (m_modelColorFilterAfter->
valueLow(curveName), VALUE_MIN, VALUE_MAX);
477 m_dividerHigh->
setX (m_modelColorFilterAfter->
valueHigh(curveName), VALUE_MIN, VALUE_MAX);
481 ENGAUGE_ASSERT (
false);
485 free (histogramBins);
488 void DlgSettingsColorFilter::updatePreview ()
490 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettings::updatePreview";
495 QString curveName = m_cmbCurveName->currentText();
497 m_modelColorFilterAfter->
low(curveName),
498 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.