Ejemplo n.º 1
0
void IsisMain() {
  // Open the match cube and get the camera model on it
  ProcessRubberSheet m;
  Cube *mcube = m.SetInputCube("MATCH");
  Cube *ocube = m.SetOutputCube("TO");

  // Set up the default reference band to the middle of the cube
  // If we have even bands it will be close to the middle
  int referenceBand = ocube->bandCount();
  referenceBand += (referenceBand % 2);
  referenceBand /= 2;

  // See if the user wants to override the reference band
  UserInterface &ui = Application::GetUserInterface();
  if(ui.WasEntered("REFBAND")) {
    referenceBand = ui.GetInteger("REFBAND");
  }

  // Using the Camera method out of the object opack will not work, because the
  // filename required by the Camera is not passed by the process class in this
  // case.  Use the CameraFactory to create the Camera instead to get around this
  // problem.
  Camera *outcam = CameraFactory::Create(*(mcube->label()));

  // Set the reference band we want to match
  PvlGroup instgrp = mcube->group("Instrument");
  if(!outcam->IsBandIndependent()) {
    PvlKeyword rBand("ReferenceBand", toString(referenceBand));
    rBand.addComment("# All bands are aligned to reference band");
    instgrp += rBand;
    mcube->putGroup(instgrp);
    delete outcam;
    outcam = NULL;
  }

  // Only recreate the output camera if it was band dependent
  if(outcam == NULL) outcam = CameraFactory::Create(*(mcube->label()));

  // We might need the instrument group later, so get a copy before clearing the input
  //   cubes.
  m.ClearInputCubes();

  Cube *icube = m.SetInputCube("FROM");
  incam = icube->camera();

  // Set up the transform object which will simply map
  // output line/samps -> output lat/lons -> input line/samps
  Transform *transform = new cam2cam(icube->sampleCount(),
                                     icube->lineCount(),
                                     incam,
                                     ocube->sampleCount(),
                                     ocube->lineCount(),
                                     outcam);


  // Add the reference band to the output if necessary
  ocube->putGroup(instgrp);

  // Set up the interpolator
  Interpolator *interp = NULL;
  if(ui.GetString("INTERP") == "NEARESTNEIGHBOR") {
    interp = new Interpolator(Interpolator::NearestNeighborType);
  }
  else if(ui.GetString("INTERP") == "BILINEAR") {
    interp = new Interpolator(Interpolator::BiLinearType);
  }
  else if(ui.GetString("INTERP") == "CUBICCONVOLUTION") {
    interp = new Interpolator(Interpolator::CubicConvolutionType);
  }

  // See if we need to deal with band dependent camera models
  if(!incam->IsBandIndependent()) {
    m.BandChange(BandChange);
  }

  // Warp the cube
  m.StartProcess(*transform, *interp);
  m.EndProcess();

  // Cleanup
  delete transform;
  delete interp;
}
Ejemplo n.º 2
0
void IsisMain() {
  // We will be warping a cube
  ProcessRubberSheet p;

  // Get the map projection file provided by the user
  UserInterface &ui = Application::GetUserInterface();
  Pvl userMap;
  userMap.read(ui.GetFileName("MAP"));
  PvlGroup &userGrp = userMap.findGroup("Mapping", Pvl::Traverse);

  // Open the input cube and get the camera
  icube = p.SetInputCube("FROM");
  incam = icube->camera();

  // Make sure it is not the sky
  if(incam->target()->isSky()) {
    QString msg = "The image [" + ui.GetFileName("FROM") +
                  "] is targeting the sky, use skymap instead.";
    throw IException(IException::User, msg, _FILEINFO_);
  }

  // Get the mapping group from the camera
  Pvl camMap;
  incam->basicRingMapping(camMap);
  PvlGroup &camGrp = camMap.findGroup("Mapping");

  // Make the target info match the user mapfile
  double minrad, maxrad, minaz, maxaz;
  incam->ringRange(minrad, maxrad, minaz, maxaz, userMap);
  camGrp.addKeyword(PvlKeyword("MinimumRingRadius", toString(minrad)), Pvl::Replace);
  camGrp.addKeyword(PvlKeyword("MaximumRingRadius", toString(maxrad)), Pvl::Replace);
  camGrp.addKeyword(PvlKeyword("MinimumRingLongitude", toString(minaz)), Pvl::Replace);
  camGrp.addKeyword(PvlKeyword("MaximumRingLongitude", toString(maxaz)), Pvl::Replace);

  // We want to delete the keywords we just added if the user wants the range
  // out of the mapfile, otherwise they will replace any keywords not in the
  // mapfile
  if (ui.GetString("DEFAULTRANGE") == "MAP" || ui.GetBoolean("MATCHMAP")) {
    camGrp.deleteKeyword("MinimumRingRadius");
    camGrp.deleteKeyword("MaximumRingRadius");
    camGrp.deleteKeyword("MinimumRingLongitude");
    camGrp.deleteKeyword("MaximumRingLongitude");
  }
  // Otherwise, remove the keywords from the map file so the camera keywords
  // will be propogated correctly
  else {
    while(userGrp.hasKeyword("MinimumRingRadius")) {
      userGrp.deleteKeyword("MinimumRingRadius");
    }
    while(userGrp.hasKeyword("MinimumRingLongitude")) {
      userGrp.deleteKeyword("MinimumRingLongitude");
    }
    while(userGrp.hasKeyword("MaximumRingRadius")) {
      userGrp.deleteKeyword("MaximumRingRadius");
    }
    while(userGrp.hasKeyword("MaximumRingLongitude")) {
      userGrp.deleteKeyword("MaximumRingLongitude");
    }
  }

  // If the user decided to enter a ground range then override
  if(ui.WasEntered("MINRINGLON")) {
    userGrp.addKeyword(PvlKeyword("MinimumRingLongitude",
                                  toString(ui.GetDouble("MINRINGLON"))), Pvl::Replace);
  }

  if(ui.WasEntered("MAXRINGLON")) {
    userGrp.addKeyword(PvlKeyword("MaximumRingLongitude",
                                  toString(ui.GetDouble("MAXRINGLON"))), Pvl::Replace);
  }

  if(ui.WasEntered("MINRINGRAD")) {
    userGrp.addKeyword(PvlKeyword("MinimumRingRadius",
                                  toString(ui.GetDouble("MINRINGRAD"))), Pvl::Replace);
  }

  if(ui.WasEntered("MAXRINGRAD")) {
    userGrp.addKeyword(PvlKeyword("MaximumRingRadius",
                                  toString(ui.GetDouble("MAXRINGRAD"))), Pvl::Replace);
  }

  // If they want the res. from the mapfile, delete it from the camera so
  // nothing gets overridden
  if(ui.GetString("PIXRES") == "MAP" || ui.GetBoolean("MATCHMAP")) {
    camGrp.deleteKeyword("PixelResolution");
  }
  // Otherwise, delete any resolution keywords from the mapfile so the camera
  // info is propagated over
  else if(ui.GetString("PIXRES") == "CAMERA") {
    if(userGrp.hasKeyword("Scale")) {
      userGrp.deleteKeyword("Scale");
    }
    if(userGrp.hasKeyword("PixelResolution")) {
      userGrp.deleteKeyword("PixelResolution");
    }
  }

  // Copy any defaults that are not in the user map from the camera map file
  for(int k = 0; k < camGrp.keywords(); k++) {
    if(!userGrp.hasKeyword(camGrp[k].name())) {
      userGrp += camGrp[k];
    }
  }

  // If the user is not matching the map file and entered a resolution, then reset this value
  if (!ui.GetBoolean("MATCHMAP")) {
    if(ui.GetString("PIXRES") == "MPP") {
      userGrp.addKeyword(PvlKeyword("PixelResolution",
                                    toString(ui.GetDouble("RESOLUTION"))),
                         Pvl::Replace);
      if(userGrp.hasKeyword("Scale")) {
        userGrp.deleteKeyword("Scale");
      }
    }
    else if(ui.GetString("PIXRES") == "PPD") {
      userGrp.addKeyword(PvlKeyword("Scale",
                                    toString(ui.GetDouble("RESOLUTION"))),
                         Pvl::Replace);
      if(userGrp.hasKeyword("PixelResolution")) {
        userGrp.deleteKeyword("PixelResolution");
      }
    }
  }

  // See if the user want us to handle the azimuth (ring longitude) seam
  // NOTE: For ringscam2map, if the user chooses to MATCHMAP, then we treat
  // the parameter ringlonseam as if it were set to "continue" (i.e. do nothing)
  if (!ui.GetBoolean("MATCHMAP")) {
    if((ui.GetString("DEFAULTRANGE") == "CAMERA" || ui.GetString("DEFAULTRANGE") == "MINIMIZE")) {
      //TODO This camera method will need attention for rings***** Solution:  just call ringRange directly
      // if(incam->IntersectsLongitudeDomain(userMap)) {
      if (incam->ringRange(minrad, maxrad, minaz, maxaz, userMap)) {
        if(ui.GetString("RINGLONSEAM") == "AUTO") {
          if((int) userGrp["RingLongitudeDomain"] == 360) {
            userGrp.addKeyword(PvlKeyword("RingLongitudeDomain", "180"),
                               Pvl::Replace);
            if(incam->ringRange(minrad, maxrad, minaz, maxaz, userMap)) {
              // Its looks like a global image so switch back to the
              // users preference
              userGrp.addKeyword(PvlKeyword("RingLongitudeDomain", "360"),
                                 Pvl::Replace);
            }
          }
          else {
            userGrp.addKeyword(PvlKeyword("RingLongitudeDomain", "360"),
                               Pvl::Replace);
            if(incam->ringRange(minrad, maxrad, minaz, maxaz, userMap)) {
              // Its looks like a global image so switch back to the
              // users preference
              userGrp.addKeyword(PvlKeyword("RingLongitudeDomain", "180"),
                                 Pvl::Replace);
            }
          }
          // Make the target info match the new azimuth (ring longitude) domain Use radius for where
          // camera expects latitude & azimuth (ring longitude) where the camera expects longitude
          double minrad, maxrad, minaz, maxaz;
          incam->ringRange(minrad, maxrad, minaz, maxaz, userMap);
          if(!ui.WasEntered("MINRINGRAD")) {
            userGrp.addKeyword(PvlKeyword("MinimumRingRadius", toString(minrad)), Pvl::Replace);
          }
          if(!ui.WasEntered("MAXRINGRAD")) {
            userGrp.addKeyword(PvlKeyword("MaximumRingRadius", toString(maxrad)), Pvl::Replace);
          }
          if(!ui.WasEntered("MINRINGLON")) {
            userGrp.addKeyword(PvlKeyword("MinimumRingLongitude", toString(minaz)), Pvl::Replace);
          }
          if(!ui.WasEntered("MAXRINGLON")) {
            userGrp.addKeyword(PvlKeyword("MaximumRingLongitude", toString(maxaz)), Pvl::Replace);
          }
        }
        else if(ui.GetString("RINGLONSEAM") == "ERROR") {
          QString msg = "The image [" + ui.GetFileName("FROM") + "] crosses the " +
                       "ring longitude seam";
          throw IException(IException::User, msg, _FILEINFO_);
        }
      }
    }
  }

  // Use the updated label to create the output projection
  int samples, lines;
  RingPlaneProjection *outmap;
  bool trim;

  // Determine the image size
  if (ui.GetBoolean("MATCHMAP") || ui.GetString("DEFAULTRANGE") == "MAP") { // DEFAULTRANGE = MAP or MATCHMAP=true
    outmap =  (RingPlaneProjection *) ProjectionFactory::RingsCreateForCube(userMap, samples, lines,
                                                                         ui.GetBoolean("MATCHMAP"));//??? if DR=map, this is always false???
    trim = ui.GetBoolean("TRIM"); // trim allowed for defaultrange=map
  }
  else if(ui.GetString("DEFAULTRANGE") == "MINIMIZE") {
    outmap = (RingPlaneProjection *) ProjectionFactory::RingsCreateForCube(userMap, samples, lines, 
                                                                           *incam);
    trim = false;
  }
  else { // if(ui.GetString("DEFAULTRANGE") == "CAMERA") {
    outmap =  (RingPlaneProjection *) ProjectionFactory::RingsCreateForCube(userMap, samples, lines, 
                                                                            false);
    trim = ui.GetBoolean("TRIM");
  }

  // Output the mapping group used to the Gui session log
  PvlGroup cleanMapping = outmap->Mapping();
  Application::GuiLog(cleanMapping);

  // Allocate the output cube and add the mapping labels
  Cube *ocube = p.SetOutputCube("TO", samples, lines, icube->bandCount());

  ocube->putGroup(cleanMapping);

  // Set up the interpolator
  Interpolator *interp = NULL;
  if(ui.GetString("INTERP") == "NEARESTNEIGHBOR") {
    interp = new Interpolator(Interpolator::NearestNeighborType);
  }
  else if(ui.GetString("INTERP") == "BILINEAR") {
    interp = new Interpolator(Interpolator::BiLinearType);
  }
  else {//if(ui.GetString("INTERP") == "CUBICCONVOLUTION") {
    interp = new Interpolator(Interpolator::CubicConvolutionType);
  }

  // See if we need to deal with band dependent camera models
  if(!incam->IsBandIndependent()) {
    p.BandChange(BandChange);
  }

  //  See if center of input image projects.  If it does, force tile
  //  containing this center to be processed in ProcessRubberSheet.
  //  TODO:  WEIRD ... why is this needed ... Talk to Tracie or JAA???
  double centerSamp = icube->sampleCount() / 2.;
  double centerLine = icube->lineCount() / 2.;
  if(incam->SetImage(centerSamp, centerLine)) {
    // Force rings data into Isis by returning ring radius for latitude
    // and azimuth (ring longitude) for longitude
    if(outmap->SetUniversalGround(incam->LocalRadius().meters(),
                                  incam->UniversalLongitude())) {
      p.ForceTile(outmap->WorldX(), outmap->WorldY());
    }
  }
  // Create an alpha cube group for the output cube
  if(!ocube->hasGroup("AlphaCube")) {
    PvlGroup alpha("AlphaCube");
    alpha += PvlKeyword("AlphaSamples", toString(icube->sampleCount()));
    alpha += PvlKeyword("AlphaLines", toString(icube->lineCount()));
    alpha += PvlKeyword("AlphaStartingSample", toString(0.5));
    alpha += PvlKeyword("AlphaStartingLine", toString(0.5));
    alpha += PvlKeyword("AlphaEndingSample", toString(icube->sampleCount() + 0.5));
    alpha += PvlKeyword("AlphaEndingLine", toString(icube->lineCount() + 0.5));
    alpha += PvlKeyword("BetaSamples", toString(icube->sampleCount()));
    alpha += PvlKeyword("BetaLines", toString(icube->lineCount()));
    ocube->putGroup(alpha);
  }

  // We will need a transform class
  Transform *transform = 0;
  
  // Okay we need to decide how to apply the rubbersheeting for the transform
  // Does the user want to define how it is done?
  if (ui.GetString("WARPALGORITHM") == "FORWARDPATCH") {
    transform = new ringscam2mapForward(icube->sampleCount(),
                                   icube->lineCount(), incam, samples,lines,
                                   outmap, trim);
                                   // (Planar*)outmap, trim);

    int patchSize = ui.GetInteger("PATCHSIZE");
    if (patchSize <= 1) patchSize = 3; // Make the patchsize reasonable
    p.setPatchParameters(1, 1, patchSize, patchSize, 
                         patchSize-1, patchSize-1);
    p.processPatchTransform(*transform, *interp);
  }

  else if (ui.GetString("WARPALGORITHM") == "REVERSEPATCH") {
    transform = new ringscam2mapReverse(icube->sampleCount(),
                                   icube->lineCount(), incam, samples,lines,
                                   outmap, trim);
                                   // (Planar*)outmap, trim);

    int patchSize = ui.GetInteger("PATCHSIZE");
    int minPatchSize = 4;
    if (patchSize < minPatchSize) minPatchSize = patchSize;
    p.SetTiling(patchSize, minPatchSize);
    p.StartProcess(*transform, *interp);
  }

  // The user didn't want to override the program smarts.
  // Handle framing cameras.  Always process using the backward
  // driven system (tfile).
  else if (incam->GetCameraType() == Camera::Framing) {
    transform = new ringscam2mapReverse(icube->sampleCount(),
                                   icube->lineCount(), incam, samples,lines,
                                   outmap, trim);
                                   // (Planar*)outmap, trim);
    p.SetTiling(4, 4);
    p.StartProcess(*transform, *interp);
  }

  // The user didn't want to override the program smarts.
  // Handle linescan cameras.  Always process using the forward
  // driven patch option. Faster and we get better orthorectification
  // 
  // TODO:  For now use the default patch size.  Need to modify
  // to determine patch size based on 1) if the limb is in the file
  // or 2) if the DTM is much coarser than the image
  else if (incam->GetCameraType() == Camera::LineScan) {
    transform = new ringscam2mapForward(icube->sampleCount(),
                                   icube->lineCount(), incam, samples,lines,
                                   outmap, trim);
                                   // (Planar*)outmap, trim);

    p.processPatchTransform(*transform, *interp);
  }

  // The user didn't want to override the program smarts.
  // Handle pushframe cameras.  Always process using the forward driven patch 
  // option.  It is much faster than the tfile method.  We will need to 
  // determine patch sizes based on the size of the push frame.
  // 
  // TODO: What if the user has run crop, enlarge, or shrink on the push
  // frame cube.  Things probably won't work unless they do it just right
  // TODO: What about the THEMIS VIS Camera.  Will tall narrow (128x4) patches
  // work okay?
  else if (incam->GetCameraType() == Camera::PushFrame) {
    transform = new ringscam2mapForward(icube->sampleCount(),
                                   icube->lineCount(), incam, samples,lines,
                                   outmap, trim);
                                   // (Planar*)outmap, trim);

    // Get the frame height
    PushFrameCameraDetectorMap *dmap = (PushFrameCameraDetectorMap *) incam->DetectorMap();
    int frameSize = dmap->frameletHeight() / dmap->LineScaleFactor();

    // Check for even/odd cube to determine starting line
    PvlGroup &instGrp = icube->label()->findGroup("Instrument", Pvl::Traverse);
    int startLine = 1;

    // Get the alpha cube group in case they cropped the image
    AlphaCube acube(*icube);
    double betaLine = acube.AlphaLine(1.0);
    if (fabs(betaLine - 1.0) > 0.0000000001) {
      if (fabs(betaLine - (int) betaLine) > 0.00001) {
        string msg = "Input file is a pushframe camera cropped at a ";
        msg += "fractional pixel.  Can not project"; 
        throw IException(IException::User, msg, _FILEINFO_);
      }
      int offset = (((int) (betaLine + 0.5)) - 1) % frameSize;
      startLine -= offset;
    }

    if (((QString)instGrp["Framelets"]).toUpper() == "EVEN") {
      startLine += frameSize;
    }

    p.setPatchParameters(1, startLine, 5, frameSize,
                         4, frameSize * 2);

    p.processPatchTransform(*transform, *interp);
  }

  // The user didn't want to override the program smarts.  The other camera 
  // types have not be analyized.  This includes Radar and Point.  Continue to
  // use the reverse geom option with the default tiling hints
  else {
    transform = new ringscam2mapReverse(icube->sampleCount(),
                                   icube->lineCount(), incam, samples,lines,
                                   outmap, trim);
                                   // (Planar*)outmap, trim);

    int tileStart, tileEnd;
    incam->GetGeometricTilingHint(tileStart, tileEnd);
    p.SetTiling(tileStart, tileEnd);

    p.StartProcess(*transform, *interp);
  }

  // Wrap up the warping process 
  p.EndProcess();

  // add mapping to print.prt
  Application::Log(cleanMapping);

  // Cleanup
  delete outmap;
  delete transform;
  delete interp;
}