Commit 00aa70eb authored by Jeannie Backer's avatar Jeannie Backer
Browse files

Updated from trunk.

git-svn-id: http://subversion.wr.usgs.gov/repos/prog/isis3/branches/ipce@6433 41f8697f-d340-4b68-9986-7bafba869bb8
parents ffd42b89 ac55875b
Loading
Loading
Loading
Loading
+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
+151 −0
Original line number Diff line number Diff line

/**
 * @file
 *
 *   Unless noted otherwise, the portions of Isis written by the USGS are
 *   public domain. See individual third-party library and package descriptions
 *   for intellectual property information, user agreements, and related
 *   information.
 *
 *   Although Isis has been used by the USGS, no warranty, expressed or
 *   implied, is made by the USGS as to the accuracy and functioning of such
 *   software and related material nor shall the fact of distribution
 *   constitute any such warranty, and no responsibility is assumed by the
 *   USGS in connection therewith.
 *
 *   For additional information, launch
 *   $ISISROOT/doc//documents/Disclaimers/Disclaimers.html
 *   in a browser or see the Privacy & Disclaimers page on the Isis website,
 *   http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on
 *   http://www.usgs.gov/privacy.html.
 */

#include "SpectralResampleFunctor.h"

#include "Buffer.h"
#include "Camera.h"
#include "CameraDetectorMap.h"
#include "Spectel.h"
#include "SpectralDefinition.h"

namespace Isis {

  /**
   * Constructs a spectralResampleFunctor, initializing all of the private member variables.
   * 
   * @param inputSpecralDefinition the wavelength center and filter width information about the 
   *                               input cube.
   * @param outputSpectralDefinition the desired or objective wavelength center and filter width 
   *                                 information for the output cube.
   * @param inCamera the camera associated with the input cube.
   */
  SpectralResampleFunctor::SpectralResampleFunctor(SpectralDefinition *inputSpectralDefinition, 
                                                   SpectralDefinition *outputSpectralDefinition,
                                                   Camera *inCamera) {
    m_inSpectralDef = inputSpectralDefinition;
    m_outSpectralDef = outputSpectralDefinition;
    m_inCamera = inCamera; 

  }


  /**
   * Destructor
   */
  SpectralResampleFunctor::~SpectralResampleFunctor() {
  }


  /**
   * Resample the input spectra to match the output spectra 
   */
  void SpectralResampleFunctor::operator()(Buffer &in, Buffer &out) const {
    // If the entire input buffer has invalid pixel DNs:
    //   we are outside the original image or 
    //   this input spectrum is empty
    bool inHasValid = false;
    for (int index=0; index<in.size(); ++index) {
      if (Pixel::IsValid(in[index])) {
        inHasValid = true;
        break;
      }
    }

    // OUTPUT DRIVEN POSSIBILITY
    //if (inHasValid) {
    //  std::cout << "VALID" << std::endl;
    //
    //  // Find the original/raw input image coordinates of each input buffer position, and
    //  // create a spectral definition for them. Later we can ask this definition which spectels are
    //  // needed to fill an output spectrum (1 or more)
    //  //
    //  // TODO: handle sections
    //  SpectralDefinition1D inDef;
    //  for (int inIndex=0; inIndex<in.size(); ++inIndex) {
    //    int status = m_inCamera->SetImage(out.Sample(inIndex), out.Line(inIndex));
    //    if (status == 0) {
    //      double rawInSample = m_inCamera->DetectorMap()->DetectorSample();
    //      double rawInLine = m_inCamera->DetectorMap()->DetectorLine();
    //      Spectel inSpectel = m_inSpectralDef->getSpectel(rawInSample, rawInLine, inIndex+1);
    //      inSpectel.addDN(in[inIndex]);
    //      inDef.addSpectel(inSpectel);
    //    }
    //  }
    //
    //  for (int outIndex=0; outIndex<in.size(); ++outIndex) {
    //
    //    Spectel outSpectel = m_outSpectralDef->getSpectel(out.Sample(outIndex), out.Line(outIndex), outIndex+1);
    //
    //    out[outIndex] = m_inSpectralDef.getNearestNeighborDN(outSpectel);
    //
    //  }
    //}

    // INPUT DRIVEN NEAREST NEIGHBOR
    // TODO:
    //   handle unset output buffer positions
    //   Think about what needs to be done and what not when the input is NOT projected

    // The input driven process may not place a valid DN into every output buffer position, so
    // fill the output buffer with NULLs 
    for (int outIndex=0; outIndex<out.size(); ++outIndex) {
      out[outIndex] = Isis::NULL8;
    }

    if (inHasValid) {
      // TODO: Change to two for loops 0->in.numsections & 0->in.section.bandcount then remove call to getSectionNumber below
      for (int inIndex=0; inIndex<in.size(); ++inIndex) {
        // For projected images, the input image sample, line will not correctly identify the
        // spectel characteristics (wavelength, width) from the spectral definition. We need to
        // map them back to the unprojected image sample and line.
        m_inCamera->SetBand(inIndex+1);
        int status = m_inCamera->SetImage(in.Sample(inIndex), in.Line(inIndex));
        if (status) {
          double rawSample = m_inCamera->DetectorMap()->DetectorSample();
          double rawLine = m_inCamera->DetectorMap()->DetectorLine();
          //std::cout << " Get Spectel in(s,l,b) " << in.Sample(inIndex) << " " << in.Line(inIndex) << 
          //             " " << inIndex+1 << "   raw(s,l,b): " << rawSample << " " << rawLine << " " << inIndex+1 << std::endl;

          // Check that raw(Sample, Line, Band) are inside the original image
          // Don't check the line bounds. This algorithm only works for line scan instruments
          if (rawSample < 0.5 || rawSample > m_inSpectralDef->sampleCount() + 0.5 || 
              inIndex+1 < 1 || inIndex+1 > m_inSpectralDef->bandCount()) {
            continue;
          }

          // Get the input Spectel associated with original s,l,b
          // TODO: getSpectel needs to take double samp,line,band values
          Spectel inSpectel = m_inSpectralDef->findSpectel(rawSample+0.5, rawLine+0.5, inIndex+1);
          int definitionSection = m_inSpectralDef->sectionNumber(rawSample, rawLine, inIndex+1);

          // Look up the associated output Spectel by searching for the closest wavelength

          Spectel outSpectel = m_outSpectralDef->findSpectel(inSpectel, definitionSection);

          // Move this input DN to the appropriate output band
          out[outSpectel.band() - 1] = in[inIndex]; 
        }
      }
    }
  }
}
+61 −0
Original line number Diff line number Diff line
#ifndef SpectralResampleFunctor_h
#define SpectralResampleFunctor_h

/**
 * @file
 *
 *   Unless noted otherwise, the portions of Isis written by the USGS are
 *   public domain. See individual third-party library and package descriptions
 *   for intellectual property information, user agreements, and related
 *   information.
 *
 *   Although Isis has been used by the USGS, no warranty, expressed or
 *   implied, is made by the USGS as to the accuracy and functioning of such
 *   software and related material nor shall the fact of distribution
 *   constitute any such warranty, and no responsibility is assumed by the
 *   USGS in connection therewith.
 *
 *   For additional information, launch
 *   $ISISROOT/doc//documents/Disclaimers/Disclaimers.html
 *   in a browser or see the Privacy &amp; Disclaimers page on the Isis website,
 *   http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on
 *   http://www.usgs.gov/privacy.html.
 */

class QString;

namespace Isis {
  class Buffer;
  class SpectralDefinition;
  class Camera;

  /**
   * @brief Resample a spectra
   *
   * this functor provides the support and processing operator for resampling a spectra according to
   * a given input spectral definision and an output spectral definision 
   * 
   * @author 2015-05-04 Stuart Sides and Kristin Berry
   *
   * @internal
   */
  class SpectralResampleFunctor {
    public:
      SpectralResampleFunctor(SpectralDefinition *inputSpectralDefinition, 
                              SpectralDefinition *outputSpectralDefinition,
                              Camera *inCamera);
      ~SpectralResampleFunctor();

      // Processing operator for used by ISIS ProcessBySpectra
      void operator() (Buffer &in, Buffer &out) const;
      

    private:
      SpectralDefinition *m_inSpectralDef;
      SpectralDefinition *m_outSpectralDef;
      
      Camera *m_inCamera;
  };
}

#endif
+111 −0
Original line number Diff line number Diff line

#include "Isis.h"

#include <iostream>

#include "SpectralResampleFunctor.h"

#include "Camera.h"
#include "Cube.h"

#include "FileName.h"
#include "IException.h"
#include "IString.h"
#include "ProcessBySpectra.h"
#include "UserInterface.h"
#include "History.h"

#include "Spectel.h"
#include "SpectralDefinition.h" 
#include "SpectralDefinitionFactory.h"
#include "SpectralDefinition1D.h"
#include "SpectralDefinition2D.h"

using namespace std;
using namespace Isis;


void IsisMain() {

  // TODO:
  // Handle input images that are not projected a little differently (simpler)

  UserInterface &ui = Application::GetUserInterface();

  ProcessBySpectra procSpectra; 

  Cube *inCube = procSpectra.SetInputCube("FROM");

  // Get the spectral information for the input cube
  FileName smileDef = ui.GetFileName("SMILEDEF"); 
  // TODO: May want to add the cube to the constructor args so some error checks can be done
  SpectralDefinition* inputSpectralDef = SpectralDefinitionFactory::NewSpectralDefinition(smileDef); 

  // Get the spectral information for the output cube
  FileName smileObjective = ui.GetFileName("OBJECTIVE");
  SpectralDefinition* outputSpectralDef = 
      SpectralDefinitionFactory::NewSpectralDefinition(smileObjective); 

  // Set up the output cube. It may have a different number of bands than the input cube.
  Cube *outCube = procSpectra.SetOutputCube("TO", inCube->sampleCount(), inCube->lineCount(),
                                            outputSpectralDef->bandCount());

  // Correct the spectral smile
  SpectralResampleFunctor resampleFunctor(inputSpectralDef, outputSpectralDef, inCube->camera());
  procSpectra.Progress()->SetText("Adjusting spectra");

  // WARNING: DO NOT turn on threading for this process. The processing functor uses a camera
  procSpectra.ProcessCube(resampleFunctor, false);

  // Adjust the band bin group for the changes
  Isis::PvlGroup bandBin = outCube->label()->findGroup("BandBin", Isis::Pvl::Traverse);

  // Remove any keywords having the same number of values as input bands
  for (int key=0; key<bandBin.keywords(); ++key) {
    if (bandBin[key].size() == inCube->bandCount()) {
      bandBin.deleteKeyword(bandBin[key].name());
    }
  }

  //
  //// Add the new band bin keywords
  //PvlKeyword centers;
  //PvlKeyword widths;
  //for (int sample = 0; sample<inputSpectralDef) {
  //  for (int section = 0; section < inputSpectralDef->sectionCount(); ++section) {
  //    for (int i = 0; i < inputSpectralDef->bandCount(); ++i) {
  //      Spectel spec = getSpectel(1, 1, i);
  //      centers.addValue(inputSpectralDef->)
  //    }
  //  }
  //}
  //if () {
  //}
  //PvlGroup& bandBin = outCube->label().findGroup("BandBin");


  // TODO:
  // Put a new bandbin group in the output labels

  // TODO:
  // The camera model will no longer work on the output cube, so remove the ability to create a
  // camera on the output cube.
  // should be similar to what mosaic does to the instrument/kernels groups and SPICE blobs
  //  std::cout << *outCube->label() << std::endl;
    // Record apollofindrx history to the cube

  // create a History Blob with value found in the History PvlObject's Name keyword
  PvlObject &histObj = inCube->label()->findObject("History");
  Isis::History histBlob( (QString)histObj["Name"] );
  // read cube's History PvlObject data into the History Blob
  inCube->read(histBlob);
  histBlob.AddEntry();
  outCube->write(histBlob);

  procSpectra.Finalize();
  delete outputSpectralDef;
  outputSpectralDef = NULL;
  delete inputSpectralDef; 
  inputSpectralDef = NULL;
}
+149 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>

<application name="desmile" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://isis.astrogeology.usgs.gov/Schemas/Application/application.xsd">
  
  <brief>
    Resample an image to correct for spectral smile
  </brief>
  <description>
   <!-- <p>
      ROUGH DRAFT ONLY
    </p>
    <ul>
      <li>TO DO:</li>
      <li>Documentation</li>
      <li>Add a band bin group to the output labels</li>
      <li>Add option for running without a camera</li>
      <li>Investigate output driven option</li>
    </ul> -->
    <p>
      This program will spectrally resample an image. A common use is to correct for spectral smile.
      The pixels of each spectrum must be spatially aligned (i.e., The pixel at 
      (sample, line, band) (1,1,1) represents the same point on the target body as (1,1,2), and
      (1,1,3), .... and so on for all spectra in the image.) For instruments where the 
      spectra are not spatially aligned, the ISIS program cam2map can be used to project the cube. 
    </p>
    <p>
      The program requires two spectral definition files as input. See the parameters SMILEDEF 
      and OBJECTIVE for specifics. SMILEDEF  is used to define the wavelength and filter width of 
      each element in the sensor. OBJECTIVE is used to define the wavelength and filter width of 
      the pixels in the output cube.
    </p>
    <p>
      Spectral definitions can have multiple sections. Each section represents the wavelength and 
      filter width of a subset of bands. For example: a 256 band image may have two sections, where
      the first 200 entries define the wavelength centers and filter widths for 2.489 to 1.2204 um, and 
      the last 56 entries define the wavelength centers and filter widths for 2.2623 to 2.0898 um. 
      Each section is defined by a reversal of the wavelength center values (i.e., 2.2, 2.3, 2.20, 2.25, 2.30
      would define two sections with two entries in the first and three in the second). The input 
      and output spectral definitions 
      must have the same number of sections, and should contain wavelengths in the same range.
      Spectral resampling will not cross section boundaries.
    </p>
    <p>
      WARNING: This program is computationally intense and may take a long time to process
      large cubes.
    </p>
    </description>
  
  <history>
    <change name="Stuart Sides and Kristin Berry" date="2015-06-15">
      Original version
    </change> 
    <change name="Kristin Berry" date="2015-11-06">
      Added history to desmile output. 
    </change>
  </history>

  <category>
    <categoryItem>Radiometric and Photometric Correction</categoryItem>
  </category>

  <groups>
    <group name="Files">
      <parameter name="FROM">
        <type>cube</type> 
        <fileMode>input</fileMode>
        <brief>
          Multi-band cube with a spectral smile that needs to be corrected.
        </brief>
        <description>
          Use this parameter to select the file name of a multi-band cube with spectral smile that 
          needs to be corrected. The cube must have an associated ISIS camera model and may 
          be projected as long as the camera can still be used (i.e., The instrument and 
          kernels groups in the label are intact). See the main description for information about 
          how this cube must be spatially aligned.
        </description>
        <filter>
          *.cub
        </filter>
      </parameter>

      <parameter name="TO">
        <type>cube</type>
        <fileMode>output</fileMode>
        <brief>
          Output ISIS cube for the spectral smile corrected cube
        </brief>
        <description>
          The output cube file that will contain the smile-corrected cube. This cube will be created
          using the same number of samples and lines as the input cube (FROM) and the number
          of bands in the OBJECTIVE spectral definition.
        </description>
        <filter>
          *.cub
        </filter>
      </parameter>

      <parameter name="SMILEDEF">
        <type>cube</type>
        <fileMode>input</fileMode>
        <brief>
          Spectral definition of the input cube
        </brief>
        <description>
          <p>
            Spectral definition file containing center wavelength and filter width information for each element
            of the sensor. Typically elements are the pixels of the sensor, requiring a two-dimensional set of 
            wavelength center and filter width pairs. Elements can also be defined as the lines of the sensor,
            requiring a one-dimensional set of wavelength center and filter width pairs. The former case 
            is typically used to correct spectral smile and the latter case to
            to spectrally resample an image that does not contain spectral smile.
          </p>
          <p>
            The two-dimensional definition is supported as a ISIS cube. The spectral definition
            cube must have the same number of samples as the sensor, a number of bands equal to the number of lines
	    on the sensor, and two lines. The first line contains the center wavelengths and the 
            second contains the filter widths.
          </p>
          <p>
            The one-dimensional definition is supported as a text file with comma separated values. Each line
            contains the information for one band. Each line has center wavelength and filter width
            separated by a comma. 
          </p>
        </description>
        <filter>
          *.cub
        </filter>
      </parameter>

      <parameter name="OBJECTIVE">
        <type>filename</type>
        <fileMode>input</fileMode>
        <brief>
          Desired spectral definition of the output cube
        </brief>
        <description>
          The spectral definition desired for the output cube. Each spectrum of the input cube
          will be resampled to fit this definition. Both one-dimensional and two-dimensional
          definitions are allowed. The one-dimensional type is used to flatten out a spectral
          smile. See the description for the SMILEDEF parameter
          for more information regarding spectral definition files.
        </description>
        <filter>
          *.csv
        </filter>
      </parameter>
    </group>
  </groups>
</application>
Loading