File failed to load: https://isis.astrogeology.usgs.gov/9.0.0/Object/assets/jax/output/NativeMML/config.js
Isis 3 Programmer Reference
StretchTool.cpp
1#include "StretchTool.h"
2
3#include <sstream>
4
5#include <QAction>
6#include <QComboBox>
7#include <QHBoxLayout>
8#include <QLineEdit>
9#include <QMenuBar>
10#include <QMessageBox>
11#include <QPixmap>
12#include <QPushButton>
13#include <QSizePolicy>
14#include <QStackedWidget>
15#include <QToolBar>
16#include <QToolButton>
17#include <QValidator>
18#include <QInputDialog>
19
20#include "AdvancedStretchDialog.h"
21#include "Brick.h"
22#include "Blob.h"
23#include "CubeViewport.h"
24#include "Histogram.h"
25#include "IException.h"
26#include "IString.h"
27#include "MainWindow.h"
28#include "MdiCubeViewport.h"
29#include "RubberBandTool.h"
30#include "Statistics.h"
31#include "Stretch.h"
32#include "ToolPad.h"
33#include "ViewportBuffer.h"
34#include "ViewportMainWindow.h"
35#include "Workspace.h"
36
37#include "CubeStretch.h"
38
39using namespace std;
40
41namespace Isis {
51 m_advancedStretch = NULL;
52
54
56 connect(m_advancedStretch, SIGNAL(stretchChanged()),
57 this, SLOT(advancedStretchChanged()));
58 connect(m_advancedStretch, SIGNAL(visibilityChanged()),
59 this, SLOT(updateTool()));
60 connect(m_advancedStretch, SIGNAL(saveToCube()),
61 this, SLOT(saveStretchToCube()));
62 connect(m_advancedStretch, SIGNAL(deleteFromCube()),
63 this, SLOT(deleteFromCube()));
64 connect(m_advancedStretch, SIGNAL(loadStretch()),
65 this, SLOT(loadStretchFromCube()));
66
67 QPushButton *hiddenButton = new QPushButton();
68 hiddenButton->setVisible(false);
69 hiddenButton->setDefault(true);
70
71 m_stretchGlobal = new QAction(parent);
72 m_stretchGlobal->setShortcut(Qt::CTRL + Qt::Key_G);
73 m_stretchGlobal->setText("Global Stretch");
74 connect(m_stretchGlobal, SIGNAL(triggered()), this, SLOT(stretchGlobal()));
75
76 m_stretchRegional = new QAction(parent);
77 m_stretchRegional->setShortcut(Qt::CTRL + Qt::Key_R);
78 m_stretchRegional->setText("Regional Stretch");
79 connect(m_stretchRegional, SIGNAL(triggered()), this, SLOT(stretchRegional()));
80
81 // Emit a signal when an exception occurs and connect to the Warning object
82 // to display Warning icon and the message
83 ViewportMainWindow *parentMainWindow = qobject_cast<ViewportMainWindow *>(parent);
84 if (parentMainWindow) {
85 connect(this, SIGNAL(warningSignal(std::string &, const std::string)),
86 parentMainWindow, SLOT(displayWarning(std::string &, const std::string &)));
87 }
88 }
89
90
101
102
112 QAction *action = new QAction(pad);
113 action->setIcon(QPixmap(toolIconDir() + "/stretch_global.png"));
114 action->setToolTip("Stretch (S)");
115 action->setShortcut(Qt::Key_S);
116 QString text =
117 "<b>Function:</b> Change the stretch range of the cube.\
118 <p><b>Shortcut:</b> S</p> ";
119 action->setWhatsThis(text);
120
121 return action;
122 }
123
124
132 menu->addAction(m_stretchGlobal);
133 menu->addAction(m_stretchRegional);
134 }
135
136
145 QWidget *StretchTool::createToolBarWidget(QStackedWidget *parent) {
146 QWidget *hbox = new QWidget(parent);
147
148 QToolButton *butt = new QToolButton(hbox);
149 butt->setAutoRaise(true);
150 butt->setIconSize(QSize(22, 22));
151 butt->setIcon(QPixmap(toolIconDir() + "/regional_stretch-2.png"));
152 butt->setToolTip("Stretch");
153 QString text =
154 "<b>Function:</b> Automatically compute min/max stretch using viewed \
155 pixels in the band(s) of the active viewport. That is, only pixels \
156 that are visible in the viewport are used. \
157 If the viewport is in RGB color all three bands will be stretched. \
158 <p><b>Shortcut:</b> Ctrl+R</p> \
159 <p><b>Mouse:</b> Left click \
160 <p><b>Hint:</b> Left click and drag for a local stretch. Uses only \
161 pixels in the red marquee</p>";
162 butt->setWhatsThis(text);
163 connect(butt, SIGNAL(clicked()), this, SLOT(stretchRegional()));
165
167 m_stretchBandComboBox->setEditable(false);
168 m_stretchBandComboBox->addItem("Red Band", Red);
169 m_stretchBandComboBox->addItem("Green Band", Green);
170 m_stretchBandComboBox->addItem("Blue Band", Blue);
171 m_stretchBandComboBox->addItem("All Bands", All);
172 m_stretchBandComboBox->setToolTip("Select Color");
173 text =
174 "<b>Function:</b> Selecting the color will allow the appropriate \
175 min/max to be seen and/or edited in text fields to the right.";
176
177// The All option implies the same min/max will be applied
178// to all three colors (RGB) if either text field is edited";
179 m_stretchBandComboBox->setWhatsThis(text);
181 m_stretchBandComboBox->setCurrentIndex(
183 connect(m_stretchBandComboBox, SIGNAL(currentIndexChanged(int)),
184 this, SLOT(stretchBandChanged(int)));
185
186 // Create drop-down selection option to set min/max type
188 p_minMaxTypeSelection->setToolTip("Min/Max Type");
189 text =
190 "<b>Function:</b> Select the minimum & maximum value types to \
191 set the stretch to. The four options are: \
192 <p>- Default: Min and max values are set to the \
193 0.5 and 99.5 percentiles, respectively. \
194 <p>- Best: The better of the absolute min/max or the \
195 Chebyshev min/max. The better value is considered the value \
196 closest to the mean. \
197 <p>- Absolute: The absolute min/max value of all valid pixels. \
198 <p>- Chebyshev: The min/max value such that a certain percentage \
199 of data will fall within K standard deviations of the average \
200 (Chebyshev's Theorem). It can be used to obtain a value that \
201 does not include statistical outliers.";
202 p_minMaxTypeSelection->setWhatsThis(text);
203 p_minMaxTypeSelection->addItem("Default", 0);
204 p_minMaxTypeSelection->addItem("Best", 1);
205 p_minMaxTypeSelection->addItem("Absolute", 2);
206 p_minMaxTypeSelection->addItem("Chebyshev", 3);
207
208 connect(p_minMaxTypeSelection, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this] {
209 changeStretch(true);
210 });
211
212 QDoubleValidator *dval = new QDoubleValidator(hbox);
213 m_stretchMinEdit = new QLineEdit(hbox);
214 m_stretchMinEdit->setValidator(dval);
215 m_stretchMinEdit->setToolTip("Minimum");
216 text =
217 "<b>Function:</b> Shows the current minimum pixel value. Pixel values \
218 below minimum are shown as black. Pixel values above the maximum \
219 are shown as white or the highest intensity of red/green/blue \
220 if in color. Pixel values between the minimum and maximum are stretched \
221 linearly between black and white (or color component). \
222 <p><b>Hint:</b> You can manually edit the minimum but it must be \
223 less than the maximum.";
224 m_stretchMinEdit->setWhatsThis(text);
225 m_stretchMinEdit->setMaximumWidth(100);
226 connect(m_stretchMinEdit, SIGNAL(returnPressed()),
227 this, SLOT(changeStretch()));
228
229 m_stretchMaxEdit = new QLineEdit(hbox);
230 m_stretchMaxEdit->setValidator(dval);
231 m_stretchMaxEdit->setToolTip("Maximum");
232 text =
233 "<b>Function:</b> Shows the current maximum pixel value. Pixel values \
234 below minimum are shown as black. Pixel values above the maximum \
235 are shown as white or the highest intensity of red/green/blue \
236 if in color. Pixel values between the minimum and maximum are stretched \
237 linearly between black and white (or color component). \
238 <p><b>Hint:</b> You can manually edit the maximum but it must be \
239 greater than the minimum";
240 m_stretchMaxEdit->setWhatsThis(text);
241 m_stretchMaxEdit->setMaximumWidth(100);
242 connect(m_stretchMaxEdit, SIGNAL(returnPressed()), this, SLOT(changeStretch()));
243
244 // Create the two menus that drop down from the buttons
245 QMenu *copyMenu = new QMenu();
246 QMenu *globalMenu = new QMenu();
247
248 m_copyBands = new QAction(parent);
249 m_copyBands->setText("to All Bands");
250 connect(m_copyBands, SIGNAL(triggered(bool)), this, SLOT(setStretchAcrossBands()));
251
252 QAction *copyAll = new QAction(parent);
253 copyAll->setIcon(QPixmap(toolIconDir() + "/copy_stretch.png"));
254 copyAll->setText("to All Viewports");
255 connect(copyAll, SIGNAL(triggered(bool)), this, SLOT(setStretchAllViewports()));
256
257 copyMenu->addAction(copyAll);
258 copyMenu->addAction(m_copyBands);
259
260 m_copyButton = new QToolButton();
261 m_copyButton->setAutoRaise(true);
262 m_copyButton->setIconSize(QSize(22, 22));
263 m_copyButton->setIcon(QPixmap(toolIconDir() + "/copy_stretch.png"));
264 m_copyButton->setPopupMode(QToolButton::MenuButtonPopup);
265 m_copyButton->setMenu(copyMenu);
266 m_copyButton->setDefaultAction(copyAll);
267 m_copyButton->setToolTip("Copy");
268 text =
269 "<b>Function:</b> Copy the current stretch to all the \
270 active viewports. Or use the drop down menu to copy the current stretch \
271 to all the bands in the active viewport. \
272 <p><b>Hint:</b> Can reset the stretch to an automaticaly computed \
273 stretch by using the 'Reset' stretch button option. </p>";
274 m_copyButton->setWhatsThis(text);
275
276 QAction *currentView = new QAction(parent);
277 currentView->setText("Active Viewport");
278 currentView->setIcon(QPixmap(toolIconDir() + "/global_stretch.png"));
279 globalMenu->addAction(currentView);
280 connect(currentView, SIGNAL(triggered(bool)), this, SLOT(stretchGlobal()));
281
282 QAction *globalAll = new QAction(parent);
283 globalAll->setText("All Viewports");
284 globalMenu->addAction(globalAll);
285 connect(globalAll, SIGNAL(triggered(bool)), this, SLOT(stretchGlobalAllViewports()));
286
287 QAction *globalBands = new QAction(parent);
288 globalBands->setText("All Bands");
289 globalMenu->addAction(globalBands);
290 connect(globalBands, SIGNAL(triggered(bool)), this, SLOT(stretchGlobalAllBands()));
291
292 m_globalButton = new QToolButton(); //basically acts as a 'reset'
293 m_globalButton->setAutoRaise(true);
294 m_globalButton->setIconSize(QSize(22, 22));
295 m_globalButton->setPopupMode(QToolButton::MenuButtonPopup);
296 m_globalButton->setMenu(globalMenu);
297 m_globalButton->setDefaultAction(currentView);
298 m_globalButton->setToolTip("Reset");
299 text =
300 "<b>Function:</b> Reset the stretch to be automatically computed "
301 "using the statisics from the entire image. Use the drop down menu "
302 "to reset the stretch for all the bands in the active viewport or "
303 "to reset the stretch for all the viewports.";
304 m_globalButton->setWhatsThis(text);
305
306 QPushButton *advancedButton = new QPushButton("Advanced");
307 connect(advancedButton, SIGNAL(clicked()), this, SLOT(showAdvancedDialog()));
308
309 m_flashButton = new QPushButton("Show Global");
310 text =
311 "<b>Function:</b> While this button is pressed down, the visible stretch "
312 "will be the automatically computed stretch using the statisics from the "
313 "entire image. The original stretch is restored once you let up on this "
314 "button.";
315 m_flashButton->setWhatsThis(text);
316 connect(m_flashButton, SIGNAL(pressed()), this, SLOT(stretchChanged()));
317 connect(m_flashButton, SIGNAL(released()), this, SLOT(stretchChanged()));
318
319 // Buttons migrated out of Advanced Stretch Tool
320 QPushButton *saveToCubeButton = new QPushButton("Save");
321 connect(saveToCubeButton, SIGNAL(clicked(bool)), this, SLOT(saveStretchToCube()));
322
323 QPushButton *deleteFromCubeButton = new QPushButton("Delete");
324 connect(deleteFromCubeButton, SIGNAL(clicked(bool)), this, SLOT(deleteFromCube()));
325
326 QPushButton *loadStretchButton = new QPushButton("Restore");
327 connect(loadStretchButton, SIGNAL(clicked(bool)), this, SLOT(loadStretchFromCube()));
328
329 QHBoxLayout *layout = new QHBoxLayout(hbox);
330 layout->setMargin(0);
331 layout->addWidget(m_copyButton);
332 layout->addWidget(m_globalButton);
333 layout->addWidget(m_stretchRegionalButton);
334 layout->addWidget(m_stretchBandComboBox);
335 layout->addWidget(p_minMaxTypeSelection);
336 layout->addWidget(m_stretchMinEdit);
337 layout->addWidget(m_stretchMaxEdit);
338 layout->addWidget(advancedButton);
339 layout->addWidget(m_flashButton);
340
341 // should only display if gray stretch
342 // Save/Restore strech only supported for Grayscale images. Hide buttons if in RGB.
343 layout->addWidget(saveToCubeButton);
344 layout->addWidget(deleteFromCubeButton);
345 layout->addWidget(loadStretchButton);
346
347 layout->addStretch(); // Pushes everything else left in the menu bar
348 hbox->setLayout(layout);
349
350 return hbox;
351 }
352
353
359 if(m_advancedStretch->isVisible()) {
361
362 if(!cvp) return;
363
364 if(cvp->isGray() && !cvp->grayBuffer()->working()) {
365 if(m_advancedStretch->isRgbMode()) {
366 updateTool();
367 }
368 else {
369 Histogram hist(histFromBuffer(cvp->grayBuffer()));
370
371 if(hist.ValidPixels() > 0) {
372 m_advancedStretch->updateHistogram(hist);
373 }
374 }
375 }
376 // Otherwise it is in color mode
377 else if(!cvp->isGray() &&
378 !cvp->redBuffer()->working() &&
379 !cvp->greenBuffer()->working() &&
380 !cvp->blueBuffer()->working()) {
381 if(!m_advancedStretch->isRgbMode()) {
382 updateTool();
383 }
384 else {
385 Histogram redHist(histFromBuffer(cvp->redBuffer()));
386 Histogram grnHist(histFromBuffer(cvp->greenBuffer()));
387 Histogram bluHist(histFromBuffer(cvp->blueBuffer()));
388
389 if(redHist.ValidPixels() > 0 &&
390 grnHist.ValidPixels() > 0 &&
391 bluHist.ValidPixels() > 0) {
392 m_advancedStretch->updateHistograms(redHist, grnHist, bluHist);
393 }
394 }
395 }
396 }
397 }
398
399
407 {
408 if(m_advancedStretch->isVisible()) {
410
411 if(!cvp->isGray() &&
412 !cvp->redBuffer()->working() &&
413 !cvp->greenBuffer()->working() &&
414 !cvp->blueBuffer()->working()) {
415
416 Histogram redHist(histFromBuffer(cvp->redBuffer()));
417 Histogram grnHist(histFromBuffer(cvp->greenBuffer()));
418 Histogram bluHist(histFromBuffer(cvp->blueBuffer()));
419 Stretch redStretch(cvp->redStretch());
420 Stretch grnStretch(cvp->greenStretch());
421 Stretch bluStretch(cvp->blueStretch());
422
423 m_advancedStretch->updateForRGBMode(redStretch, redHist,
424 grnStretch, grnHist,
425 bluStretch, bluHist);
426 }
427 }
428 }
429
430
436 Cube* icube = cvp->cube();
437 Pvl* lab = icube->label();
438
439 QStringList namelist;
440
441 // Create a list of existing Stretch names
442 if (cvp->isGray()) {
444 for (objIter=lab->beginObject(); objIter<lab->endObject(); objIter++) {
445 if (objIter->name() == "Stretch") {
446 PvlKeyword tempKeyword = objIter->findKeyword("Name");
447 int bandNumber = int(objIter->findKeyword("BandNumber"));
448 if (cvp->grayBand() == bandNumber) {
449 QString tempName = tempKeyword[0];
450 namelist.append(tempName);
451 }
452 }
453 }
454 }
455 else {
456 int redBandNumber = cvp->redBand();
457 int greenBandNumber = cvp->greenBand();
458 int blueBandNumber = cvp->blueBand();
459
460 QMap<QString, QList<int>> tempNameMap;
462 for (objIter=lab->beginObject(); objIter<lab->endObject(); objIter++) {
463 if (objIter->name() == "Stretch") {
464 PvlKeyword tempKeyword = objIter->findKeyword("Name");
465 int bandNumber = int(objIter->findKeyword("BandNumber"));
466 if (bandNumber == redBandNumber || bandNumber == greenBandNumber
467 || bandNumber == blueBandNumber) {
468 QString tempName = tempKeyword[0];
469 if (tempNameMap.contains(tempName)) {
470 tempNameMap[tempName].append(bandNumber);
471 }
472 else
473 {
474 tempNameMap[tempName] = {bandNumber};
475 }
476 }
477 }
478 }
479 QMap<QString, QList<int>>::const_iterator i = tempNameMap.constBegin();
480 while (i != tempNameMap.constEnd()) {
481 if (i.value().contains(redBandNumber) && i.value().contains(greenBandNumber) &&
482 i.value().contains(blueBandNumber) ){
483 namelist.append(i.key());
484 }
485 ++i;
486 }
487 }
488
489 bool ok = false;
490 QString stretchName;
491 // Only display load stretch dialog if there are stretches saved to the cube
492 if (namelist.size() >=1) {
493 stretchName = QInputDialog::getItem((QWidget *)parent(), tr("Load Stretch"),
494 tr("Name of Stretch to Load:"), namelist, 0,
495 false, &ok);
496 }
497 else {
498 QMessageBox::information((QWidget *)parent(), "Information",
499 "There are no saved stretches to restore.");
500 }
501
502 if (ok) {
503 if (cvp->isGray()) {
504 CubeStretch cubeStretch = icube->readCubeStretch(stretchName);
505 if (m_advancedStretch->isVisible()) {
506 m_advancedStretch->restoreGrayStretch(cubeStretch);
507 }
508 // Get the current cube stretche and copy the new stretch pairs over so that the
509 // special pixel values set in the viewport are maintained.
510 CubeStretch grayOriginal = cvp->grayStretch();
511 grayOriginal.CopyPairs(cubeStretch);
512 cvp->stretchGray(grayOriginal);
513 }
514 else {
515 std::vector<PvlKeyword> keywordValueRed;
516 keywordValueRed.push_back(PvlKeyword("BandNumber", QString::number(cvp->redBand())));
517
518 std::vector<PvlKeyword> keywordValueGreen;
519 keywordValueGreen.push_back(PvlKeyword("BandNumber", QString::number(cvp->greenBand())));
520
521 std::vector<PvlKeyword> keywordValueBlue;
522 keywordValueBlue.push_back(PvlKeyword("BandNumber", QString::number(cvp->blueBand())));
523
524 CubeStretch redStretch = icube->readCubeStretch(stretchName, keywordValueRed);
525 CubeStretch greenStretch = icube->readCubeStretch(stretchName, keywordValueGreen);
526 CubeStretch blueStretch = icube->readCubeStretch(stretchName, keywordValueBlue);
527
528 if (m_advancedStretch->isVisible()) {
529 m_advancedStretch->restoreRgbStretch(redStretch, greenStretch, blueStretch);
530 }
531
532 // Get the current cube stretches and copy the new stretch pairs over so that the
533 // special pixel values set in the viewport are maintained.
534 CubeStretch redOriginal = cvp->redStretch();
535 CubeStretch greenOriginal = cvp->greenStretch();
536 CubeStretch blueOriginal = cvp->blueStretch();
537
538 redOriginal.CopyPairs(redStretch);
539 greenOriginal.CopyPairs(greenStretch);
540 blueOriginal.CopyPairs(blueStretch);
541
542 cvp->stretchRed(redOriginal);
543 cvp->stretchGreen(greenOriginal);
544 cvp->stretchBlue(blueOriginal);
545 }
546 emit stretchChanged();
547 }
548 }
549
550
556 Cube* icube = cvp->cube();
557 Pvl* lab = icube->label();
558
559 // Create a list of existing Stretch names
560 QStringList namelist;
562 for (objIter=lab->beginObject(); objIter<lab->endObject(); objIter++) {
563 if (objIter->name() == "Stretch") {
564 PvlKeyword tempKeyword = objIter->findKeyword("Name");
565 int bandNumber = int(objIter->findKeyword("BandNumber"));
566 if (cvp->grayBand() == bandNumber) {
567 QString tempName = tempKeyword[0];
568 namelist.append(tempName);
569 }
570 }
571 }
572
573 bool ok = false;
574 QString toDelete;
575 // Only display list of stretches to delete if there are stretches saved to the cube
576 if (namelist.size() >= 1) {
577 toDelete = QInputDialog::getItem((QWidget *)parent(), tr("Delete Stretch"),
578 tr("Name of Stretch to Delete:"), namelist, 0,
579 false, &ok);
580 }
581 else {
582 QMessageBox::information((QWidget *)parent(), "Information",
583 "There are no saved stretches to delete.");
584 }
585
586 if (ok) {
587 if (icube->isReadOnly()) {
588 try {
589 cvp->cube()->reopen("rw");
590 }
591 catch(IException &) {
592 cvp->cube()->reopen("r");
593 QMessageBox::information((QWidget *)parent(), "Error",
594 "Cannot open cube read/write to delete stretch");
595 return;
596 }
597 }
598
599 bool cubeDeleted = icube->deleteBlob(toDelete, "Stretch");
600
601 if (!cubeDeleted) {
602 QMessageBox msgBox;
603 msgBox.setText("Stretch Could Not Be Deleted!");
604 msgBox.setInformativeText("A stretch with name: \"" + toDelete +
605 "\" Could not be found, so there was nothing to delete from the Cube.");
606 msgBox.setStandardButtons(QMessageBox::Ok);
607 msgBox.setIcon(QMessageBox::Critical);
608 msgBox.exec();
609 }
610
611 // Don't leave open rw -- not optimal.
612 cvp->cube()->reopen("r");
613 }
614 }
615
616
622 Cube* icube = cvp->cube();
623 Pvl* lab = icube->label();
624
625 // Create a list of existing Stretch names
626 QStringList namelist;
628 for (objIter=lab->beginObject(); objIter<lab->endObject(); objIter++) {
629 if (objIter->name() == "Stretch") {
630 PvlKeyword tempKeyword = objIter->findKeyword("Name");
631 QString tempName = tempKeyword[0];
632 namelist.append(tempName);
633 }
634 }
635
636 bool ok;
637 QString name;
638
639 //
640 // At this time, it is NOT possible to save an RGB stretch with the same band number
641 // multiple times, if the saved stretch for each is different. If the saved stretch is the same
642 // this is okay.
643 //
644 // For example, r=1, g=1, b=1, with the same stretch for each is okay
645 // r=1, g=1, b=2, where the stretches for band 1 are the same, is okay
646 // r=1, g=1, b=1, where the the stretches for band 1 are different (red stretch !=
647 // green stretch)
648 //
649 if (!cvp->isGray()) {
650 CubeStretch redStretch, greenStretch, blueStretch;
651 if (m_advancedStretch->isVisible()) {
652 redStretch = m_advancedStretch->getRedStretch();
653 greenStretch = m_advancedStretch->getGrnStretch();
654 blueStretch = m_advancedStretch->getBluStretch();
655 }
656 else {
657 redStretch = cvp->redStretch();
658 greenStretch = cvp->greenStretch();
659 blueStretch = cvp->blueStretch();
660 }
661
662 int redBand = cvp->redBand();
663 int greenBand = cvp->greenBand();
664 int blueBand = cvp->blueBand();
665
666 if (((redBand == greenBand) && !(redStretch == greenStretch)) ||
667 ((redBand == blueBand) && !(redBand == blueBand)) ||
668 ((greenBand == blueBand) && !(greenBand == blueBand))) {
669 QMessageBox::information((QWidget *)parent(), "Error", "Sorry, cannot save RGB stretches which include the same band multiple times, but have different stretches for each");
670 return;
671 }
672 }
673
674 // "Get the name for the stretch" dialog
675 QString text = QInputDialog::getText(m_advancedStretch, tr("Save Stretch"),
676 tr("Enter a name to save the stretch as:"), QLineEdit::Normal,
677 "stretch", &ok);
678
679 if (ok) {
680 // Stretch Name Already Exists Dialog!
681 if (namelist.contains(text)) {
682 QMessageBox msgBox;
683 msgBox.setText(tr("Stretch Name Already Exists!"));
684 msgBox.setInformativeText("A stretch pair with name: \"" + text + "\" already exists and "
685 "the existing saved data will be overwritten. Are you sure you "
686 "wish to proceed?");
687 msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
688 msgBox.setIcon(QMessageBox::Warning);
689 msgBox.setDefaultButton(QMessageBox::Cancel);
690 int ret = msgBox.exec();
691
692 switch (ret) {
693 case QMessageBox::Save:
694 break;
695 case QMessageBox::Cancel:
696 // Cancel was clicked, exit this function
697 return;
698 break;
699 default:
700 // should never be reached
701 return;
702 break;
703 }
704 }
705
706 if (icube->isReadOnly()) {
707 // reOpen cube as read/write
708 try {
709 icube->reopen("rw");
710 }
711 catch(IException &) {
712 icube->reopen("r");
713 QMessageBox::information((QWidget *)parent(), "Error", "Cannot open cube read/write to save stretch");
714 return;
715 }
716 }
717
718 // If gray, only one stretch to save
719 if (cvp->isGray()) {
720 CubeStretch stretch;
721 if (m_advancedStretch->isVisible()) {
722 stretch = m_advancedStretch->getGrayStretch();
723 }
724 else {
725 stretch = cvp->grayStretch();
726 }
727
728 // Write single stretch to cube
729 stretch.setName(text);
730 stretch.setBandNumber(cvp->grayBand());
731
732 // Overwrite an existing stretch with the same name if it exists. The user was warned
733 // and decided to overwrite.
734 icube->write(stretch);
735 }
736 else {
737 CubeStretch redStretch, greenStretch, blueStretch;
738 if (m_advancedStretch->isVisible()) {
739 redStretch = m_advancedStretch->getRedStretch();
740 greenStretch = m_advancedStretch->getGrnStretch();
741 blueStretch = m_advancedStretch->getBluStretch();
742 }
743 else {
744 redStretch = cvp->redStretch();
745 greenStretch = cvp->greenStretch();
746 blueStretch = cvp->blueStretch();
747 }
748
749 redStretch.setName(text);
750 redStretch.setBandNumber(cvp->redBand());
751 Blob stretchBlob = redStretch.toBlob();
752 icube->write(stretchBlob, false);
753
754 greenStretch.setName(text);
755 greenStretch.setBandNumber(cvp->greenBand());
756 stretchBlob = greenStretch.toBlob();
757 icube->write(stretchBlob, false);
758
759 blueStretch.setName(text);
760 blueStretch.setBandNumber(cvp->blueBand());
761 stretchBlob = blueStretch.toBlob();
762 icube->write(stretchBlob, false);
763 }
764
765 // Don't leave open rw -- not optimal.
766 cvp->cube()->reopen("r");
767 }
768 }
769
770
777
778
785 if(m_advancedStretch->isVisible()) {
786 m_advancedStretch->enable(true);
787 //If the viewport is in gray mode
788 if(cvp->isGray() && !cvp->grayBuffer()->working()) {
789 Histogram hist(histFromBuffer(cvp->grayBuffer()));
790 Stretch stretch(cvp->grayStretch());
791 m_advancedStretch->enableGrayMode(stretch, hist);
792 }
793 //Otherwise it is in color mode
794 else if(!cvp->isGray() &&
795 !cvp->redBuffer()->working() &&
796 !cvp->greenBuffer()->working() &&
797 !cvp->blueBuffer()->working()) {
798 Histogram redHist(histFromBuffer(cvp->redBuffer()));
799 Histogram grnHist(histFromBuffer(cvp->greenBuffer()));
800 Histogram bluHist(histFromBuffer(cvp->blueBuffer()));
801 Stretch redStretch(cvp->redStretch());
802 Stretch grnStretch(cvp->greenStretch());
803 Stretch bluStretch(cvp->blueStretch());
804 m_advancedStretch->enableRgbMode(redStretch, redHist,
805 grnStretch, grnHist,
806 bluStretch, bluHist);
807 }
808 else {
809 m_advancedStretch->enable(false);
810 }
811 }
812 else {
813 m_advancedStretch->enable(false);
814 }
815 }
816
817
823 CubeViewport *cvp = cubeViewport();
824
825 if(cvp == NULL) {
826 //If the current viewport is NULL and the advanced dialog is visible, hide it
827 if(m_advancedStretch->isVisible()) {
828 m_advancedStretch->hide();
829 }
830 }
831 else {
832 if(!m_advancedStretch->enabled() ||
833 m_advancedStretch->isRgbMode() != !cvp->isGray()) {
834 setCubeViewport(cvp);
835 }
836 }
837
838 if(cvp && cvp->isGray()) {
839 m_copyBands->setEnabled(true);
840 m_stretchBandComboBox->setVisible(false);
841 m_stretchMinEdit->show();
842 m_stretchMaxEdit->show();
843 }
844 else if(cvp) {
845 m_copyBands->setEnabled(true);
846 m_stretchBandComboBox->setVisible(true);
848 }
849 else {
850 m_copyBands->setEnabled(false);
851 m_stretchBandComboBox->setVisible(false);
852 }
853
854 if(m_advancedStretch->isVisible()) {
855 m_stretchMinEdit->setEnabled(false);
856 m_stretchMaxEdit->setEnabled(false);
857 }
858 else {
859 m_stretchMinEdit->setEnabled(true);
860 m_stretchMaxEdit->setEnabled(true);
861 }
862
865 }
866
867
876 // Yeah this is a hack... but it's necessary to make this tool
877 // do anything while its not the active tool.
878 connect(cvp, SIGNAL(screenPixelsChanged()), this, SLOT(updateHistograms()));
879 QRect rect(0, 0, cvp->viewport()->width(), cvp->viewport()->height());
880
881 if(bandId == (int)Gray) {
882 if(cvp->grayBuffer() && cvp->grayBuffer()->hasEntireCube()) {
883 Stretch newStretch = cvp->grayStretch();
884 newStretch.CopyPairs(stretchBuffer(cvp->grayBuffer(), rect));
885 cvp->stretchGray(newStretch);
886 }
887 else {
888 Stretch newStretch = stretchBand(cvp, (StretchBand)bandId);
889 cvp->stretchGray(newStretch);
890 }
891 }
892 else
893 {
894 if(bandId == (int)Red || bandId == (int)All) {
895 if(cvp->redBuffer() && cvp->redBuffer()->hasEntireCube()) {
896 Stretch newStretch = cvp->redStretch();
897 newStretch.CopyPairs(stretchBuffer(cvp->redBuffer(), rect));
898 cvp->stretchRed(newStretch);
899 }
900 else {
901 Stretch newStretch = stretchBand(cvp, Red);
902 cvp->stretchRed(newStretch);
903 }
904 }
905 if(bandId == (int)Green || bandId == (int)All) {
906 if(cvp->greenBuffer() && cvp->greenBuffer()->hasEntireCube()) {
907 Stretch newStretch = cvp->greenStretch();
908 newStretch.CopyPairs(stretchBuffer(cvp->greenBuffer(), rect));
909 cvp->stretchGreen(newStretch);
910 }
911 else {
912 Stretch newStretch = stretchBand(cvp, Green);
913 cvp->stretchGreen(newStretch);
914 }
915 }
916 if(bandId == (int)Blue || bandId == (int)All) {
917 if(cvp->blueBuffer() && cvp->blueBuffer()->hasEntireCube()) {
918 Stretch newStretch = cvp->blueStretch();
919 newStretch.CopyPairs(stretchBuffer(cvp->blueBuffer(), rect));
920 cvp->stretchBlue(newStretch);
921 }
922 else {
923 Stretch newStretch = stretchBand(cvp, Blue);
924 cvp->stretchBlue(newStretch);
925 }
926 }
927 }
929 }
930
931
939 if(cvp == NULL) return;
940
941 if(m_flashButton->isDown()) {
948 }
949
950 cvp->stretchKnownGlobal();
951 return;
952 }
953 else if(m_preGlobalStretches) {
954 if(cvp->isGray()) {
956 }
957 else {
961 }
962
963 delete [] m_preGlobalStretches;
965 }
966
967 double min = 0, max = 0;
968 //If the viewport is in gray mode
969 if(cvp->isGray()) {
970 //Get the min/max from the current stretch
971 Stretch stretch = cvp->grayStretch();
972 min = stretch.Input(0);
973 max = stretch.Input(stretch.Pairs() - 1);
974 }
975
976 //Otherwise it is in color mode
977 else {
978 Stretch rstretch = cvp->redStretch();
979 Stretch gstretch = cvp->greenStretch();
980 Stretch bstretch = cvp->blueStretch();
981
982 //Get the min/max from the current stretch
983 if(m_stretchBand == Red) {
984 min = rstretch.Input(0);
985 max = rstretch.Input(rstretch.Pairs() - 1);
986 }
987 else if(m_stretchBand == Green) {
988 min = gstretch.Input(0);
989 max = gstretch.Input(gstretch.Pairs() - 1);
990 }
991 else if(m_stretchBand == Blue) {
992 min = bstretch.Input(0);
993 max = bstretch.Input(bstretch.Pairs() - 1);
994 }
995 }
996
997 //Set the min/max text fields
998 if(m_stretchBand != All || cvp->isGray()) {
999 QString strMin;
1000 strMin.setNum(min);
1001 m_stretchMinEdit->setText(strMin);
1002
1003 QString strMax;
1004 strMax.setNum(max);
1005 m_stretchMaxEdit->setText(strMax);
1006 }
1007
1008 if(m_advancedStretch->isVisible()) {
1009 if(m_stretchBand == All){
1011 }
1012 m_advancedStretch->updateStretch(cvp);
1013 }
1014 }
1015
1016
1022 CubeViewport *cvp = cubeViewport();
1023 if(cvp == NULL) return;
1024
1025 if(!m_advancedStretch->isRgbMode()) {
1026 Stretch grayStretch = cvp->grayStretch();
1027 grayStretch.ClearPairs();
1028 grayStretch.CopyPairs(m_advancedStretch->getGrayStretch());
1029 cvp->stretchGray(grayStretch);
1030
1031 // send the stretch to any ChipViewports that want to listen
1032 *m_chipViewportStretch = grayStretch;
1034 }
1035 else {
1036 Stretch redStretch = cvp->redStretch();
1037 redStretch.ClearPairs();
1038 redStretch.CopyPairs(m_advancedStretch->getRedStretch());
1039 cvp->stretchRed(redStretch);
1040
1041 Stretch grnStretch = cvp->greenStretch();
1042 grnStretch.ClearPairs();
1043 grnStretch.CopyPairs(m_advancedStretch->getGrnStretch());
1044 cvp->stretchGreen(grnStretch);
1045
1046 Stretch bluStretch = cvp->blueStretch();
1047 bluStretch.ClearPairs();
1048 bluStretch.CopyPairs(m_advancedStretch->getBluStretch());
1049 cvp->stretchBlue(bluStretch);
1050 }
1052 }
1053
1054
1061 void StretchTool::changeStretch(bool useMinMaxTypeSelection) {
1063 if(cvp == NULL) return;
1064
1065 // Set the min/max based on selected type
1066 if (useMinMaxTypeSelection) {
1067 stretchMinMaxType(cvp);
1068 }
1069
1070 // Make sure the user didn't enter bad min/max and if so fix it
1071 double min = m_stretchMinEdit->text().toDouble();
1072 double max = m_stretchMaxEdit->text().toDouble();
1073
1074 if(min >= max || m_stretchMinEdit->text() == "" ||
1075 m_stretchMaxEdit->text() == "") {
1076 updateTool();
1077 return;
1078 }
1079
1080 //The viewport is in gray mode
1081 if(cvp->isGray()) {
1082 Stretch stretch = cvp->grayStretch();
1083 stretch.ClearPairs();
1084 stretch.AddPair(min, 0.0);
1085 stretch.AddPair(max, 255.0);
1086
1087 // send the stretch to any ChipViewports that want to listen
1088 *m_chipViewportStretch = stretch;
1090
1091 cvp->stretchGray(stretch);
1092 }
1093 //Otherwise the viewport is in color mode
1094 else {
1095 Stretch redStretch = cvp->redStretch();
1096 Stretch greenStretch = cvp->greenStretch();
1097 Stretch blueStretch = cvp->blueStretch();
1098
1099 if(m_stretchBand == Red) {
1100 redStretch.ClearPairs();
1101 redStretch.AddPair(min, 0.0);
1102 redStretch.AddPair(max, 255.0);
1103 }
1104 if(m_stretchBand == Green) {
1105 greenStretch.ClearPairs();
1106 greenStretch.AddPair(min, 0.0);
1107 greenStretch.AddPair(max, 255.0);
1108 }
1109 if(m_stretchBand == Blue) {
1110 blueStretch.ClearPairs();
1111 blueStretch.AddPair(min, 0.0);
1112 blueStretch.AddPair(max, 255.0);
1113 }
1114
1115 cvp->stretchRed(redStretch);
1116 cvp->stretchGreen(greenStretch);
1117 cvp->stretchBlue(blueStretch);
1118 }
1119
1121 }
1122
1128 // Get current band
1129 int bandId = m_stretchBandComboBox->currentIndex();
1130 int bandNum = cvp->grayBand();
1131 if(bandId == (int)Red) {
1132 bandNum = cvp->redBand();
1133 }
1134 else if(bandId == (int)Green) {
1135 bandNum = cvp->greenBand();
1136 }
1137 else if(bandId == (int)Blue) {
1138 bandNum = cvp->blueBand();
1139 }
1140
1141 // Get current band statistics
1142 Statistics stats = statsFromCube(cvp->cube(), bandNum);
1143 Histogram hist = histFromCube(cvp->cube(), bandNum, stats.BestMinimum(), stats.BestMaximum());
1144
1145 // Set min/max given ComboBox selection
1146 int minMaxIndex = p_minMaxTypeSelection->currentIndex();
1147 double selectedMin = 0;
1148 double selectedMax = 0;
1149
1150 if (minMaxIndex == 0) {
1151 selectedMin = hist.Percent(0.5);
1152 selectedMax = hist.Percent(99.5);
1153 } else if (minMaxIndex == 1) {
1154 // Best
1155 selectedMin = stats.BestMinimum();
1156 selectedMax = stats.BestMaximum();
1157 } else if (minMaxIndex == 2) {
1158 // Absolute
1159 selectedMin = stats.Minimum();
1160 selectedMax = stats.Maximum();
1161 } else if (minMaxIndex == 3) {
1162 // Chebyshev
1163 selectedMin = stats.ChebyshevMinimum();
1164 selectedMax = stats.ChebyshevMaximum();
1165 }
1166
1167 QString qMin = QString::number(selectedMin);
1168 QString qMax = QString::number(selectedMax);
1169
1170 // Set the min/max text
1171 m_stretchMinEdit->setText(qMin);
1172 m_stretchMaxEdit->setText(qMax);
1173 }
1174
1175
1181 if(m_advancedStretch->isVisible()) return;
1182
1183 if(cubeViewport()) {
1184 m_advancedStretch->updateStretch(cubeViewport());
1185 m_advancedStretch->show();
1186 }
1187 updateTool();
1188 }
1189
1190
1196 CubeViewport *cvp = cubeViewport();
1197 if(cvp == NULL) return;
1198
1199 stretchGlobal(cvp);
1200 }
1201
1202
1207 CubeViewport *cvp = cubeViewport();
1208 if(cvp == NULL) return;
1209
1210 cvp->forgetStretches();
1211 stretchGlobal(cvp);
1212 }
1213
1214
1223
1224
1230 for(int i = 0; i < (int)cubeViewportList()->size(); i++) {
1231 CubeViewport *cvp = cubeViewportList()->at(i);
1232
1233 stretchGlobal(cvp);
1234 }
1235 }
1236
1237
1243 CubeViewport *cvp = cubeViewport();
1244 if(cvp == NULL) return;
1245
1246 stretchRegional(cvp);
1247 }
1248
1254 try {
1255 QRect rect(0, 0, cvp->viewport()->width(), cvp->viewport()->height());
1256
1257 stretchRect(cvp, rect);
1258 }
1259 catch (IException &e) {
1260 QString message = "Cannot stretch while the cube is still loading";
1261 QMessageBox::warning((QWidget *)parent(), "Warning", message);
1262 return;
1263 }
1264 }
1265
1266
1274 CubeViewport *cvp = cubeViewport();
1275 if(cvp == NULL) return;
1276 if(!rubberBandTool()->isValid()) return;
1277
1278 QRect rubberBandRect = rubberBandTool()->rectangle();
1279 //Return if the width or height is zero
1280 if(rubberBandRect.width() == 0 || rubberBandRect.height() == 0) return;
1281
1282 stretchRect(cvp, rubberBandRect);
1283 }
1284
1285
1293 Stretch newStretch;
1294 if(cvp->isGray()) {
1295 newStretch = cvp->grayStretch();
1296 newStretch.ClearPairs();
1297 newStretch.CopyPairs(stretchBuffer(cvp->grayBuffer(), rect));
1298 cvp->stretchGray(newStretch);
1299
1300 // send the stretch to any ChipViewports that want to listen
1301 *m_chipViewportStretch = newStretch;
1303 }
1304 else {
1306 newStretch = cvp->redStretch();
1307 newStretch.ClearPairs();
1308 newStretch.CopyPairs(stretchBuffer(cvp->redBuffer(), rect));
1309 cvp->stretchRed(newStretch);
1310 }
1312 newStretch = cvp->greenStretch();
1313 newStretch.ClearPairs();
1314 newStretch.CopyPairs(stretchBuffer(cvp->greenBuffer(), rect));
1315 cvp->stretchGreen(newStretch);
1316 }
1318 newStretch = cvp->blueStretch();
1319 newStretch.ClearPairs();
1320 newStretch.CopyPairs(stretchBuffer(cvp->blueBuffer(), rect));
1321 cvp->stretchBlue(newStretch);
1322 }
1323 if(m_stretchBand != Red && m_stretchBand != Blue &&
1326 "Unknown stretch band",
1327 _FILEINFO_);
1328 }
1329 }
1330
1332 }
1333
1334
1342 void StretchTool::mouseButtonRelease(QPoint start, Qt::MouseButton s) {
1343 CubeViewport *cvp = cubeViewport();
1344 if(cvp == NULL) return;
1345
1346 // Call the parent Tool function to reset the Warning as different activity is
1347 // taking place
1348 Tool::mouseButtonRelease(start, s);
1349
1350 if(s == Qt::RightButton) {
1351 stretchGlobal(cvp);
1352
1353 // notify any ChipViewports listening that the CubeViewport was stretched
1354 // back to global
1355 emit stretchChipViewport(NULL, cvp);
1356
1357 // Resets the RubberBandTool on screen.
1359 }
1360 }
1361
1367 rubberBandTool()->enable(RubberBandTool::RectangleMode);
1368 rubberBandTool()->setDrawActiveViewportOnly(true);
1369 }
1370
1371
1378 CubeViewport *cvp = cubeViewport();
1379 if(cvp == NULL) return;
1380
1381 double min = m_stretchMinEdit->text().toDouble();
1382 double max = m_stretchMaxEdit->text().toDouble();
1383
1384 Stretch stretch;
1385 if(cvp->isGray()) {
1386 stretch = cvp->grayStretch();
1387 stretch.ClearPairs();
1388 stretch.AddPair(min, 0.0);
1389 stretch.AddPair(max, 255.0);
1390 }
1391 else if(m_stretchBand == Red) {
1392 stretch = cvp->redStretch();
1393 stretch.ClearPairs();
1394 stretch.AddPair(min, 0.0);
1395 stretch.AddPair(max, 255.0);
1396 cvp->stretchGreen(stretch);
1397 cvp->stretchBlue(stretch);
1398 }
1399 else if(m_stretchBand == Green) {
1400 stretch = cvp->greenStretch();
1401 stretch.ClearPairs();
1402 stretch.AddPair(min, 0.0);
1403 stretch.AddPair(max, 255.0);
1404 cvp->stretchRed(stretch);
1405 cvp->stretchBlue(stretch);
1406 }
1407 else if(m_stretchBand == Blue) {
1408 stretch = cvp->blueStretch();
1409 stretch.ClearPairs();
1410 stretch.AddPair(min, 0.0);
1411 stretch.AddPair(max, 255.0);
1412 cvp->stretchRed(stretch);
1413 cvp->stretchGreen(stretch);
1414 }
1415 else {
1416 return;
1417 }
1418
1419 cvp->setAllBandStretches(stretch);
1420 }
1421
1422
1429 CubeViewport *thisViewport = cubeViewport();
1430
1431 if(thisViewport == NULL) return;
1432
1433 for(int i = 0; i < (int)cubeViewportList()->size(); i++) {
1434 CubeViewport *cvp = cubeViewportList()->at(i);
1435
1436 if(thisViewport->isGray() && cvp->isGray()) {
1437 Stretch newStretch(cvp->grayStretch());
1438 newStretch.CopyPairs(thisViewport->grayStretch());
1439 cvp->stretchGray(newStretch);
1440 }
1441 else if(!thisViewport->isGray() && !cvp->isGray()) {
1442 Stretch newStretchRed(cvp->redStretch());
1443 newStretchRed.CopyPairs(thisViewport->redStretch());
1444 cvp->stretchRed(newStretchRed);
1445
1446 Stretch newStretchGreen(cvp->greenStretch());
1447 newStretchGreen.CopyPairs(thisViewport->greenStretch());
1448 cvp->stretchGreen(newStretchGreen);
1449
1450 Stretch newStretchBlue(cvp->blueStretch());
1451 newStretchBlue.CopyPairs(thisViewport->blueStretch());
1452 cvp->stretchBlue(newStretchBlue);
1453 }
1454 else if(!thisViewport->isGray() && cvp->isGray()) {
1455 // don't copy rgb to gray
1456 }
1457 else if(thisViewport->isGray() && !cvp->isGray()) {
1458 // don't copy gray stretches to rgb
1459 }
1460 }
1461
1463 }
1464
1465
1473 //Get the statistics and histogram from the region
1474 Statistics stats = statsFromBuffer(buffer, rect);
1475 Stretch stretch;
1476 if(stats.ValidPixels() > 1 &&
1477 fabs(stats.Minimum() - stats.Maximum()) > DBL_EPSILON) {
1478 Histogram hist = histFromBuffer(buffer, rect,
1479 stats.BestMinimum(), stats.BestMaximum());
1480
1481 if(fabs(hist.Percent(0.5) - hist.Percent(99.5)) > DBL_EPSILON) {
1482 stretch.AddPair(hist.Percent(0.5), 0.0);
1483 stretch.AddPair(hist.Percent(99.5), 255.0);
1484 }
1485 }
1486
1487 if(stretch.Pairs() == 0) {
1488 stretch.AddPair(-DBL_MAX, 0.0);
1489 stretch.AddPair(DBL_MAX, 255.0);
1490 }
1491
1492 return stretch;
1493 }
1494
1495
1503
1504 int bandNum = cvp->grayBand();
1505 Stretch stretch = cvp->grayStretch();
1506 if(band == Red) {
1507 bandNum = cvp->redBand();
1508 stretch = cvp->redStretch();
1509 }
1510 else if(band == Green) {
1511 bandNum = cvp->greenBand();
1512 stretch = cvp->greenStretch();
1513 }
1514 else if(band == Blue) {
1515 bandNum = cvp->blueBand();
1516 stretch = cvp->blueStretch();
1517 }
1518
1519 Statistics stats = statsFromCube(cvp->cube(), bandNum);
1520 Histogram hist = histFromCube(cvp->cube(), bandNum,
1521 stats.BestMinimum(), stats.BestMaximum());
1522
1523 stretch.ClearPairs();
1524 if(fabs(hist.Percent(0.5) - hist.Percent(99.5)) > DBL_EPSILON) {
1525 stretch.AddPair(hist.Percent(0.5), 0.0);
1526 stretch.AddPair(hist.Percent(99.5), 255.0);
1527 }
1528 else {
1529 stretch.AddPair(-DBL_MAX, 0.0);
1530 stretch.AddPair(DBL_MAX, 255.0);
1531 }
1532
1533 return stretch;
1534 }
1535
1546 Statistics stats;
1547 Brick brick(cube->sampleCount(), 1, 1, cube->pixelType());
1548
1549 for(int line = 0; line < cube->lineCount(); line++) {
1550 brick.SetBasePosition(0, line, band);
1551 cube->read(brick);
1552 stats.AddData(brick.DoubleBuffer(), cube->sampleCount());
1553 }
1554
1555 return stats;
1556 }
1557
1558
1569 QRect rect) {
1570 if(buffer->working()) {
1572 "Cannot stretch while the cube is still loading",
1573 _FILEINFO_);
1574 }
1575
1576 QRect dataArea = QRect(buffer->bufferXYRect().intersected(rect));
1577 Statistics stats;
1578
1579 for(int y = dataArea.top();
1580 !dataArea.isNull() && y <= dataArea.bottom();
1581 y++) {
1582 const std::vector<double> &line = buffer->getLine(y - buffer->bufferXYRect().top());
1583
1584 for(int x = dataArea.left(); x < dataArea.right(); x++) {
1585 stats.AddData(line[x - buffer->bufferXYRect().left()]);
1586 }
1587 }
1588
1589 return stats;
1590 }
1591
1604 double min, double max) {
1605 Histogram hist(min, max);
1606 Brick brick(cube->sampleCount(), 1, 1, cube->pixelType());
1607
1608 for(int line = 0; line < cube->lineCount(); line++) {
1609 brick.SetBasePosition(0, line, band);
1610 cube->read(brick);
1611 hist.AddData(brick.DoubleBuffer(), cube->sampleCount());
1612 }
1613
1614 return hist;
1615 }
1616
1617
1626 Statistics stats = statsFromBuffer(buffer, buffer->bufferXYRect());
1627 return histFromBuffer(buffer, buffer->bufferXYRect(),
1628 stats.BestMinimum(), stats.BestMaximum());
1629
1630 }
1631
1632
1645 QRect rect, double min, double max) {
1646 QRect dataArea = QRect(buffer->bufferXYRect().intersected(rect));
1647
1648 try {
1649 Histogram hist(min, max);
1650
1651 for(int y = dataArea.top(); !dataArea.isNull() && y <= dataArea.bottom(); y++) {
1652 const std::vector<double> &line = buffer->getLine(y - buffer->bufferXYRect().top());
1653 hist.AddData(&line.front() + (dataArea.left() - buffer->bufferXYRect().left()), dataArea.width());
1654 }
1655
1656 return hist;
1657 }
1658 catch(IException &e) {
1659 // get the min and max DN values of the data area
1660 IString sMin(min);
1661 IString sMax(max);
1662 std::string msg = "Insufficient data Min [" + sMin + "], Max [" + sMax + "]";
1663 msg += " in the stretch area.";
1664
1665 // Emit signal to the parent tool to display Warning object with the warning message
1666 //emit warningSignal(msg, e.Errors());
1667
1668 throw IException(e, IException::Unknown, msg, _FILEINFO_);
1669 }
1670 }
1671
1672
1673
1678
1680 m_stretchBandComboBox->currentIndex()
1681 ).toInt();
1682
1683 if(m_stretchBand == All) {
1684 m_stretchMinEdit->hide();
1685 m_stretchMaxEdit->hide();
1686 }
1687 else {
1688 m_stretchMinEdit->show();
1689 m_stretchMaxEdit->show();
1690 }
1692 }
1693
1694
1716
1717
1809}
Buffer for containing a three dimensional section of an image.
Definition Brick.h:45
void SetBasePosition(const int start_sample, const int start_line, const int start_band)
This method is used to set the base position of the shape buffer.
Definition Brick.h:120
double * DoubleBuffer() const
Returns the value of the shape buffer.
Definition Buffer.h:138
IO Handler for Isis Cubes.
Definition Cube.h:168
bool deleteBlob(QString BlobName, QString BlobType)
This method will delete a blob label object from the cube as specified by the Blob type and name.
Definition Cube.cpp:1988
int lineCount() const
Definition Cube.cpp:1767
CubeStretch readCubeStretch(QString name="CubeStretch", const std::vector< PvlKeyword > keywords=std::vector< PvlKeyword >()) const
Read a Stretch from a cube.
Definition Cube.cpp:925
int sampleCount() const
Definition Cube.cpp:1840
bool isReadOnly() const
Test if the opened cube is read-only, that is write operations will fail if this is true.
Definition Cube.cpp:215
PixelType pixelType() const
Definition Cube.cpp:1791
void read(Blob &blob, const std::vector< PvlKeyword > keywords=std::vector< PvlKeyword >()) const
This method will read data from the specified Blob object.
Definition Cube.cpp:820
void write(Blob &blob, bool overwrite=true)
This method will write a blob of data (e.g.
Definition Cube.cpp:984
Pvl * label() const
Returns a pointer to the IsisLabel object associated with the cube.
Definition Cube.cpp:1734
void reopen(QString access="r")
This method will reopen an isis sube for reading or reading/writing.
Definition Cube.cpp:787
Stores stretch information for a cube.
Definition CubeStretch.h:27
void setBandNumber(int bandNumber)
Set the band number for the stretch.
void setName(QString name)
Set the Stretch name.
Isis::Blob toBlob() const
Serialize the CubeStretch to a Blob.
Widget to display Isis cubes for qt apps.
void stretchGray(const QString &string)
Apply stretch pairs to gray band.
void stretchBlue(const QString &string)
Apply stretch pairs to blue bands.
CubeStretch grayStretch() const
Return the gray band stretch.
int greenBand() const
CubeStretch redStretch() const
Return the red band stretch.
int redBand() const
ViewportBuffer * grayBuffer()
Returns the gray viewport buffer (Will be NULL if in RGB mode.)
void stretchKnownGlobal()
List<Tool *> p This stretches to the global stretch.
void stretchGreen(const QString &string)
Apply stretch pairs to green bands.
void stretchRed(const QString &string)
Apply stretch pairs to red bands.
CubeStretch greenStretch() const
Return the green band stretch.
void forgetStretches()
Resets all remembered stretches.
int grayBand() const
Cube * cube() const
ViewportBuffer * greenBuffer()
Returns the green viewport buffer (Will be NULL if in Gray mode.)
ViewportBuffer * redBuffer()
Returns the red viewport buffer (Will be NULL if in Gray mode.)
void setAllBandStretches(Stretch stretch)
Sets a stretch for all bands.
ViewportBuffer * blueBuffer()
Returns the blue viewport buffer (Will be NULL if in Gray mode.)
bool isGray() const
int blueBand() const
CubeStretch blueStretch() const
Return the blue band stretch.
Container of a cube histogram.
Definition Histogram.h:74
double Percent(const double percent) const
Computes and returns the value at X percent of the histogram.
virtual void AddData(const double *data, const unsigned int count)
Add an array of doubles to the histogram counters.
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition IException.h:126
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
Adds specific functionality to C++ strings.
Definition IString.h:165
Cube display widget for certain Isis MDI applications.
Container for cube-like labels.
Definition Pvl.h:119
A single keyword-value pair.
Definition PvlKeyword.h:87
PvlObjectIterator beginObject()
Returns the index of the beginning object.
Definition PvlObject.h:235
QList< PvlObject >::iterator PvlObjectIterator
The counter for objects.
Definition PvlObject.h:227
This class is used to accumulate statistics on double arrays.
Definition Statistics.h:93
double ChebyshevMinimum(const double percent=99.5) const
This method returns a minimum such that X percent of the data will fall with K standard deviations of...
double Minimum() const
Returns the absolute minimum double found in all data passed through the AddData method.
double BestMinimum(const double percent=99.5) const
This method returns the better of the absolute minimum or the Chebyshev minimum.
BigInt ValidPixels() const
Returns the total number of valid pixels processed.
double ChebyshevMaximum(const double percent=99.5) const
This method returns a maximum such that X percent of the data will fall with K standard deviations of...
void AddData(const double *data, const unsigned int count)
Add an array of doubles to the accumulators and counters.
double BestMaximum(const double percent=99.5) const
This method returns the better of the absolute maximum or the Chebyshev maximum.
double Maximum() const
Returns the absolute maximum double found in all data passed through the AddData method.
Pixel value mapper.
Definition Stretch.h:58
void CopyPairs(const Stretch &other)
Copies the stretch pairs from another Stretch object, but maintains special pixel values.
Definition Stretch.cpp:392
void AddPair(const double input, const double output)
Adds a stretch pair to the list of pairs.
Definition Stretch.cpp:48
double Input(const int index) const
Returns the value of the input side of the stretch pair at the specified index.
Definition Stretch.cpp:287
void ClearPairs()
Clears the stretch pairs.
Definition Stretch.h:170
int Pairs() const
Returns the number of stretch pairs.
Definition Stretch.h:162
void showAdvancedDialog()
This methods shows and updates the advanced dialog.
QAction * m_stretchGlobal
Global stretch action.
QComboBox * m_stretchBandComboBox
Stretch combo box.
QAction * m_stretchRegional
Regional stretch action.
void updateAdvStretchDialogforAll(void)
Update the streches and corresponding histograms for all the colors Red, Green and Blue for Stretch A...
void stretchRect(CubeViewport *cvp, QRect rect)
stretch the specified CubeViewport with the given rect
static Statistics statsFromBuffer(ViewportBuffer *buffer, QRect rect)
This method will calculate and return the statistics for a given region and viewport buffer.
void stretchGlobal()
Does a global stretch for the active viewport.
QAction * m_copyBands
Copy band stretch action.
void setStretchAcrossBands()
Sets the stretch for all the bands in the active viewport to the current stretch.
void stretchRegional()
Does a regional stretch for the active viewport.
void changeStretch(bool useMinMaxTypeSelection=false)
This method is called when the stretch has changed and sets the min/max text fields to the correct va...
QToolButton * m_copyButton
Copy Button.
static Histogram histFromCube(Cube *cube, int band, double min, double max)
This method will calculate and return the histogram for a given cube and band.
void screenPixelsChanged()
This is called when the visible area changes.
Stretch * m_preGlobalStretches
Stretches before global button pressed.
StretchBand m_stretchBand
Current stretch band.
QLineEdit * m_stretchMaxEdit
Max. line edit.
StretchBand
Enum to store the bands.
Definition StretchTool.h:96
@ Gray
Gray Band.
Definition StretchTool.h:97
@ Green
Green Band.
Definition StretchTool.h:99
@ Blue
Blue Band.
@ All
All Bands.
void rubberBandComplete()
This method is called when the RubberBandTool is complete.
QLineEdit * m_stretchMinEdit
Min. line edit.
static Statistics statsFromCube(Cube *cube, int band)
This method will calculate and return the statistics for a given cube and band.
void stretchRequested(MdiCubeViewport *cvp, int bandId)
The cube viewport requested a stretch at this time, give it to the viewport.
~StretchTool()
Destructor.
static Histogram histFromBuffer(ViewportBuffer *buffer)
Given a viewport buffer, this calculates a histogram.
QAction * toolPadAction(ToolPad *pad)
Adds the stretch action to the toolpad.
StretchTool(QWidget *parent)
StretchTool constructor.
void updateHistograms()
This updates the visible histograms in the advanced stretch, if present.
QComboBox * p_minMaxTypeSelection
Min/Max type combo box.
void deleteFromCube()
Deletes a saved stretch from the cube.
void addTo(QMenu *menu)
Adds the stretch action to the given menu.
void setCubeViewport(CubeViewport *)
This updates the advanced stretch to use the given viewport.
void enableRubberBandTool()
This method enables the RubberBandTool.
QToolButton * m_globalButton
Global Button.
void stretchChanged()
This method is called when the stretch has changed and sets the min/max text fields to the correct va...
void stretchGlobalAllViewports()
Does a global stretch for all the viewports.
Stretch * m_chipViewportStretch
ChipViewport's stretch.
void mouseButtonRelease(QPoint p, Qt::MouseButton s)
This method will call a global stretch if the right mouse button is released.
static Stretch stretchBuffer(ViewportBuffer *buffer, QRect rect)
This method computes the stretch over a region using the viewport buffer.
void setStretchAllViewports()
Sets the stretch for all the viewports to the current stretch in the active viewport.
AdvancedStretchDialog * m_advancedStretch
The advanced dialog.
void saveStretchToCube()
Saves a strech to the cube.
QWidget * createToolBarWidget(QStackedWidget *parent)
Creates the widget to add to the tool bar.
void stretchGlobalAllBands()
This resets the stretch across all bands.
void advancedStretchChanged()
This is called when one of the advanced stretches changed.
void updateTool()
Updates the stretch tool.
void stretchMinMaxType(CubeViewport *cvp)
Sets stretch for current band in active viewport given the min/max type selection.
void stretchChipViewport(Stretch *, CubeViewport *)
when a viewport is stretched, send the stretch and the viewport associated with it to any ChipViewpor...
void loadStretchFromCube()
Restores a saved stretch from the cube.
static Stretch stretchBand(CubeViewport *cvp, StretchBand band)
This method computes the stretch over the entire cube.
QPushButton * m_flashButton
Button to press for global stretch.
QToolButton * m_stretchRegionalButton
Regional Stretch Button.
void stretchBandChanged(int)
The selected band for stretching changed.
void warningSignal(std::string &pStr, const std::string pExStr)
Shows a warning.
Tool(QWidget *parent)
Tool constructor.
Definition Tool.cpp:27
virtual void mouseButtonRelease(QPoint p, Qt::MouseButton s)
Resets the Warning to Nowarning when a different activity occurs on the application.
Definition Tool.cpp:380
CubeViewportList * cubeViewportList() const
Return the list of cubeviewports.
Definition Tool.cpp:390
MdiCubeViewport * cubeViewport() const
Return the current cubeviewport.
Definition Tool.h:197
QString toolIconDir() const
returns the path to the icon directory.
Definition Tool.h:113
Reads and stores visible DN values.
const std::vector< double > & getLine(int line)
Retrieves a line from the buffer.
QRect bufferXYRect()
Returns a rect, in screen pixels, of the area this buffer covers.
bool hasEntireCube()
Method to see if the entire cube is in the buffer.
bool working()
This tests if queued actions exist in the viewport buffer.
This was called the Qisis MainWindow.
This is free and unencumbered software released into the public domain.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
Namespace for the standard library.