Commit 587c6d2a authored by Kris Becker's avatar Kris Becker
Browse files

LROC WAC camera model has a new band dependent distortion model...

LROC WAC camera model has a new band dependent distortion model implementation. This model is now designated as version 3 which requires spiceinit to be rerun on all LRO WAC images.

git-svn-id: http://subversion.wr.usgs.gov/repos/prog/isis3/trunk@5801 41f8697f-d340-4b68-9986-7bafba869bb8
parent ee12ff03
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
Group = LUNAR_RECONNAISSANCE_ORBITER/WAC-VIS
  Library = LroWideAngleCamera
  Routine = LroWideAngleCameraPlugin
  Version = 2
  Version = 3
EndGroup

Group = LUNAR_RECONNAISSANCE_ORBITER/WAC-UV
  Library = LroWideAngleCamera
  Routine = LroWideAngleCameraPlugin
  Version = 2
  Version = 3
EndGroup
+62 −42
Original line number Diff line number Diff line
@@ -19,15 +19,20 @@
 */

#include "LroWideAngleCamera.h"
#include "LroWideAngleCameraFocalPlaneMap.h"
#include "LroWideAngleCameraDistortionMap.h"

#include <sstream>
#include <iomanip>

#include <QString>
#include <QVector>

#include "CameraFocalPlaneMap.h"
#include "CameraSkyMap.h"
#include "CollectorMap.h"
#include "IException.h"
#include "IString.h"
#include "iTime.h"
#include "NaifStatus.h"
#include "PushFrameCameraDetectorMap.h"
@@ -47,40 +52,45 @@ namespace Isis {
   */
  LroWideAngleCamera::LroWideAngleCamera(Cube &cube) :
    PushFrameCamera(cube) {

    NaifStatus::CheckErrors();
    // Set up the camera characteristics
    instrumentRotation()->SetFrame(naifIkCode());
    SetFocalLength();
    SetPixelPitch();

    Pvl &lab = *cube.label();

    // Get the ephemeris time from the labels
    double et;
    Pvl &lab = *cube.label();
    PvlGroup &inst = lab.findGroup("Instrument", Pvl::Traverse);
    QString stime = inst["SpacecraftClockStartCount"];
    et = getClockTime(stime).Et();

    p_exposureDur = inst["ExposureDuration"];
    p_exposureDur = toDouble(inst["ExposureDuration"]);
    // TODO:  Changed et - exposure to et + exposure.
    //   Think about if this is correct
    p_etStart = et + ((p_exposureDur / 1000.0) / 2.0);

    // Compute the framelet size and number of framelets
    IString instId = QString((QString) inst["InstrumentId"]).toUpper();
    QString instId = inst["InstrumentId"][0].toUpper();

    int frameletSize = 14;
    int sumMode = 1;
    int filterIKBase = 10;

    if (instId == "WAC-UV") {
      sumMode = 4;
      frameletSize = 16;
      filterIKBase = 15 - 1; //  New UV IK code = filterIKBase + BANDID
    }
    else if (instId == "WAC-VIS") {
      sumMode = 1;
      frameletSize = 14;
      filterIKBase = 10 - 3; //  New VIS IK code = filterIKBase + BANDID
    }
    else {
      string msg = "Invalid value [" + instId
      QString msg = "Invalid value [" + instId
                    + "] for keyword [InstrumentId]";
      throw IException(IException::User, msg, _FILEINFO_);
    }
@@ -91,6 +101,7 @@ namespace Isis {
    int nbands = (int) lab.findKeyword("Bands", PvlObject::Traverse);
    const PvlGroup &bandBin = lab.findGroup("BandBin", Pvl::Traverse);
    const PvlKeyword &filtNames = bandBin["Center"];

    // Sanity check
    if (nbands != filtNames.size()) {
      ostringstream mess;
@@ -104,20 +115,27 @@ namespace Isis {
    bool dataflipped = (inst["DataFlipped"][0].toUpper() == "YES");

    //  Now create detector offsets
    QString instCode = "INS" + toString(naifIkCode());
    QString instCode = "INS" + QString::number(naifIkCode());

    QString ikernKey = instCode + "_FILTER_BANDCENTER";
    vector<int> fbc = GetVector(ikernKey);
    IntParameterList fbc = GetVector(ikernKey);

    ikernKey = instCode + "_FILTER_OFFSET";
    vector<int> foffset = GetVector(ikernKey);
    IntParameterList foffset = GetVector(ikernKey);

    //  Get band ID to determine new filter dependent IK codes
    ikernKey = instCode + "_FILTER_BANDID";
    IntParameterList fbandid = GetVector(ikernKey);


    // Create a map of filter wavelength to offset.  Also needs a reverse
    // lookup to order the offset into the CCD (ascending sort provided
    // automagically be CollectorMap).
    CollectorMap<int, int> filterToDetectorOffset, wavel;
    for(unsigned int i = 0 ; i < foffset.size() ; i++) {
    CollectorMap<int, int> filterToDetectorOffset, wavel,filterIKCode;
    for (int i = 0 ; i < foffset.size() ; i++) {
      filterToDetectorOffset.add(fbc[i], foffset[i]);
      wavel.add(foffset[i], fbc[i]);
      filterIKCode.add(fbc[i], naifIkCode() - (filterIKBase + fbandid[i]));  // New IK code
    }

    // Construct special format for framelet offsets into CCD.  Uses the above
@@ -131,15 +149,21 @@ namespace Isis {
      filterToFrameletOffset.add(wavelen, j * frameletOffsetFactor);
    }

    //  Now map the actual filter that exist in cube
    //  Now map the actual filters that exist in cube to camera components or
    // storage vectors for later band selection (see SetBand(vband))
    for (int i = 0; i < filtNames.size(); i++) {
      if(!filterToDetectorOffset.exists((IString)filtNames[i])) {
      if (!filterToDetectorOffset.exists(filtNames[i].toInt())) {
        QString msg = "Unrecognized filter name [" + filtNames[i] + "]";
        throw IException(IException::Programmer, msg, _FILEINFO_);
      }

      p_detectorStartLines.push_back(filterToDetectorOffset.get((IString)filtNames[i]));
      p_frameletOffsets.push_back(filterToFrameletOffset.get((IString)filtNames[i]));
      p_detectorStartLines.push_back(filterToDetectorOffset.get(filtNames[i].toInt()));
      p_frameletOffsets.push_back(filterToFrameletOffset.get(filtNames[i].toInt()));

      QString kBase = "INS" + QString::number(filterIKCode.get(filtNames[i].toInt()));
      p_focalLength.push_back(getDouble(kBase+"_FOCAL_LENGTH"));
      p_boreSightSample.push_back(getDouble(kBase+"_BORESIGHT_SAMPLE"));
      p_boreSightLine.push_back(getDouble(kBase+"_BORESIGHT_LINE"));
    }

    // Setup detector map
@@ -152,24 +176,10 @@ namespace Isis {
    // flipping disabled if already flipped
    bool flippedFramelets = dataflipped;
    dmap->SetFlippedFramelets(flippedFramelets, p_nframelets);

    // Setup focal plane map
    new CameraFocalPlaneMap(this, naifIkCode());

    // The line detector origin varies based on instrument mode
    double detectorOriginLine;
    double detectorOriginSamp;

    dmap->SetGeometricallyFlippedFramelets(false);

    ikernKey = instCode + "_BORESIGHT_SAMPLE";
    double sampleBoreSight = getDouble(ikernKey);

    ikernKey = instCode + "_BORESIGHT_LINE";
    double lineBoreSight = getDouble(ikernKey);

    //  get instrument-specific sample offset
    QString instModeId = ((QString)inst["InstrumentModeId"]).toUpper();
    QString instModeId = inst["InstrumentModeId"][0].toUpper();
    // For BW mode, add the mode (0,1 (non-polar) or 2,3 (polar)) used to
    // acquire image
    if (instModeId == "BW") {
@@ -178,26 +188,25 @@ namespace Isis {
      //   and there must be 1 filter.
      p_frameletOffsets[0] = 0;
    }

    ikernKey = instCode + "_" + instModeId + "_SAMPLE_OFFSET";
    int sampOffset = getInteger(ikernKey);

    detectorOriginSamp = sampleBoreSight + 1;
    detectorOriginLine = lineBoreSight + 1;

    FocalPlaneMap()->SetDetectorOrigin(detectorOriginSamp,
                                       detectorOriginLine);
    dmap->SetStartingDetectorSample(sampOffset+1);

    // Setup distortion map
    new LroWideAngleCameraDistortionMap(this, naifIkCode());
    // Setup focal plane and distortion maps
    LroWideAngleCameraFocalPlaneMap *fplane = new LroWideAngleCameraFocalPlaneMap(this, naifIkCode());
    LroWideAngleCameraDistortionMap *distort = new LroWideAngleCameraDistortionMap(this, naifIkCode());
    for ( int i = 0 ; i < filtNames.size() ; i++ ) {
      fplane->addFilter(filterIKCode.get(filtNames[i].toInt()));
      distort->addFilter(filterIKCode.get(filtNames[i].toInt()));
    }

    // Setup the ground and sky map
    bool evenFramelets = (QString(inst["Framelets"][0]).toUpper()
                          == "EVEN");

    bool evenFramelets = (inst["Framelets"][0].toUpper() == "EVEN");
    new PushFrameCameraGroundMap(this, evenFramelets);

    new CameraSkyMap(this);

    SetBand(1);
    LoadCache();
    NaifStatus::CheckErrors();

@@ -233,6 +242,17 @@ namespace Isis {
    dmap = (PushFrameCameraDetectorMap *) DetectorMap();
    dmap->SetBandFirstDetectorLine(p_detectorStartLines[vband - 1]);
    dmap->SetFrameletOffset(p_frameletOffsets[vband - 1]);

    SetFocalLength(p_focalLength[vband-1]);

    LroWideAngleCameraFocalPlaneMap *fplane = (LroWideAngleCameraFocalPlaneMap *) FocalPlaneMap();
    fplane->setBand(vband);
    fplane->SetDetectorOrigin(p_boreSightSample[vband-1] + 1.0, 
                              p_boreSightLine[vband-1]   + 1.0);

    LroWideAngleCameraDistortionMap *distort = (LroWideAngleCameraDistortionMap *) DistortionMap();
    distort->setBand(vband);
    return;
  }

  /**
@@ -252,7 +272,7 @@ namespace Isis {
   * @param key
   * @return @b vector < @b int >
   */
  vector<int> LroWideAngleCamera::GetVector(const QString &key) {
  LroWideAngleCamera::IntParameterList LroWideAngleCamera::GetVector(const QString &key) {
    QVariant poolKeySize = getStoredResult(key + "_SIZE", SpiceIntType);

    int nvals = poolKeySize.toInt();
@@ -267,7 +287,7 @@ namespace Isis {
      throw IException(IException::Programmer, mess, _FILEINFO_);
    }

    vector<int> parms;
    IntParameterList parms;
    for (int i = 0 ; i < nvals ; i++) {
      parms.push_back(getInteger(key, i));
    }
+30 −5
Original line number Diff line number Diff line
@@ -22,12 +22,29 @@

#include "PushFrameCamera.h"

#include <QString>
#include <QVector>

namespace Isis {
  /**
   * @brief LRO Wide Angle Camera Model
   *
   * This is the camera model for the Lunar Reconnaissance Orbiter wide angle 
   * camera. 
   * camera. Much work has been put into this model by the ASU LROC team. 
   *  
   * The current best model (2013-02-19) has the following items changing per 
   * band: 
   *     - FOCAL_LENGTH
   *     - BORESIGHT_SAMPLE
   *     - BORESIGHT_LINE
   *     - OD_K
   *     - TRANSX
   *     - TRANSY
   *     - ITRANSS
   *     - ITRANSL 
   *  
   *  
   * These values are incorporated in the SPICE kernels (FK, IK and IAK). 
   *  
   * @ingroup SpiceInstrumentsAndCameras
   * @ingroup LunarReconnaissanceOrbiter
@@ -65,6 +82,8 @@ namespace Isis {
   *            Added NAIF error check to constructor.
   *   @history 2012-07-06 Debbie A. Cook, Updated Spice members to be more compliant with Isis 
   *            coding standards. References #972.
   *   @history 2013-03-05 Kris Becker - added band dependent parameters as
   *            determined by the ASU LROC team.
   *  
   */
  class LroWideAngleCamera : public PushFrameCamera {
@@ -112,17 +131,23 @@ namespace Isis {
      virtual int SpkReferenceId() const { return (1); }

    private:
      typedef QVector<int>    IntParameterList;
      typedef QVector<double> DblParameterList;
      double p_etStart;              //!< Ephemeris Start iTime
      double p_bandTimeOffset;       //!< Offset iTime for Band
      double p_exposureDur;          //!< Exposure Duration value from labels
      double p_interframeDelay;      //!< Interframe Delay value from labels
      int p_nframelets;                 //!< Number of framelets in whole image
      std::vector<int> p_detectorStartLines;
      std::vector<int> p_frameletOffsets;
      IntParameterList p_detectorStartLines;
      IntParameterList p_frameletOffsets;
      DblParameterList p_focalLength;
      DblParameterList p_boreSightSample;
      DblParameterList p_boreSightLine;


      int PoolKeySize(const QString &key) const;
      std::vector<int> GetVector(const QString &key);
  };
      IntParameterList GetVector(const QString &key);
  };
}  // namespace Isis
#endif
+13 −8
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
 *   http://www.usgs.gov/privacy.html.
 */

#include <QVector>
#include "CameraDistortionMap.h"

namespace Isis {
@@ -47,26 +48,30 @@ namespace Isis {
   *            the IK based upon analysis of the VIS and UV.
   *   @history 2012-07-06 Debbie A. Cook, Updated Spice members to be more compliant with Isis 
   *            coding standards. References #972.
   *   @history 2011-08-30 Kris Becker - Implemented new decentering distortion
   *            model.  This becomes version 3 of the camera model
   *   @history 2012-03-06 Kris Becker - Added distortion model tolerance parameter
   *   @history 2013-03-07 Kris Becker - Modified to implement new distortion
   *            model with three terms and allow for band independant
   *            distortions.
   */
  class LroWideAngleCameraDistortionMap : public CameraDistortionMap {
    public:
      LroWideAngleCameraDistortionMap(Camera *parent, int naifIkCode);

      //! Destroys the LroWideAngleCameraDistortionMap object
      virtual ~LroWideAngleCameraDistortionMap() {};
      virtual ~LroWideAngleCameraDistortionMap() { }

      void addFilter(int naifIkCode);
      void setBand(int vband);

      virtual bool SetFocalPlane(const double dx, const double dy);

      virtual bool SetUndistortedFocalPlane(const double ux, const double uy);

      void SetFilter(int filter) {
        p_filter = filter;
      }

    private:
      int p_filter;
      double p_k1;
      double p_k2;
      QVector<std::vector<double> > m_odkFilters;

  };
};
#endif
+118 −0
Original line number Diff line number Diff line
/**
 * @file
 * $Revision: 1.5 $
 * $Date: 2010/05/12 23:28:12 $
 *
 *   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.
 */
#include <cmath>
#include <sstream>
#include <iomanip>
#include <algorithm>

#include "Camera.h"
#include "IString.h"
#include "LroWideAngleCameraFocalPlaneMap.h"

using namespace std;

namespace Isis {
  /** Camera distortion map constructor
   *
   * Create a camera distortion map.  This class maps between distorted
   * and undistorted focal plane x/y's.  The default mapping is the
   * identity, that is, the focal plane x/y and undistorted focal plane
   * x/y will be identical.
   *
   * @param parent        the parent camera that will use this distortion map
   * @param zDirection    the direction of the focal plane Z-axis
   *                      (either 1 or -1)
   *
   */
  LroWideAngleCameraFocalPlaneMap::LroWideAngleCameraFocalPlaneMap(Camera *parent, 
                                                                   int naifIkCode) : 
                                                                   CameraFocalPlaneMap(parent,
                                                                                       naifIkCode) {
  }


/**
 * @brief Add an additional set of parameters for a given LROC/WAC filter 
 *  
 * This method will read the parameters for LROC/WAC filter as indicated by the 
 * IK code provided. It will create a vector of these parameters and append them 
 * to the band list. 
 *  
 * The filters added should correspond directly to the order in which the 
 * filters are physically stored in the ISIS cube (or the virtually selected 
 * bands). 
 * 
 * @author 2013-03-07 Kris Becker
 * 
 * @param naifIkCode NAIF IK code for the desired filter to add.
 */
  void LroWideAngleCameraFocalPlaneMap::addFilter(int naifIkCode) {

    QString xkey  = "INS" + toString(naifIkCode) + "_TRANSX";
    QString ykey  = "INS" + toString(naifIkCode) + "_TRANSY";
    QString ixkey = "INS" + toString(naifIkCode) + "_ITRANSS";
    QString iykey = "INS" + toString(naifIkCode) + "_ITRANSL";
    TranslationParameters trans_p;
    for (int i = 0; i < 3; ++i) {
      trans_p.m_transx[i]  = p_camera->getDouble(xkey, i);
      trans_p.m_transy[i]  = p_camera->getDouble(ykey, i);
      trans_p.m_itranss[i] = p_camera->getDouble(ixkey, i);
      trans_p.m_itransl[i] = p_camera->getDouble(iykey, i);
    }

    m_transparms.push_back(trans_p);
    return;
  }


/**
 * @brief Implements band-dependant focal plane parameters 
 *  
 * This method should be used to switch to another band's set of distortion 
 * parameters.  See the addFilter() method to add additional band parameters to 
 * this object. Note that the band number should correspond with the same order 
 * as they were added in the addFilter() method. 
 * 
 * @author 2013-03-07 Kris Becker
 * 
 * @param vband  Band number to select.  Range is 1 to Bands.
 */
  void LroWideAngleCameraFocalPlaneMap::setBand(int vband) {
    if ( (vband <= 0) || (vband > m_transparms.size()) ) {
      QString mess = "Invalid band (" + QString::number(vband) + " requested " +
                     " Must be <= " + QString::number(m_transparms.size());
      throw IException(IException::Programmer, mess, _FILEINFO_);
    }
     
    //  Install new parameters
    int iband = vband - 1;
    for ( int i = 0 ; i < 3 ; i++) {
      p_transx[i]  = m_transparms[iband].m_transx[i];
      p_transy[i]  = m_transparms[iband].m_transy[i];
      p_itranss[i] = m_transparms[iband].m_itranss[i];
      p_itransl[i] = m_transparms[iband].m_itransl[i];
    }

    return;
  }
} // namespace Isis
Loading