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; }
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; }