Unverified Commit f3784dc2 authored by Oleg Alexandrov's avatar Oleg Alexandrov Committed by GitHub
Browse files

Incremental bugfix for stitching WAC framelets (#4950)

* Add to the framestitch tool the ability to remove lines which are redundant among the frames

* Minor code tuning

* framestitch: Add test, fix tests, resize the cube, and write numLinesOverlap to the cub

* Set framestitch num trim lines default to 0, fix two compiler warnings

* Wording fix
parent 66d3d186
Loading
Loading
Loading
Loading
+64 −34
Original line number Diff line number Diff line
#include "framestitch.h"

#include <QString>
#include <iostream>

#include "Brick.h"
#include "Buffer.h"
@@ -121,16 +122,10 @@ namespace Isis {
      }
    }

    QString outCubeFile = ui.GetCubeName("TO");
    Cube *outCube = process.SetOutputCube(
          outCubeFile, CubeAttributeOutput(outCubeFile),
          evenCube->sampleCount(), evenCube->lineCount(), evenCube->bandCount());

    int frameHeight = 1;
    if (ui.WasEntered("frameHeight")) {
      frameHeight = ui.GetInteger("FRAMEHEIGHT");
    }
    else {
    } else {
      // User didn't pass the size of the frames so attempt to infer it from
      // the cubes
      int evenFrameHeight = computeFrameHeight(evenCube);
@@ -144,6 +139,23 @@ namespace Isis {

      frameHeight = evenFrameHeight;
    }
    int numFrames = evenCube->lineCount() / frameHeight;

    int numLinesOverlap = 0; // The default value
    if (ui.WasEntered("NUM_LINES_OVERLAP"))
      numLinesOverlap = ui.GetInteger("NUM_LINES_OVERLAP");

    if (numLinesOverlap % 2 != 0 || numLinesOverlap < 0) {
      QString msg = "Expecting a non-negative and even value for NUM_LINES_OVERLAP.";
      throw IException(IException::User, msg, _FILEINFO_);
    }

    int reducedFrameHeight = frameHeight - numLinesOverlap;
    
    QString outCubeFile = ui.GetCubeName("TO");
    Cube *outCube = process.SetOutputCube(
          outCubeFile, CubeAttributeOutput(outCubeFile),
          evenCube->sampleCount(), numFrames * reducedFrameHeight, evenCube->bandCount());
    
    // If there's an even number of frames and the inputs are flipped, we have to
    // swap even and odd because the first frame in the even cube is valid and the
@@ -156,27 +168,38 @@ namespace Isis {
    // 0000  ####         ####  0000
    // ####  0000         0000  ####
    //
    int numFrames = evenCube->lineCount() / frameHeight;
    bool swapInputCubes = inputFlipped && numFrames % 2 == 0;

    // Processing Setup
    // Processing setup
    process.SetBrickSize(evenCube->sampleCount(), frameHeight, evenCube->bandCount());
    process.PropagateTables(false);
    process.PropagatePolygons(false);

    /**
     * Frame stitching processing function
     */
    auto interweaveFrames = [&](std::vector<Buffer *> &in, std::vector<Buffer *> &out)->void {
      // Assumes odd is first and even is second
      int inIndex = (in[0]->Line() / frameHeight) % 2;
      if (swapInputCubes) {
    // Put together the frames from the two input cubes. Note that we
    // wipe a total of numLinesOverlap lines from each frame as we do
    // so, by simply not reading in the lines we don't want to keep.
    for (int frame = 0; frame < numFrames; frame++) {

      Brick buff(evenCube->sampleCount(), reducedFrameHeight, evenCube->bandCount(),
                   evenCube->pixelType());
      
      // Set reading position
      buff.SetBasePosition(1, frame * frameHeight + numLinesOverlap/2 + 1, 1);

      int inIndex = frame % 2;
      if (swapInputCubes)
        inIndex = 1 - inIndex;
      }
      out[0]->Copy(*in[inIndex]);
    };

    process.StartProcess(interweaveFrames);
      if (inIndex == 0) 
        oddCube->read(buff);
      else
        evenCube->read(buff);

      // Set writing position
      buff.SetBasePosition(1, frame * reducedFrameHeight + 1, 1);
      
      outCube->write(buff);
    }

    // Update the output label
    outCube->deleteGroup("Kernels");
@@ -189,24 +212,25 @@ namespace Isis {
    }
    outInst["Framelets"].setValue("All");

    // ProcessByBrick requires that all buffers move through the cubes the same
    // way so we have to do a second manual pass to flip the output cube if requested.
    // Flip the output cube if requested
    if (ui.GetBoolean("FLIP")) {
      Brick topBuff(outCube->sampleCount(), frameHeight, outCube->bandCount(), outCube->pixelType());
      Brick bottomBuff(outCube->sampleCount(), frameHeight, outCube->bandCount(), outCube->pixelType());
      Brick tempBuff(outCube->sampleCount(), frameHeight, outCube->bandCount(), outCube->pixelType());
      // Need a temporary buffer to help with the swapping of top and
      // bottom portions of outCube.
      Brick topBuff(outCube->sampleCount(), reducedFrameHeight, outCube->bandCount(), outCube->pixelType());
      Brick botBuff(outCube->sampleCount(), reducedFrameHeight, outCube->bandCount(), outCube->pixelType());
      Brick tmpBuff(outCube->sampleCount(), reducedFrameHeight, outCube->bandCount(), outCube->pixelType());

      for (int frame = 0; frame < numFrames / 2; frame++) {
        topBuff.SetBasePosition(1,frame * frameHeight + 1,1);
        topBuff.SetBasePosition(1,frame * reducedFrameHeight + 1,1);
        outCube->read(topBuff);
        bottomBuff.SetBasePosition(1,outCube->lineCount() - (frame + 1) * frameHeight + 1,1);
        outCube->read(bottomBuff);
        botBuff.SetBasePosition(1,outCube->lineCount() - (frame + 1) * reducedFrameHeight + 1,1);
        outCube->read(botBuff);

        tempBuff.Copy(topBuff);
        topBuff.Copy(bottomBuff);
        tmpBuff.Copy(topBuff);
        topBuff.Copy(botBuff);
        outCube->write(topBuff);
        bottomBuff.Copy(tempBuff);
        outCube->write(bottomBuff);
        botBuff.Copy(tmpBuff);
        outCube->write(botBuff);
      }

      if (!outInst.hasKeyword("DataFlipped")) {
@@ -215,8 +239,14 @@ namespace Isis {
      outInst["DataFlipped"].setValue(toString(!inputFlipped));
    }

    // Record numLinesOverlap
    if (!outInst.hasKeyword("NumLinesOverlap"))
      outInst.addKeyword(PvlKeyword("NumLinesOverlap"));
    outInst["numLinesOverlap"].setValue(toString(numLinesOverlap));
    
    process.EndProcess();
    
    return;
  }

}
} // end namespace Isis
+34 −5
Original line number Diff line number Diff line
@@ -6,11 +6,16 @@

  <description>
    <p>
      This program combines the even and odd frames from push frame <def link="Cube">cubes</def> back
      into a single interwoven <def link="Cube">cube</def>. It can also optionally flip the frame order
      so that adjacent ground features appear adjacent between frames. This program
      is designed to be run before processing the data in another software package
      as it removes the camera information from the output <def link="Cube">cube</def>.
      This program combines the even and odd frames from push frame
      <def link="Cube">cubes</def> back into a single interwoven <def
      link="Cube">cube</def>. It can also optionally flip the frame
      order so that adjacent ground features appear adjacent between
      frames. If the last several rows of a frame have the same
      data as the first several rows of the next frame, reduntant
      lines can be eliminated with the num_lines_overlap parameter.
      This program is designed to be run before processing the
      data in another software package as it removes the camera
      information from the output <def link="Cube">cube</def>.
    </p>
    <p>
      When many push frame images are ingested into ISIS, their frames are separated
@@ -127,6 +132,30 @@
        <internalDefault>Camera</internalDefault>
        <minimum>1</minimum>
      </parameter>

      <parameter name="NUM_LINES_OVERLAP">
        <type>integer</type>
        <brief>
          The number of lines in each frame repeating information
          present in neighboring frames.
        </brief>
        <description>
          <p>
          The estimated total number of lines in each frame which have
          the same pixel values as frames above and below it. During
          processing, half this amount of lines will be removed from
          each of the top and bottom of the frame. Must be an even
          non-negative number.
          </p>
          <p>
            If not entered, the program will assume the value 0. A value
			of 2 or 4 works reasonably for LRO WAC images.
          </p>
        </description>
        <internalDefault>0</internalDefault>
        <minimum>0</minimum>
      </parameter>

    </group>
  </groups>

+28 −1
Original line number Diff line number Diff line
@@ -419,3 +419,30 @@ TEST_F(PushFramePair, FunctionalTestFramestitchAutoDifferentHeights) {
    FAIL() << "Expected an IException, got exception with error " << e.what() << std::endl;
  }
}

// Test removing a total of this many lines from each framelet
// (half at the top of each framelet and half at the bottom).
TEST_F(PushFramePair, FunctionalTestFramestitchRemoveOverlap) {
  QString outCubePath = tempDir.path() + "/stitched.cub";
  int numLinesOverlap = 2;
  QVector<QString> args = {
        "EVEN="+evenCube->fileName(),
        "ODD="+oddCube->fileName(),
        "FRAMEHEIGHT="+toString(frameHeight),
        "NUM_LINES_OVERLAP=" + toString(numLinesOverlap),
        "TO="+outCubePath};

  UserInterface ui(APP_XML, args);

  framestitch(ui);

  Cube outCube(outCubePath);
  std::shared_ptr<Statistics> bandStats(outCube.statistics());
  EXPECT_EQ(bandStats->Minimum(), 1);
  EXPECT_EQ(bandStats->Maximum(), numFrames);
  EXPECT_DOUBLE_EQ(bandStats->Average(), (numFrames + 1) / 2.0);
  EXPECT_EQ(bandStats->NullPixels(), 0);

  // The output cube should have fewer lines
  EXPECT_EQ(evenCube->lineCount(), outCube.lineCount() + numFrames * numLinesOverlap);
}