void IsisMain() { // Set the input image, get the camera model Process p; Cube *icube = p.SetInputCube("FROM"); Camera *cam = icube->camera(); // Get the ra/dec range and resolution double minRa, maxRa, minDec, maxDec; cam->RaDecRange(minRa, maxRa, minDec, maxDec); double res = cam->RaDecResolution(); // Get the center ra/dec cam->SetImage(icube->sampleCount() / 2.0, icube->lineCount() / 2.0); double centerRa = cam->RightAscension(); double centerDec = cam->Declination(); // Compute the rotation cam->SetRightAscensionDeclination(centerRa, centerDec + 2.0 * res); double x = cam->Sample() - icube->sampleCount() / 2.0; double y = cam->Line() - icube->lineCount() / 2.0; double rot = atan2(-y, x) * 180.0 / Isis::PI; rot = 90.0 - rot; if(rot < 0.0) rot += 360.0; // Setup and log results PvlGroup results("Range"); results += PvlKeyword("MinimumRightAscension", toString(minRa), "degrees"); results += PvlKeyword("MaximumRightAscension", toString(maxRa), "degrees"); results += PvlKeyword("MinimumDeclination", toString(minDec), "degrees"); results += PvlKeyword("MaximumDeclination", toString(maxDec), "degrees"); results += PvlKeyword("MinimumRightAscension", Projection::ToHMS(minRa), "hms"); results += PvlKeyword("MaximumRightAscension", Projection::ToHMS(maxRa), "hms"); results += PvlKeyword("MinimumDeclination", Projection::ToDMS(minDec), "dms"); results += PvlKeyword("MaximumDeclination", Projection::ToDMS(maxDec), "dms"); results += PvlKeyword("Resolution", toString(res), "degrees/pixel"); Application::Log(results); // Setup and log orientation PvlGroup orient("Orientation"); orient += PvlKeyword("CenterSample", toString(icube->sampleCount() / 2.0)); orient += PvlKeyword("CenterLine", toString(icube->lineCount() / 2.0)); orient += PvlKeyword("CenterRightAscension", toString(centerRa), "degrees"); orient += PvlKeyword("CenterDeclination", toString(centerDec), "degrees"); orient += PvlKeyword("CelestialNorthClockAngle", toString(rot), "degrees"); orient += PvlKeyword("Resolution", toString(res), "degrees/pixel"); Application::Log(orient); // Write the output file if requested UserInterface ui = Application::GetUserInterface(); if(ui.WasEntered("TO")) { Pvl temp; temp.addGroup(results); temp.addGroup(orient); temp.write(ui.GetFileName("TO", "txt")); } p.EndProcess(); }
//Helper function to get camera resolution. void ComputePixRes () { Process p; UserInterface &ui = Application::GetUserInterface(); Cube *latCube = p.SetInputCube("LATCUB"); Cube *lonCube = p.SetInputCube("LONCUB"); Brick latBrick(1,1,1,latCube->PixelType()); Brick lonBrick(1,1,1,lonCube->PixelType()); latBrick.SetBasePosition(1,1,1); latCube->Read(latBrick); lonBrick.SetBasePosition(1,1,1); lonCube->Read(lonBrick); double a = latBrick.at(0) * PI/180.0; double c = lonBrick.at(0) * PI/180.0; latBrick.SetBasePosition(latCube->Samples(),latCube->Lines(),1); latCube->Read(latBrick); lonBrick.SetBasePosition(lonCube->Samples(),lonCube->Lines(),1); lonCube->Read(lonBrick); double b = latBrick.at(0) * PI/180.0; double d = lonBrick.at(0) * PI/180.0; double angle = acos(cos(a) * cos(b) * cos(c - d) + sin(a) * sin(b)); angle *= 180/PI; double pixels = sqrt(pow(latCube->Samples() -1.0, 2.0) + pow(latCube->Lines() -1.0, 2.0)); p.EndProcess(); ui.Clear("RESOLUTION"); ui.PutDouble("RESOLUTION", pixels/angle); ui.Clear("PIXRES"); ui.PutAsString("PIXRES","PPD"); }
void IsisMain() { // Create a process so we can output the noproj'd labels without overwriting Process p; // Open the user interface and get the input file and the ideal specs file UserInterface &ui = Application::GetUserInterface(); Cube *mcube, *icube; // If a MATCH cube is entered, make sure to SetInputCube it first to get the SPICE blobs // from it propagated to the TO labels // Until polygon blobs are detached without "/" don't propagate them p.PropagatePolygons(false); if((ui.WasEntered("MATCH"))) { mcube = p.SetInputCube("MATCH"); icube = p.SetInputCube("FROM"); } else { mcube = icube = p.SetInputCube("FROM"); } Camera *incam = mcube->camera(); // Extract Instrument groups from input labels for the output match and noproj'd cubes PvlGroup inst = mcube->group("Instrument"); PvlGroup fromInst = icube->group("Instrument"); QString groupName = (QString) inst["SpacecraftName"] + "/"; groupName += (QString) inst.findKeyword("InstrumentId"); // Get Ideal camera specifications FileName specs; if((ui.WasEntered("SPECS"))) { specs = ui.GetFileName("SPECS"); } else { specs = "$base/applications/noprojInstruments???.pvl"; specs = specs.highestVersion(); } Pvl idealSpecs(specs.expanded()); PvlObject obSpecs = idealSpecs.findObject("IdealInstrumentsSpecifications"); PvlGroup idealGp = obSpecs.findGroup(groupName); double transx, transy, transl, transs; transx = transy = transl = transs = 0.; if(idealGp.hasKeyword("TransX")) transx = idealGp["TransX"]; if(idealGp.hasKeyword("TransY")) transy = idealGp["TransY"]; if(idealGp.hasKeyword("ItransL")) transl = idealGp["ItransL"]; if(idealGp.hasKeyword("ItransS")) transs = idealGp["ItransS"]; int detectorSamples = mcube->sampleCount(); if(idealGp.hasKeyword("DetectorSamples")) detectorSamples = idealGp["DetectorSamples"]; int numberLines = mcube->lineCount(); int numberBands = mcube->bandCount(); if(idealGp.hasKeyword("DetectorLines")) numberLines = idealGp["DetectorLines"]; int xDepend = incam->FocalPlaneMap()->FocalPlaneXDependency(); // Get output summing mode if(ui.GetString("SOURCE") == "FROMMATCH") { LoadMatchSummingMode(); } else if(ui.GetString("SOURCE") == "FROMINPUT") { LoadInputSummingMode(); } double pixPitch = incam->PixelPitch() * ui.GetDouble("SUMMINGMODE"); detectorSamples /= (int)(ui.GetDouble("SUMMINGMODE")); // Get the user options int sampleExpansion = int((ui.GetDouble("SAMPEXP") / 100.) * detectorSamples + .5); int lineExpansion = int((ui.GetDouble("LINEEXP") / 100.) * numberLines + .5); QString instType; // Adjust translations for summing mode transl /= ui.GetDouble("SUMMINGMODE"); transs /= ui.GetDouble("SUMMINGMODE"); detectorSamples += sampleExpansion; numberLines += lineExpansion; // Determine whether this ideal camera is a line scan or framing camera and // set the instrument id and exposure int detectorLines; int expandFlag; if(incam->DetectorMap()->LineRate() != 0.0) { instType = "LINESCAN"; // Isis3 line rate is always in seconds so convert to milliseconds for the // Ideal instrument detectorLines = 1; expandFlag = 1; } else { instType = "FRAMING"; detectorLines = numberLines; expandFlag = 0; // Framing cameras don't need exposure time } // Adjust focal plane translations with line expansion for scanners since // the CCD is only 1 line if(expandFlag) { transl += lineExpansion / 2; if(xDepend == CameraFocalPlaneMap::Line) { transx -= lineExpansion / 2.*pixPitch * expandFlag; } else { transy -= lineExpansion / 2.*pixPitch * expandFlag; } } // Get the start time for parent line 1 AlphaCube alpha(*icube); double sample = alpha.BetaSample(.5); double line = alpha.BetaLine(.5); incam->SetImage(sample, line); double et = incam->time().Et(); // Get the output file name and set its attributes CubeAttributeOutput cao; // Can we do a regular label? Didn't work on 12-15-2006 cao.setLabelAttachment(Isis::DetachedLabel); // Determine the output image size from // 1) the idealInstrument pvl if there or // 2) the input size expanded by user specified percentage Cube *ocube = p.SetOutputCube("match.cub", cao, 1, 1, 1); // Extract the times and the target from the instrument group QString startTime = inst["StartTime"]; QString stopTime; if(inst.hasKeyword("StopTime")) stopTime = (QString) inst["StopTime"]; QString target = inst["TargetName"]; // rename the instrument groups inst.setName("OriginalInstrument"); fromInst.setName("OriginalInstrument"); // add it back to the IsisCube object under a new group name ocube->putGroup(inst); // and remove the version from the IsisCube Object ocube->deleteGroup("Instrument"); // Now rename the group back to the Instrument group and clear out old keywords inst.setName("Instrument"); inst.clear(); // Add keywords for the "Ideal" instrument Isis::PvlKeyword key("SpacecraftName", "IdealSpacecraft"); inst.addKeyword(key); key.setName("InstrumentId"); key.setValue("IdealCamera"); inst.addKeyword(key); key.setName("TargetName"); key.setValue(target); inst.addKeyword(key); key.setName("SampleDetectors"); key.setValue(Isis::toString(detectorSamples)); inst.addKeyword(key); key.setName("LineDetectors"); key.setValue(Isis::toString(detectorLines)); inst.addKeyword(key); key.setName("InstrumentType"); key.setValue(instType); inst.addKeyword(key); Pvl &ocubeLabel = *ocube->label(); PvlObject *naifKeywordsObject = NULL; if (ocubeLabel.hasObject("NaifKeywords")) { naifKeywordsObject = &ocubeLabel.findObject("NaifKeywords"); // Clean up the naif keywords object... delete everything that isn't a radii for (int keyIndex = naifKeywordsObject->keywords() - 1; keyIndex >= 0; keyIndex--) { QString keyName = (*naifKeywordsObject)[keyIndex].name(); if (!keyName.contains("RADII")) { naifKeywordsObject->deleteKeyword(keyIndex); } } // Clean up the kernels group... delete everything that isn't internalized or the orig frame // code PvlGroup &kernelsGroup = ocube->group("Kernels"); for (int keyIndex = kernelsGroup.keywords() - 1; keyIndex >= 0; keyIndex--) { PvlKeyword &kernelsKeyword = kernelsGroup[keyIndex]; bool isTable = false; bool isFrameCode = kernelsKeyword.isNamed("NaifFrameCode") || kernelsKeyword.isNamed("NaifIkCode"); bool isShapeModel = kernelsKeyword.isNamed("ShapeModel"); for (int keyValueIndex = 0; keyValueIndex < kernelsKeyword.size(); keyValueIndex++) { if (kernelsKeyword[keyValueIndex] == "Table") { isTable = true; } } if (!isTable && !isFrameCode && !isShapeModel) { kernelsGroup.deleteKeyword(keyIndex); } } } if (naifKeywordsObject) { naifKeywordsObject->addKeyword(PvlKeyword("IDEAL_FOCAL_LENGTH", toString(incam->FocalLength())), Pvl::Replace); } else { inst.addKeyword(PvlKeyword("FocalLength", toString(incam->FocalLength()), "millimeters")); } double newPixelPitch = incam->PixelPitch() * ui.GetDouble("SUMMINGMODE"); if (naifKeywordsObject) { naifKeywordsObject->addKeyword(PvlKeyword("IDEAL_PIXEL_PITCH", toString(newPixelPitch)), Pvl::Replace); } else { inst.addKeyword(PvlKeyword("PixelPitch", toString(newPixelPitch), "millimeters")); } key.setName("EphemerisTime"); key.setValue(Isis::toString(et), "seconds"); inst.addKeyword(key); key.setName("StartTime"); key.setValue(startTime); inst.addKeyword(key); if(stopTime != "") { key.setName("StopTime"); key.setValue(stopTime); inst.addKeyword(key); } key.setName("FocalPlaneXDependency"); key.setValue(toString((int)incam->FocalPlaneMap()->FocalPlaneXDependency())); inst.addKeyword(key); int xDependency = incam->FocalPlaneMap()->FocalPlaneXDependency(); double newInstrumentTransX = incam->FocalPlaneMap()->SignMostSigX(); inst.addKeyword(PvlKeyword("TransX", toString(newInstrumentTransX))); double newInstrumentTransY = incam->FocalPlaneMap()->SignMostSigY(); inst.addKeyword(PvlKeyword("TransY", toString(newInstrumentTransY))); storeSpice(&inst, naifKeywordsObject, "TransX0", "IDEAL_TRANSX", transx, newPixelPitch * newInstrumentTransX, (xDependency == CameraFocalPlaneMap::Sample)); storeSpice(&inst, naifKeywordsObject, "TransY0", "IDEAL_TRANSY", transy, newPixelPitch * newInstrumentTransY, (xDependency == CameraFocalPlaneMap::Line)); double transSXCoefficient = 1.0 / newPixelPitch * newInstrumentTransX; double transLXCoefficient = 1.0 / newPixelPitch * newInstrumentTransY; if (xDependency == CameraFocalPlaneMap::Line) { swap(transSXCoefficient, transLXCoefficient); } storeSpice(&inst, naifKeywordsObject, "TransS0", "IDEAL_TRANSS", transs, transSXCoefficient, (xDependency == CameraFocalPlaneMap::Sample)); storeSpice(&inst, naifKeywordsObject, "TransL0", "IDEAL_TRANSL", transl, transLXCoefficient, (xDependency == CameraFocalPlaneMap::Line)); if(instType == "LINESCAN") { key.setName("ExposureDuration"); key.setValue(Isis::toString(incam->DetectorMap()->LineRate() * 1000.), "milliseconds"); inst.addKeyword(key); } key.setName("MatchedCube"); key.setValue(mcube->fileName()); inst.addKeyword(key); ocube->putGroup(inst); p.EndProcess(); // Now adjust the label to fake the true size of the image to match without // taking all the space it would require for the image data Pvl label; label.read("match.lbl"); PvlGroup &dims = label.findGroup("Dimensions", Pvl::Traverse); dims["Lines"] = toString(numberLines); dims["Samples"] = toString(detectorSamples); dims["Bands"] = toString(numberBands); label.write("match.lbl"); // And run cam2cam to apply the transformation QString parameters; parameters += " FROM= " + ui.GetFileName("FROM"); parameters += " MATCH= " + QString("match.cub"); parameters += " TO= " + ui.GetFileName("TO"); parameters += " INTERP=" + ui.GetString("INTERP"); ProgramLauncher::RunIsisProgram("cam2cam", parameters); // Cleanup by deleting the match files remove("match.History.IsisCube"); remove("match.lbl"); remove("match.cub"); remove("match.OriginalLabel.IsisCube"); remove("match.Table.BodyRotation"); remove("match.Table.HiRISE Ancillary"); remove("match.Table.HiRISE Calibration Ancillary"); remove("match.Table.HiRISE Calibration Image"); remove("match.Table.InstrumentPointing"); remove("match.Table.InstrumentPosition"); remove("match.Table.SunPosition"); // Finally finish by adding the OriginalInstrument group to the TO cube Cube toCube; toCube.open(ui.GetFileName("TO"), "rw"); // Extract label and create cube object Pvl *toLabel = toCube.label(); PvlObject &o = toLabel->findObject("IsisCube"); o.deleteGroup("OriginalInstrument"); o.addGroup(fromInst); toCube.close(); }
void IsisMain() { QString projName; Process pHist; Cube *icube = pHist.SetInputCube("FROM"); // Check to see if the input cube looks like a HiRISE RDR if (icube->bandCount() > 3) { QString msg = "Input file [" + Application::GetUserInterface().GetFileName("FROM") + "] does not appear to be a HiRISE RDR product. Number of " + "bands is greater than 3"; throw IException(IException::Programmer, msg, _FILEINFO_); } // Setup to get a histogram for each band g_min = new double[icube->bandCount()]; g_max = new double[icube->bandCount()]; UserInterface &ui = Application::GetUserInterface(); // Determine if the data is to be converted to JPEG2000 IString enctype = ui.GetString("ENCODING_TYPE"); enctype.DownCase(); for (int band = 1; band <= icube->bandCount(); ++band) { if (ui.GetString("TYPE").compare("AUTOMATIC") == 0) { // Set up a histogram for this band. This call sets the input range // by making an initial stats pass to find the data min and max Histogram hist(*icube, band, pHist.Progress()); // Loop and accumulate histogram pHist.Progress()->SetText("Gathering Histogram"); pHist.Progress()->SetMaximumSteps(icube->lineCount()); pHist.Progress()->CheckStatus(); LineManager line(*icube); for (int i = 1; i <= icube->lineCount(); i++) { line.SetLine(i, band); icube->read(line); hist.AddData(line.DoubleBuffer(), line.size()); pHist.Progress()->CheckStatus(); } // get the requested cumulative percentages g_min[band-1] = ui.GetDouble("MINPER") == 0.0 ? hist.Minimum() : hist.Percent(ui.GetDouble("MINPER")); g_max[band-1] = ui.GetDouble("MAXPER") == 100.0 ? hist.Maximum() : hist.Percent(ui.GetDouble("MAXPER")); } else { g_min[band-1] = ui.GetDouble("MIN"); g_max[band-1] = ui.GetDouble("MAX"); } } // Find the minimum min and maximum max for all bands double minmin = g_min[0]; double maxmax = g_max[0]; for (int band = 1; band < icube->bandCount(); ++band) { if (g_min[band] < minmin) minmin = g_min[band]; if (g_max[band] > maxmax) maxmax = g_max[band]; } pHist.EndProcess(); // Set up for writing the data to a PDS formatted file ProcessExportPds p; Cube *icube2 = p.SetInputCube("FROM"); if (enctype.Equal("jp2")) { g_jp2buf = new char* [icube2->bandCount()]; FileName lblFile(ui.GetFileName("TO")); QString lblFileName = lblFile.path() + "/" + lblFile.baseName() + ".lbl"; p.SetDetached(lblFileName); p.setFormat(ProcessExport::JP2); } // Set the output pixel type and the special pixel values int nbits = ui.GetInteger("BITS"); if (nbits == 8) { if (enctype.Equal("jp2")) { for (int i = 0; i < icube2->bandCount(); i++) { g_jp2buf[i] = new char[icube2->sampleCount()]; } } g_oType = Isis::UnsignedByte; p.SetOutputType(g_oType); p.SetOutputRange(VALID_MIN1, VALID_MAX1); p.SetOutputNull(NULL1); p.SetOutputLis(LOW_INSTR_SAT1); p.SetOutputLrs(LOW_REPR_SAT1); p.SetOutputHis(HIGH_INSTR_SAT1); p.SetOutputHrs(HIGH_REPR_SAT1); } else if (nbits == 16) { if (enctype.Equal("jp2")) { for (int i = 0; i < icube2->bandCount(); i++) { g_jp2buf[i] = new char[icube2->sampleCount()*2]; } } g_oType = UnsignedWord; p.SetOutputType(g_oType); p.SetOutputRange(VALID_MINU2, VALID_MAXU2); p.SetOutputNull(NULLU2); p.SetOutputLis(LOW_INSTR_SATU2); p.SetOutputLrs(LOW_REPR_SATU2); p.SetOutputHis(HIGH_INSTR_SATU2); p.SetOutputHrs(HIGH_REPR_SATU2); } else { if (enctype.Equal("jp2")) { for (int i = 0; i < icube2->bandCount(); i++) { g_jp2buf[i] = new char[icube2->sampleCount()*2]; } } g_oType = UnsignedWord; p.SetOutputType(g_oType); p.SetOutputRange(3.0, pow(2.0, (double)(nbits)) - 1.0 - 2.0); p.SetOutputNull(0); p.SetOutputLrs(1); p.SetOutputLis(2); p.SetOutputHis(pow(2.0, (double)(nbits)) - 1.0 - 1.0); p.SetOutputHrs(pow(2.0, (double)(nbits)) - 1.0); } p.SetOutputEndian(Isis::Msb); p.SetInputRange(minmin, maxmax); // Get the PDS label from the process ProcessExportPds::PdsFileType type; if (enctype.Equal("jp2")) { type = ProcessExportPds::JP2Image; } else { type = ProcessExportPds::Image; } Pvl &pdsLabel = p.StandardPdsLabel(type); // Translate the keywords from the input cube label that go in the PDS label PvlTranslationManager cubeLab(*(icube2->label()), "$mro/translations/hirisePdsRdrCubeLabel.trn"); cubeLab.Auto(pdsLabel); // Translate the keywords from the original EDR PDS label that go in // this RDR PDS label OriginalLabel origBlob; icube2->read(origBlob); Pvl origLabel; PvlObject origLabelObj = origBlob.ReturnLabels(); origLabelObj.setName("OriginalLabelObject"); origLabel.addObject(origLabelObj); PvlTranslationManager orig(origLabel, "$mro/translations/hirisePdsRdrOriginalLabel.trn"); orig.Auto(pdsLabel); // Add labels to the PDS product that could not be handled by the translater if (ui.WasEntered("RATIONALE_DESC")) { pdsLabel.addKeyword( PvlKeyword("RATIONALE_DESC", ui.GetString("RATIONALE_DESC")), Pvl::Replace); } // Add PRODUCT_CREATION_TIME time_t startTime = time(NULL); struct tm *tmbuf = gmtime(&startTime); char timestr[80]; strftime(timestr, 80, "%Y-%m-%dT%H:%M:%S", tmbuf); QString dateTime = (QString) timestr; iTime tmpDateTime(dateTime); PvlGroup &timeParam = pdsLabel.findGroup("TIME_PARAMETERS"); timeParam += PvlKeyword("PRODUCT_CREATION_TIME", tmpDateTime.UTC()); // Add the N/A constant keyword to the ROOT pdsLabel += PvlKeyword("NOT_APPLICABLE_CONSTANT", toString(-9998)); // Add SOFTWARE_NAME to the ROOT QString sfname; sfname.clear(); sfname += "Isis " + Application::Version() + " " + Application::GetUserInterface().ProgramName(); pdsLabel += PvlKeyword("SOFTWARE_NAME", sfname); // Add the PRODUCT_VERSION_ID from the user parameter VERSION pdsLabel += PvlKeyword("PRODUCT_VERSION_ID", ui.GetString("VERSION")); // Add MRO:CCD_FLAG, MRO:BINNING, MRO:TDI // As pulled from the input Isis cube, the values are in CPMM order, so // convert them to CCD order PvlKeyword ccdFlag("MRO:CCD_FLAG"); PvlKeyword &cpmmFlag = origLabel.findObject("OriginalLabelObject"). findGroup("INSTRUMENT_SETTING_PARAMETERS"). findKeyword("MRO:POWERED_CPMM_FLAG"); PvlKeyword ccdBin("MRO:BINNING"); PvlKeyword &cpmmBin = icube2->label()->findObject("IsisCube"). findGroup("Mosaic")["cpmmSummingFlag"]; PvlKeyword ccdTdi("MRO:TDI"); PvlKeyword &cpmmTdi = icube2->label()->findObject("IsisCube"). findGroup("Mosaic")["cpmmTdiFlag"]; PvlKeyword ccdSpecial("MRO:SPECIAL_PROCESSING_FLAG"); PvlKeyword &cpmmSpecial = icube2->label()->findObject("IsisCube"). findGroup("Mosaic")["SpecialProcessingFlag"]; for (int ccd = 0; ccd < 14; ++ccd) { const unsigned int cpmmByCcd[] = {0, 1, 2, 3, 5, 8, 10, 11, 12, 13, 6, 7, 4, 9}; ccdFlag.addValue(cpmmFlag[cpmmByCcd[ccd]]); ccdBin.addValue(cpmmBin[cpmmByCcd[ccd]] != "Null" ? cpmmBin[cpmmByCcd[ccd]] : "-9998"); ccdTdi.addValue(cpmmTdi[cpmmByCcd[ccd]] != "Null" ? cpmmTdi[cpmmByCcd[ccd]] : "-9998"); IString tmp = cpmmSpecial[cpmmByCcd[ccd]]; tmp.Trim("\""); ccdSpecial.addValue(tmp.ToQt()); } if (!pdsLabel.hasGroup("INSTRUMENT_SETTING_PARAMETERS")) { pdsLabel.addGroup(PvlGroup("INSTRUMENT_SETTING_PARAMETERS")); } pdsLabel.findGroup("INSTRUMENT_SETTING_PARAMETERS") += ccdFlag; pdsLabel.findGroup("INSTRUMENT_SETTING_PARAMETERS") += ccdBin; pdsLabel.findGroup("INSTRUMENT_SETTING_PARAMETERS") += ccdTdi; pdsLabel.findGroup("INSTRUMENT_SETTING_PARAMETERS") += ccdSpecial; // Add/modify projection info if there is a projection if (pdsLabel.hasObject("IMAGE_MAP_PROJECTION")) { PvlObject &mapObject = pdsLabel.findObject("IMAGE_MAP_PROJECTION"); mapObject += PvlKeyword("^DATA_SET_MAP_PROJECTION", "DSMAP.CAT"); // Add the HiRISE comment to the CENTER_LATITUDE keyword PvlKeyword &clat = mapObject["CENTER_LATITUDE"]; clat.addComment("/* NOTE: CENTER_LATITUDE and CENTER_LONGITUDE describe the location */"); clat.addComment("/* of the center of projection, which is not necessarily equal to the */"); clat.addComment("/* location of the center point of the image. */"); if (mapObject.hasKeyword("CENTER_LATITUDE")) { PvlKeyword ¢erLat = mapObject["CENTER_LATITUDE"]; // if (centerLat[0] == "N/A") centerLat = -9998; if (centerLat[0] == "N/A") mapObject.deleteKeyword("CENTER_LATITUDE"); } if (mapObject.hasKeyword("CENTER_LONGITUDE")) { PvlKeyword ¢erLon = mapObject["CENTER_LONGITUDE"]; // if (centerLon[0] == "N/A") centerLon = -9998; if (centerLon[0] == "N/A") mapObject.deleteKeyword("CENTER_LONGITUDE"); } if (mapObject.hasKeyword("REFERENCE_LATITUDE")) { PvlKeyword &refLat = mapObject["REFERENCE_LATITUDE"]; // if (refLat[0] == "N/A") refLat = -9998; if (refLat[0] == "N/A") mapObject.deleteKeyword("REFERENCE_LATITUDE"); } if (mapObject.hasKeyword("REFERENCE_LONGITUE")) { PvlKeyword &refLon = mapObject["REFERENCE_LONGITUDE"]; // if (refLon[0] == "N/A") refLon = -9998; if (refLon[0] == "N/A") mapObject.deleteKeyword("REFERENCE_LONGITUDE"); } if (mapObject.hasKeyword("FIRST_STANDARD_PARALLEL")) { PvlKeyword &firstSP = mapObject["FIRST_STANDARD_PARALLEL"]; // if (firstSP[0] == "N/A") firstSP = -9998; if (firstSP[0] == "N/A") mapObject.deleteKeyword("FIRST_STANDARD_PARALLEL"); } if (mapObject.hasKeyword("SECOND_STANDARD_PARALLEL")) { PvlKeyword &secondSP = mapObject["SECOND_STANDARD_PARALLEL"]; // if (secondSP[0] == "N/A") secondSP = -9998; if (secondSP[0] == "N/A") mapObject.deleteKeyword("SECOND_STANDARD_PARALLEL"); } // For Equirectangular ONLY // Modify the radii in the pds label to use the radius at the center latitude // instead of the target radii from NAIF if (mapObject["MAP_PROJECTION_TYPE"][0] == "EQUIRECTANGULAR") { Projection *proj = ProjectionFactory::CreateFromCube(*icube2); PvlGroup &mapping = icube2->label()->findGroup("MAPPING", Pvl::Traverse); double radius = proj->LocalRadius((double)mapping["CenterLatitude"]) / 1000.0; mapObject["A_AXIS_RADIUS"].setValue(toString(radius), "KM"); mapObject["B_AXIS_RADIUS"].setValue(toString(radius), "KM"); mapObject["C_AXIS_RADIUS"].setValue(toString(radius), "KM"); } projName = mapObject["MAP_PROJECTION_TYPE"][0]; } // Calculate the min/max per band keywords // These come from the input real DN and are converted to the PDS file DN // The input to output mapping is opposite from the one above double slope = (p.GetOutputMaximum() - p.GetOutputMinimum()) / (maxmax - minmin); double intercept = p.GetOutputMaximum() - slope * maxmax; PvlKeyword minimum("MRO:MINIMUM_STRETCH", toString(slope * g_min[0] + intercept)); PvlKeyword maximum("MRO:MAXIMUM_STRETCH", toString(slope * g_max[0] + intercept)); for (int band = 1; band < icube2->bandCount(); ++band) { minimum += toString(slope * g_min[band] + intercept); maximum += toString(slope * g_max[band] + intercept); } if (enctype.Equal("jp2")) { // Add keywords to the PDS JP2 IMAGE object PvlObject &imagejp2 = pdsLabel.findObject("UNCOMPRESSED_FILE").findObject("IMAGE"); // Add the HiRISE specific description of the IMAGE object imagejp2 += PvlKeyword("DESCRIPTION", "HiRISE projected and mosaicked product"); // Add the SCALLING_FACTOR and OFFSET keywords imagejp2.addKeyword(PvlKeyword("SCALING_FACTOR", toString(slope)), Pvl::Replace); imagejp2.addKeyword(PvlKeyword("OFFSET", toString(intercept)), Pvl::Replace); // Reformat some keyword units in the image object // This is lame, but PDS units are difficult to work with, so for now??? PvlKeyword &oldFilterNamejp2 = imagejp2["FILTER_NAME"]; PvlKeyword newFilterName("FILTER_NAME"); for (int val = 0; val < oldFilterNamejp2.size(); ++val) { QString filtname(oldFilterNamejp2[val].toUpper()); if (filtname == "BLUEGREEN") filtname = "BLUE-GREEN"; else if (filtname == "NEARINFRARED") filtname = "NEAR-INFRARED"; newFilterName.addValue(filtname); } imagejp2.addKeyword(newFilterName, Pvl::Replace); PvlKeyword &oldCenterjp2 = imagejp2["CENTER_FILTER_WAVELENGTH"]; PvlKeyword newCenter("CENTER_FILTER_WAVELENGTH"); for (int val = 0; val < oldCenterjp2.size(); ++val) { if (((IString)(oldCenterjp2.unit(val))).UpCase() == "NANOMETERS") { newCenter.addValue(oldCenterjp2[val], "NM"); } else { newCenter.addValue(oldCenterjp2[val], oldCenterjp2.unit(val)); } } imagejp2.addKeyword(newCenter, Pvl::Replace); PvlKeyword &oldBandWidthjp2 = imagejp2["BAND_WIDTH"]; PvlKeyword newBandWidth("BAND_WIDTH"); for (int val = 0; val < oldBandWidthjp2.size(); ++val) { if (((IString)(oldBandWidthjp2.unit(val))).UpCase() == "NANOMETERS") { newBandWidth.addValue(oldBandWidthjp2[val], "nm"); } else { newBandWidth.addValue(oldBandWidthjp2[val], oldBandWidthjp2.unit(val)); } } imagejp2.addKeyword(newBandWidth, Pvl::Replace); // Add the min/max per band keywords imagejp2 += minimum; imagejp2 += maximum; // Modify the default SAMPLE_BIT_MASK keyword placed there by the // ProcessExportPds if (nbits != 8 && nbits != 16) { imagejp2.addKeyword(PvlKeyword("SAMPLE_BIT_MASK", toString((int)pow(2.0, (double)ui.GetInteger("BITS")) - 1)), Pvl::Replace); } } else { // Add keywords to the PDS IMAGE object PvlObject &image = pdsLabel.findObject("IMAGE"); // Add the HiRISE specific description of the IMAGE object image += PvlKeyword("DESCRIPTION", "HiRISE projected and mosaicked product"); /** * Calculate the SCALING_FACTOR and OFFSET keywords * Set these so the unsigned 16bit PDS disk values can be converted back * to the correct values Isis had * These keywords are used to map stored/disk values to the correct values so, * the input(x axis) values are the unsigned Xbit values from the PDS file */ // ??? unneccessary calculation - this is done by ProcessExportPds class. double slope = (maxmax - minmin) / (p.GetOutputMaximum() - p.GetOutputMinimum()); double intercept = maxmax - slope * p.GetOutputMaximum(); image.addKeyword(PvlKeyword("SCALING_FACTOR", toString(slope)), Pvl::Replace); image.addKeyword(PvlKeyword("OFFSET", toString(intercept)), Pvl::Replace); // Reformat some keyword units in the image object // This is lame, but PDS units are difficult to work with, so for now PvlKeyword &oldFilterName = image["FILTER_NAME"]; PvlKeyword newFilterName("FILTER_NAME"); for (int val = 0; val < oldFilterName.size(); ++val) { QString filtname(oldFilterName[val].toUpper()); if (filtname == "BLUEGREEN") filtname = "BLUE-GREEN"; else if (filtname == "NEARINFRARED") filtname = "NEAR-INFRARED"; newFilterName.addValue(filtname); } image.addKeyword(newFilterName, Pvl::Replace); PvlKeyword &oldCenter = image["CENTER_FILTER_WAVELENGTH"]; PvlKeyword newCenter("CENTER_FILTER_WAVELENGTH"); for (int val = 0; val < oldCenter.size(); ++val) { if (((IString)(oldCenter.unit(val))).UpCase() == "NANOMETERS") { newCenter.addValue(oldCenter[val], "NM"); } else { newCenter.addValue(oldCenter[val], oldCenter.unit(val)); } } image.addKeyword(newCenter, Pvl::Replace); PvlKeyword &oldBandWidth = image["BAND_WIDTH"]; PvlKeyword newBandWidth("BAND_WIDTH"); for (int val = 0; val < oldBandWidth.size(); ++val) { if (((IString)(oldBandWidth.unit(val))).UpCase() == "NANOMETERS") { newBandWidth.addValue(oldBandWidth[val], "NM"); } else { newBandWidth.addValue(oldBandWidth[val], oldBandWidth.unit(val)); } } image.addKeyword(newBandWidth, Pvl::Replace); // Add the min/max per band keywords image += minimum; image += maximum; // Modify the default SAMPLE_BIT_MASK keyword placed there by the // ProcessExportPds if (nbits != 8 && nbits != 16) { image.addKeyword(PvlKeyword("SAMPLE_BIT_MASK", toString((int)pow(2.0, (double)ui.GetInteger("BITS")) - 1)), Pvl::Replace); } } // Modify the units in the viewing_parameters group // if (pdsLabel.hasGroup("VIEWING_PARAMETERS")) { // PvlGroup &viewGroup = pdsLabel.findGroup("VIEWING_PARAMETERS"); // PvlKeyword &incidence = viewGroup["INCIDENCE_ANGLE"]; // IString tstr = incidence.unit(); // if (tstr.UpCase() == "DEG") incidence.setValue((QString)incidence, "deg"); // PvlKeyword &emission = viewGroup["EMISSION_ANGLE"]; // tstr = emission.unit(); // if (tstr.UpCase() == "DEG") emission.setValue((QString)emission, "deg"); // PvlKeyword &phase = viewGroup["PHASE_ANGLE"]; // tstr = phase.unit(); // if (tstr.UpCase() == "DEG") phase.setValue((QString)phase, "deg"); // PvlKeyword &solarLon = viewGroup["SOLAR_LONGITUDE"]; // tstr = solarLon.unit(); q // if (tstr.UpCase() == "DEG") solarLon.setValue((QString)solarLon, "deg"); // PvlKeyword &localTime = viewGroup["LOCAL_TIME"]; // tstr = localTime.unit(); // if (tstr.UpCase() == "LOCALDAY/24") localTime.setValue((QString)localTime, "local day/24"); // } // Add a keyword type (i.e., QString, bool, int...) file to the PDS label Pvl PvlFormat *formatter = pdsLabel.format(); formatter->add("$mro/translations/hirisePdsRdrExtras.typ"); // Add an output format template (group, object, & keyword output order) to // the PDS PVL if (projName == "EQUIRECTANGULAR") { if (enctype.Equal("jp2")) { pdsLabel.setFormatTemplate("$mro/templates/labels/hirisePdsRdrEquiJP2.pft"); } else { pdsLabel.setFormatTemplate("$mro/templates/labels/hirisePdsRdrEqui.pft"); } } else { if (enctype.Equal("jp2")) { pdsLabel.setFormatTemplate("$mro/templates/labels/hirisePdsRdrPolarJP2.pft"); } else { pdsLabel.setFormatTemplate("$mro/templates/labels/hirisePdsRdrPolar.pft"); } } // Open the output PDS file and dump the label and cube data if (enctype.Equal("jp2")) { p.OutputDetachedLabel(); g_jp2Encoder = new JP2Encoder(ui.GetFileName("TO"), icube2->sampleCount(), icube2->lineCount(), icube2->bandCount(), g_oType); g_jp2Encoder->OpenFile(); g_jp2ns = icube2->sampleCount(); g_jp2nb = icube2->bandCount(); g_jp2band = 0; p.StartProcess(writeJP2Image); p.EndProcess(); delete g_jp2Encoder; for (int i = 0; i < icube2->bandCount(); i++) { delete [] g_jp2buf[i]; } } else { FileName outFile(ui.GetFileName("TO")); ofstream oCube(outFile.expanded().toAscii().data()); p.OutputLabel(oCube); p.StartProcess(oCube); oCube.close(); p.EndProcess(); } delete [] g_min; delete [] g_max; }
void IsisMain() { // Get the list of cubes to mosaic FileList imageList; UserInterface &ui = Application::GetUserInterface(); imageList.Read(ui.GetFilename("FROMLIST")); if (imageList.size() < 1) { std::string msg = "The list file [" + ui.GetFilename("FROMLIST") + "] does not contain any data"; throw iException::Message(iException::User,msg,_FILEINFO_); } // Make sure the user enters a "OUTSTATS" file if the CALCULATE option // is selected std::string processOpt = ui.GetString("PROCESS"); if (processOpt == "CALCULATE") { if (!ui.WasEntered("OUTSTATS")) { std::string msg = "If the CALCULATE option is selected, you must enter"; msg += " an OUTSTATS file"; throw iException::Message(iException::User,msg,_FILEINFO_); } } // Make sure number of bands and projection parameters match for all cubes for (unsigned int i=0; i<imageList.size(); i++) { Cube cube1; cube1.Open(imageList[i]); g_maxBand = cube1.Bands(); for (unsigned int j=(i+1); j<imageList.size(); j++) { Cube cube2; cube2.Open(imageList[j]); // Make sure number of bands match if (g_maxBand != cube2.Bands()) { string msg = "Number of bands do not match between cubes [" + imageList[i] + "] and [" + imageList[j] + "]"; throw iException::Message(iException::User,msg,_FILEINFO_); } //Create projection from each cube Projection *proj1 = cube1.Projection(); Projection *proj2 = cube2.Projection(); // Test to make sure projection parameters match if (*proj1 != *proj2) { string msg = "Mapping groups do not match between cubes [" + imageList[i] + "] and [" + imageList[j] + "]"; throw iException::Message(iException::User,msg,_FILEINFO_); } } } // Read hold list if one was entered std::vector<int> hold; if (ui.WasEntered("HOLD")) { FileList holdList; holdList.Read(ui.GetFilename("HOLD")); // Make sure each file in the holdlist matches a file in the fromlist for (int i=0; i<(int)holdList.size(); i++) { bool matched = false; for (int j=0; j<(int)imageList.size(); j++) { if (holdList[i] == imageList[j]) { matched = true; hold.push_back(j); break; } } if (!matched) { std::string msg = "The hold list file [" + holdList[i] + "] does not match a file in the from list"; throw iException::Message(iException::User,msg,_FILEINFO_); } } } // Read to list if one was entered FileList outList; if (ui.WasEntered("TOLIST")) { outList.Read(ui.GetFilename("TOLIST")); // Make sure each file in the tolist matches a file in the fromlist if (outList.size() != imageList.size()) { std::string msg = "Each input file in the FROM LIST must have a "; msg += "corresponding output file in the TO LIST."; throw iException::Message(iException::User,msg,_FILEINFO_); } // Make sure that all output files do not have the same names as their // corresponding input files for (unsigned i = 0; i < outList.size(); i++) { if (outList[i].compare(imageList[i]) == 0) { std::string msg = "The to list file [" + outList[i] + "] has the same name as its corresponding from list file."; throw iException::Message(iException::User,msg,_FILEINFO_); } } } // Test to ensure sampling percent in bound double sampPercent = ui.GetDouble("PERCENT"); if (sampPercent <= 0.0 || sampPercent > 100.0) { string msg = "The sampling percent must be a decimal (0.0, 100.0]"; throw iException::Message(iException::User,msg,_FILEINFO_); } int mincnt = ui.GetInteger("MINCOUNT"); bool wtopt = ui.GetBoolean("WEIGHT"); if (processOpt != "APPLY") { // Loop through all the input cubes, calculating statistics for each cube to use later iString maxCubeStr ((int)imageList.size()); for (int band=1; band<=g_maxBand; band++) { std::vector<Statistics> statsList; for (int img=0; img<(int)imageList.size(); img++) { Process p; const CubeAttributeInput att; const std::string inp = imageList[img]; Cube *icube = p.SetInputCube(inp, att); // Add a Statistics object to the list for every band of every input cube g_imageIndex = img; Statistics stats = GatherStatistics(*icube, band, sampPercent, maxCubeStr); statsList.push_back(stats); p.EndProcess(); } // Create a separate OverlapNormalization object for every band OverlapNormalization *oNorm = new OverlapNormalization (statsList); for (int h=0; h<(int)hold.size(); h++) oNorm->AddHold(hold[h]); g_oNormList.push_back(oNorm); } // A list for keeping track of which input cubes are known to overlap another std::vector<bool> doesOverlapList; for (unsigned int i=0; i<imageList.size(); i++) doesOverlapList.push_back(false); // Find overlapping areas and add them to the set of known overlaps for each // band shared amongst cubes for (unsigned int i=0; i<imageList.size(); i++){ Cube cube1; cube1.Open(imageList[i]); for (unsigned int j=(i+1); j<imageList.size(); j++) { Cube cube2; cube2.Open(imageList[j]); iString cubeStr1 ((int)(i+1)); iString cubeStr2 ((int)(j+1)); string statMsg = "Gathering Overlap Statisitcs for Cube " + cubeStr1 + " vs " + cubeStr2 + " of " + maxCubeStr; // Get overlap statistics for cubes OverlapStatistics oStats(cube1, cube2, statMsg, sampPercent); // Only push the stats onto the oList vector if there is an overlap in at // least one of the bands if (oStats.HasOverlap()) { oStats.SetMincount(mincnt); g_overlapList.push_back(oStats); for (int band=1; band<=g_maxBand; band++) { // Fill wt vector with 1's if the overlaps are not to be weighted, or // fill the vector with the number of valid pixels in each overlap int weight = 1; if (wtopt) weight = oStats.GetMStats(band).ValidPixels(); // Make sure overlap has at least MINCOUNT pixels and add if (oStats.GetMStats(band).ValidPixels() >= mincnt) { g_oNormList[band-1]->AddOverlap(oStats.GetMStats(band).X(), i, oStats.GetMStats(band).Y(), j, weight); doesOverlapList[i] = true; doesOverlapList[j] = true; } } } } } // Print an error if one or more of the images does not overlap another { std::string badFiles = ""; for (unsigned int img=0; img<imageList.size(); img++) { // Print the name of each input cube without an overlap if (!doesOverlapList[img]) { badFiles += "[" + imageList[img] + "] "; } } if (badFiles != "") { std::string msg = "File(s) " + badFiles; msg += " do(es) not overlap any other input images with enough valid pixels"; throw iException::Message(iException::User,msg,_FILEINFO_); } } // Determine whether to calculate gains or offsets std::string adjust = ui.GetString("ADJUST"); OverlapNormalization::SolutionType sType = OverlapNormalization::Both; if (adjust == "CONTRAST") sType = OverlapNormalization::Gains; if (adjust == "BRIGHTNESS") sType = OverlapNormalization::Offsets; // Loop through each band making all necessary calculations for (int band=0; band<g_maxBand; band++) { g_oNormList[band]->Solve(sType); } } // Print gathered statistics to the gui and the print file int validCnt = 0; int invalidCnt = 0; if (processOpt != "APPLY") { PvlGroup results("Results"); // Compute the number valid and invalid overlaps for (unsigned int o=0; o<g_overlapList.size(); o++) { for (int band=1; band<=g_maxBand; band++) { if (g_overlapList[o].IsValid(band)) validCnt++; else invalidCnt++; } } results += PvlKeyword("TotalOverlaps", validCnt+invalidCnt); results += PvlKeyword("ValidOverlaps", validCnt); results += PvlKeyword("InvalidOverlaps", invalidCnt); std::string weightStr = "false"; if (wtopt) weightStr = "true"; results += PvlKeyword("Weighted", weightStr); results += PvlKeyword("MinCount", mincnt); // Name and band modifiers for each image for (unsigned int img=0; img<imageList.size(); img++) { results += PvlKeyword("FileName", imageList[img]); // Band by band statistics for (int band=1; band<=g_maxBand; band++) { iString mult (g_oNormList[band-1]->Gain(img)); iString base (g_oNormList[band-1]->Offset(img)); iString avg (g_oNormList[band-1]->Average(img)); iString bandNum (band); std::string bandStr = "Band" + bandNum; PvlKeyword bandStats(bandStr); bandStats += mult; bandStats += base; bandStats += avg; results += bandStats; } } // Write the results to the log Application::Log(results); } // Setup the output text file if the user requested one if (ui.WasEntered("OUTSTATS")) { PvlObject equ("EqualizationInformation"); PvlGroup gen("General"); gen += PvlKeyword("TotalOverlaps", validCnt+invalidCnt); gen += PvlKeyword("ValidOverlaps", validCnt); gen += PvlKeyword("InvalidOverlaps", invalidCnt); std::string weightStr = "false"; if (wtopt) weightStr = "true"; gen += PvlKeyword("Weighted", weightStr); gen += PvlKeyword("MinCount", mincnt); equ.AddGroup(gen); for (unsigned int img=0; img<imageList.size(); img++) { // Format and name information PvlGroup norm("Normalization"); norm.AddComment("Formula: newDN = (oldDN - AVERAGE) * GAIN + AVERAGE + OFFSET"); norm.AddComment("BandN = (GAIN, OFFSET, AVERAGE)"); norm += PvlKeyword("FileName", imageList[img]); // Band by band statistics for (int band=1; band<=g_maxBand; band++) { iString mult (g_oNormList[band-1]->Gain(img)); iString base (g_oNormList[band-1]->Offset(img)); iString avg (g_oNormList[band-1]->Average(img)); iString bandNum (band); std::string bandStr = "Band" + bandNum; PvlKeyword bandStats(bandStr); bandStats += mult; bandStats += base; bandStats += avg; norm += bandStats; } equ.AddGroup(norm); } // Write the equalization and overlap statistics to the file std::string out = Filename(ui.GetFilename("OUTSTATS")).Expanded(); std::ofstream os; os.open(out.c_str(),std::ios::app); Pvl p; p.SetTerminator(""); p.AddObject(equ); os << p << std::endl; for (unsigned int i=0; i<g_overlapList.size(); i++) { os << g_overlapList[i]; if (i != g_overlapList.size()-1) os << std::endl; } os << "End"; } // Check for errors with the input statistics if (processOpt == "APPLY") { Pvl inStats (ui.GetFilename("INSTATS")); PvlObject &equalInfo = inStats.FindObject("EqualizationInformation"); // Make sure each file in the instats matches a file in the fromlist if (imageList.size() > (unsigned)equalInfo.Groups()-1) { std::string msg = "Each input file in the FROM LIST must have a "; msg += "corresponding input file in the INPUT STATISTICS."; throw iException::Message(iException::User,msg,_FILEINFO_); } // Check that each file in the FROM LIST is present in the INPUT STATISTICS for (unsigned i = 0; i < imageList.size(); i++) { std::string fromFile = imageList[i]; bool foundFile = false; for (int j = 1; j < equalInfo.Groups(); j++) { PvlGroup &normalization = equalInfo.Group(j); std::string normFile = normalization["Filename"][0]; if (fromFile == normFile) { // Store the index in INPUT STATISTICS file corresponding to the // current FROM LIST file normIndices.push_back(j); foundFile = true; } } if (!foundFile) { std::string msg = "The from list file [" + fromFile + "] does not have any corresponding file in the stats list."; throw iException::Message(iException::User,msg,_FILEINFO_); } } } // Apply the correction to the images if the user wants this done if (processOpt != "CALCULATE") { iString maxCubeStr ((int)imageList.size()); for (int img=0; img<(int)imageList.size(); img++) { // Set up for progress bar ProcessByLine p; iString curCubeStr (img+1); p.Progress()->SetText("Equalizing Cube " + curCubeStr + " of " + maxCubeStr); // Open input cube CubeAttributeInput att; const std::string inp = imageList[img]; Cube *icube = p.SetInputCube(inp, att); // Establish the output file depending upon whether or not a to list // was entered std::string out; if (ui.WasEntered("TOLIST")) { out = outList[img]; } else { Filename file = imageList[img]; out = file.Path() + "/" + file.Basename() + ".equ." + file.Extension(); } // Allocate output cube CubeAttributeOutput outAtt; p.SetOutputCube(out,outAtt,icube->Samples(),icube->Lines(),icube->Bands()); // Apply gain/offset to the image g_imageIndex = img; if (processOpt == "APPLY") { // Apply correction based on pre-determined statistics information Pvl inStats (ui.GetFilename("INSTATS")); PvlObject &equalInfo = inStats.FindObject("EqualizationInformation"); PvlGroup &normalization = equalInfo.Group(normIndices[g_imageIndex]); gains.clear(); offsets.clear(); avgs.clear(); // Get and store the modifiers for each band for (int band = 1; band < normalization.Keywords(); band++) { gains.push_back(normalization[band][0]); offsets.push_back(normalization[band][1]); avgs.push_back(normalization[band][2]); } p.StartProcess(ApplyViaFile); } else { // Apply correction based on the statistics gathered in this run p.StartProcess(ApplyViaObject); } p.EndProcess(); } } // Clean-up for batch list runs for (unsigned int o=0; o<g_oNormList.size(); o++) delete g_oNormList[o]; g_oNormList.clear(); g_overlapList.clear(); normIndices.clear(); gains.clear(); offsets.clear(); avgs.clear(); }
void IsisMain() { // Open the input cube Process p; UserInterface &ui = Application::GetUserInterface(); CubeAttributeInput cai; Cube *icube = p.SetInputCube(ui.GetFilename("FROM"), cai, ReadWrite); // Make sure at least one CK & SPK quality was selected if (!ui.GetBoolean("CKPREDICTED") && !ui.GetBoolean("CKRECON") && !ui.GetBoolean("CKSMITHED") && !ui.GetBoolean("CKNADIR")) { string msg = "At least one CK quality must be selected"; throw iException::Message(iException::User,msg,_FILEINFO_); } if (!ui.GetBoolean("SPKPREDICTED") && !ui.GetBoolean("SPKRECON") && !ui.GetBoolean("SPKSMITHED")) { string msg = "At least one SPK quality must be selected"; throw iException::Message(iException::User,msg,_FILEINFO_); } // Make sure it is not projected Projection *proj = NULL; try { proj = icube->Projection(); } catch (iException &e) { proj = NULL; e.Clear(); } if (proj != NULL) { string msg = "Can not initialize SPICE for a map projected cube"; throw iException::Message(iException::User,msg,_FILEINFO_); } Pvl lab = *icube->Label(); // if cube has existing polygon delete it if (icube->Label()->HasObject("Polygon")) { icube->Label()->DeleteObject("Polygon"); } // Set up for getting the mission name // Get the directory where the system missions translation table is. string transFile = p.MissionData("base", "translations/MissionName2DataDir.trn"); // Get the mission translation manager ready PvlTranslationManager missionXlater (lab, transFile); // Get the mission name so we can search the correct DB's for kernels string mission = missionXlater.Translate ("MissionName"); // Get system base kernels unsigned int allowed = 0; unsigned int allowedCK = 0; unsigned int allowedSPK = 0; if (ui.GetBoolean("CKPREDICTED")) allowedCK |= spiceInit::kernelTypeEnum("PREDICTED"); if (ui.GetBoolean("CKRECON")) allowedCK |= spiceInit::kernelTypeEnum("RECONSTRUCTED"); if (ui.GetBoolean("CKSMITHED")) allowedCK |= spiceInit::kernelTypeEnum("SMITHED"); if (ui.GetBoolean("CKNADIR")) allowedCK |= spiceInit::kernelTypeEnum("NADIR"); if (ui.GetBoolean("SPKPREDICTED")) allowedSPK |= spiceInit::kernelTypeEnum("PREDICTED"); if (ui.GetBoolean("SPKRECON")) allowedSPK |= spiceInit::kernelTypeEnum("RECONSTRUCTED"); if (ui.GetBoolean("SPKSMITHED")) allowedSPK |= spiceInit::kernelTypeEnum("SMITHED"); KernelDb baseKernels (allowed); KernelDb ckKernels (allowedCK); KernelDb spkKernels (allowedSPK); baseKernels.LoadSystemDb(mission); ckKernels.LoadSystemDb(mission); spkKernels.LoadSystemDb(mission); Kernel lk, pck, targetSpk, fk, ik, sclk, spk, iak, dem, exk; std::priority_queue< Kernel > ck; lk = baseKernels.LeapSecond(lab); pck = baseKernels.TargetAttitudeShape(lab); targetSpk = baseKernels.TargetPosition(lab); ik = baseKernels.Instrument(lab); sclk = baseKernels.SpacecraftClock(lab); iak = baseKernels.InstrumentAddendum(lab); fk = ckKernels.Frame(lab); ck = ckKernels.SpacecraftPointing(lab); spk = spkKernels.SpacecraftPosition(lab); if (ui.GetBoolean("CKNADIR")) { // Only add nadir if no spacecraft pointing found std::vector<std::string> kernels; kernels.push_back("Nadir"); ck.push(Kernel((spiceInit::kernelTypes)0, kernels)); } // Get user defined kernels and override ones already found GetUserEnteredKernel("LS", lk); GetUserEnteredKernel("PCK", pck); GetUserEnteredKernel("TSPK", targetSpk); GetUserEnteredKernel("FK", fk); GetUserEnteredKernel("IK", ik); GetUserEnteredKernel("SCLK", sclk); GetUserEnteredKernel("SPK", spk); GetUserEnteredKernel("IAK", iak); GetUserEnteredKernel("EXTRA", exk); // Get shape kernel if (ui.GetString ("SHAPE") == "USER") { GetUserEnteredKernel("MODEL", dem); } else if (ui.GetString("SHAPE") == "SYSTEM") { dem = baseKernels.Dem(lab); } bool kernelSuccess = false; if (ck.size() == 0 && !ui.WasEntered("CK")) { throw iException::Message(iException::Camera, "No Camera Kernel found for the image ["+ui.GetFilename("FROM") +"]", _FILEINFO_); } else if(ui.WasEntered("CK")) { // ck needs to be array size 1 and empty kernel objects while(ck.size()) ck.pop(); ck.push(Kernel()); } while(ck.size() != 0 && !kernelSuccess) { Kernel realCkKernel = ck.top(); ck.pop(); if (ui.WasEntered("CK")) { ui.GetAsString("CK", realCkKernel.kernels); } // Merge SpacecraftPointing and Frame into ck for (int i = 0; i < fk.size(); i++) { realCkKernel.push_back(fk[i]); } kernelSuccess = TryKernels(icube, p, lk, pck, targetSpk, realCkKernel, fk, ik, sclk, spk, iak, dem, exk); } if(!kernelSuccess) { throw iException::Message(iException::Camera, "Unable to initialize camera model", _FILEINFO_); } p.EndProcess(); }
void IsisMain() { Process p; // Get the list of names of input CCD cubes to stitch together FileList flist; UserInterface &ui = Application::GetUserInterface(); flist.Read(ui.GetFilename("FROMLIST")); if (flist.size() < 1) { string msg = "The list file[" + ui.GetFilename("FROMLIST") + " does not contain any filenames"; throw iException::Message(iException::User,msg,_FILEINFO_); } string projection("Equirectangular"); if(ui.WasEntered("MAP")) { Pvl mapfile(ui.GetFilename("MAP")); projection = (string) mapfile.FindGroup("Mapping")["ProjectionName"]; } if(ui.WasEntered("PROJECTION")) { projection = ui.GetString("PROJECTION"); } // Gather other user inputs to projection string lattype = ui.GetString("LATTYPE"); string londir = ui.GetString("LONDIR"); string londom = ui.GetString("LONDOM"); int digits = ui.GetInteger("PRECISION"); // Fix them for mapping group lattype = (lattype == "PLANETOCENTRIC") ? "Planetocentric" : "Planetographic"; londir = (londir == "POSITIVEEAST") ? "PositiveEast" : "PositiveWest"; Progress prog; prog.SetMaximumSteps(flist.size()); prog.CheckStatus(); Statistics scaleStat; Statistics longitudeStat; Statistics latitudeStat; Statistics equiRadStat; Statistics poleRadStat; PvlObject fileset("FileSet"); // Save major equitorial and polar radii for last occuring double eqRad; double eq2Rad; double poleRad; string target("Unknown"); for (unsigned int i = 0 ; i < flist.size() ; i++) { // Set the input image, get the camera model, and a basic mapping // group Cube cube; cube.Open(flist[i]); int lines = cube.Lines(); int samples = cube.Samples(); PvlObject fmap("File"); fmap += PvlKeyword("Name",flist[i]); fmap += PvlKeyword("Lines", lines); fmap += PvlKeyword("Samples", samples); Camera *cam = cube.Camera(); Pvl mapping; cam->BasicMapping(mapping); PvlGroup &mapgrp = mapping.FindGroup("Mapping"); mapgrp.AddKeyword(PvlKeyword("ProjectionName",projection),Pvl::Replace); mapgrp.AddKeyword(PvlKeyword("LatitudeType",lattype),Pvl::Replace); mapgrp.AddKeyword(PvlKeyword("LongitudeDirection",londir),Pvl::Replace); mapgrp.AddKeyword(PvlKeyword("LongitudeDomain",londom),Pvl::Replace); // Get the radii double radii[3]; cam->Radii(radii); eqRad = radii[0] * 1000.0; eq2Rad = radii[1] * 1000.0; poleRad = radii[2] * 1000.0; target = cam->Target(); equiRadStat.AddData(&eqRad, 1); poleRadStat.AddData(&poleRad, 1); // Get resolution double lowres = cam->LowestImageResolution(); double hires = cam->HighestImageResolution(); scaleStat.AddData(&lowres, 1); scaleStat.AddData(&hires, 1); double pixres = (lowres+hires)/2.0; double scale = Scale(pixres, poleRad, eqRad); mapgrp.AddKeyword(PvlKeyword("PixelResolution",pixres),Pvl::Replace); mapgrp.AddKeyword(PvlKeyword("Scale",scale,"pixels/degree"),Pvl::Replace); mapgrp += PvlKeyword("MinPixelResolution",lowres,"meters"); mapgrp += PvlKeyword("MaxPixelResolution",hires,"meters"); // Get the universal ground range double minlat,maxlat,minlon,maxlon; cam->GroundRange(minlat,maxlat,minlon,maxlon,mapping); mapgrp.AddKeyword(PvlKeyword("MinimumLatitude",minlat),Pvl::Replace); mapgrp.AddKeyword(PvlKeyword("MaximumLatitude",maxlat),Pvl::Replace); mapgrp.AddKeyword(PvlKeyword("MinimumLongitude",minlon),Pvl::Replace); mapgrp.AddKeyword(PvlKeyword("MaximumLongitude",maxlon),Pvl::Replace); fmap.AddGroup(mapgrp); fileset.AddObject(fmap); longitudeStat.AddData(&minlon, 1); longitudeStat.AddData(&maxlon, 1); latitudeStat.AddData(&minlat, 1); latitudeStat.AddData(&maxlat, 1); p.ClearInputCubes(); prog.CheckStatus(); } // Construct the output mapping group with statistics PvlGroup mapping("Mapping"); double avgPixRes((scaleStat.Minimum()+scaleStat.Maximum())/2.0); double avgLat((latitudeStat.Minimum()+latitudeStat.Maximum())/2.0); double avgLon((longitudeStat.Minimum()+longitudeStat.Maximum())/2.0); double avgEqRad((equiRadStat.Minimum()+equiRadStat.Maximum())/2.0); double avgPoleRad((poleRadStat.Minimum()+poleRadStat.Maximum())/2.0); double scale = Scale(avgPixRes, avgPoleRad, avgEqRad); mapping += PvlKeyword("ProjectionName",projection); mapping += PvlKeyword("TargetName", target); mapping += PvlKeyword("EquatorialRadius",eqRad,"meters"); mapping += PvlKeyword("PolarRadius",poleRad,"meters"); mapping += PvlKeyword("LatitudeType",lattype); mapping += PvlKeyword("LongitudeDirection",londir); mapping += PvlKeyword("LongitudeDomain",londom); mapping += PvlKeyword("PixelResolution", SetRound(avgPixRes, digits), "meters/pixel"); mapping += PvlKeyword("Scale", SetRound(scale, digits), "pixels/degree"); mapping += PvlKeyword("MinPixelResolution",scaleStat.Minimum(),"meters"); mapping += PvlKeyword("MaxPixelResolution",scaleStat.Maximum(),"meters"); mapping += PvlKeyword("CenterLongitude", SetRound(avgLon,digits)); mapping += PvlKeyword("CenterLatitude", SetRound(avgLat,digits)); mapping += PvlKeyword("MinimumLatitude", MAX(SetFloor(latitudeStat.Minimum(),digits), -90.0)); mapping += PvlKeyword("MaximumLatitude", MIN(SetCeil(latitudeStat.Maximum(),digits), 90.0)); mapping += PvlKeyword("MinimumLongitude",MAX(SetFloor(longitudeStat.Minimum(),digits), -180.0)); mapping += PvlKeyword("MaximumLongitude",MIN(SetCeil(longitudeStat.Maximum(),digits), 360.0)); PvlKeyword clat("PreciseCenterLongitude", avgLon); clat.AddComment("Actual Parameters without precision applied"); mapping += clat; mapping += PvlKeyword("PreciseCenterLatitude", avgLat); mapping += PvlKeyword("PreciseMinimumLatitude", latitudeStat.Minimum()); mapping += PvlKeyword("PreciseMaximumLatitude", latitudeStat.Maximum()); mapping += PvlKeyword("PreciseMinimumLongitude",longitudeStat.Minimum()); mapping += PvlKeyword("PreciseMaximumLongitude",longitudeStat.Maximum()); Application::GuiLog(mapping); // Write the output file if requested if (ui.WasEntered("TO")) { Pvl temp; temp.AddGroup(mapping); temp.Write(ui.GetFilename("TO","map")); } if (ui.WasEntered("LOG")) { Pvl temp; temp.AddObject(fileset); temp.Write(ui.GetFilename("LOG","log")); } p.EndProcess(); }
void IsisMain() { Process p; Cube *icube = p.SetInputCube("FROM"); // Setup the histogram UserInterface &ui = Application::GetUserInterface(); Histogram hist(*icube,1,p.Progress()); if (ui.WasEntered("MINIMUM")) { hist.SetValidRange(ui.GetDouble("MINIMUM"),ui.GetDouble("MAXIMUM")); } if (ui.WasEntered("NBINS")) { hist.SetBins(ui.GetInteger("NBINS")); } // Loop and accumulate histogram p.Progress()->SetText("Gathering Histogram"); p.Progress()->SetMaximumSteps(icube->Lines()); p.Progress()->CheckStatus(); LineManager line(*icube); for (int i=1; i<=icube->Lines(); i++) { line.SetLine(i); icube->Read(line); hist.AddData(line.DoubleBuffer(),line.size()); p.Progress()->CheckStatus(); } if(!ui.IsInteractive() || ui.WasEntered("TO")) { // Write the results if (!ui.WasEntered("TO")) { string msg = "The [TO] parameter must be entered"; throw iException::Message(iException::User,msg,_FILEINFO_); } string outfile = ui.GetFilename("TO"); ofstream fout; fout.open (outfile.c_str()); fout << "Cube: " << ui.GetFilename("FROM") << endl; fout << "Band: " << icube->Bands() << endl; fout << "Average: " << hist.Average() << endl; fout << "Std Deviation: " << hist.StandardDeviation() << endl; fout << "Variance: " << hist.Variance() << endl; fout << "Median: " << hist.Median() << endl; fout << "Mode: " << hist.Mode() << endl; fout << "Skew: " << hist.Skew() << endl; fout << "Minimum: " << hist.Minimum() << endl; fout << "Maximum: " << hist.Maximum() << endl; fout << endl; fout << "Total Pixels: " << hist.TotalPixels() << endl; fout << "Valid Pixels: " << hist.ValidPixels() << endl; fout << "Null Pixels: " << hist.NullPixels() << endl; fout << "Lis Pixels: " << hist.LisPixels() << endl; fout << "Lrs Pixels: " << hist.LrsPixels() << endl; fout << "His Pixels: " << hist.HisPixels() << endl; fout << "Hrs Pixels: " << hist.HrsPixels() << endl; // Write histogram in tabular format fout << endl; fout << endl; fout << "DN,Pixels,CumulativePixels,Percent,CumulativePercent" << endl; Isis::BigInt total = 0; double cumpct = 0.0; for (int i=0; i<hist.Bins(); i++) { if (hist.BinCount(i) > 0) { total += hist.BinCount(i); double pct = (double)hist.BinCount(i) / hist.ValidPixels() * 100.; cumpct += pct; fout << hist.BinMiddle(i) << ","; fout << hist.BinCount(i) << ","; fout << total << ","; fout << pct << ","; fout << cumpct << endl; } } fout.close(); } // If we are in gui mode, create a histogram plot if (ui.IsInteractive()) { // Set the title for the dialog string title; if (ui.WasEntered("TITLE")) { title = ui.GetString("TITLE"); } else { title = "Histogram Plot for " + Filename(ui.GetAsString("FROM")).Name(); } // Create the QHistogram, set the title & load the Isis::Histogram into it Qisis::HistogramToolWindow *plot = new Qisis::HistogramToolWindow(title.c_str(), ui.TheGui()); // Set the xaxis title if they entered one if (ui.WasEntered("XAXIS")) { string xaxis(ui.GetString("XAXIS")); plot->setAxisLabel(QwtPlot::xBottom,xaxis.c_str()); } // Set the yLeft axis title if they entered one if (ui.WasEntered("Y1AXIS")) { string yaxis(ui.GetString("Y1AXIS")); plot->setAxisLabel(QwtPlot::yLeft,yaxis.c_str()); } // Set the yRight axis title if they entered one if (ui.WasEntered("Y2AXIS")) { string y2axis(ui.GetString("Y2AXIS")); plot->setAxisLabel(QwtPlot::yRight,y2axis.c_str()); } //Transfer data from histogram to the plotcurve std::vector<double> xarray,yarray,y2array; double cumpct = 0.0; for (int i=0; i<hist.Bins(); i++) { if (hist.BinCount(i) > 0) { xarray.push_back(hist.BinMiddle(i)); yarray.push_back(hist.BinCount(i)); double pct = (double)hist.BinCount(i) / hist.ValidPixels() * 100.; cumpct += pct; y2array.push_back(cumpct); } } Qisis::HistogramItem *histCurve = new Qisis::HistogramItem(); histCurve->setColor(Qt::darkCyan); histCurve->setTitle("Frequency"); Qisis::PlotToolCurve *cdfCurve = new Qisis::PlotToolCurve(); cdfCurve->setStyle(QwtPlotCurve::Lines); cdfCurve->setTitle("Percentage"); QPen *pen = new QPen(Qt::red); pen->setWidth(2); histCurve->setYAxis(QwtPlot::yLeft); cdfCurve->setYAxis(QwtPlot::yRight); cdfCurve->setPen(*pen); //These are all variables needed in the following for loop. //---------------------------------------------- QwtArray<QwtDoubleInterval> intervals(xarray.size()); QwtArray<double> values(yarray.size()); double maxYValue = DBL_MIN; double minYValue = DBL_MAX; // --------------------------------------------- for(unsigned int y = 0; y < yarray.size(); y++) { intervals[y] = QwtDoubleInterval(xarray[y], xarray[y] + hist.BinSize()); values[y] = yarray[y]; if(values[y] > maxYValue) maxYValue = values[y]; if(values[y] < minYValue) minYValue = values[y]; } histCurve->setData(QwtIntervalData(intervals, values)); cdfCurve->setData(&xarray[0],&y2array[0],xarray.size()); plot->add(histCurve); plot->add(cdfCurve); plot->fillTable(); plot->setScale(QwtPlot::yLeft,0,maxYValue); plot->setScale(QwtPlot::xBottom,hist.Minimum(),hist.Maximum()); QLabel *label = new QLabel(" Average = " + QString::number(hist.Average()) + '\n' + "\n Minimum = " + QString::number(hist.Minimum()) + '\n' + "\n Maximum = " + QString::number(hist.Maximum()) + '\n' + "\n Stand. Dev.= " + QString::number(hist.StandardDeviation()) + '\n' + "\n Variance = " + QString::number(hist.Variance()) + '\n' + "\n Median = " + QString::number(hist.Median()) + '\n' + "\n Mode = " + QString::number(hist.Mode()) +'\n' + "\n Skew = " + QString::number(hist.Skew()), plot); plot->getDockWidget()->setWidget(label); plot->showWindow(); } p.EndProcess(); }
//Helper function to compute input range. void ComputeInputRange () { Process p; Cube *latCub = p.SetInputCube("LATCUB"); Cube *lonCub = p.SetInputCube("LONCUB"); UserInterface &ui = Application::GetUserInterface(); Pvl userMap; userMap.Read(ui.GetFilename("MAP")); PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); Statistics *latStats = latCub->Statistics(); Statistics *lonStats = lonCub->Statistics(); double minLat = latStats->Minimum(); double maxLat = latStats->Maximum(); int lonDomain = userGrp.HasKeyword("LongitudeDomain") ? (int)userGrp.FindKeyword("LongitudeDomain") : 360; double minLon = lonDomain == 360 ? Projection::To360Domain(lonStats->Minimum()) : Projection::To180Domain(lonStats->Minimum()); double maxLon = lonDomain == 360 ? Projection::To360Domain(lonStats->Maximum()) : Projection::To180Domain(lonStats->Maximum()); if(userGrp.HasKeyword("LatitudeType")) { bool isOcentric = ((std::string)userGrp.FindKeyword("LatitudeType")) == "Planetocentric"; double equRadius; double polRadius; //If the user entered the equatorial and polar radii if(ui.WasEntered("EQURADIUS") && ui.WasEntered("POLRADIUS")) { equRadius = ui.GetDouble("EQURADIUS"); polRadius = ui.GetDouble("POLRADIUS"); } //Else read them from the pck else { Filename pckFile("$base/kernels/pck/pck?????.tpc"); pckFile.HighestVersion(); string pckFilename = pckFile.Expanded(); furnsh_c(pckFilename.c_str()); string target; //If user entered target if(ui.WasEntered("TARGET")) { target = ui.GetString("TARGET"); } //Else read the target name from the input cube else { Pvl fromFile; fromFile.Read(ui.GetFilename("FROM")); target = (string)fromFile.FindKeyword("TargetName", Pvl::Traverse); } SpiceInt code; SpiceBoolean found; bodn2c_c (target.c_str(), &code, &found); if (!found) { string msg = "Could not convert Target [" + target + "] to NAIF code"; throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); } SpiceInt n; SpiceDouble radii[3]; bodvar_c(code,"RADII",&n,radii); equRadius = radii[0] * 1000; polRadius = radii[2] * 1000; } if(isOcentric) { if(ui.GetString("LATTYPE") != "PLANETOCENTRIC") { minLat = Projection::ToPlanetocentric(minLat, (double)equRadius, (double)polRadius); maxLat = Projection::ToPlanetocentric(maxLat, (double)equRadius, (double)polRadius); } } else { if(ui.GetString("LATTYPE") == "PLANETOCENTRIC") { minLat = Projection::ToPlanetographic(minLat, (double)equRadius, (double)polRadius); maxLat = Projection::ToPlanetographic(maxLat, (double)equRadius, (double)polRadius); } } } if(userGrp.HasKeyword("LongitudeDirection")) { bool isPosEast = ((std::string)userGrp.FindKeyword("LongitudeDirection")) == "PositiveEast"; if(isPosEast) { if(ui.GetString("LONDIR") != "POSITIVEEAST") { minLon = Projection::ToPositiveEast(minLon, lonDomain); maxLon = Projection::ToPositiveEast(maxLon, lonDomain); if(minLon > maxLon) { double temp = minLon; minLon = maxLon; maxLon = temp; } } } else { if(ui.GetString("LONDIR") == "POSITIVEEAST") { minLon = Projection::ToPositiveWest(minLon, lonDomain); maxLon = Projection::ToPositiveWest(maxLon, lonDomain); if(minLon > maxLon) { double temp = minLon; minLon = maxLon; maxLon = temp; } } } } // Set ground range parameters in UI ui.Clear("MINLAT"); ui.PutDouble("MINLAT", minLat); ui.Clear("MAXLAT"); ui.PutDouble("MAXLAT", maxLat); ui.Clear("MINLON"); ui.PutDouble("MINLON", minLon); ui.Clear("MAXLON"); ui.PutDouble("MAXLON", maxLon); p.EndProcess(); // Set default ground range param to camera ui.Clear("DEFAULTRANGE"); ui.PutAsString("DEFAULTRANGE","COMPUTE"); }
void IsisMain() { //Create a process to create the input cubes Process p; //Create the input cubes, matching sample/lines Cube *inCube = p.SetInputCube ("FROM"); Cube *latCube = p.SetInputCube("LATCUB", SpatialMatch); Cube *lonCube = p.SetInputCube("LONCUB", SpatialMatch); //A 1x1 brick to read in the latitude and longitude DN values from //the specified cubes Brick latBrick(1,1,1, latCube->PixelType()); Brick lonBrick(1,1,1, lonCube->PixelType()); UserInterface &ui = Application::GetUserInterface(); //Set the sample and line increments int sinc = (int)(inCube->Samples() * 0.10); if(ui.WasEntered("SINC")) { sinc = ui.GetInteger("SINC"); } int linc = (int)(inCube->Lines() * 0.10); if(ui.WasEntered("LINC")) { linc = ui.GetInteger("LINC"); } //Set the degree of the polynomial to use in our functions int degree = ui.GetInteger("DEGREE"); //We are using a polynomial with two variables PolynomialBivariate sampFunct(degree); PolynomialBivariate lineFunct(degree); //We will be solving the function using the least squares method LeastSquares sampSol(sampFunct); LeastSquares lineSol(lineFunct); //Setup the variables for solving the stereographic projection //x = cos(latitude) * sin(longitude - lon_center) //y = cos(lat_center) * sin(latitude) - sin(lat_center) * cos(latitude) * cos(longitude - lon_center) //Get the center lat and long from the input cubes double lat_center = latCube->Statistics()->Average() * PI/180.0; double lon_center = lonCube->Statistics()->Average() * PI/180.0; /** * Loop through lines and samples projecting the latitude and longitude at those * points to stereographic x and y and adding these points to the LeastSquares * matrix. */ for(int i = 1; i <= inCube->Lines(); i+= linc) { for(int j = 1; j <= inCube->Samples(); j+= sinc) { latBrick.SetBasePosition(j, i, 1); latCube->Read(latBrick); if(IsSpecial(latBrick.at(0))) continue; double lat = latBrick.at(0) * PI/180.0; lonBrick.SetBasePosition(j, i, 1); lonCube->Read(lonBrick); if(IsSpecial(lonBrick.at(0))) continue; double lon = lonBrick.at(0) * PI/180.0; //Project lat and lon to x and y using a stereographic projection double k = 2/(1 + sin(lat_center) * sin(lat) + cos(lat_center)*cos(lat)*cos(lon - lon_center)); double x = k * cos(lat) * sin(lon - lon_center); double y = k * (cos(lat_center) * sin(lat)) - (sin(lat_center) * cos(lat) * cos(lon - lon_center)); //Add x and y to the least squares matrix vector<double> data; data.push_back(x); data.push_back(y); sampSol.AddKnown(data, j); lineSol.AddKnown(data, i); //If the sample increment goes past the last sample in the line, we want to //always read the last sample.. if(j != inCube->Samples() && j + sinc > inCube->Samples()) { j = inCube->Samples() - sinc; } } //If the line increment goes past the last line in the cube, we want to //always read the last line.. if(i != inCube->Lines() && i + linc > inCube->Lines()) { i = inCube->Lines() - linc; } } //Solve the least squares functions using QR Decomposition sampSol.Solve(LeastSquares::QRD); lineSol.Solve(LeastSquares::QRD); //If the user wants to save the residuals to a file, create a file and write //the column titles to it. TextFile oFile; if(ui.WasEntered("RESIDUALS")) { oFile.Open(ui.GetFilename("RESIDUALS"), "overwrite"); oFile.PutLine("Sample,\tLine,\tX,\tY,\tSample Error,\tLine Error\n"); } //Gather the statistics for the residuals from the least squares solutions Statistics sampErr; Statistics lineErr; vector<double> sampResiduals = sampSol.Residuals(); vector<double> lineResiduals = lineSol.Residuals(); for(int i = 0; i < (int)sampResiduals.size(); i++) { sampErr.AddData(sampResiduals[i]); lineErr.AddData(lineResiduals[i]); } //If a residuals file was specified, write the previous data, and the errors to the file. if(ui.WasEntered("RESIDUALS")) { for(int i = 0; i < sampSol.Rows(); i++) { vector<double> data = sampSol.GetInput(i); iString tmp = ""; tmp += iString(sampSol.GetExpected(i)); tmp += ",\t"; tmp += iString(lineSol.GetExpected(i)); tmp += ",\t"; tmp += iString(data[0]); tmp += ",\t"; tmp += iString(data[1]); tmp += ",\t"; tmp += iString(sampResiduals[i]); tmp += ",\t"; tmp += iString(lineResiduals[i]); oFile.PutLine(tmp + "\n"); } } oFile.Close(); //Records the error to the log PvlGroup error( "Error" ); error += PvlKeyword( "Degree", degree ); error += PvlKeyword( "NumberOfPoints", (int)sampResiduals.size() ); error += PvlKeyword( "SampleMinimumError", sampErr.Minimum() ); error += PvlKeyword( "SampleAverageError", sampErr.Average() ); error += PvlKeyword( "SampleMaximumError", sampErr.Maximum() ); error += PvlKeyword( "SampleStdDeviationError", sampErr.StandardDeviation() ); error += PvlKeyword( "LineMinimumError", lineErr.Minimum() ); error += PvlKeyword( "LineAverageError", lineErr.Average() ); error += PvlKeyword( "LineMaximumError", lineErr.Maximum() ); error += PvlKeyword( "LineStdDeviationError", lineErr.StandardDeviation() ); Application::Log( error ); //Close the input cubes for cleanup p.EndProcess(); //If we want to warp the image, then continue, otherwise return if(!ui.GetBoolean("NOWARP")) { //Creates the mapping group Pvl mapFile; mapFile.Read(ui.GetFilename("MAP")); PvlGroup &mapGrp = mapFile.FindGroup("Mapping",Pvl::Traverse); //Reopen the lat and long cubes latCube = new Cube(); latCube->SetVirtualBands(ui.GetInputAttribute("LATCUB").Bands()); latCube->Open(ui.GetFilename("LATCUB")); lonCube = new Cube(); lonCube->SetVirtualBands(ui.GetInputAttribute("LONCUB").Bands()); lonCube->Open(ui.GetFilename("LONCUB")); PvlKeyword targetName; //If the user entered the target name if(ui.WasEntered("TARGET")) { targetName = PvlKeyword("TargetName", ui.GetString("TARGET")); } //Else read the target name from the input cube else { Pvl fromFile; fromFile.Read(ui.GetFilename("FROM")); targetName = fromFile.FindKeyword("TargetName", Pvl::Traverse); } mapGrp.AddKeyword(targetName, Pvl::Replace); PvlKeyword equRadius; PvlKeyword polRadius; //If the user entered the equatorial and polar radii if(ui.WasEntered("EQURADIUS") && ui.WasEntered("POLRADIUS")) { equRadius = PvlKeyword("EquatorialRadius", ui.GetDouble("EQURADIUS")); polRadius = PvlKeyword("PolarRadius", ui.GetDouble("POLRADIUS")); } //Else read them from the pck else { Filename pckFile("$base/kernels/pck/pck?????.tpc"); pckFile.HighestVersion(); string pckFilename = pckFile.Expanded(); furnsh_c(pckFilename.c_str()); string target = targetName[0]; SpiceInt code; SpiceBoolean found; bodn2c_c (target.c_str(), &code, &found); if (!found) { string msg = "Could not convert Target [" + target + "] to NAIF code"; throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); } SpiceInt n; SpiceDouble radii[3]; bodvar_c(code,"RADII",&n,radii); equRadius = PvlKeyword("EquatorialRadius", radii[0] * 1000); polRadius = PvlKeyword("PolarRadius", radii[2] * 1000); } mapGrp.AddKeyword(equRadius, Pvl::Replace); mapGrp.AddKeyword(polRadius, Pvl::Replace); //If the latitude type is not in the mapping group, copy it from the input if(!mapGrp.HasKeyword("LatitudeType")) { if(ui.GetString("LATTYPE") == "PLANETOCENTRIC") { mapGrp.AddKeyword(PvlKeyword("LatitudeType","Planetocentric"), Pvl::Replace); } else { mapGrp.AddKeyword(PvlKeyword("LatitudeType","Planetographic"), Pvl::Replace); } } //If the longitude direction is not in the mapping group, copy it from the input if(!mapGrp.HasKeyword("LongitudeDirection")) { if(ui.GetString("LONDIR") == "POSITIVEEAST") { mapGrp.AddKeyword(PvlKeyword("LongitudeDirection","PositiveEast"), Pvl::Replace); } else { mapGrp.AddKeyword(PvlKeyword("LongitudeDirection","PositiveWest"), Pvl::Replace); } } //If the longitude domain is not in the mapping group, assume it is 360 if(!mapGrp.HasKeyword("LongitudeDomain")) { mapGrp.AddKeyword(PvlKeyword("LongitudeDomain","360"), Pvl::Replace); } //If the default range is to be computed, use the input lat/long cubes to determine the range if(ui.GetString("DEFAULTRANGE") == "COMPUTE") { //NOTE - When computing the min/max longitude this application does not account for the //longitude seam if it exists. Since the min/max are calculated from the statistics of //the input longitude cube and then converted to the mapping group's domain they may be //invalid for cubes containing the longitude seam. Statistics *latStats = latCube->Statistics(); Statistics *lonStats = lonCube->Statistics(); double minLat = latStats->Minimum(); double maxLat = latStats->Maximum(); bool isOcentric = ((std::string)mapGrp.FindKeyword("LatitudeType")) == "Planetocentric"; if(isOcentric) { if(ui.GetString("LATTYPE") != "PLANETOCENTRIC") { minLat = Projection::ToPlanetocentric(minLat, (double)equRadius, (double)polRadius); maxLat = Projection::ToPlanetocentric(maxLat, (double)equRadius, (double)polRadius); } } else { if(ui.GetString("LATTYPE") == "PLANETOCENTRIC") { minLat = Projection::ToPlanetographic(minLat, (double)equRadius, (double)polRadius); maxLat = Projection::ToPlanetographic(maxLat, (double)equRadius, (double)polRadius); } } int lonDomain = (int)mapGrp.FindKeyword("LongitudeDomain"); double minLon = lonDomain == 360 ? Projection::To360Domain(lonStats->Minimum()) : Projection::To180Domain(lonStats->Minimum()); double maxLon = lonDomain == 360 ? Projection::To360Domain(lonStats->Maximum()) : Projection::To180Domain(lonStats->Maximum()); bool isPosEast = ((std::string)mapGrp.FindKeyword("LongitudeDirection")) == "PositiveEast"; if(isPosEast) { if(ui.GetString("LONDIR") != "POSITIVEEAST") { minLon = Projection::ToPositiveEast(minLon, lonDomain); maxLon = Projection::ToPositiveEast(maxLon, lonDomain); } } else { if(ui.GetString("LONDIR") == "POSITIVEEAST") { minLon = Projection::ToPositiveWest(minLon, lonDomain); maxLon = Projection::ToPositiveWest(maxLon, lonDomain); } } if(minLon > maxLon) { double temp = minLon; minLon = maxLon; maxLon = temp; } mapGrp.AddKeyword(PvlKeyword("MinimumLatitude", minLat),Pvl::Replace); mapGrp.AddKeyword(PvlKeyword("MaximumLatitude", maxLat),Pvl::Replace); mapGrp.AddKeyword(PvlKeyword("MinimumLongitude", minLon),Pvl::Replace); mapGrp.AddKeyword(PvlKeyword("MaximumLongitude", maxLon),Pvl::Replace); } //If the user decided to enter a ground range then override if (ui.WasEntered("MINLAT")) { mapGrp.AddKeyword(PvlKeyword("MinimumLatitude", ui.GetDouble("MINLAT")),Pvl::Replace); } if (ui.WasEntered("MAXLAT")) { mapGrp.AddKeyword(PvlKeyword("MaximumLatitude", ui.GetDouble("MAXLAT")),Pvl::Replace); } if (ui.WasEntered("MINLON")) { mapGrp.AddKeyword(PvlKeyword("MinimumLongitude", ui.GetDouble("MINLON")),Pvl::Replace); } if (ui.WasEntered("MAXLON")) { mapGrp.AddKeyword(PvlKeyword("MaximumLongitude", ui.GetDouble("MAXLON")),Pvl::Replace); } //If the pixel resolution is to be computed, compute the pixels/degree from the input if (ui.GetString("PIXRES") == "COMPUTE") { latBrick.SetBasePosition(1,1,1); latCube->Read(latBrick); lonBrick.SetBasePosition(1,1,1); lonCube->Read(lonBrick); //Read the lat and long at the upper left corner double a = latBrick.at(0) * PI/180.0; double c = lonBrick.at(0) * PI/180.0; latBrick.SetBasePosition(latCube->Samples(),latCube->Lines(),1); latCube->Read(latBrick); lonBrick.SetBasePosition(lonCube->Samples(),lonCube->Lines(),1); lonCube->Read(lonBrick); //Read the lat and long at the lower right corner double b = latBrick.at(0) * PI/180.0; double d = lonBrick.at(0) * PI/180.0; //Determine the angle between the two points double angle = acos(cos(a) * cos(b) * cos(c - d) + sin(a) * sin(b)); //double angle = acos((cos(a1) * cos(b1) * cos(b2)) + (cos(a1) * sin(b1) * cos(a2) * sin(b2)) + (sin(a1) * sin(a2))); angle *= 180/PI; //Determine the number of pixels between the two points double pixels = sqrt(pow(latCube->Samples() -1.0, 2.0) + pow(latCube->Lines() -1.0, 2.0)); //Add the scale in pixels/degree to the mapping group mapGrp.AddKeyword(PvlKeyword("Scale", pixels/angle, "pixels/degree"), Pvl::Replace); if (mapGrp.HasKeyword("PixelResolution")) { mapGrp.DeleteKeyword("PixelResolution"); } } // If the user decided to enter a resolution then override if (ui.GetString("PIXRES") == "MPP") { mapGrp.AddKeyword(PvlKeyword("PixelResolution", ui.GetDouble("RESOLUTION"), "meters/pixel"), Pvl::Replace); if (mapGrp.HasKeyword("Scale")) { mapGrp.DeleteKeyword("Scale"); } } else if (ui.GetString("PIXRES") == "PPD") { mapGrp.AddKeyword(PvlKeyword("Scale", ui.GetDouble("RESOLUTION"), "pixels/degree"), Pvl::Replace); if (mapGrp.HasKeyword("PixelResolution")) { mapGrp.DeleteKeyword("PixelResolution"); } } //Create a projection using the map file we created int samples,lines; Projection *outmap = ProjectionFactory::CreateForCube(mapFile,samples,lines,false); //Write the map file to the log Application::GuiLog(mapGrp); //Create a process rubber sheet ProcessRubberSheet r; //Set the input cube inCube = r.SetInputCube("FROM"); double tolerance = ui.GetDouble("TOLERANCE") * outmap->Resolution(); //Create a new transform object Transform *transform = new nocam2map (sampSol, lineSol, outmap, latCube, lonCube, ui.GetString("LATTYPE") == "PLANETOCENTRIC", ui.GetString("LONDIR") == "POSITIVEEAST", tolerance, ui.GetInteger("ITERATIONS"), inCube->Samples(), inCube->Lines(), samples, lines); //Allocate the output cube and add the mapping labels Cube *oCube = r.SetOutputCube ("TO", transform->OutputSamples(), transform->OutputLines(), inCube->Bands()); oCube->PutGroup(mapGrp); //Determine which interpolation to use 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); } //Warp the cube r.StartProcess(*transform, *interp); r.EndProcess(); // add mapping to print.prt PvlGroup mapping = outmap->Mapping(); Application::Log(mapping); //Clean up delete latCube; delete lonCube; delete outmap; delete transform; delete interp; } }
/** The ISIS smtk main application */ void IsisMain() { UserInterface &ui = Application::GetUserInterface(); // Open the first cube. It is the left hand image. Cube lhImage; CubeAttributeInput &attLeft = ui.GetInputAttribute("FROM"); vector<QString> bandLeft = attLeft.bands(); lhImage.setVirtualBands(bandLeft); lhImage.open(ui.GetFileName("FROM"),"r"); // Open the second cube, it is geomertricallty altered. We will be matching the // first to this one by attempting to compute a sample/line offsets Cube rhImage; CubeAttributeInput &attRight = ui.GetInputAttribute("MATCH"); vector<QString> bandRight = attRight.bands(); rhImage.setVirtualBands(bandRight); rhImage.open(ui.GetFileName("MATCH"),"r"); // Ensure only single bands if (lhImage.bandCount() != 1 || rhImage.bandCount() != 1) { QString msg = "Input Cubes must have only one band!"; throw IException(IException::User,msg,_FILEINFO_); } // Both images must have a Camera and can also have a Projection. We will // only deal with a Camera, however as a projected, non-mosaicked image // uses a Projection internal to the Camera object. Camera *lhCamera = NULL; Camera *rhCamera = NULL; try { lhCamera = lhImage.camera(); rhCamera = rhImage.camera(); } catch (IException &ie) { QString msg = "Both input images must have a camera"; throw IException(ie, IException::User, msg, _FILEINFO_); } // Since we are generating a DEM, we must turn off any existing // DEM that may have been initialized with spiceinit. lhCamera->IgnoreElevationModel(true); rhCamera->IgnoreElevationModel(true); // Get serial number QString serialLeft = SerialNumber::Compose(lhImage, true); QString serialRight = SerialNumber::Compose(rhImage, true); // This still precludes band to band registrations. if (serialLeft == serialRight) { QString sLeft = FileName(lhImage.fileName()).name(); QString sRight = FileName(rhImage.fileName()).name(); if (sLeft == sRight) { QString msg = "Cube Serial Numbers must be unique - FROM=" + serialLeft + ", MATCH=" + serialRight; throw IException(IException::User,msg,_FILEINFO_); } serialLeft = sLeft; serialRight = sRight; } Progress prog; prog.SetText("Finding Initial Seeds"); int nl = lhImage.lineCount(); int ns = lhImage.sampleCount(); BigInt numAttemptedInitialPoints = 0; // Declare Gruen matcher SmtkMatcher matcher(ui.GetFileName("REGDEF"), &lhImage, &rhImage); // Get line/sample linc/sinc parameters int space = ui.GetInteger("SPACE"); int linc (space), sinc(space); // Do we have a seed points from a control net file? bool useseed = ui.WasEntered("CNET"); // Base points on an input cnet SmtkQStack gstack; double lastEigen(0.0); if (useseed) { ControlNet cnet(ui.GetFileName("CNET")); prog.SetMaximumSteps(cnet.GetNumPoints()); prog.CheckStatus(); gstack.reserve(cnet.GetNumPoints()); for (int cpIndex = 0; cpIndex < cnet.GetNumPoints(); cpIndex ++) { ControlPoint *cp = cnet.GetPoint(cpIndex); if (!cp->IsIgnored()) { ControlMeasure *cmLeft(0), *cmRight(0); for(int cmIndex = 0; cmIndex < cp->GetNumMeasures(); cmIndex ++) { ControlMeasure *cm = cp->GetMeasure(cmIndex); if (!cm->IsIgnored()) { if (cm->GetCubeSerialNumber() == serialLeft) cmLeft = cp->GetMeasure(cmIndex); if (cm->GetCubeSerialNumber() == serialRight) cmRight = cp->GetMeasure(cmIndex); } } // If we have both left and right images in the control point, save it if ( (cmLeft != 0) && (cmRight != 0) ) { Coordinate left = Coordinate(cmLeft->GetLine(), cmLeft->GetSample()); Coordinate right = Coordinate(cmRight->GetLine(), cmRight->GetSample()); SmtkPoint spnt = matcher.Create(left, right); // Insert the point (unregistered) if ( spnt.isValid() ) { int line = (int) cmLeft->GetLine(); int samp = (int) cmLeft->GetSample(); matcher.isValid(spnt); gstack.insert(qMakePair(line, samp), spnt); lastEigen = spnt.GoodnessOfFit(); } } } prog.CheckStatus(); } } else { // We want to create a grid of control points that is N rows by M columns. int rows = (lhImage.lineCount() + linc - 1)/linc; int cols = (lhImage.sampleCount() + sinc - 1)/sinc; prog.SetMaximumSteps(rows * cols); prog.CheckStatus(); // First pass stack and eigen value statistics SmtkQStack fpass; fpass.reserve(rows * cols); Statistics temp_mev; // Loop through grid of points and get statistics to compute // initial set of points for (int line = linc / 2 + 1; line < nl; line += linc) { for (int samp = sinc / 2 + 1 ; samp < ns; samp += sinc) { numAttemptedInitialPoints ++; SmtkPoint spnt = matcher.Register(Coordinate(line,samp)); if ( spnt.isValid() ) { matcher.isValid(spnt); fpass.insert(qMakePair(line, samp), spnt); temp_mev.AddData(spnt.GoodnessOfFit()); } prog.CheckStatus(); } } // Now select a subset of fpass points as the seed points cout << "Number of Potential Seed Points: " << fpass.size() << "\n"; cout << "Min / Max Eigenvalues Matched: " << temp_mev.Minimum() << ", " << temp_mev.Maximum() << "\n"; // How many seed points are requested double nseed = ui.GetDouble("NSEED"); int inseed; if (nseed >= 1.0) inseed = (int) nseed; else if (nseed > 0.0) inseed = (int) (nseed * (double) (fpass.size())); else inseed = (int) ((double) (fpass.size()) * 0.05); double seedsample = ui.GetDouble("SEEDSAMPLE"); // Generate a new stack gstack.reserve(inseed); while ((gstack.size() < inseed) && (!fpass.isEmpty() )) { SmtkQStack::iterator bestm; if (seedsample <= 0.0) { bestm = matcher.FindSmallestEV(fpass); } else { bestm = matcher.FindExpDistEV(fpass, seedsample, temp_mev.Minimum(), temp_mev.Maximum()); } // Add point to stack if (bestm != fpass.end()) { Coordinate right = bestm.value().getRight(); matcher.isValid(bestm.value()); gstack.insert(bestm.key(), bestm.value()); lastEigen = bestm.value().GoodnessOfFit(); fpass.erase(bestm); } } // If a user wants to see the seed network, write it out here if (ui.WasEntered("OSEEDNET")) { WriteCnet(ui.GetFileName("OSEEDNET"), gstack, lhCamera->target()->name(), serialLeft, serialRight); } } /////////////////////////////////////////////////////////////////////// // All done with seed points. Sanity check ensures we actually found // some. /////////////////////////////////////////////////////////////////////// if (gstack.size() <= 0) { QString msg = "No seed points found - may need to check Gruen parameters."; throw IException(IException::User, msg, _FILEINFO_); } // Report seed point status if (!useseed) { cout << "Number of Seed Points used: " << gstack.size() << "\n"; cout << "EV of last Seed Point: " << lastEigen << "\n"; } else { cout << "Number of Manual Seed Points: " << gstack.size() << "\n"; } // Use seed points (in stack) to grow SmtkQStack bmf; bmf.reserve(gstack.size()); // Probably need much more but for starters... BigInt numOrigPoints = gstack.size(); BigInt passpix2 = 0; int subcbox = ui.GetInteger("SUBCBOX"); int halfBox((subcbox-1)/2); while (!gstack.isEmpty()) { SmtkQStackIter cstack = matcher.FindSmallestEV(gstack); // Print number on stack if ((gstack.size() % 1000) == 0) { cout << "Number on Stack: " << gstack.size() << ". " << cstack.value().GoodnessOfFit() << "\n"; } // Test to see if already determined SmtkQStackIter bmfPt = bmf.find(cstack.key()); if (bmfPt == bmf.end()) { // Its not in the final stack, process it // Retrieve the point SmtkPoint spnt = cstack.value(); // Register if its not already registered if (!spnt.isRegistered()) { spnt = matcher.Register(spnt, spnt.getAffine()); } // Still must check for validity if the point was just registered, // otherwise should be good if ( spnt.isValid() ) { passpix2++; bmf.insert(cstack.key(), spnt); // inserts (0,0) offset excluded below int line = cstack.key().first; int sample = cstack.key().second; // Determine match points double eigen(spnt.GoodnessOfFit()); for (int sampBox = -halfBox ; sampBox <= halfBox ; sampBox++ ) { int csamp = sample + sampBox; for (int lineBox = -halfBox ; lineBox <= halfBox ; lineBox++) { int cline = line + lineBox; if ( !( (sampBox == 0) && (lineBox == 0)) ) {// Already added above SmtkQPair dupPair(cline, csamp); SmtkQStackIter temp = bmf.find(dupPair); SmtkPoint bmfpnt; if (temp != bmf.end()) { if (temp.value().GoodnessOfFit() > eigen) { // Create cloned point with better fit bmfpnt = matcher.Clone(spnt, Coordinate(cline,csamp)); } } else { // ISIS2 is BMF(SAMP,LINE,7) .EQ VALID_MAX4) // Clone new point for insert bmfpnt = matcher.Clone(spnt, Coordinate(cline,csamp)); } // Add if good point if (bmfpnt.isValid()) { bmf.insert(dupPair, bmfpnt); } } } } // Grow stack with spacing adding info to stack for (int i = -1 ; i <= 1 ; i ++) { // Sample for (int j = -1 ; j <= 1 ; j ++) { // Line // Don't re-add the original sample, line if ( !((i == 0) && (j == 0)) ) { // Grow based upon spacing double ssamp = sample + (i * space); double sline = line + (j * space); Coordinate pnt = Coordinate(sline, ssamp); SmtkPoint gpnt = matcher.Clone(spnt, pnt); if ( gpnt.isValid() ) { SmtkQPair growpt((int) sline, (int) ssamp); // double check we don't have a finalized result at this position SmtkQStackIter temp = bmf.find(growpt); if(temp == bmf.end()) { gstack.insert(growpt, gpnt); } } } } } } } // Remove the current point from the grow stack (hole) gstack.erase(cstack); } ///////////////////////////////////////////////////////////////////////// // All done with creating points. Perform output options. ///////////////////////////////////////////////////////////////////////// // If a TO parameter was specified, create DEM with errors if (ui.WasEntered("TO")) { // Create the output DEM cout << "\nCreating output DEM from " << bmf.size() << " points.\n"; Process p; Cube *icube = p.SetInputCube("FROM"); Cube *ocube = p.SetOutputCube("TO", icube->sampleCount(), icube->lineCount(), 3); p.ClearInputCubes(); int boxsize = ui.GetInteger("BOXSIZE"); double plotdist = ui.GetDouble("PLOTDIST"); TileManager dem(*ocube), eigen(*ocube), stErr(*ocube); dem.SetTile(1, 1); // DEM Data/elevation stErr.SetTile(1, 2); // Error in stereo computation eigen.SetTile(1, 3); // Eigenvalue of the solution int nBTiles(eigen.Tiles()/3); // Total tiles / 3 bands prog.SetText("Creating DEM"); prog.SetMaximumSteps(nBTiles); prog.CheckStatus(); Statistics stAng; while ( !eigen.end() ) { // Must use the last band for this!! PointPlot tm = for_each(bmf.begin(), bmf.end(), PointPlot(dem, plotdist)); tm.FillPoints(*lhCamera, *rhCamera, boxsize, dem, stErr, eigen, &stAng); ocube->write(dem); ocube->write(stErr); ocube->write(eigen); dem.next(); stErr.next(); eigen.next(); prog.CheckStatus(); } // Report Stereo separation angles PvlGroup stresultsPvl("StereoSeparationAngle"); stresultsPvl += PvlKeyword("Minimum", toString(stAng.Minimum()), "deg"); stresultsPvl += PvlKeyword("Average", toString(stAng.Average()), "deg"); stresultsPvl += PvlKeyword("Maximum", toString(stAng.Maximum()), "deg"); stresultsPvl += PvlKeyword("StandardDeviation", toString(stAng.StandardDeviation()), "deg"); Application::Log(stresultsPvl); // Update the label with BandBin keywords PvlKeyword filter("FilterName", "Elevation", "meters"); filter.addValue("ElevationError", "meters"); filter.addValue("GoodnessOfFit", "unitless"); PvlKeyword center("Center", "1.0"); center.addValue("1.0"); center.addValue("1.0"); PvlGroup &bandbin = ocube->label()->findGroup("BandBin", PvlObject::Traverse); bandbin.addKeyword(filter, PvlContainer::Replace); bandbin.addKeyword(center, PvlContainer::Replace); center.setName("Width"); bandbin.addKeyword(center, PvlContainer::Replace); p.EndProcess(); } // If a cnet file was entered, write the ControlNet pvl to the file if (ui.WasEntered("ONET")) { WriteCnet(ui.GetFileName("ONET"), bmf, lhCamera->target()->name(), serialLeft, serialRight); } // Create output data PvlGroup totalPointsPvl("Totals"); totalPointsPvl += PvlKeyword("AttemptedPoints", toString(numAttemptedInitialPoints)); totalPointsPvl += PvlKeyword("InitialSuccesses", toString(numOrigPoints)); totalPointsPvl += PvlKeyword("GrowSuccesses", toString(passpix2)); totalPointsPvl += PvlKeyword("ResultingPoints", toString(bmf.size())); Application::Log(totalPointsPvl); Pvl arPvl = matcher.RegistrationStatistics(); PvlGroup smtkresultsPvl("SmtkResults"); smtkresultsPvl += PvlKeyword("SpiceOffImage", toString(matcher.OffImageErrorCount())); smtkresultsPvl += PvlKeyword("SpiceDistanceError", toString(matcher.SpiceErrorCount())); arPvl.addGroup(smtkresultsPvl); for(int i = 0; i < arPvl.groups(); i++) { Application::Log(arPvl.group(i)); } // add the auto registration information to print.prt PvlGroup autoRegTemplate = matcher.RegTemplate(); Application::Log(autoRegTemplate); // Don't need the cubes opened anymore lhImage.close(); rhImage.close(); }