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);
108 void DlgSettingsColorFilter::createPreview (QGridLayout *layout,
int &row)
110 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createPreview";
112 QLabel *labelPreview =
new QLabel (
"Preview");
113 layout->addWidget (labelPreview, row++, 0, 1, 5);
115 m_scenePreview =
new QGraphicsScene (
this);
117 ViewPreview::VIEW_ASPECT_RATIO_VARIABLE,
119 m_viewPreview->setWhatsThis (tr (
"Preview window that shows how current settings affect the filtering of the original image."));
120 m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
121 m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
123 m_viewPreview->setRenderHint(QPainter::Antialiasing);
125 layout->addWidget (m_viewPreview, row++, 0, 1, 5);
128 void DlgSettingsColorFilter::createProfileAndScale (QGridLayout *layout,
int &row)
130 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createProfileAndScale";
132 const int MINIMUM_VIEW_PROFILE_WIDTH = 70;
134 QLabel *labelProfile =
new QLabel (
"Filter Parameter Histogram Profile");
135 layout->addWidget (labelProfile, row++, 3);
137 m_sceneProfile =
new QGraphicsScene;
138 m_sceneProfile->setSceneRect(0, 0, PROFILE_SCENE_WIDTH (), PROFILE_SCENE_HEIGHT ());
141 MINIMUM_VIEW_PROFILE_WIDTH);
142 m_viewProfile->setWhatsThis (tr (
"Histogram profile of the selected filter parameter. The two Dividers can be moved back and forth to adjust "
143 "the range of filter parameter values that will be included in the filtered image. The clear portion will "
144 "be included, and the shaded portion will be excluded."));
145 layout->addWidget (m_viewProfile, row, 3, PROFILE_HEIGHT_IN_ROWS (), 1);
146 row += PROFILE_HEIGHT_IN_ROWS ();
149 m_scale->setWhatsThis (tr (
"This read-only box displays a graphical representation of the horizontal axis in the histogram profile above."));
150 m_scale->setAutoFillBackground(
true);
151 layout->addWidget (m_scale, row++, 3, 1, 1);
156 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createSubPanel";
158 const int EMPTY_COLUMN_WIDTH = 40;
160 QWidget *subPanel =
new QWidget ();
161 QGridLayout *layout =
new QGridLayout (subPanel);
162 subPanel->setLayout (layout);
164 layout->setColumnStretch(0, 0);
165 layout->setColumnMinimumWidth(0, EMPTY_COLUMN_WIDTH);
166 layout->setColumnStretch(1, 0);
167 layout->setColumnMinimumWidth(1, 210);
168 layout->setColumnStretch(2, 0);
169 layout->setColumnMinimumWidth(2, 15);
170 layout->setColumnStretch(3, 1);
171 layout->setColumnMinimumWidth(4, EMPTY_COLUMN_WIDTH);
172 layout->setColumnStretch(4, 0);
174 int rowLeft = 0, rowRight = 0;
175 createControls (layout, rowLeft);
176 createProfileAndScale (layout, rowRight);
178 int row = qMax (rowLeft, rowRight);
179 createPreview (layout, row);
184 QRgb DlgSettingsColorFilter::createThread ()
186 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::createThread";
194 if (m_filterThread == 0) {
199 m_filterThread->start();
202 return rgbBackground;
207 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::handleOk";
211 *m_modelColorFilterBefore,
212 *m_modelColorFilterAfter);
220 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::load";
225 if (m_modelColorFilterBefore != 0) {
226 delete m_modelColorFilterBefore;
228 if (m_modelColorFilterAfter != 0) {
229 delete m_modelColorFilterAfter;
237 m_cmbCurveName->clear ();
238 m_cmbCurveName->addItem (AXIS_CURVE_NAME);
240 QStringList::const_iterator itr;
241 for (itr = curveNames.begin (); itr != curveNames.end (); itr++) {
243 QString curveName = *itr;
244 m_cmbCurveName->addItem (curveName);
248 m_cmbCurveName->setCurrentText (
mainWindow().selectedGraphCurve());
254 void DlgSettingsColorFilter::loadForCurveName()
256 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::loadForCurveName";
259 QString curveName = m_cmbCurveName->currentText();
262 if (!curveName.isEmpty () && m_modelColorFilterAfter != 0) {
265 ColorFilterMode colorFilterMode = m_modelColorFilterAfter->
colorFilterMode(curveName);
266 m_btnIntensity->setChecked (colorFilterMode == COLOR_FILTER_MODE_INTENSITY);
267 m_btnForeground->setChecked (colorFilterMode == COLOR_FILTER_MODE_FOREGROUND);
268 m_btnHue->setChecked (colorFilterMode == COLOR_FILTER_MODE_HUE);
269 m_btnSaturation->setChecked (colorFilterMode == COLOR_FILTER_MODE_SATURATION);
270 m_btnValue->setChecked (colorFilterMode == COLOR_FILTER_MODE_VALUE);
272 m_scenePreview->clear();
274 m_scenePreview->addPixmap (QPixmap::fromImage (m_imagePreview));
276 QRgb rgbBackground = createThread ();
284 void DlgSettingsColorFilter::slotCurveName(
const QString & )
286 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotCurveName";
291 void DlgSettingsColorFilter::slotDividerHigh (
double xCenter)
293 m_modelColorFilterAfter->
setHigh (m_cmbCurveName->currentText(),
294 xCenter / (double) PROFILE_SCENE_WIDTH ());
298 void DlgSettingsColorFilter::slotDividerLow (
double xCenter)
300 m_modelColorFilterAfter->
setLow (m_cmbCurveName->currentText(),
301 xCenter / (double) PROFILE_SCENE_WIDTH ());
305 void DlgSettingsColorFilter::slotForeground ()
307 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotForeground";
310 COLOR_FILTER_MODE_FOREGROUND);
315 void DlgSettingsColorFilter::slotHue ()
317 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotHue";
320 COLOR_FILTER_MODE_HUE);
325 void DlgSettingsColorFilter::slotIntensity ()
327 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotIntensity";
330 COLOR_FILTER_MODE_INTENSITY);
335 void DlgSettingsColorFilter::slotSaturation ()
337 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotSaturation";
340 COLOR_FILTER_MODE_SATURATION);
353 for (
int xFrom = 0, xTo = xLeft; xFrom < image.width(); xFrom++, xTo++) {
354 for (
int y = 0; y < image.height (); y++) {
356 QColor pixel = image.pixel (xFrom, y);
357 m_imagePreview.setPixel (xTo, y, pixel.rgb());
362 QGraphicsItem *itemPixmap = m_scenePreview->items().at(0);
363 m_scenePreview->removeItem (itemPixmap);
367 m_scenePreview->addPixmap (QPixmap::fromImage (m_imagePreview));
370 void DlgSettingsColorFilter::slotValue ()
372 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::slotValue";
375 COLOR_FILTER_MODE_VALUE);
380 void DlgSettingsColorFilter::updateHistogram()
382 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettingsColorFilter::updateHistogram";
386 const double PEN_WIDTH = 0.0;
388 QString curveName = m_cmbCurveName->currentText();
390 m_sceneProfile->clear();
410 double logMaxBinCount = qLn (maxBinCount);
416 double count0 = 1.0 + histogramBins [bin - 1];
417 double y0 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count0) / logMaxBinCount);
422 double count1 = 1.0 + histogramBins [bin];
423 double y1 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count1) / logMaxBinCount);
425 QGraphicsLineItem *line =
new QGraphicsLineItem (x0, y0, x1, y1);
426 line->setPen (QPen (QBrush (Qt::black), PEN_WIDTH));
427 m_sceneProfile->addItem (line);
433 PROFILE_SCENE_WIDTH (),
434 PROFILE_SCENE_HEIGHT (),
435 PROFILE_SCENE_HEIGHT () * 2.0 / 3.0,
439 PROFILE_SCENE_HEIGHT (),
440 PROFILE_SCENE_WIDTH (),
441 PROFILE_SCENE_HEIGHT () / 3.0,
446 connect (m_dividerLow, SIGNAL (signalMovedLow (
double)), m_dividerHigh, SLOT (slotOtherMoved(
double)));
447 connect (m_dividerHigh, SIGNAL (signalMovedHigh (
double)), m_dividerLow, SLOT (slotOtherMoved(
double)));
450 connect (m_dividerLow, SIGNAL (signalMovedLow (
double)),
this, SLOT (slotDividerLow (
double)));
451 connect (m_dividerHigh, SIGNAL(signalMovedHigh (
double)),
this, SLOT (slotDividerHigh (
double)));
453 if (m_btnForeground->isChecked()) {
456 m_dividerLow->
setX (m_modelColorFilterAfter->
foregroundLow(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
457 m_dividerHigh->
setX (m_modelColorFilterAfter->
foregroundHigh(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
459 }
else if (m_btnIntensity->isChecked()) {
462 m_dividerLow->
setX (m_modelColorFilterAfter->
intensityLow(curveName), INTENSITY_MIN, INTENSITY_MAX);
463 m_dividerHigh->
setX (m_modelColorFilterAfter->
intensityHigh(curveName), INTENSITY_MIN, INTENSITY_MAX);
465 }
else if (m_btnHue->isChecked()) {
468 m_dividerLow->
setX (m_modelColorFilterAfter->
hueLow(curveName), HUE_MIN, HUE_MAX);
469 m_dividerHigh->
setX (m_modelColorFilterAfter->
hueHigh(curveName), HUE_MIN, HUE_MAX);
471 }
else if (m_btnSaturation->isChecked()) {
474 m_dividerLow->
setX (m_modelColorFilterAfter->
saturationLow(curveName), SATURATION_MIN, SATURATION_MAX);
475 m_dividerHigh->
setX (m_modelColorFilterAfter->
saturationHigh(curveName), SATURATION_MIN, SATURATION_MAX);
477 }
else if (m_btnValue->isChecked()) {
480 m_dividerLow->
setX (m_modelColorFilterAfter->
valueLow(curveName), VALUE_MIN, VALUE_MAX);
481 m_dividerHigh->
setX (m_modelColorFilterAfter->
valueHigh(curveName), VALUE_MIN, VALUE_MAX);
485 ENGAUGE_ASSERT (
false);
489 free (histogramBins);
492 void DlgSettingsColorFilter::updatePreview ()
494 LOG4CPP_INFO_S ((*mainCat)) <<
"DlgSettings::updatePreview";
499 QString curveName = m_cmbCurveName->currentText();
501 m_modelColorFilterAfter->
low(curveName),
502 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 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.