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 ImageHistogram hist(*cube, band);
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 Brick *brick = new Brick(*cube, 1, 1, 1);
276
277 //For each point read that value from the cube and add it to the histogram
278 for(int i = 0; linePts && i < (int)linePts->size(); i++) {
279 QPoint *pt = (*linePts)[i];
280 int is = pt->x();
281 int il = pt->y();
282 brick->SetBasePosition(is, il, band);
283 cube->read(*brick);
284 hist.AddData(brick->DoubleBuffer(), 1);
285 }
286 delete brick;
287
288 delete linePts;
289
290 }
291 //If rubber band is a rectangle
292 else if(rubberBandTool()->currentMode() == RubberBandTool::RectangleMode) {
293 double ssamp, sline, esamp, eline;
294
295 // Convert vertices to line sample values
296 activeViewport->viewportToCube(vertices[0].x(), vertices[0].y(),
297 ssamp, sline);
298
299 activeViewport->viewportToCube(vertices[2].x(), vertices[2].y(),
300 esamp, eline);
301
302 ssamp = round(ssamp);
303 sline = round(sline);
304 esamp = round(esamp);
305 eline = round(eline);
306
307 int nsamps = (int)(std::fabs(esamp - ssamp) + 1);
308
309 Brick *brick = new Brick(*cube, nsamps, 1, 1);
310
311 //For each line read nsamps and add it to the histogram
312 for(int line = (int)std::min(sline, eline); line <= (int)std::max(sline, eline); line++) {
313 int isamp = std::min(ssamp,esamp);
314 brick->SetBasePosition(isamp, line, band);
315 cube->read(*brick);
316 hist.AddData(brick->DoubleBuffer(), nsamps);
317 }
318 delete brick;
319 }
320 //If rubber band is a polygon or circle
321 else {
322 geos::geom::Geometry *polygon = rubberBandTool()->geometry();
323
324 std::vector <int> x_contained, y_contained;
325 if(polygon != NULL) {
326 const geos::geom::Envelope *envelope = polygon->getEnvelopeInternal();
327 double ssamp, esamp, sline, eline;
328 activeViewport->viewportToCube((int)floor(envelope->getMinX()),
329 (int)floor(envelope->getMinY()),
330 ssamp, sline);
331 activeViewport->viewportToCube((int)ceil(envelope->getMaxX()),
332 (int)ceil(envelope->getMaxY()),
333 esamp, eline);
334
335
336 for(int y = (int)sline; y <= (int)eline; y++) {
337 for(int x = (int)ssamp; x <= (int)esamp; x++) {
338 int x1, y1;
339 activeViewport->cubeToViewport(x, y, x1, y1);
340 geos::geom::Coordinate c(x1, y1);
341 geos::geom::Point *p = globalFactory->createPoint(c).release();
342 bool contains = p->within(polygon);
343 delete p;
344
345 if(contains) {
346 x_contained.push_back(x);
347 y_contained.push_back(y);
348 }
349 }
350 }
351
352 delete polygon;
353
354 Brick *brick = new Brick(*cube, 1, 1, 1);
355
356 //Read each point from the cube and add it to the histogram
357 for(unsigned int j = 0; j < x_contained.size(); j++) {
358 brick->SetBasePosition(x_contained[j], y_contained[j], band);
359 cube->read(*brick);
360 hist.AddData(brick->DoubleBuffer(), 1);
361 }
362 delete brick;
363 }
364 }
365
366
367 //Transfer data from histogram to the plotcurve
368 QVector<QPointF> binCountData;
369 QVector<QPointF> cumPctData;
370 double cumpct = 0.0;
371 for(int i = 0; i < hist.Bins(); i++) {
372 if(hist.BinCount(i) > 0) {
373 binCountData.append(QPointF(hist.BinMiddle(i), hist.BinCount(i)));
374
375 double pct = (double)hist.BinCount(i) / hist.ValidPixels() * 100.;
376 cumpct += pct;
377 cumPctData.append(QPointF(hist.BinMiddle(i), cumpct));
378 }
379 }
380
381 //p_histCurve->setData(&xarray[0],&yarray[0],xarray.size());
382
383
384 //These are all variables needed in the following for loop.
385 //----------------------------------------------
386 QVector<QwtIntervalSample> intervals(binCountData.size());
387 double maxYValue = DBL_MIN;
388 double minYValue = DBL_MAX;
389 // ---------------------------------------------
390
391 for(int y = 0; y < binCountData.size(); y++) {
392 intervals[y].interval = QwtInterval(binCountData[y].x(), binCountData[y].x() + hist.BinSize());
393
394 intervals[y].value = binCountData[y].y();
395 if(binCountData[y].y() > maxYValue) maxYValue = binCountData[y].y();
396 if(binCountData[y].y() < minYValue) minYValue = binCountData[y].y();
397 }
398
399 if (binCountData.size()) {
401 m_frequencyItem->setData(QwtIntervalSeriesData(intervals));
402// m_frequencyItem->setSource(activeViewport, vertices);
403 m_percentageCurve->setData(new QwtPointSeriesData(cumPctData));
404 m_percentageCurve->setSource(activeViewport, vertices);
405 }
406
407
408 QLabel *label = new QLabel(" Average = " + QString::number(hist.Average()) + '\n' +
409 "\n Minimum = " + QString::number(hist.Minimum()) + '\n' +
410 "\n Maximum = " + QString::number(hist.Maximum()) + '\n' +
411 "\n Stand. Dev.= " + QString::number(hist.StandardDeviation()) + '\n' +
412 "\n Variance = " + QString::number(hist.Variance()) + '\n' +
413 "\n Median = " + QString::number(hist.Median()) + '\n' +
414 "\n Mode = " + QString::number(hist.Mode()) + '\n' +
415 "\n Skew = " + QString::number(hist.Skew()), targetWindow);
416
417
418 QVBoxLayout *dockLayout = new QVBoxLayout;
419 dockLayout->addWidget(label);
420 dockLayout->addStretch();
421
422 QWidget *dockContents = new QWidget;
423 dockContents->setLayout(dockLayout);
424 targetWindow->getDockWidget()->setWidget(dockContents);
425 targetWindow->replot();
426 }
427 }
428
429
438 HistogramPlotWindow *targetWindow = qobject_cast<HistogramPlotWindow *>(
440
441 if (targetWindow) {
442 if (!m_frequencyItem) {
444 m_frequencyItem->setYAxis(QwtPlot::yRight);
445 m_frequencyItem->setColor(Qt::darkCyan);
446 m_frequencyItem->setTitle("Frequency");
447 targetWindow->add(m_frequencyItem);
448 }
449
450 QPen percentagePen(Qt::red);
451 percentagePen.setWidth(2);
452
453 if (!m_percentageCurve) {
454 m_percentageCurve = createCurve("Percentage", percentagePen,
456 m_percentageCurve->setMarkerSymbol(QwtSymbol::NoSymbol);
457 targetWindow->add(m_percentageCurve);
458 }
459 }
460 }
461}
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