From b953e984b66ddd2cd8bcebd1f744c0dc650ba868 Mon Sep 17 00:00:00 2001 From: Amy Stamile <74275278+amystamile-usgs@users.noreply.github.com> Date: Fri, 23 Apr 2021 13:41:09 -0700 Subject: [PATCH] Fixed hist outputs to N/A when all DNs are special pixels (#4412) * Updated bad stats to NA. * Added gtests and removed old makefile tests. * Updated changelog. * Addressed PR feedback --- CHANGELOG.md | 1 + isis/src/base/apps/hist/hist.cpp | 277 +++++++++++++ isis/src/base/apps/hist/hist.h | 20 + isis/src/base/apps/hist/main.cpp | 235 +---------- isis/src/base/apps/hist/tsts/Makefile | 4 - isis/src/base/apps/hist/tsts/default/Makefile | 26 -- isis/tests/Fixtures.cpp | 57 ++- isis/tests/Fixtures.h | 10 +- isis/tests/FunctionalTestsHist.cpp | 380 ++++++++++++++++++ 9 files changed, 733 insertions(+), 277 deletions(-) create mode 100644 isis/src/base/apps/hist/hist.cpp create mode 100644 isis/src/base/apps/hist/hist.h delete mode 100644 isis/src/base/apps/hist/tsts/Makefile delete mode 100644 isis/src/base/apps/hist/tsts/default/Makefile create mode 100644 isis/tests/FunctionalTestsHist.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 987465f683..02985eeec5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ release. - Fixed bug where the time bias was not being added to the ephemeris times in ckwriter. [4129](https://github.com/USGS-Astrogeology/ISIS3/issues/4129) - Fixed logging in FindFeatures where we were trying to get a non-existent Pvl group from the Pvl log. [#4375](https://github.com/USGS-Astrogeology/ISIS3/issues/4375) - Fixed an arccos evaluating a double close to either 1, -1 when calculating the ground azimuth in camera.cpp. [#4393](https://github.com/USGS-Astrogeology/ISIS3/issues/4393) +- Fixed hist outputs to N/A when all DNs are special pixels. [#3709](https://github.com/USGS-Astrogeology/ISIS3/issues/3709) ### Changed diff --git a/isis/src/base/apps/hist/hist.cpp b/isis/src/base/apps/hist/hist.cpp new file mode 100644 index 0000000000..71a8e402b0 --- /dev/null +++ b/isis/src/base/apps/hist/hist.cpp @@ -0,0 +1,277 @@ +#include "hist.h" + +#include +#include +#include + +#include "CubePlotCurve.h" +#include "Histogram.h" +#include "ImageHistogram.h" +#include "HistogramItem.h" +#include "HistogramPlotWindow.h" +#include "LineManager.h" +#include "Process.h" +#include "Progress.h" +#include "QHistogram.h" +#include "UserInterface.h" + + +using namespace std; + +namespace Isis { + + void hist(UserInterface &ui) { + Cube cube; + CubeAttributeInput inAtt = ui.GetInputAttribute("FROM"); + if (inAtt.bands().size() != 0) { + cube.setVirtualBands(inAtt.bands()); + } + cube.open(ui.GetFileName("FROM")); + hist(&cube, ui); + } + + void hist(Cube *icube, UserInterface &ui) { + Process p; + + if (!ui.WasEntered("TO") && !ui.IsInteractive()) { + QString msg = "The [TO] parameter must be entered"; + throw IException(IException::User, msg, _FILEINFO_); + } + + Histogram *hist; + if (ui.WasEntered("MINIMUM") && ui.WasEntered("MAXIMUM")) { + int nbins = 0; + + if (ui.WasEntered("NBINS")){ + nbins = ui.GetInteger("NBINS"); + } + else { + // Calculate bins based on data type. + // Bin calculations are based on logic in Histogram::InitializeFromCube + if (icube->pixelType() == UnsignedByte) { + nbins = 256; + } + else if (icube->pixelType() == SignedWord || + icube->pixelType() == UnsignedWord || + icube->pixelType() == UnsignedInteger || + icube->pixelType() == SignedInteger || + icube->pixelType() == Real) { + nbins = 65536; + } + else { + IString msg = "Unsupported pixel type"; + throw IException(IException::Programmer, msg, _FILEINFO_); + } + } + hist = new Histogram(ui.GetDouble("MINIMUM"), ui.GetDouble("MAXIMUM"), nbins); + } + else { + + if (ui.WasEntered("NBINS")){ + hist = new ImageHistogram(*icube, 1, p.Progress(), 1, 1, Null, Null, ui.GetInteger("NBINS")); + } + else { + hist = new ImageHistogram(*icube, 1, p.Progress()); + } + } + + // Setup the histogram + + // Loop and accumulate histogram + p.Progress()->SetText("Gathering Histogram"); + p.Progress()->SetMaximumSteps(icube->lineCount()); + p.Progress()->CheckStatus(); + LineManager line(*icube); + + for (int i = 1; i <= icube->lineCount(); i++) { + line.SetLine(i); + icube->read(line); + hist->AddData(line.DoubleBuffer(), line.size()); + p.Progress()->CheckStatus(); + } + + if (!ui.IsInteractive() || ui.WasEntered("TO") ) { + // Write the results + QString outfile = ui.GetFileName("TO"); + ofstream fout; + fout.open(outfile.toLatin1().data()); + + fout << "Cube: " << icube->fileName() << endl; + fout << "Band: " << icube->bandCount() << endl; + + if(hist->ValidPixels() != 0) { + fout << "Average: " << hist->Average() << endl; + fout << "Std Deviation: " << hist->StandardDeviation() << endl; + fout << "Variance: " << hist->Variance() << endl; + fout << "Median: " << hist->Median() << endl; + fout << "Mode: " << hist->Mode() << endl; + fout << "Skew: " << hist->Skew() << endl; + fout << "Minimum: " << hist->Minimum() << endl; + fout << "Maximum: " << hist->Maximum() << endl; + } + else { + fout << "Average: " << "N/A" << endl; + fout << "Std Deviation: " << "N/A" << endl; + fout << "Variance: " << "N/A" << endl; + fout << "Median: " << "N/A" << endl; + fout << "Mode: " << "N/A" << endl; + fout << "Skew: " << "N/A" << endl; + fout << "Minimum: " << "N/A" << endl; + fout << "Maximum: " << "N/A" << endl; + } + + fout << endl; + fout << "Total Pixels: " << hist->TotalPixels() << endl; + fout << "Valid Pixels: " << hist->ValidPixels() << endl; + fout << "Pixels Below Min: " << hist->UnderRangePixels() << endl; + fout << "Pixels Above Max: " << hist->OverRangePixels() << endl; + fout << "Null Pixels: " << hist->NullPixels() << endl; + fout << "Lis Pixels: " << hist->LisPixels() << endl; + fout << "Lrs Pixels: " << hist->LrsPixels() << endl; + fout << "His Pixels: " << hist->HisPixels() << endl; + fout << "Hrs Pixels: " << hist->HrsPixels() << endl; + + // Write histogram in tabular format + fout << endl; + fout << endl; + fout << "MinInclusive,MaxExclusive,Pixels,CumulativePixels,Percent,CumulativePercent" << endl; + + Isis::BigInt total = 0; + double cumpct = 0.0; + double low; + double high; + + for (int i = 0; i < hist->Bins(); i++) { + if (hist->BinCount(i) > 0) { + total += hist->BinCount(i); + double pct = (double)hist->BinCount(i) / hist->ValidPixels() * 100.; + cumpct += pct; + + hist->BinRange(i, low, high); + + fout << low << ","; + fout << high << ","; + fout << hist->BinCount(i) << ","; + fout << total << ","; + fout << pct << ","; + fout << cumpct << endl; + } + } + fout.close(); + } + // If we are in gui mode, create a histogram plot + if (ui.IsInteractive()) { + // Set the title for the dialog + QString title; + if (ui.WasEntered("TITLE") ) { + title = ui.GetString("TITLE"); + } + else { + title = "Histogram Plot for " + FileName(ui.GetAsString("FROM")).name(); + } + + // Create the QHistogram, set the title & load the Isis::Histogram into it + + HistogramPlotWindow *plot = new HistogramPlotWindow(title.toLatin1().data(), + ui.TheGui()); + + // Set the xaxis title if they entered one + if (ui.WasEntered("XAXIS") ) { + QString xaxis(ui.GetString("XAXIS")); + plot->setAxisLabel(QwtPlot::xBottom, xaxis.toLatin1().data()); + } + + // Set the yLeft axis title if they entered one + if (ui.WasEntered("FREQAXIS") ) { + QString yaxis(ui.GetString("FREQAXIS")); + plot->setAxisLabel(QwtPlot::yRight, yaxis.toLatin1().data()); + } + + // Set the yRight axis title if they entered one + if (ui.WasEntered("PERCENTAXIS") ) { + QString y2axis(ui.GetString("PERCENTAXIS") ); + plot->setAxisLabel(QwtPlot::yLeft, y2axis.toLatin1().data()); + } + + //Transfer data from histogram to the plotcurve + QVector binCountData; + QVector cumPctData; + double cumpct = 0.0; + double low; + double high; + for (int i = 0; i < hist->Bins(); i++) { + if (hist->BinCount(i) > 0) { + hist->BinRange(i, low, high); + binCountData.append(QPointF(low, hist->BinCount(i) ) ); + + double pct = (double)hist->BinCount(i) / hist->ValidPixels() * 100.0; + cumpct += pct; + cumPctData.append(QPointF(low, cumpct) ); + } + } + + HistogramItem *histCurve = new HistogramItem(); + histCurve->setColor(Qt::darkCyan); + histCurve->setTitle("Frequency"); + + CubePlotCurve *cdfCurve = new CubePlotCurve(CubePlotCurve::CubeDN, + CubePlotCurve::Percentage); + cdfCurve->setStyle(QwtPlotCurve::Lines); + cdfCurve->setTitle("Percentage"); + + QPen *pen = new QPen(Qt::red); + pen->setWidth(2); + histCurve->setYAxis(QwtPlot::yRight); + cdfCurve->setYAxis(QwtPlot::yLeft); + cdfCurve->setPen(*pen); + + QVector intervals(binCountData.size() ); + for (int y = 0; y < binCountData.size(); y++) { + + intervals[y].interval = QwtInterval(binCountData[y].x(), + binCountData[y].x() + hist->BinSize()); + + intervals[y].value = binCountData[y].y(); + } + + QPen percentagePen(Qt::red); + percentagePen.setWidth(2); + cdfCurve->setColor(Qt::red); + cdfCurve->setMarkerSymbol(QwtSymbol::NoSymbol); + + histCurve->setData(QwtIntervalSeriesData(intervals)); + cdfCurve->setData(new QwtPointSeriesData(cumPctData)); + + plot->add(histCurve); + plot->add(cdfCurve); + + QLabel *label; + if(hist->ValidPixels() != 0) { + label = new QLabel(" Average = " + QString::number(hist->Average()) + '\n' + + "\n Minimum = " + QString::number(hist->Minimum()) + '\n' + + "\n Maximum = " + QString::number(hist->Maximum()) + '\n' + + "\n Stand. Dev.= " + QString::number(hist->StandardDeviation()) + '\n' + + "\n Variance = " + QString::number(hist->Variance()) + '\n' + + "\n Median = " + QString::number(hist->Median()) + '\n' + + "\n Mode = " + QString::number(hist->Mode()) + '\n' + + "\n Skew = " + QString::number(hist->Skew()), plot); + } + else { + label = new QLabel(" Average = N/A" + "\n\n Minimum = N/A" + "\n\n Maximum = N/A" + "\n\n Stand. Dev.= N/A" + "\n\n Variance = N/A" + "\n\n Median = N/A" + "\n\n Mode = N/A" + "\n\n Skew = N/A" , plot); + } + + plot->getDockWidget()->setWidget(label); + + plot->showWindow(); + } + delete hist; + p.EndProcess(); + } +} diff --git a/isis/src/base/apps/hist/hist.h b/isis/src/base/apps/hist/hist.h new file mode 100644 index 0000000000..e51b482805 --- /dev/null +++ b/isis/src/base/apps/hist/hist.h @@ -0,0 +1,20 @@ +#ifndef hist_h +#define hist_h + +/** This is free and unencumbered software released into the public domain. + +The authors of ISIS do not claim copyright on the contents of this file. +For more details about the LICENSE terms and the AUTHORS, you will +find files of those names at the top level of this repository. **/ + +/* SPDX-License-Identifier: CC0-1.0 */ + +#include "Cube.h" +#include "UserInterface.h" + +namespace Isis{ + extern void hist(Cube *cube, UserInterface &ui); + extern void hist(UserInterface &ui); +} + +#endif diff --git a/isis/src/base/apps/hist/main.cpp b/isis/src/base/apps/hist/main.cpp index a242c2346e..97ec876c51 100644 --- a/isis/src/base/apps/hist/main.cpp +++ b/isis/src/base/apps/hist/main.cpp @@ -1,24 +1,13 @@ #define GUIHELPERS #include "Isis.h" -#include -#include -#include - -#include "CubePlotCurve.h" -#include "Histogram.h" +#include "Application.h" #include "ImageHistogram.h" -#include "HistogramItem.h" -#include "HistogramPlotWindow.h" #include "LineManager.h" -#include "Process.h" -#include "Progress.h" -#include "QHistogram.h" -#include "UserInterface.h" - +#include "hist.h" -using namespace std; using namespace Isis; +using namespace std; void helperButtonCalcMinMax(); @@ -28,227 +17,11 @@ map GuiHelpers() { return helper; } - void IsisMain() { - Process p; - Cube *icube = p.SetInputCube("FROM"); - UserInterface &ui = Application::GetUserInterface(); - if (!ui.WasEntered("TO") && !ui.IsInteractive()) { - QString msg = "The [TO] parameter must be entered"; - throw IException(IException::User, msg, _FILEINFO_); - } - - Histogram *hist; - if (ui.WasEntered("MINIMUM") && ui.WasEntered("MAXIMUM")) { - int nbins = 0; - - if (ui.WasEntered("NBINS")){ - nbins = ui.GetInteger("NBINS"); - } - else { - // Calculate bins based on data type. - // Bin calculations are based on logic in Histogram::InitializeFromCube - if (icube->pixelType() == UnsignedByte) { - nbins = 256; - } - else if (icube->pixelType() == SignedWord || - icube->pixelType() == UnsignedWord || - icube->pixelType() == UnsignedInteger || - icube->pixelType() == SignedInteger || - icube->pixelType() == Real) { - nbins = 65536; - } - else { - IString msg = "Unsupported pixel type"; - throw IException(IException::Programmer, msg, _FILEINFO_); - } - } - hist = new Histogram(ui.GetDouble("MINIMUM"), ui.GetDouble("MAXIMUM"), nbins); - } - else { - - if (ui.WasEntered("NBINS")){ - hist = new ImageHistogram(*icube, 1, p.Progress(), 1, 1, Null, Null, ui.GetInteger("NBINS")); - } - else { - hist = new ImageHistogram(*icube, 1, p.Progress()); - } - } - - // Setup the histogram - - // Loop and accumulate histogram - p.Progress()->SetText("Gathering Histogram"); - p.Progress()->SetMaximumSteps(icube->lineCount()); - p.Progress()->CheckStatus(); - LineManager line(*icube); - - for (int i = 1; i <= icube->lineCount(); i++) { - line.SetLine(i); - icube->read(line); - hist->AddData(line.DoubleBuffer(), line.size()); - p.Progress()->CheckStatus(); - } - - if (!ui.IsInteractive() || ui.WasEntered("TO") ) { - // Write the results - QString outfile = ui.GetFileName("TO"); - ofstream fout; - fout.open(outfile.toLatin1().data()); - - fout << "Cube: " << ui.GetFileName("FROM") << endl; - fout << "Band: " << icube->bandCount() << endl; - fout << "Average: " << hist->Average() << endl; - fout << "Std Deviation: " << hist->StandardDeviation() << endl; - fout << "Variance: " << hist->Variance() << endl; - fout << "Median: " << hist->Median() << endl; - fout << "Mode: " << hist->Mode() << endl; - fout << "Skew: " << hist->Skew() << endl; - fout << "Minimum: " << hist->Minimum() << endl; - fout << "Maximum: " << hist->Maximum() << endl; - fout << endl; - fout << "Total Pixels: " << hist->TotalPixels() << endl; - fout << "Valid Pixels: " << hist->ValidPixels() << endl; - fout << "Pixels Below Min: " << hist->UnderRangePixels() << endl; - fout << "Pixels Above Max: " << hist->OverRangePixels() << endl; - fout << "Null Pixels: " << hist->NullPixels() << endl; - fout << "Lis Pixels: " << hist->LisPixels() << endl; - fout << "Lrs Pixels: " << hist->LrsPixels() << endl; - fout << "His Pixels: " << hist->HisPixels() << endl; - fout << "Hrs Pixels: " << hist->HrsPixels() << endl; - - // Write histogram in tabular format - fout << endl; - fout << endl; - fout << "MinInclusive,MaxExclusive,Pixels,CumulativePixels,Percent,CumulativePercent" << endl; - - Isis::BigInt total = 0; - double cumpct = 0.0; - double low; - double high; - - for (int i = 0; i < hist->Bins(); i++) { - if (hist->BinCount(i) > 0) { - total += hist->BinCount(i); - double pct = (double)hist->BinCount(i) / hist->ValidPixels() * 100.; - cumpct += pct; - - hist->BinRange(i, low, high); - - fout << low << ","; - fout << high << ","; - fout << hist->BinCount(i) << ","; - fout << total << ","; - fout << pct << ","; - fout << cumpct << endl; - } - } - fout.close(); - } - // If we are in gui mode, create a histogram plot - if (ui.IsInteractive()) { - // Set the title for the dialog - QString title; - if (ui.WasEntered("TITLE") ) { - title = ui.GetString("TITLE"); - } - else { - title = "Histogram Plot for " + FileName(ui.GetAsString("FROM")).name(); - } - - // Create the QHistogram, set the title & load the Isis::Histogram into it - - HistogramPlotWindow *plot = new HistogramPlotWindow(title.toLatin1().data(), - ui.TheGui()); - - // Set the xaxis title if they entered one - if (ui.WasEntered("XAXIS") ) { - QString xaxis(ui.GetString("XAXIS")); - plot->setAxisLabel(QwtPlot::xBottom, xaxis.toLatin1().data()); - } - - // Set the yLeft axis title if they entered one - if (ui.WasEntered("FREQAXIS") ) { - QString yaxis(ui.GetString("FREQAXIS")); - plot->setAxisLabel(QwtPlot::yRight, yaxis.toLatin1().data()); - } - - // Set the yRight axis title if they entered one - if (ui.WasEntered("PERCENTAXIS") ) { - QString y2axis(ui.GetString("PERCENTAXIS") ); - plot->setAxisLabel(QwtPlot::yLeft, y2axis.toLatin1().data()); - } - - //Transfer data from histogram to the plotcurve - QVector binCountData; - QVector cumPctData; - double cumpct = 0.0; - double low; - double high; - for (int i = 0; i < hist->Bins(); i++) { - if (hist->BinCount(i) > 0) { - hist->BinRange(i, low, high); - binCountData.append(QPointF(low, hist->BinCount(i) ) ); - - double pct = (double)hist->BinCount(i) / hist->ValidPixels() * 100.0; - cumpct += pct; - cumPctData.append(QPointF(low, cumpct) ); - } - } - - HistogramItem *histCurve = new HistogramItem(); - histCurve->setColor(Qt::darkCyan); - histCurve->setTitle("Frequency"); - - CubePlotCurve *cdfCurve = new CubePlotCurve(CubePlotCurve::CubeDN, - CubePlotCurve::Percentage); - cdfCurve->setStyle(QwtPlotCurve::Lines); - cdfCurve->setTitle("Percentage"); - - QPen *pen = new QPen(Qt::red); - pen->setWidth(2); - histCurve->setYAxis(QwtPlot::yRight); - cdfCurve->setYAxis(QwtPlot::yLeft); - cdfCurve->setPen(*pen); - - QVector intervals(binCountData.size() ); - for (int y = 0; y < binCountData.size(); y++) { - - intervals[y].interval = QwtInterval(binCountData[y].x(), - binCountData[y].x() + hist->BinSize()); - - intervals[y].value = binCountData[y].y(); - } - - QPen percentagePen(Qt::red); - percentagePen.setWidth(2); - cdfCurve->setColor(Qt::red); - cdfCurve->setMarkerSymbol(QwtSymbol::NoSymbol); - - histCurve->setData(QwtIntervalSeriesData(intervals)); - cdfCurve->setData(new QwtPointSeriesData(cumPctData)); - - plot->add(histCurve); - plot->add(cdfCurve); - - QLabel *label = new QLabel(" Average = " + QString::number(hist->Average()) + '\n' + - "\n Minimum = " + QString::number(hist->Minimum()) + '\n' + - "\n Maximum = " + QString::number(hist->Maximum()) + '\n' + - "\n Stand. Dev.= " + QString::number(hist->StandardDeviation()) + '\n' + - "\n Variance = " + QString::number(hist->Variance()) + '\n' + - "\n Median = " + QString::number(hist->Median()) + '\n' + - "\n Mode = " + QString::number(hist->Mode()) + '\n' + - "\n Skew = " + QString::number(hist->Skew()), plot); - plot->getDockWidget()->setWidget(label); - - plot->showWindow(); - } - delete hist; - p.EndProcess(); + hist(ui); } - // Helper function to fill in the auto calculated min/max. void helperButtonCalcMinMax() { diff --git a/isis/src/base/apps/hist/tsts/Makefile b/isis/src/base/apps/hist/tsts/Makefile deleted file mode 100644 index 46d84c74c2..0000000000 --- a/isis/src/base/apps/hist/tsts/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -BLANKS = "%-6s" -LENGTH = "%-40s" - -include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/hist/tsts/default/Makefile b/isis/src/base/apps/hist/tsts/default/Makefile deleted file mode 100644 index 14a5b34e64..0000000000 --- a/isis/src/base/apps/hist/tsts/default/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# 2020-06-25 - Kristin Berry - Added a test to check that if nbins is set, it is used. -# To make the truthdata for this test, I set the number of bins to 25, a number much smaller than -# the internal default, and just checked that the output was different from the default test. - -APPNAME = hist -histTruth.txt.IGNORELINES = Cube -histTruthNbins.txt.IGNORELINES = Cube -histTruthMinMax.txt.IGNORELINES = Cube -TEMP = $(OUTPUT)/histTruth.txt -TEMPNBINS = $(OUTPUT)/histTruthNbins.txt -TEMPMINMAX = $(OUTPUT)/histTruthMinMax.txt - -include $(ISISROOT)/make/isismake.tsts - -commands: - # Test without additional arguments - $(APPNAME) from=$(INPUT)/isisTruth.cub \ - to=$(TEMP) > /dev/null; - - # Test with setting nbins - $(APPNAME) from=$(INPUT)/isisTruth.cub nbins=25\ - to=$(TEMPNBINS) > /dev/null; - - # Test with a min and max - $(APPNAME) from=$(INPUT)/isisTruth.cub\ - to=$(TEMPMINMAX) minimum=0 maximum=255 nbins=255> /dev/null; diff --git a/isis/tests/Fixtures.cpp b/isis/tests/Fixtures.cpp index d19d5a2242..73784e4dbc 100644 --- a/isis/tests/Fixtures.cpp +++ b/isis/tests/Fixtures.cpp @@ -268,9 +268,9 @@ namespace Isis { LineManager line(*testCube); int pixelValue = 1; for(int band = 1; band <= bands; band++) { - for (int i = 1; i <= testCube->lineCount(); i++) { + for (int i = 1; i <= testCube->lineCount(); i++) { line.SetLine(i, band); - for (int j = 0; j < line.size(); j++) { + for (int j = 0; j < line.size(); j++) { line[j] = (double) (pixelValue % 255); pixelValue++; } @@ -294,9 +294,9 @@ namespace Isis { line = LineManager(*projTestCube); pixelValue = 1; for(int band = 1; band <= bands; band++) { - for (int i = 1; i <= projTestCube->lineCount(); i++) { + for (int i = 1; i <= projTestCube->lineCount(); i++) { line.SetLine(i, band); - for (int j = 0; j < line.size(); j++) { + for (int j = 0; j < line.size(); j++) { line[j] = (double) (pixelValue % 255); pixelValue++; } @@ -605,7 +605,7 @@ namespace Isis { void GalileoSsiCube::SetUp() { DefaultCube::SetUp(); - // Change default dims + // Change default dims PvlGroup &dim = label.findObject("IsisCube").findObject("Core").findGroup("Dimensions"); dim.findKeyword("Samples").setValue("800"); dim.findKeyword("Lines").setValue("800"); @@ -620,7 +620,7 @@ namespace Isis { PvlGroup &kernels = testCube->label()->findObject("IsisCube").findGroup("Kernels"); kernels.findKeyword("NaifFrameCode").setValue("-77001"); PvlGroup &inst = testCube->label()->findObject("IsisCube").findGroup("Instrument"); - + std::istringstream iss(R"( Group = Instrument SpacecraftName = "Galileo Orbiter" @@ -678,7 +678,7 @@ namespace Isis { INS-77001_BORESIGHT_LINE = 400.0 End_Object )"); - + PvlObject newNaifKeywords; nk >> newNaifKeywords; naifKeywords = newNaifKeywords; @@ -693,8 +693,8 @@ namespace Isis { End_Group )"); - PvlGroup &archive = testCube->label()->findObject("IsisCube").findGroup("Archive"); - PvlGroup newArchive; + PvlGroup &archive = testCube->label()->findObject("IsisCube").findGroup("Archive"); + PvlGroup newArchive; ar >> newArchive; archive = newArchive; @@ -1056,8 +1056,8 @@ namespace Isis { FileName newCube(tempDir.path() + "/testing.cub"); - testCube->fromIsd(newCube, label, isd, "rw"); - + testCube->fromIsd(newCube, label, isd, "rw"); + PvlGroup &kernels = testCube->label()->findObject("IsisCube").findGroup("Kernels"); kernels.findKeyword("NaifFrameCode").setValue(ikid); kernels["ShapeModel"] = "Null"; @@ -1095,8 +1095,8 @@ namespace Isis { bandBin = newBandBin; json nk; - nk["BODY2101955_RADII"] = {2825, 2675, 254}; - nk["INS"+ikid.toStdString()+"_FOCAL_LENGTH"] = 630.0; + nk["BODY2101955_RADII"] = {2825, 2675, 254}; + nk["INS"+ikid.toStdString()+"_FOCAL_LENGTH"] = 630.0; nk["INS"+ikid.toStdString()+"_PIXEL_SIZE"] = 8.5; nk["CLOCK_ET_-64_1/0600694569.00000_COMPUTED"] = "8ed6ae8930f3bd41"; nk["INS"+ikid.toStdString()+"_TRANSX"] = {0.0, 0.0085, 0.0}; @@ -1105,12 +1105,12 @@ namespace Isis { nk["INS"+ikid.toStdString()+"_ITRANSL"] = {0.0, 0.0, -117.64705882353}; nk["INS"+ikid.toStdString()+"_CCD_CENTER"] = {511.5, 511.5}; nk["BODY_FRAME_CODE"] = 2101955; - + PvlObject &naifKeywords = testCube->label()->findObject("NaifKeywords"); PvlObject newNaifKeywords("NaifKeywords", nk); naifKeywords = newNaifKeywords; - QString fileName = testCube->fileName(); + QString fileName = testCube->fileName(); delete testCube; testCube = new Cube(fileName, "rw"); } @@ -1285,4 +1285,31 @@ namespace Isis { testCube.reset(); } + void NullPixelCube::SetUp() { + TempTestingFiles::SetUp(); + + testCube = new Cube(); + testCube->setDimensions(10, 10, 10); + QString path = tempDir.path() + "/null.cub"; + testCube->create(path); + + LineManager line(*testCube); + for(line.begin(); !line.end(); line++) { + for(int i = 0; i < line.size(); i++) { + line[i] = NULL8; + } + testCube->write(line); + } + } + + void NullPixelCube::TearDown() { + if (testCube->isOpen()) { + testCube->close(); + } + + if (testCube) { + delete testCube; + } + } + } diff --git a/isis/tests/Fixtures.h b/isis/tests/Fixtures.h index 22dc59c91c..6c5daf145e 100644 --- a/isis/tests/Fixtures.h +++ b/isis/tests/Fixtures.h @@ -238,7 +238,7 @@ namespace Isis { void setInstrument(QString ikid, QString instrumentId, QString spacecraftName); }; - + class OsirisRexCube : public DefaultCube { protected: void setInstrument(QString ikid, QString instrumentId); @@ -305,6 +305,14 @@ class HistoryBlob : public TempTestingFiles { void SetUp() override; }; + +class NullPixelCube : public TempTestingFiles { + protected: + Cube *testCube; + + void SetUp() override; + void TearDown() override; +}; } #endif diff --git a/isis/tests/FunctionalTestsHist.cpp b/isis/tests/FunctionalTestsHist.cpp new file mode 100644 index 0000000000..80e1f7456b --- /dev/null +++ b/isis/tests/FunctionalTestsHist.cpp @@ -0,0 +1,380 @@ +#include "hist.h" + +#include +#include +#include + +#include "Fixtures.h" +#include "PvlGroup.h" +#include "TestUtilities.h" +#include "CSVReader.h" +#include "LineManager.h" + +#include "gmock/gmock.h" + +using namespace Isis; + +static QString APP_XML = FileName("$ISISROOT/bin/xml/hist.xml").expanded(); + +TEST_F(SmallCube, FunctionalTestHistDefault) { + QString outputFile = tempDir.path()+"/output.txt"; + QVector args = {"to=" + outputFile}; + UserInterface ui(APP_XML, args); + + hist(testCube, ui); + + CSVReader::CSVAxis csvLine; + + CSVReader header = CSVReader(outputFile, + false, 0, ':', false, true); + + // Validate the header information is correct + csvLine = header.getRow(0); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Cube"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[1].trimmed(),testCube->fileName()); + + csvLine = header.getRow(1); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Band"); + EXPECT_EQ(csvLine[1].toInt(), 10); + + csvLine = header.getRow(2); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Average"); + EXPECT_DOUBLE_EQ(csvLine[1].toDouble(), 49.5); + + csvLine = header.getRow(3); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Std Deviation"); + EXPECT_DOUBLE_EQ(csvLine[1].toDouble(), 29.0115); + + csvLine = header.getRow(4); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Variance"); + EXPECT_DOUBLE_EQ(csvLine[1].toDouble(), 841.667); + + csvLine = header.getRow(5); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Median"); + EXPECT_DOUBLE_EQ(csvLine[1].toDouble(), 49.0007); + + csvLine = header.getRow(6); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Mode"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(7); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Skew"); + EXPECT_DOUBLE_EQ(csvLine[1].toDouble(), 0.0516279); + + csvLine = header.getRow(8); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Minimum"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(9); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Maximum"); + EXPECT_EQ(csvLine[1].toInt(), 99); + + csvLine = header.getRow(10); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Total Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 100); + + csvLine = header.getRow(11); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Valid Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 100); + + csvLine = header.getRow(12); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Pixels Below Min"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(13); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Pixels Above Max"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(14); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Null Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(15); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Lis Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(16); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Lrs Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(17); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "His Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(18); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Hrs Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); +} + +TEST_F(NullPixelCube, FunctionalTestHistNulls) { + QString outputFile = tempDir.path()+"/output.txt"; + QVector args = {"to=" + outputFile}; + UserInterface ui(APP_XML, args); + + hist(testCube, ui); + + CSVReader::CSVAxis csvLine; + + CSVReader header = CSVReader(outputFile, + false, 0, ':', false, true); + + // Validate the header information is correct + csvLine = header.getRow(0); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Cube"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[1].trimmed(), testCube->fileName()); + + csvLine = header.getRow(1); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Band"); + EXPECT_EQ(csvLine[1].toInt(), 10); + + csvLine = header.getRow(2); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Average"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[1].trimmed(), "N/A"); + + csvLine = header.getRow(3); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Std Deviation"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[1].trimmed(), "N/A"); + + csvLine = header.getRow(4); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Variance"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[1].trimmed(), "N/A"); + + csvLine = header.getRow(5); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Median"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[1].trimmed(), "N/A"); + + csvLine = header.getRow(6); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Mode"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[1].trimmed(), "N/A"); + + csvLine = header.getRow(7); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Skew"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[1].trimmed(), "N/A"); + + csvLine = header.getRow(8); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Minimum"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[1].trimmed(), "N/A"); + + csvLine = header.getRow(9); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Maximum"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[1].trimmed(), "N/A"); + + csvLine = header.getRow(10); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Total Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 100); + + csvLine = header.getRow(11); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Valid Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(12); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Pixels Below Min"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(13); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Pixels Above Max"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(14); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Null Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 100); + + csvLine = header.getRow(15); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Lis Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(16); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Lrs Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(17); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "His Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(18); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Hrs Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); +} + +TEST_F(SmallCube, FunctionalTestHistNbins) { + QString outputFile = tempDir.path()+"/output.txt"; + QVector args = {"to=" + outputFile, "nbins=25"}; + UserInterface ui(APP_XML, args); + + hist(testCube, ui); + + CSVReader::CSVAxis csvLine; + + CSVReader header = CSVReader(outputFile, + false, 0, ':', false, true); + + // Validate the header information is correct + csvLine = header.getRow(0); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Cube"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[1].trimmed(),testCube->fileName()); + + csvLine = header.getRow(1); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Band"); + EXPECT_EQ(csvLine[1].toInt(), 10); + + csvLine = header.getRow(2); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Average"); + EXPECT_DOUBLE_EQ(csvLine[1].toDouble(), 49.5); + + csvLine = header.getRow(3); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Std Deviation"); + EXPECT_DOUBLE_EQ(csvLine[1].toDouble(), 29.0115); + + csvLine = header.getRow(4); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Variance"); + EXPECT_DOUBLE_EQ(csvLine[1].toDouble(), 841.667); + + csvLine = header.getRow(5); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Median"); + EXPECT_DOUBLE_EQ(csvLine[1].toDouble(), 49.5); + + csvLine = header.getRow(6); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Mode"); + EXPECT_EQ(csvLine[1].toInt(), 33); + + csvLine = header.getRow(7); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Skew"); + EXPECT_EQ(csvLine[1].toDouble(), 0); + + csvLine = header.getRow(8); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Minimum"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(9); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Maximum"); + EXPECT_EQ(csvLine[1].toInt(), 99); + + csvLine = header.getRow(10); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Total Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 100); + + csvLine = header.getRow(11); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Valid Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 100); + + csvLine = header.getRow(12); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Pixels Below Min"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(13); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Pixels Above Max"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(14); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Null Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(15); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Lis Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(16); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Lrs Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(17); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "His Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(18); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Hrs Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); +} + +TEST_F(LargeCube, FunctionalTestHistMinMax) { + QString outputFile = tempDir.path()+"/output.txt"; + QVector args = {"to=" + outputFile, + "nbins=255", + "minimum=0", + "maximum=255"}; + UserInterface ui(APP_XML, args); + + hist(testCube, ui); + + CSVReader::CSVAxis csvLine; + + CSVReader header = CSVReader(outputFile, + false, 0, ':', false, true); + + // Validate the header information is correct + csvLine = header.getRow(0); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Cube"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[1].trimmed(),testCube->fileName()); + + csvLine = header.getRow(1); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Band"); + EXPECT_EQ(csvLine[1].toInt(), 10); + + csvLine = header.getRow(2); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Average"); + EXPECT_DOUBLE_EQ(csvLine[1].toDouble(), 127.5); + + csvLine = header.getRow(3); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Std Deviation"); + EXPECT_DOUBLE_EQ(csvLine[1].toDouble(), 73.9004); + + csvLine = header.getRow(4); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Variance"); + EXPECT_DOUBLE_EQ(csvLine[1].toDouble(), 5461.27); + + csvLine = header.getRow(5); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Median"); + EXPECT_DOUBLE_EQ(csvLine[1].toDouble(), 127.5); + + csvLine = header.getRow(6); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Mode"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(7); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Skew"); + EXPECT_EQ(csvLine[1].toDouble(), 0); + + csvLine = header.getRow(8); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Minimum"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(9); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Maximum"); + EXPECT_EQ(csvLine[1].toInt(), 255); + + csvLine = header.getRow(10); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Total Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 1000000); + + csvLine = header.getRow(11); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Valid Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 256000); + + csvLine = header.getRow(12); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Pixels Below Min"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(13); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Pixels Above Max"); + EXPECT_EQ(csvLine[1].toInt(), 744000); + + csvLine = header.getRow(14); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Null Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(15); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Lis Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(16); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Lrs Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(17); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "His Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); + + csvLine = header.getRow(18); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "Hrs Pixels"); + EXPECT_EQ(csvLine[1].toInt(), 0); +}