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