00001
00002
00003
00004
00005
00006
00007 #include "CmdMediator.h"
00008 #include "CmdSettingsColorFilter.h"
00009 #include "ColorFilter.h"
00010 #include "ColorFilterHistogram.h"
00011 #include "ColorConstants.h"
00012 #include "DlgFilterThread.h"
00013 #include "DlgSettingsColorFilter.h"
00014 #include "EngaugeAssert.h"
00015 #include "Logger.h"
00016 #include "MainWindow.h"
00017 #include <QComboBox>
00018 #include <QDebug>
00019 #include <QGraphicsLineItem>
00020 #include <QGraphicsScene>
00021 #include <QGridLayout>
00022 #include <QImage>
00023 #include <QLabel>
00024 #include <qmath.h>
00025 #include <QPixmap>
00026 #include <QRadioButton>
00027 #include <QRgb>
00028 #include "ViewPreview.h"
00029 #include "ViewProfile.h"
00030 #include "ViewProfileDivider.h"
00031 #include "ViewProfileScale.h"
00032
00033 DlgSettingsColorFilter::DlgSettingsColorFilter(MainWindow &mainWindow) :
00034 DlgSettingsAbstractBase (tr ("Color Filter"),
00035 "DlgSettingsColorFilter",
00036 mainWindow),
00037 m_scenePreview (0),
00038 m_viewPreview (0),
00039 m_filterThread (0),
00040 m_modelColorFilterBefore (0),
00041 m_modelColorFilterAfter (0)
00042 {
00043 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::DlgSettingsColorFilter";
00044
00045 QWidget *subPanel = createSubPanel ();
00046 finishPanel (subPanel);
00047 }
00048
00049 DlgSettingsColorFilter::~DlgSettingsColorFilter()
00050 {
00051 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::~DlgSettingsColorFilter";
00052 }
00053
00054 void DlgSettingsColorFilter::createControls (QGridLayout *layout, int &row)
00055 {
00056 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::createControls";
00057
00058 QLabel *labelCurve = new QLabel (tr ("Curve Name:"));
00059 layout->addWidget (labelCurve, row++, 1);
00060
00061 m_cmbCurveName = new QComboBox ();
00062 m_cmbCurveName->setWhatsThis (tr ("Name of the curve that is currently selected for editing"));
00063 connect (m_cmbCurveName, SIGNAL (activated (const QString &)), this, SLOT (slotCurveName (const QString &)));
00064 layout->addWidget (m_cmbCurveName, row++, 1);
00065
00066 QLabel *labelProfile = new QLabel (tr ("Filter mode:"));
00067 layout->addWidget (labelProfile, row++, 1);
00068
00069 m_btnIntensity = new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_INTENSITY));
00070 m_btnIntensity->setWhatsThis (tr ("Filter the original image into black and white pixels using the Intensity parameter, "
00071 "to hide unimportant information and emphasize important information.\n\n"
00072 "The Intensity value of a pixel is computed from the red, green "
00073 "and blue components as I = squareroot (R * R + G * G + B * B)"));
00074 connect (m_btnIntensity, SIGNAL (released ()), this, SLOT (slotIntensity ()));
00075 layout->addWidget (m_btnIntensity, row++, 1);
00076
00077 m_btnForeground = new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_FOREGROUND));
00078 m_btnForeground->setWhatsThis (tr ("Filter the original image into black and white pixels by isolating the foreground from the background, "
00079 "to hide unimportant information and emphasize important information.\n\n"
00080 "The background color is shown on the left side of the scale bar.\n\n"
00081 "The distance of any color (R, G, B) from the background color (Rb, Gb, Bb) is computed as "
00082 "F = squareroot ((R - Rb) * (R - Rb) + (G - Gb) * (G - Gb) + (B - Bb)). On the left end of the "
00083 "scale, the foreground distance value is zero, and it increases linearly to the maximum on the far right."));
00084 connect (m_btnForeground, SIGNAL (released ()), this, SLOT (slotForeground ()));
00085 layout->addWidget (m_btnForeground, row++, 1);
00086
00087 m_btnHue = new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_HUE));
00088 m_btnHue->setWhatsThis (tr ("Filter the original image into black and white pixels using the Hue component of the "
00089 "Hue, Saturation and Value (HSV) color components, "
00090 "to hide unimportant information and emphasize important information."));
00091 connect (m_btnHue, SIGNAL (released ()), this, SLOT (slotHue ()));
00092 layout->addWidget (m_btnHue, row++, 1);
00093
00094 m_btnSaturation = new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_SATURATION));
00095 m_btnSaturation->setWhatsThis (tr ("Filter the original image into black and white pixels using the Saturation component of the "
00096 "Hue, Saturation and Value (HSV) color components, "
00097 "to hide unimportant information and emphasize important information."));
00098 connect (m_btnSaturation, SIGNAL (released ()), this, SLOT (slotSaturation ()));
00099 layout->addWidget (m_btnSaturation, row++, 1);
00100
00101 m_btnValue = new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_VALUE));
00102 m_btnValue->setWhatsThis (tr ("Filter the original image into black and white pixels using the Value component of the "
00103 "Hue, Saturation and Value (HSV) color components, "
00104 "to hide unimportant information and emphasize important information.\n\n"
00105 "The Value component is also called the Lightness."));
00106 connect (m_btnValue, SIGNAL (released ()), this, SLOT (slotValue ()));
00107 layout->addWidget (m_btnValue, row++, 1);
00108 }
00109
00110 void DlgSettingsColorFilter::createOptionalSaveDefault (QHBoxLayout * )
00111 {
00112 }
00113
00114 void DlgSettingsColorFilter::createPreview (QGridLayout *layout, int &row)
00115 {
00116 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::createPreview";
00117
00118 QLabel *labelPreview = new QLabel (tr ("Preview"));
00119 layout->addWidget (labelPreview, row++, 0, 1, 5);
00120
00121 m_scenePreview = new QGraphicsScene (this);
00122 m_viewPreview = new ViewPreview (m_scenePreview,
00123 ViewPreview::VIEW_ASPECT_RATIO_VARIABLE,
00124 this);
00125 m_viewPreview->setWhatsThis (tr ("Preview window that shows how current settings affect the filtering of the original image."));
00126 m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00127 m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00128 m_viewPreview->setMinimumHeight (MINIMUM_PREVIEW_HEIGHT);
00129 m_viewPreview->setRenderHint(QPainter::Antialiasing);
00130
00131 layout->addWidget (m_viewPreview, row++, 0, 1, 5);
00132 }
00133
00134 void DlgSettingsColorFilter::createProfileAndScale (QGridLayout *layout, int &row)
00135 {
00136 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::createProfileAndScale";
00137
00138 const int MINIMUM_VIEW_PROFILE_WIDTH = 70;
00139
00140 QLabel *labelProfile = new QLabel (tr ("Filter Parameter Histogram Profile"));
00141 layout->addWidget (labelProfile, row++, 3);
00142
00143 m_sceneProfile = new QGraphicsScene;
00144 m_sceneProfile->setSceneRect(0, 0, PROFILE_SCENE_WIDTH (), PROFILE_SCENE_HEIGHT ());
00145
00146 m_viewProfile = new ViewProfile (m_sceneProfile,
00147 MINIMUM_VIEW_PROFILE_WIDTH);
00148 m_viewProfile->setWhatsThis (tr ("Histogram profile of the selected filter parameter. The two Dividers can be moved back and forth to adjust "
00149 "the range of filter parameter values that will be included in the filtered image. The clear portion will "
00150 "be included, and the shaded portion will be excluded."));
00151 layout->addWidget (m_viewProfile, row, 3, PROFILE_HEIGHT_IN_ROWS (), 1);
00152 row += PROFILE_HEIGHT_IN_ROWS ();
00153
00154 m_scale = new ViewProfileScale (MINIMUM_VIEW_PROFILE_WIDTH);
00155 m_scale->setWhatsThis (tr ("This read-only box displays a graphical representation of the horizontal axis in the histogram profile above."));
00156 m_scale->setAutoFillBackground(true);
00157 layout->addWidget (m_scale, row++, 3, 1, 1);
00158 }
00159
00160 QWidget *DlgSettingsColorFilter::createSubPanel ()
00161 {
00162 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::createSubPanel";
00163
00164 const int EMPTY_COLUMN_WIDTH = 40;
00165
00166 QWidget *subPanel = new QWidget ();
00167 QGridLayout *layout = new QGridLayout (subPanel);
00168 subPanel->setLayout (layout);
00169
00170 layout->setColumnStretch(0, 0);
00171 layout->setColumnMinimumWidth(0, EMPTY_COLUMN_WIDTH);
00172 layout->setColumnStretch(1, 0);
00173 layout->setColumnMinimumWidth(1, 210);
00174 layout->setColumnStretch(2, 0);
00175 layout->setColumnMinimumWidth(2, 15);
00176 layout->setColumnStretch(3, 1);
00177 layout->setColumnMinimumWidth(4, EMPTY_COLUMN_WIDTH);
00178 layout->setColumnStretch(4, 0);
00179
00180 int rowLeft = 0, rowRight = 0;
00181 createControls (layout, rowLeft);
00182 createProfileAndScale (layout, rowRight);
00183
00184 int row = qMax (rowLeft, rowRight);
00185 createPreview (layout, row);
00186
00187 return subPanel;
00188 }
00189
00190 QRgb DlgSettingsColorFilter::createThread ()
00191 {
00192 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::createThread";
00193
00194
00195 QImage image = cmdMediator().document().pixmap().toImage();
00196 ColorFilter filter;
00197 QRgb rgbBackground = filter.marginColor(&image);
00198
00199
00200 if (m_filterThread == 0) {
00201
00202 m_filterThread = new DlgFilterThread (cmdMediator().document().pixmap(),
00203 rgbBackground,
00204 *this);
00205 m_filterThread->start();
00206 }
00207
00208 return rgbBackground;
00209 }
00210
00211 void DlgSettingsColorFilter::handleOk ()
00212 {
00213 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::handleOk";
00214
00215 CmdSettingsColorFilter *cmd = new CmdSettingsColorFilter (mainWindow (),
00216 cmdMediator ().document(),
00217 *m_modelColorFilterBefore,
00218 *m_modelColorFilterAfter);
00219 cmdMediator ().push (cmd);
00220
00221 hide ();
00222 }
00223
00224 void DlgSettingsColorFilter::load (CmdMediator &cmdMediator)
00225 {
00226 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::load";
00227
00228 setCmdMediator (cmdMediator);
00229
00230
00231 if (m_modelColorFilterBefore != 0) {
00232 delete m_modelColorFilterBefore;
00233 }
00234 if (m_modelColorFilterAfter != 0) {
00235 delete m_modelColorFilterAfter;
00236 }
00237
00238
00239 m_modelColorFilterBefore = new DocumentModelColorFilter (cmdMediator.document().modelColorFilter());
00240 m_modelColorFilterAfter = new DocumentModelColorFilter (cmdMediator.document().modelColorFilter());
00241
00242
00243 m_cmbCurveName->clear ();
00244 m_cmbCurveName->addItem (AXIS_CURVE_NAME);
00245 QStringList curveNames = cmdMediator.curvesGraphsNames();
00246 QStringList::const_iterator itr;
00247 for (itr = curveNames.begin (); itr != curveNames.end (); itr++) {
00248
00249 QString curveName = *itr;
00250 m_cmbCurveName->addItem (curveName);
00251 }
00252
00253
00254 m_cmbCurveName->setCurrentText (mainWindow().selectedGraphCurve());
00255 loadForCurveName();
00256
00257 enableOk (false);
00258 }
00259
00260 void DlgSettingsColorFilter::loadForCurveName()
00261 {
00262 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::loadForCurveName";
00263
00264
00265 QString curveName = m_cmbCurveName->currentText();
00266
00267
00268 if (!curveName.isEmpty () && m_modelColorFilterAfter != 0) {
00269
00270
00271 ColorFilterMode colorFilterMode = m_modelColorFilterAfter->colorFilterMode(curveName);
00272 m_btnIntensity->setChecked (colorFilterMode == COLOR_FILTER_MODE_INTENSITY);
00273 m_btnForeground->setChecked (colorFilterMode == COLOR_FILTER_MODE_FOREGROUND);
00274 m_btnHue->setChecked (colorFilterMode == COLOR_FILTER_MODE_HUE);
00275 m_btnSaturation->setChecked (colorFilterMode == COLOR_FILTER_MODE_SATURATION);
00276 m_btnValue->setChecked (colorFilterMode == COLOR_FILTER_MODE_VALUE);
00277
00278 m_scenePreview->clear();
00279 m_imagePreview = cmdMediator().document().pixmap().toImage();
00280 m_scenePreview->addPixmap (QPixmap::fromImage (m_imagePreview));
00281
00282 QRgb rgbBackground = createThread ();
00283 m_scale->setBackgroundColor (rgbBackground);
00284 createThread ();
00285 updateHistogram();
00286 updatePreview();
00287 }
00288 }
00289
00290 void DlgSettingsColorFilter::slotCurveName(const QString & )
00291 {
00292 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::slotCurveName";
00293
00294 loadForCurveName ();
00295 }
00296
00297 void DlgSettingsColorFilter::slotDividerHigh (double xCenter)
00298 {
00299 m_modelColorFilterAfter->setHigh (m_cmbCurveName->currentText(),
00300 xCenter / (double) PROFILE_SCENE_WIDTH ());
00301 updatePreview();
00302 }
00303
00304 void DlgSettingsColorFilter::slotDividerLow (double xCenter)
00305 {
00306 m_modelColorFilterAfter->setLow (m_cmbCurveName->currentText(),
00307 xCenter / (double) PROFILE_SCENE_WIDTH ());
00308 updatePreview();
00309 }
00310
00311 void DlgSettingsColorFilter::slotForeground ()
00312 {
00313 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::slotForeground";
00314
00315 m_modelColorFilterAfter->setColorFilterMode(m_cmbCurveName->currentText(),
00316 COLOR_FILTER_MODE_FOREGROUND);
00317 updateHistogram();
00318 updatePreview();
00319 }
00320
00321 void DlgSettingsColorFilter::slotHue ()
00322 {
00323 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::slotHue";
00324
00325 m_modelColorFilterAfter->setColorFilterMode(m_cmbCurveName->currentText(),
00326 COLOR_FILTER_MODE_HUE);
00327 updateHistogram();
00328 updatePreview();
00329 }
00330
00331 void DlgSettingsColorFilter::slotIntensity ()
00332 {
00333 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::slotIntensity";
00334
00335 m_modelColorFilterAfter->setColorFilterMode(m_cmbCurveName->currentText(),
00336 COLOR_FILTER_MODE_INTENSITY);
00337 updateHistogram();
00338 updatePreview();
00339 }
00340
00341 void DlgSettingsColorFilter::slotSaturation ()
00342 {
00343 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::slotSaturation";
00344
00345 m_modelColorFilterAfter->setColorFilterMode(m_cmbCurveName->currentText(),
00346 COLOR_FILTER_MODE_SATURATION);
00347 updateHistogram();
00348 updatePreview();
00349 }
00350
00351 void DlgSettingsColorFilter::slotTransferPiece (int xLeft,
00352 QImage image)
00353 {
00354
00355
00356
00357
00358
00359 for (int xFrom = 0, xTo = xLeft; xFrom < image.width(); xFrom++, xTo++) {
00360 for (int y = 0; y < image.height (); y++) {
00361
00362 QColor pixel = image.pixel (xFrom, y);
00363 m_imagePreview.setPixel (xTo, y, pixel.rgb());
00364 }
00365 }
00366
00367
00368 QGraphicsItem *itemPixmap = m_scenePreview->items().at(0);
00369 m_scenePreview->removeItem (itemPixmap);
00370 delete itemPixmap;
00371
00372
00373 m_scenePreview->addPixmap (QPixmap::fromImage (m_imagePreview));
00374 }
00375
00376 void DlgSettingsColorFilter::slotValue ()
00377 {
00378 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::slotValue";
00379
00380 m_modelColorFilterAfter->setColorFilterMode(m_cmbCurveName->currentText(),
00381 COLOR_FILTER_MODE_VALUE);
00382 updateHistogram();
00383 updatePreview();
00384 }
00385
00386 void DlgSettingsColorFilter::updateHistogram()
00387 {
00388 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::updateHistogram";
00389
00390 enableOk (true);
00391
00392 const double PEN_WIDTH = 0.0;
00393
00394 QString curveName = m_cmbCurveName->currentText();
00395
00396 m_sceneProfile->clear();
00397
00398 m_scale->setColorFilterMode (m_modelColorFilterAfter->colorFilterMode(curveName));
00399
00400
00401 QImage image = cmdMediator().document().pixmap().toImage();
00402
00403 double *histogramBins = new double [ColorFilterHistogram::HISTOGRAM_BINS ()];
00404
00405 ColorFilter filter;
00406 ColorFilterHistogram filterHistogram;
00407 int maxBinCount;
00408 filterHistogram.generate (filter,
00409 histogramBins,
00410 m_modelColorFilterAfter->colorFilterMode (curveName),
00411 image,
00412 maxBinCount);
00413
00414
00415
00416 double logMaxBinCount = qLn (maxBinCount);
00417 for (int bin = 1; bin < ColorFilterHistogram::HISTOGRAM_BINS (); bin++) {
00418
00419 double x0 = PROFILE_SCENE_WIDTH () * (bin - 1.0) / (ColorFilterHistogram::HISTOGRAM_BINS () - 1.0);
00420
00421
00422 double count0 = 1.0 + histogramBins [bin - 1];
00423 double y0 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count0) / logMaxBinCount);
00424
00425 double x1 = PROFILE_SCENE_WIDTH () * (bin - 0.0) / (ColorFilterHistogram::HISTOGRAM_BINS () - 1.0);
00426
00427
00428 double count1 = 1.0 + histogramBins [bin];
00429 double y1 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count1) / logMaxBinCount);
00430
00431 QGraphicsLineItem *line = new QGraphicsLineItem (x0, y0, x1, y1);
00432 line->setPen (QPen (QBrush (Qt::black), PEN_WIDTH));
00433 m_sceneProfile->addItem (line);
00434 }
00435
00436
00437 m_dividerLow = new ViewProfileDivider(*m_sceneProfile,
00438 *m_viewProfile,
00439 PROFILE_SCENE_WIDTH (),
00440 PROFILE_SCENE_HEIGHT (),
00441 PROFILE_SCENE_HEIGHT () * 2.0 / 3.0,
00442 true);
00443 m_dividerHigh = new ViewProfileDivider(*m_sceneProfile,
00444 *m_viewProfile,
00445 PROFILE_SCENE_HEIGHT (),
00446 PROFILE_SCENE_WIDTH (),
00447 PROFILE_SCENE_HEIGHT () / 3.0,
00448 false);
00449
00450
00451
00452 connect (m_dividerLow, SIGNAL (signalMovedLow (double)), m_dividerHigh, SLOT (slotOtherMoved(double)));
00453 connect (m_dividerHigh, SIGNAL (signalMovedHigh (double)), m_dividerLow, SLOT (slotOtherMoved(double)));
00454
00455
00456 connect (m_dividerLow, SIGNAL (signalMovedLow (double)), this, SLOT (slotDividerLow (double)));
00457 connect (m_dividerHigh, SIGNAL(signalMovedHigh (double)), this, SLOT (slotDividerHigh (double)));
00458
00459 if (m_btnForeground->isChecked()) {
00460
00461
00462 m_dividerLow->setX (m_modelColorFilterAfter->foregroundLow(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
00463 m_dividerHigh->setX (m_modelColorFilterAfter->foregroundHigh(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
00464
00465 } else if (m_btnIntensity->isChecked()) {
00466
00467
00468 m_dividerLow->setX (m_modelColorFilterAfter->intensityLow(curveName), INTENSITY_MIN, INTENSITY_MAX);
00469 m_dividerHigh->setX (m_modelColorFilterAfter->intensityHigh(curveName), INTENSITY_MIN, INTENSITY_MAX);
00470
00471 } else if (m_btnHue->isChecked()) {
00472
00473
00474 m_dividerLow->setX (m_modelColorFilterAfter->hueLow(curveName), HUE_MIN, HUE_MAX);
00475 m_dividerHigh->setX (m_modelColorFilterAfter->hueHigh(curveName), HUE_MIN, HUE_MAX);
00476
00477 } else if (m_btnSaturation->isChecked()) {
00478
00479
00480 m_dividerLow->setX (m_modelColorFilterAfter->saturationLow(curveName), SATURATION_MIN, SATURATION_MAX);
00481 m_dividerHigh->setX (m_modelColorFilterAfter->saturationHigh(curveName), SATURATION_MIN, SATURATION_MAX);
00482
00483 } else if (m_btnValue->isChecked()) {
00484
00485
00486 m_dividerLow->setX (m_modelColorFilterAfter->valueLow(curveName), VALUE_MIN, VALUE_MAX);
00487 m_dividerHigh->setX (m_modelColorFilterAfter->valueHigh(curveName), VALUE_MIN, VALUE_MAX);
00488
00489 } else {
00490
00491 ENGAUGE_ASSERT (false);
00492
00493 }
00494
00495 free (histogramBins);
00496 }
00497
00498 void DlgSettingsColorFilter::updatePreview ()
00499 {
00500 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettings::updatePreview";
00501
00502 enableOk (true);
00503
00504
00505 QString curveName = m_cmbCurveName->currentText();
00506 emit signalApplyFilter (m_modelColorFilterAfter->colorFilterMode(curveName),
00507 m_modelColorFilterAfter->low(curveName),
00508 m_modelColorFilterAfter->high(curveName));
00509 }