Unverified Commit 8066e7c6 authored by kledmundson's avatar kledmundson Committed by GitHub
Browse files

Merge pull request #59 from kledmundson/BundleLidar

Bundle lidar
parents 08d12055 23409b01
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ object_script.*.Debug
*_plugin_import.cpp
*.moc
ui_*.h
*.html

# ignore all files created by squish coco
*csmes
+8 −8
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@ using namespace Isis;
// Global variables
Cube *icube;
Camera *cam;
TProjection *proj;
TProjection *projection;
double minlat;
double maxlat;
double minlon;
@@ -53,14 +53,14 @@ void IsisMain() {
  if(ui.WasEntered("MAP")) {
    Pvl lab;
    lab.read(ui.GetFileName("MAP"));
    proj = (TProjection *) ProjectionFactory::Create(lab);
    projection = (TProjection *) ProjectionFactory::Create(lab);

    // add mapping to print.prt
    PvlGroup mapping = proj->Mapping();
    PvlGroup mapping = projection->Mapping();
    Application::Log(mapping);
  }
  else {
    proj = NULL;
    projection = NULL;
  }

  // Start the processing
@@ -86,10 +86,10 @@ void camtrim(Buffer &in, Buffer &out) {
    if(cam->HasSurfaceIntersection()) {
      lat = cam->UniversalLatitude();
      lon = cam->UniversalLongitude();
      if(proj != NULL) {
        proj->SetUniversalGround(lat, lon);
        lat = proj->Latitude();
        lon = proj->Longitude();
      if(projection != NULL) {
        projection->SetUniversalGround(lat, lon);
        lat = projection->Latitude();
        lon = projection->Longitude();
      }
      // Pixel is outside range
      if((lat < minlat) || (lat > maxlat) ||
+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
+209 −0
Original line number Diff line number Diff line
#include "Isis.h"

#include <cmath>
#include <iostream>

#include <QFile>
#include <QMap>
#include <QPair>
#include <QString>
#include <QTextStream>
#include <QVector>

#include "Camera.h"
#include "Cube.h"
#include "FileList.h"
#include "FileName.h"
#include "Histogram.h"
#include "IException.h"
#include "PiecewisePolynomial.h"
#include "Progress.h"
#include "SpicePosition.h"
#include "SpiceRotation.h"
#include "UserInterface.h"

using namespace std;
using namespace Isis;

QVector< QPair<double, double> > testFit(FileName inCubeFile,
                                         int positionDegree, int positionSegments,
                                         int pointingDegree, int pointingSegments);

void IsisMain() {
  UserInterface &ui = Application::GetUserInterface();

  // Read in the list of cubes to check
  FileList cubeList;
  cubeList.read( ui.GetFileName("FROMLIST") );

  // Get the fit parameters
  int positionDegree = ui.GetInteger("SPKDEGREE");
  int positionSegments = ui.GetInteger("SPKSEGMENTS");
  int pointingDegree = ui.GetInteger("CKDEGREE");
  int pointingSegments = ui.GetInteger("CKSEGMENTS");

  // Setup the map for storing fit quality
  QMap<QString, QVector< QPair<double, double> > > qualityMap;

  // Setup the progress tracker
  Progress cubeProgress;
  cubeProgress.SetMaximumSteps(cubeList.size());
  cubeProgress.CheckStatus();

  // Compute a test fit for each cube
  for (int cubeIndex = 0; cubeIndex < cubeList.size(); cubeIndex++) {
    FileName cubeFileName = cubeList[cubeIndex];
    QVector< QPair<double, double> > fitQuality;
    try {
      cubeProgress.CheckStatus();
      fitQuality = testFit(cubeFileName,
                           positionDegree, positionSegments,
                           pointingDegree, pointingSegments);
    }
    catch(IException &e) {
      QString warning = "**WARNING** Failed checking cube [" + cubeFileName.expanded() + "].";
      std::cerr << warning << std::endl << e.toString() << std::endl;
      continue;
    }
    qualityMap.insert(cubeFileName.expanded(), fitQuality);
  }

  // Open the TO file for writing
  FileName outFileName = ui.GetFileName("TO");
  QFile outFile(outFileName.expanded());
  if (outFile.open(QFile::WriteOnly |QFile::Truncate)) {
    QTextStream outWriter(&outFile);
    // Output the header
    outWriter << "Cube,"
              << "Position Segments,Position Fit Degree,Minimum Position Error,"
              << "Median Position Error,Maximum Position Error,RMS Position Error,"
              << "Mean Position Error,Standard Deviation of Position Error,"
              << "Chebyshev Minimum Position Error,Chebyshev Maximum Position Error,"
              << "Pointing Segments,Pointing Fit Degree,Minimum Pointing Error,"
              << "Median Pointing Error,Maximum Pointing Error,RMS Pointing Error,"
              << "Mean Pointing Error,Standard Deviation of Pointing Error,"
              << "Chebyshev Minimum Pointing Error,Chebyshev Maximum Pointing Error"
              << "\n";
    QList<QString> cubeNames = qualityMap.keys();
    for (int i = 0; i < cubeNames.size(); i++) {
      QString cubeName = cubeNames[i];
      QVector< QPair<double, double> > fitQuality = qualityMap.value(cubeName);
      outWriter << cubeName;
      // Output Position Error Stats
      for (int j = 0; j < fitQuality.size(); j++) {
        outWriter  << "," << toString(fitQuality[j].first);
      }
      // Output Pointing Error Stats
      for (int j = 0; j < fitQuality.size(); j++) {
        outWriter  << "," << toString(fitQuality[j].second);
      }
      outWriter << "\n";
    }
  }
  else {
    QString msg = "Failed opening output file [" + outFileName.expanded() + "].";
    throw IException(IException::Io, msg, _FILEINFO_);
  }
}

/**
 * <p>
 * Computes the position and pointing fit error, then outputs statistics on
 * them. The statistics are output as a vector of pairs. Each element of the
 * vector contains a pair of values for a specific statistic. The first value
 * is the value of the statistic for position error in km. The second value is
 * the value of the statistic for pointing error in radians.
 * </p>
 * <p>
 * The output statistics are:
 * </p>
 * <ol>
 *   <li>Number of Segments</li>
 *   <li>Min Error</li>
 *   <li>Median Error</li>
 *   <li>Maximum Error</li>
 *   <li>RMS Error</li>
 *   <li>Mean Error</li>
 *   <li>Standard Deviation of the Error</li>
 *   <li>Chebyshev Minimum Error</li>
 *   <li>Chebyshev Maximum Error</li>
 * </ol>
 * 
 * @param inCubeFile The cube file to test
 * @param positionDegree The degree of the position fit
 * @param positionSegments The number of segments used in the position fit.
 * @param pointingDegree The degree of the pointing fit
 * @param pointingSegments The number of segments used in the pointing fit.
 * 
 * @return @b QVector<QPair<double,double>> A vector containing pairs of
 *                                          statistic values for the position
 *                                          and pointing error in km and
 *                                          radians respectively.
 */
QVector< QPair<double, double> > testFit(FileName inCubeFile,
                                         int positionDegree, int positionSegments,
                                         int pointingDegree, int pointingSegments) {
  // TODO validate these pointers
  Cube inCube(inCubeFile);
  Camera *inCam = inCube.camera();
  SpicePosition *instPosition = inCam->instrumentPosition();
  SpiceRotation *instRotation = inCam->instrumentRotation();

  // Fit the position
  PiecewisePolynomial positionPoly;
  try {
    positionPoly = instPosition->fitPolynomial(positionDegree, positionSegments);
  }
  catch (IException &e) {
    QString msg = "Failed Fitting Instrument Position.";
    throw IException(e, IException::Unknown, msg, _FILEINFO_);
  }

  // Fit the rotation
  PiecewisePolynomial rotationPoly;
  try {
    rotationPoly = instRotation->fitPolynomial(pointingDegree, pointingSegments);
  }
  catch (IException &e) {
    QString msg = "Failed Fitting Instrument Pointing.";
    throw IException(e, IException::Unknown, msg, _FILEINFO_);
  }

  // Calculate and store the error statistics
  QVector< QPair<double, double> > fitStats;
  Histogram positionHist = instPosition->computeError(positionPoly);
  Histogram rotationHist = instRotation->computeError(rotationPoly);

  // Number of Segments
  fitStats.push_back( QPair<double, double>( positionPoly.segments(), rotationPoly.segments() ) );

  // Fit Degree
  fitStats.push_back( QPair<double, double>( positionPoly.degree(), rotationPoly.degree() ) );

  // Min Error
  fitStats.push_back( QPair<double, double>( positionHist.Minimum(), rotationHist.Minimum() ) );

  // Median Error
  fitStats.push_back( QPair<double, double>( positionHist.Median(), rotationHist.Median() ) );

  // Maximum Error
  fitStats.push_back( QPair<double, double>( positionHist.Maximum(), rotationHist.Maximum() ) );

  // RMS Error
  fitStats.push_back( QPair<double, double>( positionHist.Rms(), rotationHist.Rms() ) );

  // Mean Error
  fitStats.push_back( QPair<double, double>( positionHist.Average(), rotationHist.Average() ) );

  // Standard Deviation of the Error
  fitStats.push_back( QPair<double, double>( positionHist.StandardDeviation(), rotationHist.StandardDeviation() ) );

  // Chebyshev Minimum Error
  fitStats.push_back( QPair<double, double>( positionHist.ChebyshevMinimum(), rotationHist.ChebyshevMinimum() ) );

  // Chebyshev Maximum Error
  fitStats.push_back( QPair<double, double>( positionHist.ChebyshevMaximum(), rotationHist.ChebyshevMaximum() ) );

  return fitStats;
}
+142 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>

<application name="checkfit" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://isis.astrogeology.usgs.gov/Schemas/Application/application.xsd">
  <brief>
    Test the quality of polynomial fits to cube exterior orientation
  </brief>

  <description>
    This program takes a list of cubes and tests the quality of the polynomial
    fit over instrument position and pointing values. This emulates how the
    jigsaw app converts exterior orientation into polynomials prior to
    adjustment. This app can be used to help determine jigsaw parameters that
    will work well with a data set.
  </description>

  <category>
    <categoryItem>Utility</categoryItem>
  </category>

  <seeAlso>
    <applications>
      <item>jigsaw</item>
    </applications>
  </seeAlso>

  <history>
    <change name="Jesse Mapel" date="2017-07-17">
      Original version
    </change>
  </history>

  <groups>
    <group name="Files">
      <parameter name="FROMLIST">
        <type>filename</type>
        <fileMode>input</fileMode>
        <brief>
          List of input cubes to check
        </brief>
        <description>
          The list of input cubes that test polynomial fits will be done for.
          Each cube will have polnomials fit over its instrument position and
          instrument pointing.
        </description>
        <filter>
          *.lis
        </filter>
      </parameter>

      <parameter name="TO">
        <type>filename</type>
        <fileMode>output</fileMode>
        <brief>
          Output file that contains information about the quality of fits.
        </brief>
        <description>
          This text file will contain the quality of fit for each input cube.
          Each row contains information and statistics about the instrument
          position and pointing fit. If there is an existing file with the same
          name, then it will be overwritten.
        </description>
        <filter>
          *.txt, *.csv
        </filter>
      </parameter>
    </group>

    <group name="Fit options">
      <parameter name="SPKDEGREE">
        <type>integer</type>
        <brief>
          The degree of the instrument position polynomial fits.
        </brief>
        <description>
          The degree of the instrument position polynomial fits. This
          corresponds to the SPKSOLVEDEGREE parameter in the jigsaw
          application. It is recommended that a fit no higher than 2nd degree
          is used. High degree polynomial fits often result in overfitting with
          minimal gain. Increasing the number of segments with lower degree
          polynomial fits is suggested when working with highly volatile data.
        </description>
        <minimum inclusive="yes">0</minimum>
        <default>
          <item>2</item>
        </default>
      </parameter>

      <parameter name="SPKSEGMENTS">
        <type>integer</type>
        <brief>
          The number of polynomial segments used in the instrument position
          fits.
        </brief>
        <description>
          The number of polynomial segments used in the instrument position
          fits. Increasing the number of segments with lower degree polynomial
          fits is suggested when working with highly volatile data.
        </description>
        <minimum inclusive="yes">1</minimum>
        <default>
          <item>1</item>
        </default>
      </parameter>

      <parameter name="CKDEGREE">
        <type>integer</type>
        <brief>
          The degree of the instrument pointing polynomial fit.
        </brief>
        <description>
          The degree of the instrument pointing polynomial fit. This
          corresponds to the CKSOLVEDEGREE parameter in the jigsaw
          application. It is recommended that a fit no higher than 2nd degree
          is used. High degree polynomial fits often result in overfitting with
          minimal gain. Increasing the number of segments with lower degree
          polynomial fits is suggested when working with highly volatile data.
        </description>
        <minimum inclusive="yes">0</minimum>
        <default>
          <item>2</item>
        </default>
      </parameter>

      <parameter name="CKSEGMENTS">
        <type>integer</type>
        <brief>
          The number of polynomial segments used in the instrument pointing
          fit.
        </brief>
        <description>
          The number of polynomial segments used in the instrument pointing
          fit. Increasing the number of segments with lower degree polynomial
          fits is suggested when working with highly volatile data.
        </description>
        <minimum inclusive="yes">1</minimum>
        <default>
          <item>1</item>
        </default>
      </parameter>
    </group>
  </groups>
</application>
Loading