Commit 4f73ccb4 authored by Summer Stapleton's avatar Summer Stapleton
Browse files

Updated high saturation pixels to be ingested as HRS for cassini2isis. Fixes #5106

git-svn-id: http://subversion.wr.usgs.gov/repos/prog/isis3/trunk@8317 41f8697f-d340-4b68-9986-7bafba869bb8
parent 9578b99a
Loading
Loading
Loading
Loading
+13 −9
Original line number Diff line number Diff line
@@ -229,12 +229,17 @@ void CreateStretchPairs() {
  return;
}

// The input buffer has a raw 16 bit buffer but the values are still 0 to 255.
// We know that 255 (stretched to 4095 if Table converted) is saturated.
// Sky pixels could have valid DN of 0, but missing pixels are also saved as 0,
// so it is impossible to distinguish between them.
// This method is used by ConvertLinePrefixPixels() and IsisMain() for ProcessByLine p2.
// author Jeannie Walldren 2008-08-21
/**
* The input buffer has a raw 16 bit buffer but the values are still 0 to 255.
* We know that 255 (stretched to 4095 if Table converted) is saturated.
* Sky pixels could have valid DN of 0, but missing pixels are also saved as 0,
* so it is impossible to distinguish between them.
* This method is used by ConvertLinePrefixPixels() and IsisMain() for ProcessByLine p2.
* author Jeannie Walldren 2008-08-21
*
* @history 2017-11-22 Summer Stapleton - Changed returned max value from HRS to HIS.
*                        Fixes #5106.
*/
void FixDns(Buffer &buf) {
  for(int i = 0; i < buf.size(); i++) {
    // zeros and negatives are valid DN values, according to scientists,
@@ -246,9 +251,9 @@ void FixDns(Buffer &buf) {
    else if(dataConversionType == "Table") {
      buf[i] = stretch.Map((int)buf[i]);
    }
    // save max values (4095 for table-converted images and 255 for others) as HRS
    // save max values (4095 for table-converted images and 255 for others) as HIS
    if(buf[i] == validMax) {
      buf[i] = Hrs;
      buf[i] = His;
    }
  }
}
@@ -452,4 +457,3 @@ double ComputeOverclockAvg(vector <double> pixel) {
//        IDL cisscal application files: cassimg_subtractdark.pro and linetime.pro
// -Jeannie Walldren 08/06/2008
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+27 −24
Original line number Diff line number Diff line
@@ -64,6 +64,9 @@
    <change name="Tracie Sucharski" date="2012-05-04">
      Added error message when input image does not contain Pds labels.
    </change>
    <change name="Summer Stapleton" date="2017-11-22">
      Changed returned max value from HRS to HIS in FixDns method.
    </change>
  </history>
  <liens>
    <item>
+7 −0
Original line number Diff line number Diff line
ifeq ($(ISISROOT), $(BLANK))
.SILENT:
error:
	echo "Please set ISISROOT";
else
	include $(ISISROOT)/make/isismake.apps
endif
 No newline at end of file
+287 −0
Original line number Diff line number Diff line
#include "Isis.h"

#include <QList>
#include <QMap>
#include <QString>

#include "AlphaCube.h"
#include "Blob.h"
#include "CubeAttribute.h"
#include "Cube.h"
#include "FileName.h"
#include "History.h"
#include "IException.h"
#include "LineManager.h"
#include "ObservationNumberList.h"
#include "ProcessByLine.h"
#include "Pvl.h"
#include "UserInterface.h"

using namespace std;
using namespace Isis;

QMap<QString, FileName> sortFramelets(FileName frameletListFile);
void stitchFrame(QList<FileName> frameletList, FileName frameFileName);

/**
 * Functor for stitching framelets into a full frame
 * 
 * @author 2017-09-09 Jesse Mapel
 * @internal
 *   @history 2017-09-09 Original Version.
 */
class StitchFunctor {
public:
  StitchFunctor(Cube *inputCube, Cube *outputCube);
  ~StitchFunctor() {};
  AlphaCube alphaCube() const;
  Cube *outputCube() const;
  void operator()(Isis::Buffer &in) const;
  
private:
  AlphaCube m_alphaCube;
  Cube *m_outputCube;
};

void IsisMain() {

  UserInterface &ui = Application::GetUserInterface();

  QMap<QString, FileName> frameMap;

  try {
    // Open up the list of framelet files
    FileName frameletListFile = ui.GetFileName("FROMLIST");

    // Sort the framelets into frames based on start time
    frameMap = sortFramelets(frameletListFile);
  }
  catch (IException &e) {
    QString msg = "Failed reading and sorting framelets into frames.";
    throw IException(e, IException::Unknown, msg, _FILEINFO_);
  }

  // Stitch together the individual frames
  FileName outputFileName(ui.GetFileName("TO"));
  QString outputBaseName = outputFileName.removeExtension().expanded();
  QStringList frameKeys = frameMap.uniqueKeys();
  Progress stitchProgress;
  stitchProgress.SetText("Stitching Frames");
  stitchProgress.SetMaximumSteps(frameKeys.size());
  stitchProgress.CheckStatus();
  foreach(QString frameKey, frameKeys) {
    try {
      QString frameIdentifier = frameKey.split("/").last();
      FileName frameFileName(outputBaseName + "_" + frameIdentifier + ".cub");
      stitchFrame( frameMap.values(frameKey), frameFileName );
      stitchProgress.CheckStatus();
    }
    catch (IException &e) {
      QString msg = "Failed stitch frame for observation ["
                    + frameKey + "].";
      throw IException(e, IException::Unknown, msg, _FILEINFO_);
    }
  }

  return;
}


/**
 * Go through a list of framelet cube files and sort them into frames based on
 * their timing.
 * 
 * @param frameletList The file containing the list of framelet cubes
 * 
 * @return @b QMap<QString,FileName> A multi-valued mapping from observation
 *                                   number for a frame to the framelet cube
 *                                   files in that frame.
 */
QMap<QString, FileName> sortFramelets(FileName frameletListFile) {
  QMap<QString, FileName> frameMap;

  ObservationNumberList frameletList(frameletListFile.expanded(), false);

  for (int i = 0; i < frameletList.size(); i++) {
    frameMap.insertMulti( frameletList.observationNumber(i),
                          frameletList.fileName(i) );
  }

  return frameMap;
}


/**
 * Combine several framelet cubes into a single frame cube. The labels from the
 * first framelet will be propegated to the frame cube.
 * 
 * @param frameletList A list of the framelet cubes to stitch together
 * @param frameFileName The file name of the output frame cube
 */
void stitchFrame(QList<FileName> frameletList, FileName frameFileName) {
  // Create the frame cube based on the first framelet cube
  Cube firstFrameletCube( frameletList.first() );
  AlphaCube firstAlphaCube(firstFrameletCube);
  Cube frameCube;
  frameCube.setDimensions( firstAlphaCube.AlphaSamples(), firstAlphaCube.AlphaLines(), 1 );
  frameCube.setPixelType( firstFrameletCube.pixelType() );
  frameCube.setByteOrder( firstFrameletCube.byteOrder() );
  frameCube.setBaseMultiplier( firstFrameletCube.base(), firstFrameletCube.multiplier() );
  frameCube.create( frameFileName.expanded() );

  // Setup the label for the new cube
  PvlGroup archGroup = firstFrameletCube.group("Archive");
  PvlGroup kernGroup = firstFrameletCube.group("Kernels");
  PvlGroup instGroup = firstFrameletCube.group("Instrument");
  PvlGroup bandBinGroup("BandBin");
  if ( instGroup.hasKeyword("Filter") ) {
    instGroup["Filter"].setValue("FULLCCD");
  }
  if ( archGroup.hasKeyword("ProductId") ) {
    archGroup.deleteKeyword("ProductId");
  }
  if ( archGroup.hasKeyword("FileName") ) {
    archGroup.deleteKeyword("FileName");
  }
  bandBinGroup += PvlKeyword("FilterName", "FULLCCD");

  // Setup Stitch group keywords
  PvlGroup stitchGroup("Stitch");
  stitchGroup += PvlKeyword("OriginalFilters");
  stitchGroup += PvlKeyword("FilterCenters");
  stitchGroup += PvlKeyword("FilterWidths");
  stitchGroup += PvlKeyword("FilterIkCodes");
  stitchGroup += PvlKeyword("FilterStartSamples");
  stitchGroup += PvlKeyword("FilterSamples");
  stitchGroup += PvlKeyword("FilterStartLines");
  stitchGroup += PvlKeyword("FilterLines");
  stitchGroup += PvlKeyword("FilterProductIds");
  stitchGroup += PvlKeyword("FilterFileNames");

  // Propagate tables and spice
  Pvl &firstFrameletLabel = *firstFrameletCube.label();
  Pvl &frameCubeLabel = *frameCube.label();
  for(int i = 0; i < firstFrameletLabel.objects(); i++) {
    if(firstFrameletLabel.object(i).isNamed("Table")) {
      Isis::Blob table((QString)firstFrameletLabel.object(i)["Name"], firstFrameletLabel.object(i).name());
      firstFrameletCube.read(table);
      frameCube.write(table);
    }
  }
  if (firstFrameletLabel.hasObject("NaifKeywords")) {
    frameCubeLabel.addObject(firstFrameletLabel.findObject("NaifKeywords"));
  }

  // Close the first framelet cube because we are done with it for now
  firstFrameletCube.close();

  // Process each framelet cube
  foreach(FileName frameletFile, frameletList) {
    // Write the cube DNs to the frame cube
    ProcessByLine frameletProcess;
    frameletProcess.Progress()->DisableAutomaticDisplay();
    CubeAttributeInput inputAtts(frameletFile);
    Cube *frameletCube = frameletProcess.SetInputCube(frameletFile.expanded(), inputAtts);
    // Check for summing in the framelet cube
    // Eventually summing can be handled, but right now we don't know enough, so error
    PvlGroup frameletInst = frameletCube->group("Instrument");
    if ((int)frameletInst["SummingMode"] != 0) {
      QString msg = "Summing mode [" + (QString)frameletInst["SummingMode"]
                    + "] for framelet [" + frameletFile.expanded()
                    + "] is not supported.";
      throw IException(IException::User, msg, _FILEINFO_);
    }
    StitchFunctor stitchFunctor(frameletCube, &frameCube);
    frameletProcess.ProcessCubeInPlace(stitchFunctor);

    // Propagate framelet information and history to the frame cube
    PvlGroup frameletBandBin = frameletCube->group("BandBin");
    stitchGroup["OriginalFilters"] += frameletBandBin["FilterName"];
    stitchGroup["FilterCenters"]   += frameletBandBin["Center"];
    stitchGroup["FilterWidths"]    += frameletBandBin["Width"];
    stitchGroup["FilterIkCodes"]   += frameletBandBin["NaifIkCode"];

    AlphaCube frameletAlphaCube(*frameletCube);
    stitchGroup["FilterStartSamples"] += toString(frameletAlphaCube.AlphaSample(0.0));
    stitchGroup["FilterSamples"]      += toString(frameletAlphaCube.BetaSamples());
    stitchGroup["FilterStartLines"]   += toString(frameletAlphaCube.AlphaLine(0.0));
    stitchGroup["FilterLines"]        += toString(frameletAlphaCube.BetaLines());

    PvlGroup frameletArchGroup = frameletCube->group("Archive");
    stitchGroup["FilterProductIds"] += frameletArchGroup["ProductId"];
    stitchGroup["FilterFileNames"]  += frameletArchGroup["FileName"];

    
    Pvl &frameletLabel = *frameletCube->label();
    for(int i = 0; i < frameletLabel.objects(); i++) {
      if( frameletLabel.object(i).isNamed("History") ) {
        History frameletHist( (QString) frameletLabel.object(i)["Name"] );
        frameletCube->read(frameletHist);
        frameCube.write(frameletHist);
      }
    }
  }

  // Finalize the frame cube label
  frameCube.putGroup(instGroup);
  frameCube.putGroup(kernGroup);
  frameCube.putGroup(archGroup);
  frameCube.putGroup(bandBinGroup);
  frameCube.putGroup(stitchGroup);
}


/**
 * Construct a stitch functor for input and output cubes.
 * 
 * @param inputCube A pointer to the input cube. The alpha cube will be
 *                  extracted from this cube.
 * @param outputCube The output stitched cube that will be written to.
 */
StitchFunctor::StitchFunctor(Cube *inputCube, Cube *outputCube) :
  m_alphaCube(*inputCube), m_outputCube(outputCube) { }


/**
 * Return the alpha cube for mapping the input framelet cube into the output
 * frame cube.
 * 
 * @return @b AlphaCube The framelet cube's alpha cube.
 */
AlphaCube StitchFunctor::alphaCube() const {
  return m_alphaCube;
}


/**
 * Return a pointer to the output frame cube.
 * 
 * @return @b Cube* The output frame cube.
 */
Cube *StitchFunctor::outputCube() const {
  return m_outputCube;
}


/**
 * Process method that maps a line from the input framelet cube to the output
 * frame cube.
 * 
 * @param in A line of data from the input cube.
 * 
 * @TODO handle summing
 */
void StitchFunctor::operator()(Isis::Buffer &in) const {
  // Setup the line manager to write to the frame cube
  LineManager outputManager( *outputCube() );
  outputManager.SetLine( alphaCube().AlphaLine(in.Line()) );
  outputCube()->read(outputManager);

  // Copy the data into the line manager
  for (int i = 0; i < in.size(); i++) {
    outputManager[alphaCube().AlphaSample(i)] = in[i];
  }

  // Write the data out to the frame cube
  outputCube()->write(outputManager);
}
+67 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>

<application name="stitch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://isis.astrogeology.usgs.gov/Schemas/Application/application.xsd">

  <brief>
    Stitch together multiple TGO CaSSIS framelets into full frame images.
  </brief>

  <description>
    Stitch together multiple TGO CaSSIS framelets into full frame images. The
    labels from the first framelet in each frame are used as a starting point
    for the frame labels. If spiceinit has been run on the first framelet, then
    that information will be propagated to the frame. Information that is
    unique to each framelet, along with the location of each framelet will be
    output in the "Stitch" group on the frame cubes' label.
  </description>

  <history>
    <change name="Jesse Mapel" date="2017-09-09">
      Original version
    </change>
    <change name="Jesse Mapel" date="2017-09-15">
      Changed name from tgostitch to stitch. Still only works with TGO CaSSIS images. References #5156.
    </change>
  </history>

  <category>
    <missionItem>ExoMars Trace Gas Orbiter</missionItem>
  </category>

  <groups>
    <group name="Files">
      <parameter name="FROMLIST">
        <type>filename</type>
        <fileMode>input</fileMode>
        <brief>
          A list of TGO CaSSIS framelet images to stitch into full frames.
        </brief>
        <description>
          A list of TGO CaSSIS framelet images to stitch. The images will be
          sorted into frames based on their serial number the same way that
          observation mode works in the jigsaw application. So, the list of
          images can contain framelets from multiple different frames.
        </description>
        <filter>
          *.lis
        </filter>
      </parameter>

      <parameter name="TO">
         <type>cube</type>
         <fileMode>output</fileMode>
         <brief>
           Output ISIS cube basename.
         </brief>
         <description>
           The stitched cubes will be output as this basename plus the last
           component of the serial number. Usually this will be the start time
           for the frame.
         </description>
         <filter>
           *.cub
         </filter>
       </parameter>
    </group>
  </groups>
</application>
Loading