20#include <QGraphicsLineItem>
21#include <QGraphicsScene>
27#include <QRadioButton>
40 "DlgSettingsColorFilter",
42 m_scenePreview (nullptr),
43 m_viewPreview (nullptr),
44 m_filterThread (nullptr),
45 m_modelColorFilterBefore (nullptr),
46 m_modelColorFilterAfter (nullptr)
59 delete m_filterThread;
62void DlgSettingsColorFilter::createControls (QGridLayout *layout,
int &row)
66 QLabel *labelCurve =
new QLabel (QString (
"%1:").arg (tr (
"Curve Name")));
67 layout->addWidget (labelCurve, row++, 1);
69 m_cmbCurveName =
new QComboBox ();
70 m_cmbCurveName->setWhatsThis (tr (
"Name of the curve that is currently selected for editing"));
71 connect (m_cmbCurveName, SIGNAL (activated (
const QString &)),
this, SLOT (slotCurveName (
const QString &)));
72 layout->addWidget (m_cmbCurveName, row++, 1);
74 QLabel *labelProfile =
new QLabel (QString (
"%1:").arg (tr (
"Filter mode")));
75 layout->addWidget (labelProfile, row++, 1);
78 m_btnIntensity->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Intensity parameter, "
79 "to hide unimportant information and emphasize important information.\n\n"
80 "The Intensity value of a pixel is computed from the red, green "
81 "and blue components as I = squareroot (R * R + G * G + B * B)"));
82 connect (m_btnIntensity, SIGNAL (released ()),
this, SLOT (slotIntensity ()));
83 layout->addWidget (m_btnIntensity, row++, 1);
86 m_btnForeground->setWhatsThis (tr (
"Filter the original image into black and white pixels by isolating the foreground from the background, "
87 "to hide unimportant information and emphasize important information.\n\n"
88 "The background color is shown on the left side of the scale bar.\n\n"
89 "The distance of any color (R, G, B) from the background color (Rb, Gb, Bb) is computed as "
90 "F = squareroot ((R - Rb) * (R - Rb) + (G - Gb) * (G - Gb) + (B - Bb)). On the left end of the "
91 "scale, the foreground distance value is zero, and it increases linearly to the maximum on the far right."));
92 connect (m_btnForeground, SIGNAL (released ()),
this, SLOT (slotForeground ()));
93 layout->addWidget (m_btnForeground, row++, 1);
96 m_btnHue->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Hue component of the "
97 "Hue, Saturation and Value (HSV) color components, "
98 "to hide unimportant information and emphasize important information."));
99 connect (m_btnHue, SIGNAL (released ()),
this, SLOT (slotHue ()));
100 layout->addWidget (m_btnHue, row++, 1);
103 m_btnSaturation->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Saturation component of the "
104 "Hue, Saturation and Value (HSV) color components, "
105 "to hide unimportant information and emphasize important information."));
106 connect (m_btnSaturation, SIGNAL (released ()),
this, SLOT (slotSaturation ()));
107 layout->addWidget (m_btnSaturation, row++, 1);
110 m_btnValue->setWhatsThis (tr (
"Filter the original image into black and white pixels using the Value component of the "
111 "Hue, Saturation and Value (HSV) color components, "
112 "to hide unimportant information and emphasize important information.\n\n"
113 "The Value component is also called the Lightness."));
114 connect (m_btnValue, SIGNAL (released ()),
this, SLOT (slotValue ()));
115 layout->addWidget (m_btnValue, row++, 1);
122void DlgSettingsColorFilter::createPreview (QGridLayout *layout,
int &row)
126 QLabel *labelPreview =
new QLabel (tr (
"Preview"));
127 layout->addWidget (labelPreview, row++, 0, 1, 5);
129 m_scenePreview =
new QGraphicsScene (
this);
133 m_viewPreview->setWhatsThis (tr (
"Preview window that shows how current settings affect the filtering of the original image."));
134 m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
135 m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
137 m_viewPreview->setRenderHint(QPainter::Antialiasing);
139 layout->addWidget (m_viewPreview, row++, 0, 1, 5);
142void DlgSettingsColorFilter::createProfileAndScale (QGridLayout *layout,
int &row)
146 const int MINIMUM_VIEW_PROFILE_WIDTH = 70;
148 QLabel *labelProfile =
new QLabel (tr (
"Filter Parameter Histogram Profile"));
149 layout->addWidget (labelProfile, row++, 3);
151 m_sceneProfile =
new QGraphicsScene;
152 m_sceneProfile->setSceneRect(0, 0, PROFILE_SCENE_WIDTH (), PROFILE_SCENE_HEIGHT ());
154 m_viewProfile =
new ViewProfile (m_sceneProfile,
155 MINIMUM_VIEW_PROFILE_WIDTH);
156 m_viewProfile->setWhatsThis (tr (
"Histogram profile of the selected filter parameter. The two Dividers can be moved back and forth to adjust "
157 "the range of filter parameter values that will be included in the filtered image. The clear portion will "
158 "be included, and the shaded portion will be excluded."));
159 layout->addWidget (m_viewProfile, row, 3, PROFILE_HEIGHT_IN_ROWS (), 1);
160 row += PROFILE_HEIGHT_IN_ROWS ();
162 m_scale =
new ViewProfileScale (MINIMUM_VIEW_PROFILE_WIDTH);
163 m_scale->setWhatsThis (tr (
"This read-only box displays a graphical representation of the horizontal axis in the histogram profile above."));
164 m_scale->setAutoFillBackground(
true);
165 layout->addWidget (m_scale, row++, 3, 1, 1);
172 const int EMPTY_COLUMN_WIDTH = 40;
174 QWidget *subPanel =
new QWidget ();
175 QGridLayout *layout =
new QGridLayout (subPanel);
176 subPanel->setLayout (layout);
178 layout->setColumnStretch(0, 0);
179 layout->setColumnMinimumWidth(0, EMPTY_COLUMN_WIDTH);
180 layout->setColumnStretch(1, 0);
181 layout->setColumnMinimumWidth(1, 210);
182 layout->setColumnStretch(2, 0);
183 layout->setColumnMinimumWidth(2, 15);
184 layout->setColumnStretch(3, 1);
185 layout->setColumnMinimumWidth(4, EMPTY_COLUMN_WIDTH);
186 layout->setColumnStretch(4, 0);
194 int rowLeft = row, rowRight = row;
195 createControls (layout, rowLeft);
196 createProfileAndScale (layout, rowRight);
198 row = qMax (rowLeft, rowRight);
199 createPreview (layout, row);
204QRgb DlgSettingsColorFilter::createThread ()
214 if (m_filterThread ==
nullptr) {
219 m_filterThread->start();
222 return rgbBackground;
231 *m_modelColorFilterBefore,
232 *m_modelColorFilterAfter);
245 delete m_modelColorFilterBefore;
246 delete m_modelColorFilterAfter;
253 m_cmbCurveName->clear ();
255 QStringList curveNames =
cmdMediator.curvesGraphsNames();
256 QStringList::const_iterator itr;
257 for (itr = curveNames.begin (); itr != curveNames.end (); itr++) {
259 QString curveName = *itr;
260 m_cmbCurveName->addItem (curveName);
264 m_cmbCurveName->setCurrentText (
mainWindow().selectedGraphCurve());
270void DlgSettingsColorFilter::loadForCurveName()
275 QString curveName = m_cmbCurveName->currentText();
278 if (!curveName.isEmpty () && m_modelColorFilterAfter !=
nullptr) {
288 m_scenePreview->clear();
291 QPixmap::fromImage (m_imagePreview));
293 QRgb rgbBackground = createThread ();
308void DlgSettingsColorFilter::slotCurveName(
const QString & )
315void DlgSettingsColorFilter::slotDividerHigh (
double xCenter)
317 m_modelColorFilterAfter->setHigh (m_cmbCurveName->currentText(),
318 xCenter / double (PROFILE_SCENE_WIDTH ()));
322void DlgSettingsColorFilter::slotDividerLow (
double xCenter)
324 m_modelColorFilterAfter->setLow (m_cmbCurveName->currentText(),
325 xCenter / double (PROFILE_SCENE_WIDTH ()));
329void DlgSettingsColorFilter::slotForeground ()
333 m_modelColorFilterAfter->setColorFilterMode(m_cmbCurveName->currentText(),
339void DlgSettingsColorFilter::slotHue ()
343 m_modelColorFilterAfter->setColorFilterMode(m_cmbCurveName->currentText(),
349void DlgSettingsColorFilter::slotIntensity ()
353 m_modelColorFilterAfter->setColorFilterMode(m_cmbCurveName->currentText(),
359void DlgSettingsColorFilter::slotSaturation ()
363 m_modelColorFilterAfter->setColorFilterMode(m_cmbCurveName->currentText(),
377 for (
int xFrom = 0, xTo = xLeft; xFrom < image.width(); xFrom++, xTo++) {
378 for (
int y = 0; y < image.height (); y++) {
380 QColor pixel = image.pixel (xFrom, y);
381 m_imagePreview.setPixel (xTo, y, pixel.rgb());
386 QGraphicsItem *itemPixmap = m_scenePreview->items().at(0);
387 m_scenePreview->removeItem (itemPixmap);
392 QPixmap::fromImage (m_imagePreview));
395void DlgSettingsColorFilter::slotValue ()
405void DlgSettingsColorFilter::slotWhatsThis ()
407 QWhatsThis::enterWhatsThisMode();
410void DlgSettingsColorFilter::updateHistogram()
416 const double PEN_WIDTH = 0.0;
418 QString curveName = m_cmbCurveName->currentText();
420 m_sceneProfile->clear();
422 m_scale->setColorFilterMode (m_modelColorFilterAfter->colorFilterMode(curveName));
430 ColorFilterHistogram filterHistogram;
434 m_modelColorFilterAfter->colorFilterMode (curveName),
440 double logMaxBinCount = qLn (maxBinCount);
441 if (qAbs (logMaxBinCount) > 0) {
447 double count0 = 1.0 + histogramBins [bin - 1];
448 double y0 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count0) / logMaxBinCount);
453 double count1 = 1.0 + histogramBins [bin];
454 double y1 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count1) / logMaxBinCount);
456 QGraphicsLineItem *line =
new QGraphicsLineItem (x0, y0, x1, y1);
457 line->setPen (QPen (QBrush (Qt::black), PEN_WIDTH));
458 m_sceneProfile->addItem (line);
463 m_dividerLow =
new ViewProfileDivider(*m_sceneProfile,
465 PROFILE_SCENE_WIDTH (),
466 PROFILE_SCENE_HEIGHT (),
467 qFloor (PROFILE_SCENE_HEIGHT () * 2.0 / 3.0),
469 m_dividerHigh =
new ViewProfileDivider(*m_sceneProfile,
471 PROFILE_SCENE_HEIGHT (),
472 PROFILE_SCENE_WIDTH (),
473 qFloor (PROFILE_SCENE_HEIGHT () / 3.0),
478 connect (m_dividerLow, SIGNAL (signalMovedLow (
double)), m_dividerHigh, SLOT (slotOtherMoved(
double)));
479 connect (m_dividerHigh, SIGNAL (signalMovedHigh (
double)), m_dividerLow, SLOT (slotOtherMoved(
double)));
482 connect (m_dividerLow, SIGNAL (signalMovedLow (
double)),
this, SLOT (slotDividerLow (
double)));
483 connect (m_dividerHigh, SIGNAL(signalMovedHigh (
double)),
this, SLOT (slotDividerHigh (
double)));
485 if (m_btnForeground->isChecked()) {
491 }
else if (m_btnIntensity->isChecked()) {
497 }
else if (m_btnHue->isChecked()) {
500 m_dividerLow->setX (m_modelColorFilterAfter->hueLow(curveName),
HUE_MIN,
HUE_MAX);
501 m_dividerHigh->setX (m_modelColorFilterAfter->hueHigh(curveName),
HUE_MIN,
HUE_MAX);
503 }
else if (m_btnSaturation->isChecked()) {
509 }
else if (m_btnValue->isChecked()) {
512 m_dividerLow->setX (m_modelColorFilterAfter->valueLow(curveName),
VALUE_MIN,
VALUE_MAX);
513 m_dividerHigh->setX (m_modelColorFilterAfter->valueHigh(curveName),
VALUE_MIN,
VALUE_MAX);
522 delete[] histogramBins;
525void DlgSettingsColorFilter::updatePreview ()
532 QString curveName = m_cmbCurveName->currentText();
534 m_modelColorFilterAfter->low(curveName),
535 m_modelColorFilterAfter->high(curveName));
const QString AXIS_CURVE_NAME
const int INTENSITY_MIN
Constants for use by CurveFilter and other curve-related classes.
QString colorFilterModeToString(ColorFilterMode colorFilterMode)
@ COLOR_FILTER_MODE_FOREGROUND
@ COLOR_FILTER_MODE_VALUE
@ COLOR_FILTER_MODE_INTENSITY
@ COLOR_FILTER_MODE_SATURATION
const int MINIMUM_DIALOG_WIDTH_COLOR_FILTER
#define ENGAUGE_ASSERT(cond)
Drop in replacement for Q_ASSERT.
log4cpp::Category * mainCat
Command for DlgSettingsColorFilter.
void generate(const ColorFilter &filter, double histogramBins[], ColorFilterMode colorFilterMode, const QImage &image, int &maxBinCount) const
Generate the histogram.
static int HISTOGRAM_BINS()
Number of histogram bins.
Class for filtering image to remove unimportant information.
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...
Class for processing new filter settings. This is based on http://blog.debao.me/2013/08/how-to-use-qt...
DlgSettingsAbstractBase(const QString &title, const QString &dialogName, MainWindow &mainWindow)
Single constructor.
void setCmdMediator(CmdMediator &cmdMediator)
Store CmdMediator for easy access by the leaf class.
void finishPanel(QWidget *subPanel, int minimumWidth=MINIMUM_DIALOG_WIDTH, int minimumHeightOrZero=0)
Add Ok and Cancel buttons to subpanel to get the whole dialog.
CmdMediator & cmdMediator()
Provide access to Document information wrapped inside CmdMediator.
void createWhatsThis(QGridLayout *layout, ButtonWhatsThis *button, int row, int column)
Create a WhatsThis button in a grid layout.
void addPixmap(QGraphicsScene &scene, const QPixmap &pixmap)
Adds pixmap to the scene.
void enableOk(bool enable)
Let leaf subclass control the Ok button.
static int MINIMUM_PREVIEW_HEIGHT
Dialog layout constant that guarantees preview has sufficent room.
MainWindow & mainWindow()
Get method for MainWindow.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
DlgSettingsColorFilter(MainWindow &mainWindow)
Single constructor.
virtual QWidget * createSubPanel()
Create dialog-specific panel to which base class will add Ok and Cancel buttons.
virtual void createOptionalSaveDefault(QHBoxLayout *layout)
Let subclass define an optional Save As Default button.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void slotTransferPiece(int xLeft, QImage image)
Receive processed piece of preview image, to be inserted at xLeft to xLeft+pixmap....
virtual void handleOk()
Process slotOk.
virtual ~DlgSettingsColorFilter()
void signalApplyFilter(ColorFilterMode colorFilterMode, double low, double high)
Send filter parameters to DlgFilterThread and DlgFilterWorker for processing.
Model for DlgSettingsColorFilter and CmdSettingsColorFilter.
ColorFilterMode colorFilterMode(const QString &curveName) const
Get method for filter mode.
void setColorFilterMode(const QString &curveName, ColorFilterMode colorFilterMode)
Set method for filter mode.
QPixmap pixmap() const
Return the image that is being digitized.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Class that modifies QGraphicsView to automatically expand/shrink the view to fit the window,...
@ VIEW_ASPECT_RATIO_VARIABLE
void setBackgroundColor(QRgb rgbBackground)
Save the background color for foreground calculations.
#define LOG4CPP_INFO_S(logger)
#define LOG4CPP_ERROR_S(logger)