Isis 3 Programmer Reference
HistogramTool.cpp
1#include "HistogramTool.h"
2
3#include <geos/geom/Point.h>
4
5#include <QDebug>
6#include <QDockWidget>
7#include <QHBoxLayout>
8#include <QLabel>
9#include <QMessageBox>
10#include <QVBoxLayout>
11
12#include "Brick.h"
13#include "CubePlotCurve.h"
14#include "ImageHistogram.h"
15#include "Histogram.h"
16#include "HistogramItem.h"
17#include "HistogramPlotWindow.h"
18#include "MdiCubeViewport.h"
19#include "PolygonTools.h"
20#include "RubberBandComboBox.h"
21#include "ToolPad.h"
22
23
24namespace Isis {
25
32 m_action = new QAction(this);
33 m_action->setText("Histogram Tool");
34 m_action->setIcon(QPixmap(toolIconDir() + "/histogram.png"));
35 }
36
37
38
47 m_rubberBandCombo->reset();
48 m_rubberBandCombo->setEnabled(true);
49 rubberBandTool()->setDrawActiveViewportOnly(true);
50 }
51 }
52
61 QAction *action = new QAction(toolpad);
62 action->setIcon(QPixmap(toolIconDir() + "/histogram.png"));
63 action->setToolTip("Histogram (H)");
64 action->setShortcut(Qt::Key_H);
65
66 QString text =
67 "<b>Function:</b> Plot histogram in active viewport \
68 <p><b>Shortcut:</b> H</p> ";
69 action->setWhatsThis(text);
70 return action;
71 }
72
73
83 QWidget *wrapper = new QWidget;
84
89 );
90
91 QWidget *abstractToolWidgets =
93
94 QHBoxLayout *layout = new QHBoxLayout(wrapper);
95 layout->setMargin(0);
96 layout->addWidget(m_rubberBandCombo);
97 layout->addWidget(abstractToolWidgets);
98 layout->addStretch(1);
99 wrapper->setLayout(layout);
100
101 return wrapper;
102 }
103
104
109 m_frequencyItem = NULL;
110 m_percentageCurve = NULL;
111 }
112
113
121
122
128 PlotWindow *window = new HistogramPlotWindow(
129 "Histogram " + PlotWindow::defaultWindowTitle(),
130 qobject_cast<QWidget *>(parent()));
131 return window;
132 }
133
134
142 if (selectedWindow()) {
143 selectedWindow()->raise();
144 }
145
146 if(rubberBandTool()->isValid()) {
147 if (cubeViewport()->isGray()) {
148 refreshPlot();
149 }
150 else {
151 QMessageBox::information(NULL, "Error",
152 "Cannot create histogram on colored viewport",
153 QMessageBox::Ok);
154 }
155 }
156 else {
157 QMessageBox::information(NULL, "Error",
158 "The selected Area contains no valid pixels",
159 QMessageBox::Ok);
160 }
161 }
162
163
168 MdiCubeViewport *activeViewport = cubeViewport();
169
170 if (activeViewport && rubberBandTool()->isValid()) {
171 HistogramPlotWindow *targetWindow = qobject_cast<HistogramPlotWindow *>(
172 selectedWindow(true));
173
174 QList<QPoint> vertices;
175
176 if(rubberBandTool()->currentMode() == RubberBandTool::CircleMode) {
177 geos::geom::Geometry *p = rubberBandTool()->geometry();
178 geos::geom::CoordinateSequence *c = p->getCoordinates().release();
179 for(int i = 0; i < (int)c->getSize(); i++) {
180 QPoint point((int)(c->getX(i) + 0.5), (int)(c->getY(i) + 0.5));
181 vertices.append(point);
182 }
183 delete p;
184 }
185 else {
186 vertices = rubberBandTool()->vertices();
187 }
188
189 if(vertices.size() < 1) return;
190
191 Cube *cube = activeViewport->cube();
192 int band = activeViewport->grayBand();
193 std::unique_ptr<ImageHistogram> hist;
194
195 //If the rubber band is a line
196 if (rubberBandTool()->currentMode() == RubberBandTool::LineMode) {
197 double ssamp, sline, esamp, eline;
198 activeViewport->viewportToCube(vertices[0].rx(), vertices[0].ry(),
199 ssamp, sline);
200
201 activeViewport->viewportToCube(vertices[1].rx(), vertices[1].ry(),
202 esamp, eline);
203
204 QLine line((int)ssamp, (int)sline, (int)esamp, (int)eline);
205
206 double slope;
207 int i;
208 int x, y, xinc, yinc;
209 int xsize, ysize;
210
211 //Get all of the points out of the line
212 QList<QPoint *> *linePts = new QList<QPoint *>;
213
214 int sx = line.p1().x();
215 int ex = line.p2().x();
216 int sy = line.p1().y();
217 int ey = line.p2().y();
218 if(sx > ex) {
219 xsize = sx - ex + 1;
220 xinc = -1;
221 }
222 else {
223 xsize = ex - sx + 1;
224 xinc = 1;
225 }
226
227 if(sy > ey) {
228 ysize = sy - ey + 1;
229 yinc = -1;
230 }
231 else {
232 ysize = ey - sy + 1;
233 yinc = 1;
234 }
235
236 if(ysize > xsize) {
237 slope = (double)(ex - sx) / (double)(ey - sy);
238 y = sy;
239 for(i = 0; i < ysize; i++) {
240 x = (int)(slope * (double)(y - sy) + (double) sx + 0.5);
241
242 QPoint *pt = new QPoint;
243 pt->setX(x);
244 pt->setY(y);
245 linePts->push_back(pt);
246 y += yinc;
247 }
248 }
249 else if(xsize == 1) {
250 QPoint *pt = new QPoint;
251 pt->setX(sx);
252 pt->setY(sy);
253 linePts->push_back(pt);
254 }
255 else {
256 slope = (double)(ey - sy) / (double)(ex - sx);
257 x = sx;
258 for(i = 0; i < xsize; i++) {
259 y = (int)(slope * (double)(x - sx) + (double) sy + 0.5);
260
261 QPoint *pt = new QPoint;
262 pt->setX(x);
263 pt->setY(y);
264 linePts->push_back(pt);
265 x += xinc;
266 }
267 }
268
269 if(linePts->empty()) {
270 QMessageBox::information((QWidget *)parent(),
271 "Error", "No points in edit line");
272 return;
273 }
274
275 hist = std::make_unique<ImageHistogram>(ImageHistogram(*cube, band, NULL, ssamp, sline, esamp, eline));
276 Brick *brick = new Brick(*cube, 1, 1, 1);
277
278 //For each point read that value from the cube and add it to the histogram
279 for(int i = 0; linePts && i < (int)linePts->size(); i++) {
280 QPoint *pt = (*linePts)[i];
281 int is = pt->x();
282 int il = pt->y();
283 brick->SetBasePosition(is, il, band);
284 cube->read(*brick);
285 hist->AddData(brick->DoubleBuffer(), 1);
286 }
287 delete brick;
288
289 delete linePts;
290
291 }
292 //If rubber band is a rectangle
293 else if(rubberBandTool()->currentMode() == RubberBandTool::RectangleMode) {
294 double ssamp, sline, esamp, eline;
295
296 // Convert vertices to line sample values
297 activeViewport->viewportToCube(vertices[0].x(), vertices[0].y(),
298 ssamp, sline);
299
300 activeViewport->viewportToCube(vertices[2].x(), vertices[2].y(),
301 esamp, eline);
302
303 ssamp = round(ssamp);
304 sline = round(sline);
305 esamp = round(esamp);
306 eline = round(eline);
307
308 hist = std::make_unique<ImageHistogram>(ImageHistogram(*cube, band, NULL, ssamp, sline, esamp, eline));
309 int nsamps = (int)(std::fabs(esamp - ssamp) + 1);
310
311 Brick *brick = new Brick(*cube, nsamps, 1, 1);
312
313 //For each line read nsamps and add it to the histogram
314 for(int line = (int)std::min(sline, eline); line <= (int)std::max(sline, eline); line++) {
315 int isamp = std::min(ssamp,esamp);
316 brick->SetBasePosition(isamp, line, band);
317 cube->read(*brick);
318 hist->AddData(brick->DoubleBuffer(), nsamps);
319 }
320 delete brick;
321 }
322 //If rubber band is a polygon or circle
323 else {
324 geos::geom::Geometry *polygon = rubberBandTool()->geometry();
325
326 std::vector <int> x_contained, y_contained;
327 if(polygon != NULL) {
328 const geos::geom::Envelope *envelope = polygon->getEnvelopeInternal();
329 double ssamp, esamp, sline, eline;
330 activeViewport->viewportToCube((int)floor(envelope->getMinX()),
331 (int)floor(envelope->getMinY()),
332 ssamp, sline);
333 activeViewport->viewportToCube((int)ceil(envelope->getMaxX()),
334 (int)ceil(envelope->getMaxY()),
335 esamp, eline);
336
337
338 hist = std::make_unique<ImageHistogram>(ImageHistogram(*cube, band, NULL, ssamp, sline, esamp, eline));
339 for(int y = (int)sline; y <= (int)eline; y++) {
340 for(int x = (int)ssamp; x <= (int)esamp; x++) {
341 int x1, y1;
342 activeViewport->cubeToViewport(x, y, x1, y1);
343 geos::geom::Coordinate c(x1, y1);
344 geos::geom::Point *p = globalFactory->createPoint(c).release();
345 bool contains = p->within(polygon);
346 delete p;
347
348 if(contains) {
349 x_contained.push_back(x);
350 y_contained.push_back(y);
351 }
352 }
353 }
354
355 delete polygon;
356
357 Brick *brick = new Brick(*cube, 1, 1, 1);
358
359 //Read each point from the cube and add it to the histogram
360 for(unsigned int j = 0; j < x_contained.size(); j++) {
361 brick->SetBasePosition(x_contained[j], y_contained[j], band);
362 cube->read(*brick);
363 hist->AddData(brick->DoubleBuffer(), 1);
364 }
365 delete brick;
366 }
367 }
368
369
370 //Transfer data from histogram to the plotcurve
371 QVector<QPointF> binCountData;
372 QVector<QPointF> cumPctData;
373 double cumpct = 0.0;
374 for(int i = 0; i < hist->Bins(); i++) {
375 if(hist->BinCount(i) > 0) {
376 binCountData.append(QPointF(hist->BinMiddle(i), hist->BinCount(i)));
377
378 double pct = (double)hist->BinCount(i) / hist->ValidPixels() * 100.;
379 cumpct += pct;
380 cumPctData.append(QPointF(hist->BinMiddle(i), cumpct));
381 }
382 }
383
384 //p_histCurve->setData(&xarray[0],&yarray[0],xarray.size());
385
386
387 //These are all variables needed in the following for loop.
388 //----------------------------------------------
389 QVector<QwtIntervalSample> intervals(binCountData.size());
390 double maxYValue = DBL_MIN;
391 double minYValue = DBL_MAX;
392 // ---------------------------------------------
393
394 for(int y = 0; y < binCountData.size(); y++) {
395 intervals[y].interval = QwtInterval(binCountData[y].x(), binCountData[y].x() + hist->BinSize());
396
397 intervals[y].value = binCountData[y].y();
398 if(binCountData[y].y() > maxYValue) maxYValue = binCountData[y].y();
399 if(binCountData[y].y() < minYValue) minYValue = binCountData[y].y();
400 }
401
402 if (binCountData.size()) {
404 m_frequencyItem->setData(QwtIntervalSeriesData(intervals));
405// m_frequencyItem->setSource(activeViewport, vertices);
406 m_percentageCurve->setData(new QwtPointSeriesData(cumPctData));
407 m_percentageCurve->setSource(activeViewport, vertices);
408 }
409
410
411 QLabel *label = new QLabel(" Average = " + QString::number(hist->Average()) + '\n' +
412 "\n Minimum = " + QString::number(hist->Minimum()) + '\n' +
413 "\n Maximum = " + QString::number(hist->Maximum()) + '\n' +
414 "\n Stand. Dev.= " + QString::number(hist->StandardDeviation()) + '\n' +
415 "\n Variance = " + QString::number(hist->Variance()) + '\n' +
416 "\n Median = " + QString::number(hist->Median()) + '\n' +
417 "\n Mode = " + QString::number(hist->Mode()) + '\n' +
418 "\n Skew = " + QString::number(hist->Skew()), targetWindow);
419
420
421 QVBoxLayout *dockLayout = new QVBoxLayout;
422 dockLayout->addWidget(label);
423 dockLayout->addStretch();
424
425 QWidget *dockContents = new QWidget;
426 dockContents->setLayout(dockLayout);
427 targetWindow->getDockWidget()->setWidget(dockContents);
428 targetWindow->replot();
429 }
430 }
431
432
441 HistogramPlotWindow *targetWindow = qobject_cast<HistogramPlotWindow *>(
443
444 if (targetWindow) {
445 if (!m_frequencyItem) {
447 m_frequencyItem->setYAxis(QwtPlot::yRight);
448 m_frequencyItem->setColor(Qt::darkCyan);
449 m_frequencyItem->setTitle("Frequency");
450 targetWindow->add(m_frequencyItem);
451 }
452
453 QPen percentagePen(Qt::red);
454 percentagePen.setWidth(2);
455
456 if (!m_percentageCurve) {
457 m_percentageCurve = createCurve("Percentage", percentagePen,
459 m_percentageCurve->setMarkerSymbol(QwtSymbol::NoSymbol);
460 targetWindow->add(m_percentageCurve);
461 }
462 }
463 }
464}
Parent class for plotting tools which provides common functionality.
PlotWindow * selectedWindow(bool createIfNeeded=true)
Get the 'active' plot window (the window selected by the user to contain new curves).
QWidget * createToolBarWidget(QStackedWidget *parent)
This provides the standard plot tool options, such as selecting an active plot window.
virtual void updateTool()
This forwards all update calls to the plot windows.
static CubePlotCurve * createCurve(QString name, QPen pen, PlotCurve::Units xUnits, PlotCurve::Units yUnits)
This is a helper method for children.
Buffer for containing a three dimensional section of an image.
Definition Brick.h:45
IO Handler for Isis Cubes.
Definition Cube.h:168
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:813
This is the (qwt) plot item for a histogram.
QAction * toolPadAction(ToolPad *pad)
This method adds the histogram tool to the tool pad.
void updateTool()
This method updates the histogram tool.
void rubberBandComplete()
Called when the user has finished drawing with the rubber band.
HistogramTool(QWidget *parent)
Constructor creates a new HistogramTool object.
void enableRubberBandTool()
This method is called when the tool is activated by the parent, or when the plot mode is changed.
QPointer< HistogramItem > m_frequencyItem
This is the qwt plot item which draws the histogram frequency bars.
QWidget * createToolBarWidget(QStackedWidget *parent)
This method creates the widgets for the tool bar.
QPointer< RubberBandComboBox > m_rubberBandCombo
This combo box is for various rubber band selection types.
void validatePlotCurves()
This method sets up the names, line style, and color of the all the plot items that will be used in t...
void detachCurves()
Forget the frequency histogram item and the percentage curve.
QPointer< CubePlotCurve > m_percentageCurve
This plot curve indicates the data percentage over the histogram.
QAction * m_action
This is the action that activates this tool.
void refreshPlot()
This method plots the selected data in a histogram window.
PlotWindow * createWindow()
This method creates the default histogram plot window.
Container of a cube histogram.
Cube display widget for certain Isis MDI applications.
@ CubeDN
The data is a Cube DN value.
Definition PlotCurve.h:67
@ Percentage
The data is a percentage (0-100).
Definition PlotCurve.h:75
static QString defaultWindowTitle()
This is the typical suffix for plot windows, it's here in case we want to update all plot windows to ...
Combo box for choosing a rubber band type.
geos::geom::Geometry * geometry()
void setDrawActiveViewportOnly(bool activeOnly=false)
This called to set whether rubber band is drawn on active viewport only rather than all linked viewpo...
QList< QPoint > vertices()
This method returns the vertices.
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
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16