Unverified Commit f3bc19de authored by Stuart Sides's avatar Stuart Sides Committed by GitHub
Browse files

Phocube add all bands Closes #3877 (#4689)

* Fixed band bin updates

* tweek band ben

* Added test for ALLDN option to phocube

* Addressed histogram comment and conflicts

* Updated changelog
parent 0ec76e9b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ Keywords when running CAMSTATS. [#3605](https://github.com/USGS-Astrogeology/IS
- Added additional translation files for TGO CaSSiS in order to support PSA compliant labels. [#4567](https://github.com/USGS-Astrogeology/ISIS3/issues/4567)
- Added support for KaguyaTC SP Support data ingest. [#4668](https://github.com/USGS-Astrogeology/ISIS3/issues/4668)
- Added examples to the jigsaw documentation. [#4718](https://github.com/USGS-Astrogeology/ISIS3/issues/4718)
- Added ALLDNS option to phocube. [#3877](https://github.com/USGS-Astrogeology/ISIS3/issues/3877)

### Deprecated
- Deprecated edrget as discussed in [#3313](https://github.com/USGS-Astrogeology/ISIS3/issues/3313).
+69 −12
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ namespace Isis {
  }

  void phocube(Cube *icube, UserInterface &ui)  {

    // Get the camera information if this is not a mosaic. Otherwise, get the
    // projection information
    bool noCamera;
@@ -141,8 +142,17 @@ namespace Isis {
      if ((localSolarTime = ui.GetBoolean("LOCALTIME"))) nbands++;
    }

    // ALLDN includes DN so if both are set ignore DN
    bool dn;
    bool alldn;
    if ((dn = ui.GetBoolean("DN"))) nbands++;
    if ((alldn = ui.GetBoolean("ALLDN"))) {
      if (dn) {
        dn = false;
        nbands--;
      }
      nbands += icube->bandCount();
    }

    bool latitude;
    if ((latitude = ui.GetBoolean("LATITUDE"))) nbands++;
@@ -159,9 +169,10 @@ namespace Isis {
      throw IException(IException::User, message, _FILEINFO_);
    }

    // If outputting a dn band, retrieve the orignal values for the filter name from the input cube,
    // if it exists.  Otherwise, the default will be "DN"
    // If outputting a dn band, retrieve the orignal values for the filter name(s) from the input cube,
    // if they are in the band bin group.  Otherwise, the default will be "DN"
    QString bname = "DN";
    PvlKeyword bnames;
    if (dn && icube->hasGroup("BandBin")) {
      PvlGroup &mybb = icube->group("BandBin");
      if ( mybb.hasKeyword("Name") ) {
@@ -171,6 +182,15 @@ namespace Isis {
        bname = mybb["FilterName"][0];
      }
    }
    else if (alldn && icube->hasGroup("BandBin")) {
      PvlGroup &mybb = icube->group("BandBin");
      if (mybb.hasKeyword("Name")) {
        bnames = mybb.findKeyword("Name");
      }
      else if (mybb.hasKeyword("FilterName")) {
        bnames = mybb.findKeyword("FilterName");
      }
    }

    // Create a bandbin group for the output label
    PvlKeyword name("Name");
@@ -178,6 +198,12 @@ namespace Isis {
      name += bname;
      raBandNum++;
    }
    else if (alldn) {
      for (int i = 0; i<bnames.size(); i++) {
        name += bnames[i];
        raBandNum++;
      }
    }
    if (phase) {
      name += "Phase Angle";
      raBandNum++;
@@ -317,16 +343,32 @@ namespace Isis {
          MosData mosd, *p_mosd(0);  // For special mosaic angles

          int index = i * 64 + j;
          int inIndex = index;
          int inIndex = index; // Points to the first band's DN value of the current spectra

          // Always transfer the DN(s) to the output cube
          if (dn) {
            out[index] = in[index];
            index += 64 * 64;
          }
          else if (alldn) {
            for (int i = 0; i < icube->bandCount(); i++) {
              out[index] = in[index];
              index += 64 * 64;
            }
          }

          // If dn is true, make sure to not overwrite the original pixels with NULL for the dn band
          // May need to skip the pho  calculations for the rest of this spectra. If so,
          // fill the pho bands with ISIS Null, but leave the DN band(s) alone.
          // NOTE: index -vs- inIndex below
          if (!specialPixels && IsSpecial(in[inIndex])) {
            for (int band = (dn) ? 1 : 0; band < nbands; band++) {
            int startBand = 0;
            if (dn) {
              startBand = 1;
            }
            else if (alldn) {
              startBand = icube->bandCount();
            }
            for (int band = startBand; band < nbands; band++) {
              out[index] = Isis::Null;
              index += 64 * 64;
            }
@@ -550,9 +592,17 @@ namespace Isis {
            }
          }

          // Trim outer space except RA and dec bands
          // Trim no target intersection except DN)s), RA and DEC bands
          else {
            for (int band = (dn) ? 1 : 0; band < nbands; band++) {
            int startBand = 0;
            if (dn) {
              startBand = 1;
            }
            else if (alldn) {
              startBand = icube->bandCount();
            }

            for (int band = startBand; band < nbands; band++) {
              if (ra && band == raBandNum) {
                out[index] = cam->RightAscension();
              }
@@ -567,9 +617,16 @@ namespace Isis {
          }
        }
      }
    };
    }; // End processing function


    if (alldn) {
      p.SetInputCube(icube);
    }
    else {
      p.SetInputCube(icube, OneBand);
    }

    Cube *ocube = p.SetOutputCube(ui.GetFileName("TO"), ui.GetOutputAttribute("TO"),
                                  icube->sampleCount(), icube->lineCount(), nbands);
    p.SetBrickSize(64, 64, nbands);
+84 −55
Original line number Diff line number Diff line
@@ -188,7 +188,7 @@ xsi:noNamespaceSchemaLocation=

  <liens>
    <item>Add resolution to possible outputs</item>
    <item>Convert to a IsisProcessBySpectra when it gets written</item>
    <item>Convert to an IsisProcessBySpectra when it gets written</item>
  </liens>

  <history>
@@ -319,6 +319,9 @@ xsi:noNamespaceSchemaLocation=
    <change name="Kaitlyn Lee" date="2020-03-15">
      Converted application and tests for Gtest conversion.
    </change>
    <change name="Stuart Sides" date="2021-06-01">
      Add ALLDNS parameter to propagate all input bands to the output instead of just one band.
    </change>
    <change name="Adam Paquette" date="2020-08-23">
      Added initial slope and backplane options for the local normal and the
      ellipsoid normal.
@@ -427,8 +430,11 @@ xsi:noNamespaceSchemaLocation=
        <default><item>TRUE</item></default>
        <brief>Include special pixels in the ouptut image</brief>
        <description>
          If this parameter is true, calculations will be done on special pixels.
          If this parameter is false, special pixels will be skipped and set to NULL in the output image for all bands selected.
          Controls the output of the values phocube calculates based on the DN from the first band.
          If this parameter is true, phocube will always attempt to calculate values for the requested bands.
          If this parameter is false, and the DN is a special pixel value, phocube will not
          calculate values, and will instead place ISIS Null values in all requested photometry bands.
          The DN bands, if requested, will be transfered to the output cube regardless of this setting.
        </description>
      </parameter>
      <parameter name="DN">
@@ -443,6 +449,30 @@ xsi:noNamespaceSchemaLocation=
          image information.
        </description>
      </parameter>
      <parameter name="ALLDNS">
        <type>boolean</type>
        <default><item>FALSE</item></default>
        <brief>Propagate all of the input pixel DNs to the output file</brief>
        <description>
          <p>
            If this parameter is true, all the <def link="Digital Number">DN</def> values
            from all of the bands in the input image, subject to the input cube attribute,
            will be propagated to the output file.
            Calculations for the other bands that require a sensor model (e.g., phase) will be
            based on the first band, again subject to the cube attribute.
            This doesn't affect the values calculated for those bands when the
            input image bands are spatially allinged,
            but it is very import when the bands of the input image are not
            spatially alligned (e.g., Level 1, Odyssey, Themis IR).
            Use the input cube attribute to select the band used to calculate
            the other phocube values (e.g., ThemisIR.cub+9,1-5).
            The geometry of the first band or the first band in the input attribute,
            will be used to calculate the phocube values.
            NOTE: If the DN parameter is also set then ALLDNS will take presidence,
            and DN will be ignored.
          </p>
        </description>
      </parameter>
      <parameter name="PHASE">
        <type>boolean</type>
        <default><item>TRUE</item></default>
@@ -776,8 +806,7 @@ xsi:noNamespaceSchemaLocation=
                Append the following parameters to the <i>automos</i> command line to utilize this backplane band:
              </dt>
              <dd>
              <b>priority=band type=keyword keyname=Name keyvalue=albedoRank
              criteria=lesser</b>.
                <b>priority=band type=keyword keyname=Name keyvalue=albedoRank criteria=lesser</b>.
              </dd>
            </dl>
            See <i>automos</i> documentation for further details.
+82 −12
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ using namespace Isis;

static QString APP_XML = FileName("$ISISROOT/bin/xml/phocube.xml").expanded();


TEST_F(DefaultCube, FunctionalTestPhocubeDefault) {
  QString cubeFileName = tempDir.path() + "/phocubeTEMP.cub";
  QVector<QString> args = {"to=" + cubeFileName};
@@ -54,6 +55,7 @@ TEST_F(DefaultCube, FunctionalTestPhocubeDefault) {
  cube.close();
}


TEST_F(DefaultCube, FunctionalTestPhocubeAllBands) {
  QString cubeFileName = tempDir.path() + "/phocubeTEMP.cub";
  QVector<QString> args = {"to=" + cubeFileName, "dn=true", "phase=true", "emission=true",
@@ -114,6 +116,7 @@ TEST_F(DefaultCube, FunctionalTestPhocubeAllBands) {
  cube.close();
}


TEST_F(DefaultCube, FunctionalTestPhocubeSpecialPixels) {
  QString cubeFileName = tempDir.path() + "/phocubeTEMP.cub";
  QVector<QString> args = {"to=" + cubeFileName, "specialpixels=false", "dn=true", "emission=false",
@@ -195,6 +198,7 @@ TEST_F(DefaultCube, FunctionalTestPhocubeSpecialPixels) {
  cube.close();
}


TEST_F(OffBodyCube, FunctionalTestPhocubeOffBody) {
  QString cubeFileName = tempDir.path() + "/phocubeTEMP.cub";
  QVector<QString> args = {"to=" + cubeFileName, "emission=false", "radec=true",
@@ -246,6 +250,7 @@ TEST_F(OffBodyCube, FunctionalTestPhocubeOffBody) {
  cube.close();
}


TEST_F(DefaultCube, FunctionalTestPhocubeMosaic) {
  QString cubeFileName = tempDir.path() + "/phocubeTEMP.cub";
  QVector<QString> args = {"to=" + cubeFileName, "source=projection", "dn=true",
@@ -277,6 +282,7 @@ TEST_F(DefaultCube, FunctionalTestPhocubeMosaic) {
  cube.close();
}


// Tests that we can process radar data.
TEST_F(MiniRFCube, FunctionalTestPhocubeMiniRF) {
  QString cubeFileName = tempDir.path() + "/phocubeTEMP.cub";
@@ -319,6 +325,7 @@ TEST_F(MiniRFCube, FunctionalTestPhocubeMiniRF) {
  cube.close();
}


TEST_F(DefaultCube, FunctionalTestPhocubeNoBandBin) {
  QString cubeFileName = tempDir.path() + "/phocubeTEMP.cub";
  QVector<QString> args = {"to=" + cubeFileName, "phase=no", "emission=no", "incidence=no",
@@ -347,3 +354,66 @@ TEST_F(DefaultCube, FunctionalTestPhocubeNoBandBin) {

  cube.close();
}


TEST_F(DefaultCube, FunctionalTestPhocubeAllDnBands) {
  QString cubeFileName = tempDir.path() + "/phocubeTEMP.cub";
  QVector<QString> args = {"to=" + cubeFileName, "alldn=true"};

  UserInterface options(APP_XML, args);
  resizeCube(5, 5, 3);
  Pvl *inIsisLabel = testCube->label();
  PvlGroup &inBandBin = inIsisLabel->findGroup("BandBin", Pvl::Traverse);
  inBandBin["FilterName"] = "(B1, B2, B3)";

  phocube(testCube, options);

  Cube cube(cubeFileName);
  Pvl *isisLabel = cube.label();

  ASSERT_EQ(cube.sampleCount(), testCube->sampleCount());
  ASSERT_EQ(cube.lineCount(), testCube->lineCount());
  ASSERT_EQ(cube.bandCount(), 8);

  PvlGroup bandBin = isisLabel->findGroup("BandBin", Pvl::Traverse);
  EXPECT_PRED_FORMAT2(AssertQStringsEqual, bandBin.findKeyword("FilterName")[0], "B1");
  EXPECT_PRED_FORMAT2(AssertQStringsEqual, bandBin.findKeyword("FilterName")[1], "B2");
  EXPECT_PRED_FORMAT2(AssertQStringsEqual, bandBin.findKeyword("FilterName")[2], "B3");

  // Test band 1
  {
    int band = 1;
    std::unique_ptr<Histogram> inHist (testCube->histogram(band));
    std::unique_ptr<Histogram> outHist (cube.histogram(band));
    EXPECT_NEAR(outHist->Average(), inHist->Average(), .000001);
    EXPECT_NEAR(outHist->Sum(), inHist->Sum(), .000001);
    EXPECT_EQ(outHist->ValidPixels(), inHist->ValidPixels());
    EXPECT_NEAR(outHist->StandardDeviation(), inHist->StandardDeviation(), .000001);
  }

  // Test band 2
  {
    int band = 2;
    std::unique_ptr<Histogram> inHist (testCube->histogram(band));
    std::unique_ptr<Histogram> outHist (cube.histogram(band));
    EXPECT_NEAR(outHist->Average(), inHist->Average(), .000001);
    EXPECT_NEAR(outHist->Sum(), inHist->Sum(), .000001);
    EXPECT_EQ(outHist->ValidPixels(), inHist->ValidPixels());
    EXPECT_NEAR(outHist->StandardDeviation(), inHist->StandardDeviation(), .000001);
  }

  // Test band 3
  {
    int band = 3;
    std::unique_ptr<Histogram> inHist (testCube->histogram(band));
    std::unique_ptr<Histogram> outHist (cube.histogram(band));
    EXPECT_NEAR(outHist->Average(), inHist->Average(), .000001);
    EXPECT_NEAR(outHist->Sum(), inHist->Sum(), .000001);
    EXPECT_EQ(outHist->ValidPixels(), inHist->ValidPixels());
    EXPECT_NEAR(outHist->StandardDeviation(), inHist->StandardDeviation(), .000001);
  }


  cube.close();
}