Skip to content
Snippets Groups Projects
Unverified Commit 60e884f2 authored by kledmundson's avatar kledmundson Committed by GitHub
Browse files

Algebra has been refactored to be callable; old Makefile tests have been...

Algebra has been refactored to be callable; old Makefile tests have been converted to gtests and removed. Addresses #5594. (#5597)
parent 3ecfce3c
No related branches found
No related tags found
No related merge requests found
...@@ -45,6 +45,7 @@ release. ...@@ -45,6 +45,7 @@ release.
- Added backplane options for SunIllumination and SurfaceObliqueDetectorResolution to phocube [#5467](https://github.com/DOI-USGS/ISIS3/issues/5467) - Added backplane options for SunIllumination and SurfaceObliqueDetectorResolution to phocube [#5467](https://github.com/DOI-USGS/ISIS3/issues/5467)
### Changed ### Changed
- Algebra has been refactored to be callable; old Makefile tests have been removed and replaced by gtests. Issue: [#5594](https://github.com/USGS-Astrogeology/ISIS3/issues/5594)
- Photrim has been refactored to be callable; old Makefile tests have been removed and replaced by gtests. Issue: [#5581](https://github.com/USGS-Astrogeology/ISIS3/issues/5581) - Photrim has been refactored to be callable; old Makefile tests have been removed and replaced by gtests. Issue: [#5581](https://github.com/USGS-Astrogeology/ISIS3/issues/5581)
- Bandtrim has been refactored to be callable; old Makefile tests have been removed and replaced by gtests. Issue: [#5571](https://github.com/USGS-Astrogeology/ISIS3/issues/5571) - Bandtrim has been refactored to be callable; old Makefile tests have been removed and replaced by gtests. Issue: [#5571](https://github.com/USGS-Astrogeology/ISIS3/issues/5571)
- Modified kaguyasp2isis to work with new (detached) data [#5436](https://github.com/DOI-USGS/ISIS3/issues/5436) - Modified kaguyasp2isis to work with new (detached) data [#5436](https://github.com/DOI-USGS/ISIS3/issues/5436)
......
/** 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 "algebra.h"
#include "Cube.h"
#include "FileName.h"
#include "ProcessByLine.h"
#include "SpecialPixel.h"
namespace Isis {
/*
* Algebra
*
* This program performs simple algebra on either one or two
* cubes. The two cubes may be added, subtracted, multiplied or divided.
*
* The following equations are used:
* UNARY: out = (A * from1) + C
* ADD: out = ((from1 - D) * A) + ((from2 - E) * B) + C
* SUBTRACT: out = ((from1 - D) * A) - ((from2 - E) * B) + C
* MULTIPLY: out = ((from1 - D) * A) * ((from2 - E) * B) + C
* DIVIDE: out = ((from1 - D) * A) / ((from2 - E) * B) + C
*
* The FROM2 cube must have either one band or the same number of bands
* as the FROM cube. If the FROM2 cube has one band, then the algebraic
* formula will be applied to all bands in FROM using that single band
* in FROM2. If FROM2 is a multi-band cube, the algebra will be performed
* between corresponding bands from FROM and FROM2.
*
* @param ui UserInterface object containing parameters
*/
void algebra(UserInterface &ui) {
Cube* icube1 = new Cube();
icube1->open(ui.GetCubeName("FROM"));
Cube* icube2 = nullptr;
if(ui.WasEntered("FROM2")) {
icube2 = new Cube();
icube2->open(ui.GetCubeName("FROM2"));
}
algebra(icube1, ui, icube2);
}
/*
* Algebra
*
* This program performs simple algebra on either one or two
* cubes. The two cubes may be added, subtracted, multiplied or divided.
*
* The following equations are used:
* UNARY: out = (A * from1) + C
* ADD: out = ((from1 - D) * A) + ((from2 - E) * B) + C
* SUBTRACT: out = ((from1 - D) * A) - ((from2 - E) * B) + C
* MULTIPLY: out = ((from1 - D) * A) * ((from2 - E) * B) + C
* DIVIDE: out = ((from1 - D) * A) / ((from2 - E) * B) + C
*
* The FROM2 cube must have either one band or the same number of bands
* as the FROM cube. If the FROM2 cube has one band, then the algebraic
* formula will be applied to all bands in FROM using that single band
* in FROM2. If FROM2 is a multi-band cube, the algebra will be performed
* between corresponding bands from FROM and FROM2.
*
* @param icube1 Cube* input cube1
* @param ui UserInterface object containing parameters
* @param icube2 Cube* input cube2; optional second input cube
*/
void algebra(Cube* icube1, UserInterface &ui, Cube* icube2) {
// Processing by line
ProcessByLine p;
// Set input cubes and attributes into ProcessByLine p
CubeAttributeInput inatts1 = ui.GetInputAttribute("FROM");
CubeAttributeInput inatts2;
p.SetInputCube(icube1->fileName(), inatts1);
if(icube2 != nullptr) {
inatts2 = ui.GetInputAttribute("FROM2");
p.SetInputCube(icube2->fileName(), inatts2);
}
// Set output cube and attributes into ProcessByLine p
QString outCubeFname = ui.GetCubeName("TO");
CubeAttributeOutput &outatts = ui.GetOutputAttribute("TO");
p.SetOutputCube(outCubeFname, outatts);
// Get the coefficients
double Isisa = ui.GetDouble("A");
double Isisb = ui.GetDouble("B");
double Isisc = ui.GetDouble("C");
double Isisd = ui.GetDouble("D");
double Isise = ui.GetDouble("E");
QString op = ui.GetString("OPERATOR");
//*****************************************
// Lambda functions to perform operations *
//*****************************************
// operatorProcess for add, subtract, multiply, divide
auto operatorProcess = [&](std::vector<Buffer *> &in, std::vector<Buffer *> &out)->void {
Buffer &inp1 = *in[0];
Buffer &inp2 = *in[1];
Buffer &outp = *out[0];
// Loop for each pixel in the line
// Special pixel propagation:
// 1) special pixels in inp1 propagate to output cube unchanged
// 2) if inp1 is not special and inp2 is, the output pixel is set to Null
for(int i = 0; i < inp1.size(); i++) {
if(IsSpecial(inp1[i])) {
outp[i] = inp1[i];
}
else if(IsSpecial(inp2[i])) {
outp[i] = NULL8;
}
else {
double operand1 = (inp1[i] - Isisd) * Isisa;
double operand2 = (inp2[i] - Isise) * Isisb;
if(op == "ADD") {
outp[i] = (operand1 + operand2) + Isisc;
}
if(op == "SUBTRACT") {
outp[i] = (operand1 - operand2) + Isisc;
}
if(op == "MULTIPLY") {
outp[i] = (operand1 * operand2) + Isisc;
}
if(op == "DIVIDE") {
if((inp2[i] - Isise) * Isisb == 0.0) {
outp[i] = NULL8;
}
else {
outp[i] = (operand1 / operand2) + Isisc;
}
}
}
}
};
// Unary process
auto unaryProcess = [&](Buffer &in, Buffer &out)->void {
// Loop for each pixel in the line.
// Special pixels propagate directly to output
for(int i = 0; i < in.size(); i++) {
if(IsSpecial(in[i])) {
out[i] = in[i];
}
else {
out[i] = in[i] * Isisa + Isisc;
}
}
};
//*****************************************
// End Lambda functions *
//*****************************************
// Start processing based on the operator
if(op == "UNARY") {
p.ProcessCube(unaryProcess);
}
else {
p.ProcessCubes(operatorProcess); // add, subtract, multiply, divide
}
p.EndProcess();
}
}
/** 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 */
#ifndef algebra_h
#define algebra_h
#include "UserInterface.h"
namespace Isis{
extern void algebra(UserInterface &ui);
extern void algebra(Cube* icube1, UserInterface &ui, Cube* icube2=nullptr);
}
#endif
...@@ -87,6 +87,9 @@ ...@@ -87,6 +87,9 @@
Updated to use the new ProcessByLine API. This program now takes Updated to use the new ProcessByLine API. This program now takes
advantage of multiple global processing threads. advantage of multiple global processing threads.
</change> </change>
<change name="Ken Edmundson" date="2024-08-22">
Converted to callable app and converted Makefile tests to gtests.
</change>
</history> </history>
<category> <category>
......
#include "Isis.h" /** This is free and unencumbered software released into the public domain.
#include "ProcessByBrick.h"
#include "ProcessByLine.h"
#include "SpecialPixel.h"
#include "IException.h"
using namespace std;
using namespace Isis;
void add(vector<Buffer *> &in, The authors of ISIS do not claim copyright on the contents of this file.
vector<Buffer *> &out); For more details about the LICENSE terms and the AUTHORS, you will
void sub(vector<Buffer *> &in, find files of those names at the top level of this repository. **/
vector<Buffer *> &out);
void mult(vector<Buffer *> &in,
vector<Buffer *> &out);
void divide(vector<Buffer *> &in,
vector<Buffer *> &out);
void unaryFunction(Buffer &in, Buffer &out);
double Isisa, Isisb, Isisc, Isisd, Isise;
void IsisMain() {
std::cout << "algebra - got to main...\n";
// We will be processing by line /* SPDX-License-Identifier: CC0-1.0 */
ProcessByLine p;
// Setup the input and output files
UserInterface &ui = Application::GetUserInterface();
// Setup the input and output cubes
p.SetInputCube("FROM");
if(ui.WasEntered("FROM2")) p.SetInputCube("FROM2");
p.SetOutputCube("TO");
// Get the coefficients
Isisa = ui.GetDouble("A");
Isisb = ui.GetDouble("B");
Isisc = ui.GetDouble("C");
Isisd = ui.GetDouble("D");
Isise = ui.GetDouble("E");
// Start the processing based on the operator
QString op = ui.GetString("OPERATOR");
if(op == "ADD") p.ProcessCubes(&add);
if(op == "SUBTRACT") p.ProcessCubes(&sub);
if(op == "MULTIPLY") p.ProcessCubes(&mult);
if(op == "DIVIDE") p.ProcessCubes(&divide);
if(op == "UNARY") p.ProcessCube(&unaryFunction);
}
// Add routine #include "Isis.h"
void add(vector<Buffer *> &in, vector<Buffer *> &out) {
Buffer &inp1 = *in[0];
Buffer &inp2 = *in[1];
Buffer &outp = *out[0];
// Loop for each pixel in the line.
for(int i = 0; i < inp1.size(); i++) {
if(IsSpecial(inp1[i])) {
outp[i] = inp1[i];
}
else if(IsSpecial(inp2[i])) {
outp[i] = NULL8;
}
else {
outp[i] = ((inp1[i] - Isisd) * Isisa) + ((inp2[i] - Isise) * Isisb) + Isisc;
}
}
}
// Sub routine
void sub(vector<Buffer *> &in, vector<Buffer *> &out) {
Buffer &inp1 = *in[0];
Buffer &inp2 = *in[1];
Buffer &outp = *out[0];
// Loop for each pixel in the line.
for(int i = 0; i < inp1.size(); i++) {
if(IsSpecial(inp1[i])) {
outp[i] = inp1[i];
}
else if(IsSpecial(inp2[i])) {
outp[i] = NULL8;
}
else {
outp[i] = ((inp1[i] - Isisd) * Isisa) - ((inp2[i] - Isise) * Isisb) + Isisc;
}
}
}
// Sub routine #include "algebra.h"
void mult(vector<Buffer *> &in, vector<Buffer *> &out) {
Buffer &inp1 = *in[0];
Buffer &inp2 = *in[1];
Buffer &outp = *out[0];
// Loop for each pixel in the line. #include "Application.h"
for(int i = 0; i < inp1.size(); i++) {
if(IsSpecial(inp1[i])) {
outp[i] = inp1[i];
}
else if(IsSpecial(inp2[i])) {
outp[i] = NULL8;
}
else {
outp[i] = ((inp1[i] - Isisd) * Isisa) * ((inp2[i] - Isise) * Isisb) + Isisc;
}
}
}
// Div routine using namespace Isis;
void divide(vector<Buffer *> &in, vector<Buffer *> &out) {
Buffer &inp1 = *in[0];
Buffer &inp2 = *in[1];
Buffer &outp = *out[0];
// Loop for each pixel in the line. void IsisMain() {
for(int i = 0; i < inp1.size(); i++) { UserInterface &ui = Application::GetUserInterface();
if(IsSpecial(inp1[i])) { algebra(ui);
outp[i] = inp1[i];
}
else if(IsSpecial(inp2[i])) {
outp[i] = NULL8;
}
else {
if((inp2[i] - Isise) * Isisb == 0.0) {
outp[i] = NULL8;
}
else {
outp[i] = ((inp1[i] - Isisd) * Isisa) / ((inp2[i] - Isise) * Isisb) + Isisc;
}
}
}
} }
// Unary routine
void unaryFunction(Buffer &in, Buffer &out) {
// Loop for each pixel in the line.
for(int i = 0; i < in.size(); i++) {
if(IsSpecial(in[i])) {
out[i] = in[i];
}
else {
out[i] = in[i] * Isisa + Isisc;
}
}
}
BLANKS = "%-6s"
LENGTH = "%-40s"
include $(ISISROOT)/make/isismake.tststree
APPNAME = algebra
include $(ISISROOT)/make/isismake.tsts
commands:
$(APPNAME) from=$(INPUT)/isisTruth.cub+1 \
from2=$(INPUT)/isisTruth.cub+2 \
to=$(OUTPUT)/algebraTruth2.cub \
operator=add \
a=1 \
b=1 \
c=0 > /dev/null;
APPNAME = algebra
include $(ISISROOT)/make/isismake.tsts
commands:
$(APPNAME) from=$(INPUT)/isisTruth.cub+1 \
from2=$(INPUT)/isisTruth.cub+2 \
to=$(OUTPUT)/algebraTruth5.cub \
operator=divide \
a=1 \
b=1 \
c=0 > /dev/null;
APPNAME = algebra
include $(ISISROOT)/make/isismake.tsts
commands:
$(APPNAME) from=$(INPUT)/isisTruth.cub+1 \
from2=$(INPUT)/isisTruth.cub+2 \
to=$(OUTPUT)/algebraTruth4.cub \
operator=multiply \
a=1 \
b=1 \
c=0 > /dev/null;
APPNAME = algebra
include $(ISISROOT)/make/isismake.tsts
commands:
$(APPNAME) from=$(INPUT)/isisTruth.cub+1 \
from2=$(INPUT)/isisTruth.cub+2 \
to=$(OUTPUT)/algebraTruth3.cub \
a=1 \
b=1 \
c=0 > /dev/null;
APPNAME = algebra
include $(ISISROOT)/make/isismake.tsts
commands:
$(APPNAME) from=$(INPUT)/isisTruth.cub+1 \
to= $(OUTPUT)/algebraTruth1.cub \
operator=unary \
a=1 \
c=0 > /dev/null;
#include "algebra.h"
#include "Brick.h"
#include "CameraFixtures.h"
#include "Histogram.h"
#include "LineManager.h"
#include "gtest/gtest.h"
using namespace Isis;
static QString APP_XML = FileName("$ISISROOT/bin/xml/algebra.xml").expanded();
/**
* class AlgebraCube
*
* Reimplements DefaultCube::resizeCube method to force the use
* of Real dns to properly test propagation of special pixels
* to the output cube.
*/
class AlgebraCube : public DefaultCube {
protected:
void resizeCube(int samples, int lines, int bands) {
label = Pvl();
PvlObject &isisCube = testCube->label()->findObject("IsisCube");
label.addObject(isisCube);
PvlGroup &dim = label.findObject("IsisCube").findObject("Core").findGroup("Dimensions");
dim.findKeyword("Samples").setValue(QString::number(samples));
dim.findKeyword("Lines").setValue(QString::number(lines));
dim.findKeyword("Bands").setValue(QString::number(bands));
// force Real dns
PvlObject &core = label.findObject("IsisCube").findObject("Core");
PvlGroup &pixels = core.findGroup("Pixels");
pixels.findKeyword("Type").setValue("Real");
delete testCube;
testCube = new Cube();
testCube->fromIsd(tempDir.path() + "/default.cub", label, isd, "rw");
LineManager line(*testCube);
int pixelValue = 1;
for(int band = 1; band <= bands; band++) {
for (int i = 1; i <= testCube->lineCount(); i++) {
line.SetLine(i, band);
for (int j = 0; j < line.size(); j++) {
line[j] = (double) (pixelValue % 255);
pixelValue++;
}
testCube->write(line);
}
}
// set 1st three diagonal pixels of band 1 to special pixels Null, Lrs, and Lis
// set last two diagonal pixels of band 2 to special pixels Hrs and His
Brick b(1, 1, 1, testCube->pixelType()); // create buffer of size 1 pixel
b.SetBasePosition(1, 1, 1);
b[0] = Isis::Null;
testCube->write(b);
b.SetBasePosition(2, 2, 1);
b[0] = Isis::Lrs;
testCube->write(b);
b.SetBasePosition(3, 3, 1);
b[0] = Isis::Lis;
testCube->write(b);
b.SetBasePosition(4, 4, 2);
b[0] = Isis::Hrs;
testCube->write(b);
b.SetBasePosition(5, 5, 2);
b[0] = Isis::His;
testCube->write(b);
}
};
/**
* FunctionalTestAlgebraAdd
*
* Pixel by pixel addition of bands 1 and 2 of input cube.
*
* INPUT: testCube from DefaultCube fixture with 2 bands.
* a=1 (multiplicative constant for 1st input cube)
* b=1 (multiplicative constant for 2nd input cube)
* c=0 (additive constant for entire equation)
* d=0 (additive constant for 1st input cube)
* e=0 (additive constant for 2nd input cube)
*
* Band 1 Band 2
*
* | N | 2 | 3 | 4 | 5 | | 26| 27| 28| 29| 30|
* | 6 |Lrs| 8 | 9 | 10| | 31| 32| 33| 34| 35|
* | 11| 12|Lis| 14| 15| | 36| 37| 38| 39| 40|
* | 16| 17| 18| 19| 20| | 41| 42| 43|Hrs| 45|
* | 21| 22| 23| 24| 25| | 46| 47| 48| 49|His|
*
* OUTPUT: algebraAddOut.cub
*
* | N | 29| 31| 33| 35|
* | 37|Lrs| 41| 43| 45|
* | 47| 49|Lis| 53| 55|
* | 57| 59| 61| N | 65|
* | 67| 69| 71| 73| N |
*/
TEST_F(AlgebraCube, FunctionalTestAlgebraAdd) {
// reduce test cube size, create two bands
resizeCube(5, 5, 2);
// close and reopen test cube to ensure dn buffer is available
testCube->reopen("r");
// run algebra
QVector<QString> args = {"from=" + testCube->fileName() + "+1",
"from2=" + testCube->fileName() + "+2",
"to=" + tempDir.path() + "/algebraAddOut.cub",
"operator=add",
"a=1",
"b=1",
"c=0"};
UserInterface ui(APP_XML, args);
try {
algebra(testCube, ui, testCube);
}
catch(IException &e) {
FAIL() << e.toString().toStdString().c_str() << std::endl;
}
// Open output cube
Cube outCube(tempDir.path() + "/algebraAddOut.cub");
// validate histogram statistics in output cube
std::unique_ptr<Histogram> hist (outCube.histogram(1));
EXPECT_EQ(hist->ValidPixels(), 20);
EXPECT_EQ(hist->Average(), 51);
EXPECT_EQ(hist->Sum(), 1020);
// validate propagation of special pixels
Brick b(1, 1, 1, outCube.pixelType()); // create buffer of size 1 pixel
b.SetBasePosition(1, 1, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Null");
b.SetBasePosition(2, 2, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Lrs");
b.SetBasePosition(3, 3, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Lis");
b.SetBasePosition(4, 4, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Null");
b.SetBasePosition(5, 5, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Null");
outCube.close();
}
/**
* FunctionalTestAlgebraSubtract
*
* Pixel by pixel subtraction of band 1 from band 2 of input cube.
*
* INPUT: testCube from DefaultCube fixture with 2 bands.
* a=1 (multiplicative constant for 1st input cube)
* b=1 (multiplicative constant for 2nd input cube)
* c=0 (additive constant for entire equation)
* d=0 (additive constant for 1st input cube)
* e=0 (additive constant for 2nd input cube)
*
* Band 1 Band 2
*
* | N | 2 | 3 | 4 | 5 | | 26| 27| 28| 29| 30|
* | 6 |Lrs| 8 | 9 | 10| | 31| 32| 33| 34| 35|
* | 11| 12|Lis| 14| 15| | 36| 37| 38| 39| 40|
* | 16| 17| 18| 19| 20| | 41| 42| 43|Hrs| 45|
* | 21| 22| 23| 24| 25| | 46| 47| 48| 49|His|
*
* OUTPUT: algebraSubtractOut.cub
*
* | N | 25| 25| 25| 25|
* | 25| N| 25| 25| 25|
* | 25| 25| N| 25| 25|
* | 25| 25| 25|Hrs| 25|
* | 25| 25| 25| 25|His|
*/
TEST_F(AlgebraCube, FunctionalTestAlgebraSubtract) {
// reduce test cube size, create two bands
resizeCube(5, 5, 2);
// close and reopen test cube to ensure dn buffer is available
testCube->reopen("r");
// run algebra
QVector<QString> args = {"from=" + testCube->fileName() + "+2",
"from2=" + testCube->fileName() + "+1",
"to=" + tempDir.path() + "/algebraSubtractOut.cub",
"operator=subtract",
"a=1",
"b=1",
"c=0"};
UserInterface ui(APP_XML, args);
try {
algebra(testCube, ui, testCube);
}
catch(IException &e) {
FAIL() << e.toString().toStdString().c_str() << std::endl;
}
// Open output cube
Cube outCube(tempDir.path() + "/algebraSubtractOut.cub");
// validate histogram statistics in output cube
std::unique_ptr<Histogram> hist (outCube.histogram(1));
EXPECT_EQ(hist->ValidPixels(), 20);
EXPECT_EQ(hist->Average(), 25);
EXPECT_EQ(hist->Sum(), 500);
// validate propagation of special pixels
Brick b(1, 1, 1, outCube.pixelType()); // create buffer of size 1 pixel
b.SetBasePosition(1, 1, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Null");
b.SetBasePosition(2, 2, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Null");
b.SetBasePosition(3, 3, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Null");
b.SetBasePosition(4, 4, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Hrs");
b.SetBasePosition(5, 5, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "His");
outCube.close();
}
/**
* FunctionalTestAlgebraMultiply
*
* Pixel by pixel multiplication of band 1 from band 2 of input cube.
*
* INPUT: testCube from DefaultCube fixture with 2 bands.
* a=1 (multiplicative constant for 1st input cube)
* b=1 (multiplicative constant for 2nd input cube)
* c=0 (additive constant for entire equation)
* d=0 (additive constant for 1st input cube)
* e=0 (additive constant for 2nd input cube)
*
* Band 1 Band 2
*
* | N | 2 | 3 | 4 | 5 | | 26| 27| 28| 29| 30|
* | 6 |Lrs| 8 | 9 | 10| | 31| 32| 33| 34| 35|
* | 11| 12|Lis| 14| 15| | 36| 37| 38| 39| 40|
* | 16| 17| 18| 19| 20| | 41| 42| 43|Hrs| 45|
* | 21| 22| 23| 24| 25| | 46| 47| 48| 49|His|
*
* OUTPUT: algebraMultiplyOut.cub
*
* | N| 54| 84| 116| 150|
* | 186| Lrs| 264| 306| 350|
* | 396| 444| Lis| 546| 600|
* | 656| 714| 774| N| 900|
* | 966|1034|1104|1176| N|
*/
TEST_F(AlgebraCube, FunctionalTestAlgebraMultiply) {
// reduce test cube size, create two bands
resizeCube(5, 5, 2);
// close and reopen test cube to ensure dn buffer is available
testCube->reopen("r");
// run algebra
QVector<QString> args = {"from=" + testCube->fileName() + "+1",
"from2=" + testCube->fileName() + "+2",
"to=" + tempDir.path() + "/algebraMultiplyOut.cub",
"operator=multiply",
"a=1",
"b=1",
"c=0"};
UserInterface ui(APP_XML, args);
try {
algebra(testCube, ui, testCube);
}
catch(IException &e) {
FAIL() << e.toString().toStdString().c_str() << std::endl;
}
// Open output cube
Cube outCube(tempDir.path() + "/algebraMultiplyOut.cub");
// validate histogram statistics in output cube
std::unique_ptr<Histogram> hist (outCube.histogram(1));
EXPECT_EQ(hist->ValidPixels(), 20);
EXPECT_EQ(hist->Average(), 541);
EXPECT_EQ(hist->Sum(), 10820);
// validate propagation of special pixels
Brick b(1, 1, 1, outCube.pixelType()); // create buffer of size 1 pixel
b.SetBasePosition(1, 1, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Null");
b.SetBasePosition(2, 2, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Lrs");
b.SetBasePosition(3, 3, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Lis");
b.SetBasePosition(4, 4, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Null");
b.SetBasePosition(5, 5, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Null");
outCube.close();
}
/**
* FunctionalTestAlgebraDivide
*
* Pixel by pixel division band 1 / band 2 of input cube.
*
* INPUT: testCube from DefaultCube fixture with 2 bands.
* a=1 (multiplicative constant for 1st input cube)
* b=1 (multiplicative constant for 2nd input cube)
* c=0 (additive constant for entire equation)
* d=0 (additive constant for 1st input cube)
* e=0 (additive constant for 2nd input cube)
*
* Band 1 Band 2
*
* | N | 2 | 3 | 4 | 5 | | 26| 27| 28| 29| 30|
* | 6 |Lrs| 8 | 9 | 10| | 31| 32| 33| 34| 35|
* | 11| 12|Lis| 14| 15| | 36| 37| 38| 39| 40|
* | 16| 17| 18| 19| 20| | 41| 42| 43|Hrs| 45|
* | 21| 22| 23| 24| 25| | 46| 47| 48| 49|His|
*
* OUTPUT: algebraDivideOut.cub
*
* | N|.074|.107|.137|.166| Values shown truncated at 3 decimal places
* |.193| Lrs|.242|.264|.285|
* |.305|.324| Lis|.358|.375|
* |.390|.404|.418| N|.444|
* |.456|.468|.479|.489| N|
*/
TEST_F(AlgebraCube, FunctionalTestAlgebraDivide) {
// reduce test cube size, create two bands
resizeCube(5, 5, 2);
// close and reopen test cube to ensure dn buffer is available
testCube->reopen("r");
// run algebra
QVector<QString> args = {"from=" + testCube->fileName() + "+1",
"from2=" + testCube->fileName() + "+2",
"to=" + tempDir.path() + "/algebraDivideOut.cub",
"operator=divide",
"a=1",
"b=1",
"c=0"};
UserInterface ui(APP_XML, args);
try {
algebra(testCube, ui, testCube);
}
catch(IException &e) {
FAIL() << e.toString().toStdString().c_str() << std::endl;
}
// Open output cube
Cube outCube(tempDir.path() + "/algebraDivideOut.cub");
// validate histogram statistics in output cube
std::unique_ptr<Histogram> hist (outCube.histogram(1));
EXPECT_EQ(hist->ValidPixels(), 20);
EXPECT_NEAR(hist->Average(), 0.319384, 0.000001);
EXPECT_NEAR(hist->Sum(), 6.387686, 0.000001);
// validate propagation of special pixels
Brick b(1, 1, 1, outCube.pixelType()); // create buffer of size 1 pixel
b.SetBasePosition(1, 1, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Null");
b.SetBasePosition(2, 2, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Lrs");
b.SetBasePosition(3, 3, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Lis");
b.SetBasePosition(4, 4, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Null");
b.SetBasePosition(5, 5, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Null");
outCube.close();
}
/**
* FunctionalTestAlgebraUnary
*
* Unary processing of band 1 (a * from1) + c).
*
* INPUT: testCube from DefaultCube fixture with 2 bands.
* a=1 (multiplicative constant for 1st input cube)
* b=1 (multiplicative constant for 2nd input cube)
* c=0 (additive constant for entire equation)
* d=0 (additive constant for 1st input cube)
* e=0 (additive constant for 2nd input cube)
*
* Band 1
*
* | N | 2 | 3 | 4 | 5 |
* | 6 |Lrs| 8 | 9 | 10|
* | 11| 12|Lis| 14| 15|
* | 16| 17| 18| 19| 20|
* | 21| 22| 23| 24| 25|
*
* OUTPUT: algebraUnaryOut.cub (identical to input band 1)
*
* | N | 2 | 3 | 4 | 5 |
* | 6 |Lrs| 8 | 9 | 10|
* | 11| 12|Lis| 14| 15|
* | 16| 17| 18| 19| 20|
* | 21| 22| 23| 24| 25|
*/
TEST_F(AlgebraCube, FunctionalTestAlgebraUnary) {
// reduce test cube size, create two bands
resizeCube(5, 5, 1);
// close and reopen test cube to ensure dn buffer is available
testCube->reopen("r");
// run algebra
QVector<QString> args = {"from=" + testCube->fileName() + "+1",
"to=" + tempDir.path() + "/algebraUnaryOut.cub",
"operator=unary",
"a=1",
"c=0"};
UserInterface ui(APP_XML, args);
try {
algebra(testCube, ui);
}
catch(IException &e) {
FAIL() << e.toString().toStdString().c_str() << std::endl;
}
// Open output cube
Cube outCube(tempDir.path() + "/algebraUnaryOut.cub");
// validate histogram statistics in output cube
std::unique_ptr<Histogram> hist (outCube.histogram(1));
EXPECT_EQ(hist->ValidPixels(), 22);
EXPECT_NEAR(hist->Average(), 13.818181, 0.000001);
EXPECT_EQ(hist->Sum(), 304);
// validate propagation of special pixels
Brick b(1, 1, 1, outCube.pixelType()); // create buffer of size 1 pixel
b.SetBasePosition(1, 1, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Null");
b.SetBasePosition(2, 2, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Lrs");
b.SetBasePosition(3, 3, 1);
outCube.read(b);
EXPECT_EQ(PixelToString(b[0]), "Lis");
outCube.close();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment