Commit 29ff9567 authored by Jeannie Backer's avatar Jeannie Backer
Browse files

Adding camera model for the Juno mission. Fixes #1461 #5017 #5018

git-svn-id: http://subversion.wr.usgs.gov/repos/prog/isis3/trunk@8106 41f8697f-d340-4b68-9986-7bafba869bb8
parent 212dd1f6
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
Group = JUNO/JNC
  Version = 1
  Library = JunoCamera
  Routine = JunoCameraPlugin
EndGroup
 
+209 −0
Original line number Diff line number Diff line
/**
 * @file
 * $Revision:$
 * $Date:$
 *
 *   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 "JunoCamera.h"

#include <QDebug>
#include <QString>

#include "CameraDetectorMap.h"
#include "CameraFocalPlaneMap.h"
#include "CameraGroundMap.h"
#include "CameraSkyMap.h"
#include "iTime.h"
#include "JunoDistortionMap.h"
#include "NaifStatus.h"

using namespace std;

namespace Isis {
  /**
   * @brief Initialize the Juno camera model
   *
   *
   * @param cube The image cube.
   */
  JunoCamera::JunoCamera(Cube &cube) : FramingCamera(cube) {

    m_instrumentNameLong = "Juno EPO Camera";
    m_instrumentNameShort = "JNC"; // or JunoCam?

    m_spacecraftNameLong = "Juno";
    m_spacecraftNameShort = "Juno";
    
    NaifStatus::CheckErrors();

    // Set up the camera characteristics
    instrumentRotation()->SetFrame( CkFrameId() );
    SetFocalLength();
    SetPixelPitch();

    // Get all the necessary stuff from the labels
    Pvl &lab = *cube.label();
    const PvlGroup &inst = lab.findGroup("Instrument", Pvl::Traverse);

    // Get summing mode
    // Summing modes are:
    //   1 = 1x1 (No summing)
    //   2 = 2x2
    int sumMode = (int) inst["SummingMode"];
    int summing = sumMode;

    //  Setup camera detector map
    CameraDetectorMap *detMap = new CameraDetectorMap(this);
    if ( summing > 0 ) {
      detMap->SetDetectorSampleSumming(summing);
      detMap->SetDetectorLineSumming(summing);
    }
    
    // Juno codes
    int junoCode = naifIkCode();
    QString juno = toString(junoCode);

    // Setup focal plane map and set Juno detector boresight
    new CameraFocalPlaneMap(this, junoCode);
    CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this, junoCode);
    double bsSample = getDouble("INS" + juno + "_BORESIGHT_SAMPLE");
    double bsLine = getDouble("INS" + juno + "_BORESIGHT_LINE");
    focalMap->SetDetectorOrigin(bsSample, bsLine);

    // Set starting filter location on the detector
    const PvlGroup &bandBin = lab.findGroup("BandBin", Pvl::Traverse);
    QString filterIkCode = bandBin.findKeyword("NaifIkCode")[0];
    detMap->SetStartingDetectorLine(getDouble("INS" + filterIkCode + "_FILTER_OFFSET"));

    // Set up distortion map, keeping z-direction positive JunoDistortion map defaults to z+
    JunoDistortionMap *distortionMap = new JunoDistortionMap(this);
    distortionMap->SetDistortion(CkFrameId());

    // Setup the ground and sky map
    new CameraGroundMap(this);
    new CameraSkyMap(this);

    // Set time based on clock count, frame number, exposure duration, and interframe delay
    QString startClockCount   = inst["SpacecraftClockStartCount"];
    double observationStartEt = getClockTime(startClockCount).Et(); // in seconds
    double frameNumber     = (double) inst["FrameNumber"];
    double interFrameDelay    = (double) inst["InterFrameDelay"];  // in seconds
    double exposureDur        = ((double) inst["ExposureDuration"]) / 1000.0; // in seconds

    // Get the fixed time biases
    double startTimeBias       = getDouble("INS" + juno + "_START_TIME_BIAS");
    double interFrameDelayBias = getDouble("INS" + juno + "_INTERFRAME_DELTA");

    // get start et for this frame, in seconds
    double frameStartEt = observationStartEt + startTimeBias + (frameNumber - 1)
                             * (exposureDur + interFrameDelay + interFrameDelayBias);
    // Set start time to center of exposure time to ensure the proper SPICE data is cached.
    setTime(frameStartEt + exposureDur / 2.0);

    LoadCache();
    NaifStatus::CheckErrors();
  }


  /**
   * Destroys the JunoCamera object.
   */
  JunoCamera::~JunoCamera() { 
  }


  /**
   * Returns the shutter open and close times.  The user should pass in the
   * ExposureDuration keyword value, converted from milliseconds to seconds, and
   * the SpacecraftClockCount keyword value, converted to ephemeris time. The 
   * StartTime keyword value from the labels represents the shutter open time of 
   * the observation. This method uses the FramingCamera class implementation, 
   * returning the given time value as the shutter open and the sum of the time 
   * value and exposure duration as the shutter close.
   * 
   * @param exposureDuration Exposure duration value from the labels, converted
   *                         to seconds.
   * @param time The SpacecraftClockCount value from the labels, converted to 
   *             ephemeris time
   * 
   * @return @b pair < @b iTime, @b iTime > The first value is the shutter
   *         open time and the second is the shutter close time.
   */
  pair <iTime, iTime> JunoCamera::ShutterOpenCloseTimes(double time,
                                                        double exposureDuration) {

    return FramingCamera::ShutterOpenCloseTimes(time, exposureDuration);
  }


  /**
   * Retrieves the CK frame ID for the JunoCam instrument. 
   *  
   * @return @b int The appropriate instrument code for the "Camera-matrix" 
   *                Kernel Frame ID.
   */
  int JunoCamera::CkFrameId() const {
    return -61500;
  }


  /** 
    * Retrieves the J2000 CK Reference ID for the JunoCam instrument. 
    * 
    * @return @b int The appropriate instrument code for the "Camera-matrix"
    *                Kernel Reference ID.
    */
  int JunoCamera::CkReferenceId() const {
    return 1;
  }


  /**
    * Retrieves the SPK Target Body ID for the JunoCam instrument.
    *
    * @return @b int The appropriate instrument code for the Spacecraft
    *                Kernel Target ID.
    */
  int JunoCamera::SpkTargetId() const {
    return -61;
  }


  /** 
    * Retrieves the J2000 SPK Reference ID for the JunoCam instrument.
    *  
    * @return @b int The appropriate instrument code for the Spacecraft 
    *                Kernel Reference ID.
    */
  int JunoCamera::SpkReferenceId() const {
    return 1;
  }

}

/**
 * This is the function that is called in order to instantiate a JunoCamera
 * object.
 *
 * @param cube The image cube.
 *
 * @return Isis::Camera* JunoCamera
 */
extern "C" Isis::Camera *JunoCameraPlugin(Isis::Cube &cube) {
  return new Isis::JunoCamera(cube);
}
+59 −0
Original line number Diff line number Diff line
#ifndef JunoCamera_h
#define JunoCamera_h
/**
 * @file
 * $Revision: $
 * $Date: $
 *
 *   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 "FramingCamera.h"

#include <QString>

namespace Isis {
  /**
   * @brief Juno's JNC (JunoCam) camera model
   *
   * This is the camera model for the JunoCam instrument. This
   * instrument is technically a pushframe instrument, but it is treated as a
   * framing instrument. This is
   * also a more flexible camera model since it will make controlling the
   * individual framelets alot easier.
   * 
   * @ingroup SpiceInstrumentsAndCameras
   * @ingroup Juno
   * @author 2017-07-22 Jeannie Backer
   *
   * @internal
   *   @history 2017-07-22 Jeannie Backer - Original version. 
   */
  class JunoCamera : public FramingCamera {
    public:
      JunoCamera(Cube &cube);
      ~JunoCamera();

      virtual std::pair <iTime, iTime> ShutterOpenCloseTimes(double time, 
                                                             double exposureDuration);
      virtual int CkFrameId() const;
      virtual int CkReferenceId() const;
      virtual int SpkTargetId() const;
      virtual int SpkReferenceId() const;

  };
};
#endif
+33 −0
Original line number Diff line number Diff line
Unit Test for JunoCamera...
FileName:  "JNCE_2013282_00M00099_V01_BLUE_0004.cub"
CK Frame:  -61500

Kernel IDs: 
CK Frame ID =  -61500
CK Reference ID =  1
SPK Target ID =  -61
SPK Reference ID =  1

Shutter open =  434617659.036347926
Shutter close =  434617668.63634795
Focal Length =  10.9563699999999997

For upper left corner ...
DeltaSample =  0
DeltaLine =  0

For upper right corner ...
DeltaSample =  0
DeltaLine =  0

For lower left corner ...
DeltaSample =  0
DeltaLine =  0

For lower right corner ...
DeltaSample =  0
DeltaLine =  0

For center pixel position ...
Latitude OK
Longitude OK
+217 −0
Original line number Diff line number Diff line
/**
 * @file
 * $Revision: 1.4 $
 * $Date: 2008/02/21 16:04:33 $
 *
 *   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 "IString.h"
#include "JunoDistortionMap.h"

namespace Isis {
  /** 
   * Juno JunoCam distortion map constructor 
   *  
   * Create a distortion map for Juno's JunoCam camera. 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. The Z direction is set internally to positive for 
   * JunoCam. 
   *
   * @param parent        the parent camera that will use this distortion map
   * 
   */
  JunoDistortionMap::JunoDistortionMap(Camera *parent) 
      : CameraDistortionMap(parent, 1.0) {
  }


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


  /** 
   *  Load distortion coefficients for JunoCam 
   *
   * This method loads the distortion coefficients from the instrument
   * kernel.  JunoCam's coefficients in the NAIF instrument kernel are
   * expected to be in the form of:
   *
   * @code
   * INS-61500_DISTORTION_K0 = coefficient, index 0 
   * INS-61500_DISTORTION_K1 = coefficient, index 1 
   * INS-61500_DISTORTION_K2 = coefficient, index 2 
   * @endcode
   *
   * These coefficients are designed for use with pixel coordinates, so they
   * are scaled based on the pixel pitch to operate in focal plane millimeters.
   * These coefficient will be used to convert from undistorted focal plane x,y
   * to distorted focal plane x,y as follows
   * 
   * @code
   * r2 = r2 = (ux * ux) + (uy * uy);
   * dr = 1 + INS-61500_DISTORTION_K0 + INS-61500_DISTORTION_K1*r2 +INS-61500_DISTORTION_K2*r2*r2;
   * dx = ux * dr;
   * dy = uy * dr;
   * @endcode
   *
   * @param naifIkCode Code to search for in instrument kernel
   */
  void JunoDistortionMap::SetDistortion(int naifIkCode) {

    // Use the pixel pitch to scale k1 and k2 coefficients to operate in focal
    // plane coordinates (millimeters). The coefficients found in the kernels
    // are based on detector coordinates (pixels).

    double pp = p_camera->PixelPitch();
    double p2 = pp * pp;

    // Currently k0 is non-existant in kernels (i.e equals zero). The try is
    // here in case this coefficient is needed for future distortion models.
    try {
      QString odk0 = "INS" + toString(naifIkCode) + "_DISTORTION_K0";
      p_odk.push_back(p_camera->Spice::getDouble(odk0));

    }
    catch (IException &e) {
      p_odk.push_back(0.0);
    }

    QString odk1 = "INS" + toString(naifIkCode) + "_DISTORTION_K1";
    p_odk.push_back(p_camera->Spice::getDouble(odk1) / p2);
    QString odk2 = "INS" + toString(naifIkCode) + "_DISTORTION_K2";
    p_odk.push_back(p_camera->Spice::getDouble(odk2) / (p2 * p2));
  }


  /** 
   *  Compute distorted focal plane x/y
   *
   * Compute distorted focal plane x/y given an undistorted focal plane x/y.
   * This virtual method is used to apply various techniques for adding
   * optical distortion in the focal plane of a camera.  The default
   * implementation of this virtual method uses a polynomial distortion if
   * the SetDistortion method was invoked.
   * After calling this method, you can obtain the distorted x/y via the
   * FocalPlaneX and FocalPlaneY methods
   *
   * @param ux undistorted focal plane x in millimeters
   * @param uy undistorted focal plane y in millimeters
   *
   * @return @b if the conversion was successful
   * 
   * @see SetDistortion
   */
  bool JunoDistortionMap::SetUndistortedFocalPlane(const double ux,
                                                   const double uy) {

    p_undistortedFocalPlaneX = ux;
    p_undistortedFocalPlaneY = uy;

    // Compute the distance from the focal plane center and if we are
    // close to the center then assume no distortion 
    double r2 = (ux * ux) + (uy * uy);
    if (r2 <= 1.0E-6) {
      p_focalPlaneX = ux;
      p_focalPlaneY = uy;
      return true;
    }

    // The equation given in the IK computes the undistorted focal plane
    // ux = dx * (1 + k1*r^2), r^2 = dx^2 + dy^2
    double dr = 1 + p_odk[0] + p_odk[1]*r2 + p_odk[2]*r2*r2;
    p_focalPlaneX = ux * dr;
    p_focalPlaneY = uy * dr;

    return true;

  }


  /** 
   *  Compute undistorted focal plane x/y
   *
   * Compute undistorted focal plane x/y given a distorted focal plane x/y.
   * This virtual method can be used to apply various techniques for removing
   * optical distortion in the focal plane of a camera.  The default
   * implementation uses a polynomial distortion if the SetDistortion method
   * is invoked.  After calling this method, you can obtain the undistorted
   * x/y via the UndistortedFocalPlaneX and UndistortedFocalPlaneY methods
   *
   * @param dx distorted focal plane x in millimeters
   * @param dy distorted focal plane y in millimeters
   *
   * @return if the conversion was successful
   * @see SetDistortion
   * @todo Generalize polynomial equation
   */
  bool JunoDistortionMap::SetFocalPlane(double dx, 
                                        double dy) {
    p_focalPlaneX = dx;
    p_focalPlaneY = dy;

    // Get the distance from the focal plane center and if we are close
    // then skip the distortion
    double r2 = (dx * dx) + (dy * dy);
    if (r2 <= 1.0E-6) {
      p_undistortedFocalPlaneX = dx;
      p_undistortedFocalPlaneY = dy;
      return true;
    }

    bool converged = false;
    int i = 0;
    int maximumIterations = 15;
    double tolerance = p_camera->PixelPitch() / 100.0;
    double uxEstimate = dx;
    double uyEstimate = dy;
    double uxPrev = dx;
    double uyPrev = dy;
    double xDistortion = 0.0;
    double yDistortion = 0.0;
    double dr = 0.0;
    while (!converged) {
      dr = p_odk[0] + p_odk[1]*r2 + p_odk[2]*r2*r2;
      xDistortion = uxEstimate * dr;
      yDistortion = uyEstimate * dr;
      uxEstimate = dx - xDistortion; 
      uyEstimate = dy - yDistortion;
      i++;
      if (fabs(uxEstimate - uxPrev) < tolerance &&
          fabs(uyEstimate - uyPrev) < tolerance ) {
        converged = true;
      }
      // If doesn't converge, don't do correction
      if (i > maximumIterations) {
        p_undistortedFocalPlaneX = dx;
        p_undistortedFocalPlaneY = dy;
        break;
      }
      r2 = (uxEstimate * uxEstimate) + (uyEstimate * uyEstimate);
      uxPrev = uxEstimate;
      uyPrev = uyEstimate;
    }
    p_undistortedFocalPlaneX = uxEstimate;
    p_undistortedFocalPlaneY = uyEstimate;
    return true;
  }

}
Loading