USGS

Isis 3.0 Object Programmers' Reference

Home

StatisticsTool.cpp
1 #include "StatisticsTool.h"
2 
3 #include <QCheckBox>
4 #include <QDebug>
5 #include <QDialog>
6 #include <QGroupBox>
7 #include <QHBoxLayout>
8 #include <QIntValidator>
9 #include <QLabel>
10 #include <QLineEdit>
11 #include <QMouseEvent>
12 #include <QPainter>
13 #include <QRadioButton>
14 #include <QScrollArea>
15 #include <QScrollBar>
16 #include <QStackedWidget>
17 #include <QSlider>
18 #include <QToolButton>
19 
20 #include "Brick.h"
21 #include "MdiCubeViewport.h"
22 #include "ToolPad.h"
23 
24 namespace Isis {
25 
32  p_boxSamps = 3;
33  p_boxLines = 3;
34 
35  p_ulSamp = -1;
36  p_ulLine = -1;
37 
38  p_set = false;
39 
40  p_dialog = new QDialog(parent);
41  p_dialog->setWindowTitle("Statistics");
42 
43  p_visualBox = new QGroupBox("Visual Display");
44 
45  p_visualScroll = new QScrollArea;
46  p_visualScroll->setBackgroundRole(QPalette::Dark);
47 
49  p_visualDisplay->setObjectName("dnDisplay");
50 
51  QCheckBox *checkBox = new QCheckBox("Hide Display");
52  connect(checkBox, SIGNAL(toggled(bool)), this, SLOT(hideDisplay(bool)));
53 
54  QLabel *boxLabel = new QLabel("Box Size:");
55  p_boxLabel = new QLabel;
56  QString samps, lines;
57  samps.setNum(p_boxSamps);
58  lines.setNum(p_boxLines);
59  p_boxLabel->setText(samps + "x" + lines);
60 
61  QHBoxLayout *boxLabelLayout = new QHBoxLayout;
62 
63  boxLabelLayout->addWidget(checkBox);
64  boxLabelLayout->addStretch(1);
65  boxLabelLayout->addWidget(boxLabel);
66  boxLabelLayout->addWidget(p_boxLabel);
67 
68  QSlider *slider = new QSlider(Qt::Vertical);
69  slider->setRange(2, 18);
70  slider->setSliderPosition(10);
71  slider->setSingleStep(1);
72  slider->setTickInterval(1);
73  slider->setTickPosition(QSlider::TicksBelow);
74  connect(slider, SIGNAL(valueChanged(int)), p_visualDisplay, SLOT(setBoxSize(int)));
75  connect(slider, SIGNAL(valueChanged(int)), this, SLOT(resizeScrollbars()));
76  p_visualScroll->setWidget(p_visualDisplay);
77 
78  QGroupBox *displayMode = new QGroupBox("Display Mode");
79  QRadioButton *displayText = new QRadioButton("Show Text");
80  displayText->setToolTip("Display the pixels of a region as text");
81  QRadioButton *displayPixels = new QRadioButton("Show Pixel Values");
82  displayPixels->setToolTip("Display the pixels of a region");
83  QRadioButton *displayDeviation = new QRadioButton("Show Deviation");
84  displayDeviation->setToolTip("Display standard deviation over a region,\n where red denotes a larger deviation");
85 
86  QHBoxLayout *displayModeLayout = new QHBoxLayout;
87  displayModeLayout->addWidget(displayText);
88  displayModeLayout->addWidget(displayPixels);
89  displayModeLayout->addWidget(displayDeviation);
90 
91  displayMode->setLayout(displayModeLayout);
92 
93  connect(displayText, SIGNAL(toggled(bool)), p_visualDisplay, SLOT(showText(bool)));
94  connect(displayText, SIGNAL(toggled(bool)), slider, SLOT(setDisabled(bool)));
95  connect(displayPixels, SIGNAL(toggled(bool)), p_visualDisplay, SLOT(showPixels(bool)));
96  connect(displayDeviation, SIGNAL(toggled(bool)), p_visualDisplay, SLOT(showDeviation(bool)));
97 
98  displayText->setChecked(true);
99 
100  QHBoxLayout *visualHBoxLayout = new QHBoxLayout;
101  visualHBoxLayout->addWidget(p_visualScroll);
102  visualHBoxLayout->addWidget(slider);
103 
104  QVBoxLayout *visualVBoxLayout = new QVBoxLayout;
105  visualVBoxLayout->addLayout(visualHBoxLayout);
106  visualVBoxLayout->addWidget(displayMode);
107 
108  p_visualBox->setLayout(visualVBoxLayout);
109 
110  QGroupBox *statsBox = new QGroupBox("Statistics");
111 
112  p_minLabel = new QLabel("Minimum: n/a");
113  p_minLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
114  p_minLabel->setLineWidth(1);
115  p_minLabel->setMargin(10);
116  p_minLabel->setAlignment(Qt::AlignLeft);
117 
118  p_maxLabel = new QLabel("Maximum: n/a");
119  p_maxLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
120  p_maxLabel->setLineWidth(1);
121  p_maxLabel->setMargin(10);
122  p_maxLabel->setAlignment(Qt::AlignLeft);
123 
124  p_avgLabel = new QLabel("Average: n/a");
125  p_avgLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
126  p_avgLabel->setLineWidth(1);
127  p_avgLabel->setMargin(10);
128  p_avgLabel->setAlignment(Qt::AlignLeft);
129 
130  p_stdevLabel = new QLabel("Standard Dev: n/a");
131  p_stdevLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
132  p_stdevLabel->setLineWidth(1);
133  p_stdevLabel->setMargin(10);
134  p_stdevLabel->setAlignment(Qt::AlignLeft);
135 
136  p_dnLabel = new QLabel("DN: n/a");
137  QFont labelFont = p_dnLabel->font();
138  labelFont.setPointSize(8);
139  p_dnLabel->setFont(labelFont);
140  p_dnLabel->setAlignment(Qt::AlignRight);
141  connect(p_visualDisplay, SIGNAL(setDn(QString)), p_dnLabel, SLOT(setText(QString)));
142 
143  p_sampLabel = new QLabel("Sample: n/a");
144  p_sampLabel->setFont(labelFont);
145  p_sampLabel->setAlignment(Qt::AlignLeft);
146  connect(p_visualDisplay, SIGNAL(setSample(QString)), p_sampLabel, SLOT(setText(QString)));
147 
148  p_lineLabel = new QLabel("Line: n/a");
149  p_lineLabel->setFont(labelFont);
150  p_lineLabel->setAlignment(Qt::AlignCenter);
151  connect(p_visualDisplay, SIGNAL(setLine(QString)), p_lineLabel, SLOT(setText(QString)));
152 
153  QGridLayout *statsLayout = new QGridLayout;
154  statsLayout->addWidget(p_minLabel, 0, 0, 1, 2);
155  statsLayout->addWidget(p_maxLabel, 1, 0, 1, 2);
156  statsLayout->addWidget(p_avgLabel, 0, 2, 1, 2);
157  statsLayout->addWidget(p_stdevLabel, 1, 2, 1, 2);
158  statsLayout->addWidget(p_sampLabel, 2, 0);
159  statsLayout->addWidget(p_lineLabel, 2, 1, 1, 2);
160  statsLayout->addWidget(p_dnLabel, 2, 3);
161 
162  statsBox->setLayout(statsLayout);
163 
164  QVBoxLayout *dialogLayout = new QVBoxLayout;
165  dialogLayout->addLayout(boxLabelLayout);
166  dialogLayout->addWidget(p_visualBox);
167  dialogLayout->addWidget(statsBox);
168 
169  p_dialog->setLayout(dialogLayout);
170 
171  checkBox->setChecked(true);
172  }
173 
182  QAction *action = new QAction("Statistics", toolpad);
183  action->setIcon(QPixmap(toolIconDir() + "/statistics.png"));
184  action->setToolTip("Statistics");
185  QObject::connect(action, SIGNAL(activated()), p_dialog, SLOT(show()));
186 
187  QString text = "";
188 
189  action->setWhatsThis(text);
190  return action;
191  }
192 
200  QWidget *StatisticsTool::createToolBarWidget(QStackedWidget *parent) {
201  QWidget *hbox = new QWidget(parent);
202 
203  QIntValidator *ival = new QIntValidator(hbox);
204  ival->setRange(1, 100);
205 
206  QLabel *sampleLabel = new QLabel("Box Samples:");
207  p_sampsEdit = new QLineEdit(hbox);
208  p_sampsEdit->setValidator(ival);
209  p_sampsEdit->setMaximumWidth(50);
210 
211  QString samps;
212  samps.setNum(p_boxSamps);
213 
214  p_sampsEdit->setText(samps);
215  connect(p_sampsEdit, SIGNAL(editingFinished()), this, SLOT(changeBoxSamples()));
216 
217  QLabel *lineLabel = new QLabel("Box Lines:");
218  p_linesEdit = new QLineEdit(hbox);
219  p_linesEdit->setValidator(ival);
220  p_linesEdit->setMaximumWidth(50);
221 
222  QString lines;
223  lines.setNum(p_boxLines);
224 
225  p_linesEdit->setText(lines);
226  connect(p_linesEdit, SIGNAL(editingFinished()), this, SLOT(changeBoxLines()));
227 
228  QToolButton *showButton = new QToolButton();
229  showButton->setText("Show");
230  showButton->setToolTip("");
231  QString text = "";
232  showButton->setWhatsThis(text);
233 
234  connect(showButton, SIGNAL(clicked()), p_dialog, SLOT(show()));
235 
236  QHBoxLayout *layout = new QHBoxLayout;
237  layout->setMargin(0);
238  layout->addWidget(sampleLabel);
239  layout->addWidget(p_sampsEdit);
240  layout->addWidget(lineLabel);
241  layout->addWidget(p_linesEdit);
242  layout->addWidget(showButton);
243  layout->addStretch(1);
244  hbox->setLayout(layout);
245  return hbox;
246  }
247 
254  void StatisticsTool::mouseButtonRelease(QPoint p, Qt::MouseButton s) {
255  if(s == Qt::LeftButton) {
256  getStatistics(p);
257  }
258  }
259 
265  void StatisticsTool::hideDisplay(bool hide) {
266  if(hide) {
267  p_visualBox->hide();
268  p_sampLabel->hide();
269  p_lineLabel->hide();
270  p_dnLabel->hide();
271 
272  p_dialog->setMinimumSize(350, 165);
273  p_dialog->resize(350, 165);
274  }
275  else {
276  p_visualBox->show();
277  p_sampLabel->show();
278  p_lineLabel->show();
279  p_dnLabel->show();
280 
281  p_dialog->setMinimumSize(565, 765);
282  p_dialog->resize(565, 765);
283  }
284  }
285 
293  MdiCubeViewport *cvp = cubeViewport();
294  if(cvp == NULL) return;
295 
296  double sample, line;
297  cvp->viewportToCube(p.x(), p.y(), sample, line);
298 
299  // If we are outside of the cube, do nothing
300  if((sample < 0.5) || (line < 0.5) ||
301  (sample > cvp->cubeSamples() + 0.5) || (line > cvp->cubeLines() + 0.5)) {
302  return;
303  }
304 
305  int isamp = (int)(sample + 0.5);
306  int iline = (int)(line + 0.5);
307 
308  Statistics stats;
309  Brick *brick = new Brick(1, 1, 1, cvp->cube()->pixelType());
310 
311 
313 
314  double lineDiff = p_boxLines / 2.0;
315  double sampDiff = p_boxSamps / 2.0;
316 
317  p_ulSamp = isamp - (int)floor(sampDiff);
318  p_ulLine = iline - (int)floor(lineDiff);
319 
320  int x, y;
321 
322  y = p_ulLine;
323 
324  for(int i = 0; i < p_boxLines; i++) {
325  x = p_ulSamp;
326  if(y < 1 || y > cvp->cubeLines()) {
327  y++;
328  continue;
329  }
330  for(int j = 0; j < p_boxSamps; j++) {
331  if(x < 1 || x > cvp->cubeSamples()) {
332  x++;
333  continue;
334  }
335  brick->SetBasePosition(x, y, cvp->grayBand());
336  cvp->cube()->read(*brick);
337  stats.AddData(brick->at(0));
338  pixelData[i][j] = brick->at(0);
339 
340  x++;
341  }
342  y++;
343  }
344 
346 
347  if (stats.ValidPixels()) {
348  p_minLabel->setText(QString("Minimum: %1").arg(stats.Minimum()));
349  p_maxLabel->setText(QString("Maximum: %1").arg(stats.Maximum()));
350  p_avgLabel->setText(QString("Average: %1").arg(stats.Average()));
351  p_stdevLabel->setText(QString("Standard Dev: %1").arg(stats.StandardDeviation(), 0, 'f', 6));
352  }
353  else {
354  p_minLabel->setText(QString("Minimum: n/a"));
355  p_maxLabel->setText(QString("Maximum: n/a"));
356  p_avgLabel->setText(QString("Average: n/a"));
357  p_stdevLabel->setText(QString("Standard Dev: n/a"));
358  }
359 
360  p_set = true;
361 
363  }
364 
370  QString samps = p_sampsEdit->text();
371  if(samps != "" && samps.toInt() != p_boxSamps && samps.toInt() > 0) {
372  p_boxSamps = samps.toInt();
373  QString lines;
374  lines.setNum(p_boxLines);
375  p_boxLabel->setText(samps + "x" + lines);
376 
378 
379  p_set = false;
380 
382  }
383  }
384 
390  QString lines = p_linesEdit->text();
391  if(lines != "" && lines.toInt() != p_boxLines && lines.toInt() > 0) {
392  p_boxLines = lines.toInt();
393  QString samps;
394  samps.setNum(p_boxSamps);
395  p_boxLabel->setText(samps + "x" + lines);
396 
398 
399  p_set = false;
400 
402  }
403  }
404 
410  QScrollBar *hbar = p_visualScroll->horizontalScrollBar();
411  QScrollBar *vbar = p_visualScroll->verticalScrollBar();
412  hbar->setSliderPosition((hbar->maximum() + hbar->minimum()) / 2);
413  vbar->setSliderPosition((vbar->maximum() + vbar->minimum()) / 2);
414  }
415 
422  p_boxSamps(3),
423  p_boxLines(3),
424  p_boxWidth(20),
425  p_boxHeight(20),
426  p_oldWidth(20),
427  p_oldHeight(20),
428  p_ulSamp(-1),
429  p_ulLine(-1),
430  p_set(false),
431  p_showText(true),
432  p_showPixels(false),
433  p_showDeviation(false) {
434 
435  p_stretch.SetNull(0.0);
436  p_stretch.SetLis(0.0);
437  p_stretch.SetLrs(0.0);
438  p_stretch.SetHis(255.0);
439  p_stretch.SetHrs(255.0);
440  p_stretch.SetMinimum(0.0);
441  p_stretch.SetMaximum(255.0);
443  paintPixmap();
444  setMouseTracking(true);
445  setBackgroundRole(QPalette::Dark);
446  setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
447  }
448 
455  QSize VisualDisplay::sizeHint() const {
456  return QSize(460, 460);
457  }
458 
464  void VisualDisplay::setSamples(int samps) {
465  p_boxSamps = samps;
467  p_stats.Reset();
468 
469  p_set = false;
470  updateSize();
471  }
472 
478  void VisualDisplay::setLines(int lines) {
479  p_boxLines = lines;
481  p_stats.Reset();
482 
483  p_set = false;
484  updateSize();
485  }
486 
492  void VisualDisplay::setBoxSize(int size) {
493  p_boxWidth = 2 * size;
494  p_boxHeight = 2 * size;
497  updateSize();
498  }
499 
505  if(p_boxSamps > this->sizeHint().width() / p_boxWidth) {
506  resize(this->sizeHint().width() + (p_boxWidth * (p_boxSamps - this->sizeHint().width() / p_boxWidth)), this->size().height());
507  }
508  else {
509  resize(this->sizeHint().width(), this->size().height());
510  }
511 
512  if(p_boxLines > this->sizeHint().height() / p_boxHeight) {
513  resize(this->size().width(), this->sizeHint().height() + (p_boxHeight * (p_boxLines - this->sizeHint().height() / p_boxHeight)));
514  }
515  else {
516  resize(this->size().width(), this->sizeHint().height());
517  }
518 
519  paintPixmap();
520  update();
521  }
522 
528  void VisualDisplay::showText(bool b) {
529  p_showText = b;
530  if(b) {
533  p_boxWidth = 100;
534  p_boxHeight = 20;
535  updateSize();
536  }
537  }
538 
539 
546  p_showPixels = b;
547  if(b) {
551  }
552  updateSize();
553  }
554  }
555 
562  p_showDeviation = b;
563  if(b) {
567  }
568  updateSize();
569  }
570  }
571 
579  void VisualDisplay::setPixelData(QVector<QVector<double> > data, int samp, int line) {
580  p_pixelData = data;
581  p_ulSamp = samp;
582  p_ulLine = line;
583 
584  p_stats.Reset();
585 
586  for(int i = 0; i < data.size(); i++) {
587  for(int j = 0; j < data[i].size(); j++) {
588  if(p_ulSamp + j < 0 || p_ulLine + i < 0) continue;
589  p_stats.AddData(data[i][j]);
590  }
591  }
592 
593  if(fabs(p_stats.BestMinimum()) < DBL_MAX && fabs(p_stats.BestMaximum()) < DBL_MAX) {
595  for(int i = 0; i < data.size(); i++) {
596  hist.AddData(data[i].data(), data[i].size());
597  }
598 
600  if(hist.Percent(0.5) != hist.Percent(99.5)) {
601  p_stretch.AddPair(hist.Percent(0.5), 0.0);
602  p_stretch.AddPair(hist.Percent(99.5), 255.0);
603  }
604  else {
605  p_stretch.AddPair(-DBL_MAX, 0.0);
606  p_stretch.AddPair(DBL_MAX, 255.0);
607  }
608  }
609  else {
611  p_stretch.AddPair(-DBL_MAX, 0.0);
612  p_stretch.AddPair(DBL_MAX, 255.0);
613  }
614 
615  p_set = true;
616  paintPixmap();
617  }
618 
625  p_pixmap.fill();
626  QPainter p(&p_pixmap);
627  QRect rect(0, 0, p_boxWidth, p_boxHeight);
628 
629  int midX = p_pixmap.width() / 2 - ((p_boxWidth / 2) * (p_boxSamps % 2));
630  int midY = p_pixmap.height() / 2 - ((p_boxHeight / 2) * (p_boxLines % 2));
631 
632  int x, y;
633  y = 0;
634 
635  for(int i = 0; i < p_boxLines; i++) {
636  x = 0;
637  for(int j = 0; j < p_boxSamps; j++) {
638  double dn = p_pixelData[i][j];
639  QColor c;
641  if(p_showDeviation) {
642  if(!IsSpecial(dn) && p_stats.TotalPixels() > 0 && p_stats.StandardDeviation() != 0) {
643  double diff;
644 
645  if(dn < p_stats.Average()) {
646  diff = p_stats.Average() - dn;
647  diff /= p_stats.Average() - p_stats.Minimum();
648  }
649  else {
650  diff = dn - p_stats.Average();
651  diff /= p_stats.Maximum() - p_stats.Average();
652  }
653 
654  int i = (int)(diff * 255.0);
655  c = QColor(i, 255 - i, 0);
656  }
657  else {
658  c = QColor(0, 0, 0);
659  }
660  }
661  else {
662  double visualValue = p_stretch.Map(dn);
663 
664  c = QColor(visualValue, visualValue, visualValue);
665  }
666  }
667  p.save();
668  p.translate(x, y);
669 
670  if(p_showText) {
671  p.drawRect(rect);
672 
673  if (!IsSpecial(dn))
674  p.drawText(rect, Qt::AlignCenter, QString::number(dn));
675  else
676  p.drawText(rect, Qt::AlignCenter, PixelToString(dn));
677  }
678  else {
679  p.fillRect(rect, c);
680  }
681 
682  p.restore();
683  x += p_boxWidth;
684  }
685  y += p_boxHeight;
686  }
687 
688  p.setPen(QPen(Qt::red, 1));
689  p.save();
690  p.translate(midX, midY);
691  p.drawRect(rect);
692  p.restore();
693  update();
694  }
695 
701  void VisualDisplay::paintEvent(QPaintEvent *event) {
702 
703  QPainter painter(this);
704 
705  int midX = width() / 2 - (p_boxWidth * (int)floor(p_boxSamps / 2) + (p_boxWidth / 2));
706  int midY = height() / 2 - (p_boxHeight * (int)floor(p_boxLines / 2) + (p_boxHeight / 2));
707 
708  painter.drawPixmap(midX, midY, p_pixmap);
709  }
710 
716  void VisualDisplay::mouseMoveEvent(QMouseEvent *event) {
717  double startX = width() / 2 - (p_boxWidth * (int)floor(p_boxSamps / 2) + (p_boxWidth / 2));
718  double startY = height() / 2 - (p_boxHeight * (int)floor(p_boxLines / 2) + (p_boxHeight / 2));
719 
720  int x = (int)ceil((event->x() - startX) / p_boxWidth);
721  int y = (int)ceil((event->y() - startY) / p_boxHeight);
722 
723  if(!p_set || x < 1 || y < 1 || x > p_boxSamps || y > p_boxLines) {
724  emit setSample("Sample: n/a");
725  emit setLine("Line: n/a");
726  emit setDn("DN: n/a");
727  }
728  else {
729  emit setSample(QString("Sample: %1").arg(p_ulSamp + x - 1));
730  emit setLine(QString("Line: %1").arg(p_ulLine + y - 1));
731  double dn = p_pixelData[y-1][x-1];
732  if(IsSpecial(dn))
733  emit setDn(QString("DN: %1").arg(PixelToString(dn)));
734  else
735  emit setDn(QString("DN: %1").arg(dn));
736  }
737  }
738 
744  void VisualDisplay::leaveEvent(QEvent *event) {
745  emit setSample("Sample: n/a");
746  emit setLine("Line: n/a");
747  emit setDn("DN: n/a");
748  }
749 }