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() { // 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() { UserInterface &ui = Application::GetUserInterface(); Cube cube; cube.open(ui.GetFileName("FROM"), "rw"); // Make sure cube has been run through spiceinit try { cube.camera(); } catch(IException &e) { string msg = "Spiceinit must be run before initializing the polygon"; throw IException(e, IException::User, msg, _FILEINFO_); } Progress prog; prog.SetMaximumSteps(1); prog.CheckStatus(); QString sn = SerialNumber::Compose(cube); ImagePolygon poly; if(ui.WasEntered("MAXEMISSION")) { poly.Emission(ui.GetDouble("MAXEMISSION")); } if(ui.WasEntered("MAXINCIDENCE")) { poly.Incidence(ui.GetDouble("MAXINCIDENCE")); } if(ui.GetString("LIMBTEST") == "ELLIPSOID") { poly.EllipsoidLimb(true); } int sinc = 1; int linc = 1; IString incType = ui.GetString("INCTYPE"); if(incType.UpCase() == "VERTICES") { poly.initCube(cube); sinc = linc = (int)(0.5 + (((poly.validSampleDim() * 2) + (poly.validLineDim() * 2) - 3.0) / ui.GetInteger("NUMVERTICES"))); if (sinc < 1.0 || linc < 1.0) sinc = linc = 1.0; } else if (incType.UpCase() == "LINCSINC"){ sinc = ui.GetInteger("SINC"); linc = ui.GetInteger("LINC"); } else { string msg = "Invalid INCTYPE option[" + incType + "]"; throw IException(IException::Programmer, msg, _FILEINFO_); } bool precision = ui.GetBoolean("INCREASEPRECISION"); try { poly.Create(cube, sinc, linc, 1, 1, 0, 0, 1, precision); } catch (IException &e) { QString msg = "Cannot generate polygon for [" + ui.GetFileName("FROM") + "]"; throw IException(e, IException::User, msg, _FILEINFO_); } if(ui.GetBoolean("TESTXY")) { Pvl cubeLab(ui.GetFileName("FROM")); PvlGroup inst = cubeLab.findGroup("Instrument", Pvl::Traverse); QString target = inst["TargetName"]; PvlGroup radii = Projection::TargetRadii(target); Pvl map(ui.GetFileName("MAP")); PvlGroup &mapping = map.findGroup("MAPPING"); if(!mapping.hasKeyword("TargetName")) mapping += Isis::PvlKeyword("TargetName", target); if(!mapping.hasKeyword("EquatorialRadius")) mapping += Isis::PvlKeyword("EquatorialRadius", (QString)radii["EquatorialRadius"]); if(!mapping.hasKeyword("PolarRadius")) mapping += Isis::PvlKeyword("PolarRadius", (QString)radii["PolarRadius"]); if(!mapping.hasKeyword("LatitudeType")) mapping += Isis::PvlKeyword("LatitudeType", "Planetocentric"); if(!mapping.hasKeyword("LongitudeDirection")) mapping += Isis::PvlKeyword("LongitudeDirection", "PositiveEast"); if(!mapping.hasKeyword("LongitudeDomain")) mapping += Isis::PvlKeyword("LongitudeDomain", "360"); if(!mapping.hasKeyword("CenterLatitude")) mapping += Isis::PvlKeyword("CenterLatitude", "0"); if(!mapping.hasKeyword("CenterLongitude")) mapping += Isis::PvlKeyword("CenterLongitude", "0"); sinc = poly.getSinc(); linc = poly.getLinc(); bool polygonGenerated = false; while (!polygonGenerated) { Projection *proj = NULL; geos::geom::MultiPolygon *xyPoly = NULL; try { proj = ProjectionFactory::Create(map, true); xyPoly = PolygonTools::LatLonToXY(*poly.Polys(), proj); polygonGenerated = true; } catch (IException &e) { if (precision && sinc > 1 && linc > 1) { sinc = sinc * 2 / 3; linc = linc * 2 / 3; poly.Create(cube, sinc, linc); } else { delete proj; delete xyPoly; e.print(); // This should be a NAIF error QString msg = "Cannot calculate XY for ["; msg += ui.GetFileName("FROM") + "]"; throw IException(e, IException::User, msg, _FILEINFO_); } } delete proj; delete xyPoly; } } cube.deleteBlob("Polygon", sn); cube.write(poly); if(precision) { PvlGroup results("Results"); results.addKeyword(PvlKeyword("SINC", toString(sinc))); results.addKeyword(PvlKeyword("LINC", toString(linc))); Application::Log(results); } Process p; p.SetInputCube("FROM"); p.WriteHistory(cube); cube.close(); prog.CheckStatus(); }
void IsisMain() { //get the number of samples to skip from the left and right ends // of the prefix and suffix data UserInterface &ui = Application::GetUserInterface(); int imageLeft = 0; int imageRight = 0; int rampLeft = 0; int rampRight = 0; int calLeftBuffer = 0; int calRightBuffer = 0; int calLeftDark = 0; int calRightDark = 0; int leftBuffer = 0; int rightBuffer = 0; int leftDark = 0; int rightDark = 0; if(ui.GetBoolean("USEOFFSETS")) { imageLeft = ui.GetInteger("LEFTIMAGE"); imageRight = ui.GetInteger("RIGHTIMAGE"); rampLeft = ui.GetInteger("LEFTIMAGE"); rampRight = ui.GetInteger("RIGHTIMAGE"); calLeftBuffer = ui.GetInteger("LEFTCALBUFFER"); calRightBuffer = ui.GetInteger("LEFTCALBUFFER"); calLeftDark = ui.GetInteger("LEFTCALDARK"); calRightDark = ui.GetInteger("RIGHTCALDARK"); leftBuffer = ui.GetInteger("LEFTBUFFER"); rightBuffer = ui.GetInteger("RIGHTBUFFER"); leftDark = ui.GetInteger("LEFTDARK"); rightDark = ui.GetInteger("RIGHTDARK"); } Isis::FileName fromFile = ui.GetFileName("FROM"); Isis::Cube inputCube; inputCube.open(fromFile.expanded()); //Check to make sure we got the cube properly if(!inputCube.isOpen()) { QString msg = "Could not open FROM cube " + fromFile.expanded(); throw IException(IException::User, msg, _FILEINFO_); } Process p; Cube *icube = p.SetInputCube("FROM"); // Get statistics from the cube prefix and suffix data Table hifix("HiRISE Ancillary"); icube->read(hifix); Statistics darkStats, bufStats, rampDarkStats; int tdi = icube->group("Instrument")["Tdi"]; int binning_mode = icube->group("Instrument")["Summing"]; //This gets us the statistics for the dark and buffer pixels // alongside of the image itself for(int rec = 2; rec < hifix.Records(); rec++) { vector<int> dark = hifix[rec]["DarkPixels"]; vector<int> buf = hifix[rec]["BufferPixels"]; if(buf.size() <= (unsigned int)(leftBuffer + rightBuffer)) { ThrowException(buf.size(), leftBuffer, rightBuffer, "image buffer"); } if(dark.size() <= (unsigned int)(leftDark + rightDark)) { ThrowException(dark.size(), leftDark, rightDark, "image dark reference"); } for(int i = leftDark; i < (int)dark.size() - rightDark; i++) { double d; if(dark[i] == NULL2) d = NULL8; else if(dark[i] == LOW_REPR_SAT2) d = LOW_REPR_SAT8; else if(dark[i] == LOW_INSTR_SAT2) d = LOW_INSTR_SAT8; else if(dark[i] == HIGH_INSTR_SAT2) d = HIGH_INSTR_SAT8; else if(dark[i] == HIGH_REPR_SAT2) d = HIGH_REPR_SAT8; else d = dark[i]; darkStats.AddData(&d, 1); } for(int i = leftBuffer; i < (int)buf.size() - rightBuffer; i++) { double d; if(buf[i] == NULL2) d = NULL8; else if(buf[i] == LOW_REPR_SAT2) d = LOW_REPR_SAT8; else if(buf[i] == LOW_INSTR_SAT2) d = LOW_INSTR_SAT8; else if(buf[i] == HIGH_INSTR_SAT2) d = HIGH_INSTR_SAT8; else if(buf[i] == HIGH_REPR_SAT2) d = HIGH_REPR_SAT8; else d = buf[i]; bufStats.AddData(&d, 1); } } // Get statistics from the calibration image //Calculate boundaries of the reverse readout lines, // Masked lines, and ramp lines. //There are always 20 reverse readout lines int reverseReadoutLines = 20; //Number of mask pixels depends on Binning mode int maskLines; maskLines = 20 / binning_mode; //mask lines go after reverse lines maskLines += reverseReadoutLines; // Actual starting line, number Ramp lines int rampStart = maskLines; int rampLines = tdi / binning_mode; Table calimg("HiRISE Calibration Image"); icube->read(calimg); Statistics calStats; //Statistics for the Reverse readout lines of the cal image Statistics reverseStats; //Statistics for the masked lines of the cal image Statistics maskStats; //Statistics for the ramped lines of the cal image Statistics rampStats; //Iterate through the calibration image //Add in reverse data for(int rec = 2 ; rec <= 18 ; rec++) { //Lines [2,18] vector<int> lineBuffer = calimg[rec]["Calibration"]; for(unsigned int i = 2 ; i < lineBuffer.size() - 1 ; i++) { //Samples [2, * -1] double d = lineBuffer[i]; if(lineBuffer[i] == NULL2) { d = NULL8; } else if(lineBuffer[i] == LOW_REPR_SAT2) { d = LOW_REPR_SAT8; } else if(lineBuffer[i] == LOW_INSTR_SAT2) { d = LOW_INSTR_SAT8; } else if(lineBuffer[i] == HIGH_INSTR_SAT2) { d = HIGH_INSTR_SAT8; } else if(lineBuffer[i] == HIGH_REPR_SAT2) { d = HIGH_REPR_SAT8; } reverseStats.AddData(&d, 1); } } //Add in the mask data for(int rec = 22 ; rec < maskLines - 1 ; rec++) {//Lines [22, 38] !!!!dependant on bin vector<int> lineBuffer = calimg[rec]["Calibration"]; for(int i = 2 ; i < (int)lineBuffer.size() - 1 ; i++) { //Samples [2, *-1] double d = lineBuffer[i]; if(d == NULL2) { d = NULL8; } else if(d == LOW_REPR_SAT2) { d = LOW_REPR_SAT8; } else if(d == LOW_INSTR_SAT2) { d = LOW_INSTR_SAT8; } else if(d == HIGH_INSTR_SAT2) { d = HIGH_INSTR_SAT8; } else if(d == HIGH_REPR_SAT2) { d = HIGH_REPR_SAT8; } maskStats.AddData(&d, 1); } } //Add in the ramp data for(int rec = maskLines + 2; rec < calimg.Records() - 1; rec++) { vector<int> buf = calimg[rec]["Calibration"]; //loop through all but the first and last sample of the calibration image for(int i = rampLeft; i < (int)buf.size() - rampRight; i++) { double d; if(buf[i] == NULL2) d = NULL8; else if(buf[i] == LOW_REPR_SAT2) d = LOW_REPR_SAT8; else if(buf[i] == LOW_INSTR_SAT2) d = LOW_INSTR_SAT8; else if(buf[i] == HIGH_INSTR_SAT2) d = HIGH_INSTR_SAT8; else if(buf[i] == HIGH_REPR_SAT2) d = HIGH_REPR_SAT8; else d = buf[i]; //Determine which group of stats to add to rampStats.AddData(&d, 1); } } // Get statistics from the calibration prefix and suffix data Table calfix("HiRISE Calibration Ancillary"); icube->read(calfix); Statistics calDarkStats, calBufStats; int rampLine0 = rampStart + 1; int rampLineN = (rampStart + rampLines - 1) - 1; rampLineN = calfix.Records() - 1; for(int rec = 0; rec < calfix.Records(); rec++) { vector<int> dark = calfix[rec]["DarkPixels"]; vector<int> buf = calfix[rec]["BufferPixels"]; if(buf.size() <= (unsigned int)(calLeftBuffer + calRightBuffer)) { ThrowException(buf.size(), calLeftBuffer, calRightBuffer, "calibration buffer"); } if(dark.size() <= (unsigned int)(calLeftDark + calRightDark)) { ThrowException(dark.size(), calLeftDark, calRightDark, "calibration dark reference"); } for(int i = calLeftDark; i < (int)dark.size() - calRightDark; i++) { double d; if(dark[i] == NULL2) d = NULL8; else if(dark[i] == LOW_REPR_SAT2) d = LOW_REPR_SAT8; else if(dark[i] == LOW_INSTR_SAT2) d = LOW_INSTR_SAT8; else if(dark[i] == HIGH_INSTR_SAT2) d = HIGH_INSTR_SAT8; else if(dark[i] == HIGH_REPR_SAT2) d = HIGH_REPR_SAT8; else d = dark[i]; calDarkStats.AddData(&d, 1); if((rec > rampLine0) && (rec < rampLineN)) { rampDarkStats.AddData(&d, 1); } } for(int i = calLeftBuffer; i < (int)buf.size() - calRightBuffer; i++) { double d; if(buf[i] == NULL2) d = NULL8; else if(buf[i] == LOW_REPR_SAT2) d = LOW_REPR_SAT8; else if(buf[i] == LOW_INSTR_SAT2) d = LOW_INSTR_SAT8; else if(buf[i] == HIGH_INSTR_SAT2) d = HIGH_INSTR_SAT8; else if(buf[i] == HIGH_REPR_SAT2) d = HIGH_REPR_SAT8; else d = buf[i]; calBufStats.AddData(&d, 1); } } Statistics linesPostrampStats; Statistics imageStats; Isis::LineManager imageBuffer(inputCube); imageBuffer.begin(); Buffer out(imageBuffer.SampleDimension() - (imageLeft + imageRight), imageBuffer.LineDimension(), imageBuffer.BandDimension(), imageBuffer.PixelType()); for(int postRampLine = 0 ; postRampLine < LINES_POSTRAMP ; postRampLine++) { inputCube.read(imageBuffer); for(int postRampSamp = 0 ; postRampSamp < out.SampleDimension() ; postRampSamp++) { out[postRampSamp] = imageBuffer[postRampSamp + imageLeft]; } linesPostrampStats.AddData(out.DoubleBuffer(), out.size()); imageBuffer++; } for(int imageLine = LINES_POSTRAMP; imageLine < inputCube.lineCount(); imageLine++) { inputCube.read(imageBuffer); for(int imageSample = 0 ; imageSample < out.SampleDimension(); imageSample++) { out[imageSample] = imageBuffer[imageSample + imageLeft]; } imageStats.AddData(out.DoubleBuffer(), out.size()); imageBuffer++; } // Generate the statistics in pvl form const int NUM_GROUPS = 10; PvlGroup groups[NUM_GROUPS]; groups[0] = PvlStats(linesPostrampStats, "IMAGE_POSTRAMP"); groups[1] = PvlStats(imageStats, "IMAGE"); groups[2] = PvlStats(darkStats, "IMAGE_DARK"); groups[3] = PvlStats(bufStats, "IMAGE_BUFFER"); groups[4] = PvlStats(reverseStats, "CAL_REVERSE"); groups[5] = PvlStats(maskStats, "CAL_MASK"); groups[6] = PvlStats(rampStats, "CAL_RAMP"); groups[7] = PvlStats(calDarkStats, "CAL_DARK"); groups[8] = PvlStats(rampDarkStats, "CAL_DARK_RAMP"); groups[9] = PvlStats(calBufStats, "CAL_BUFFER"); // Write the results to the output file if the user specified one if(ui.WasEntered("TO")) { Pvl temp; for(int i = 0 ; i < NUM_GROUPS ; i++) { temp.addGroup(groups[i]); } temp.write(ui.GetFileName("TO")); } else { // Log the results for(int i = 0 ; i < NUM_GROUPS ; i++) { Application::Log(groups[i]); } } }
void IsisMain() { Process p; Cube *icube = p.SetInputCube("FROM"); Camera *cam = icube->camera(); UserInterface &ui = Application::GetUserInterface(); QString from = ui.GetFileName("FROM"); int sinc = ui.GetInteger("SINC"); int linc = ui.GetInteger("LINC"); CameraStatistics camStats(cam, sinc, linc, from); // Send the Output to the log area Pvl statsPvl = camStats.toPvl(); for (int i = 0; i < statsPvl.groups(); i++) { Application::Log(statsPvl.group(i)); } if(ui.WasEntered("TO")) { QString outfile = FileName(ui.GetFileName("TO")).expanded(); bool exists = FileName(outfile).fileExists(); bool append = ui.GetBoolean("APPEND"); // If the user chose a format of PVL, then write to the output file ("TO") if(ui.GetString("FORMAT") == "PVL") { (append) ? statsPvl.append(outfile) : statsPvl.write(outfile); } else { // Create a flatfile of the data with columhn headings the flatfile is // comma-delimited and can be imported in to spreadsheets ofstream os; bool writeHeader = true; if(append) { os.open(outfile.toAscii().data(), ios::app); if(exists) { writeHeader = false; } } else { os.open(outfile.toAscii().data(), ios::out); } // if new file or append and no file exists then write header if(writeHeader) { os << "Filename," << "LatitudeMinimum," << "LatitudeMaximum," << "LatitudeAverage," << "LatitudeStandardDeviation," << "LongitudeMinimum," << "LongitudeMaximum," << "LongitudeAverage," << "LongitudeStandardDeviation," << "SampleResolutionMinimum," << "SampleResolutionMaximum," << "SampleResolutionAverage," << "SampleResolutionStandardDeviation," << "LineResolutionMinimum," << "LineResolutionMaximum," << "LineResolutionAverage," << "LineResolutionStandardDeviation," << "ResolutionMinimum," << "ResolutionMaximum," << "ResolutionAverage," << "ResolutionStandardDeviation," << "AspectRatioMinimum," << "AspectRatioMaximum," << "AspectRatioAverage," << "AspectRatioStandardDeviation," << "PhaseMinimum," << "PhaseMaximum," << "PhaseAverage," << "PhaseStandardDeviation," << "EmissionMinimum," << "EmissionMaximum," << "EmissionAverage," << "EmissionStandardDeviation," << "IncidenceMinimum," << "IncidenceMaximum," << "IncidenceAverage," << "IncidenceStandardDeviation," << "LocalSolarTimeMinimum," << "LocalSolarTimeMaximum," << "LocalSolarTimeAverage," << "LocalSolarTimeStandardDeviation," << "LocalRadiusMaximum," << "LocalRadiusMaximum," << "LocalRadiusAverage," << "LocalRadiusStandardDeviation," << "NorthAzimuthMinimum," << "NorthAzimuthMaximum," << "NorthAzimuthAverage," << "NorthAzimuthStandardDeviation," << endl; } os << FileName(from).expanded() << ","; //call the function to write out the values for each group writeFlat(os, camStats.getLatStat()); writeFlat(os, camStats.getLonStat()); writeFlat(os, camStats.getSampleResStat()); writeFlat(os, camStats.getLineResStat()); writeFlat(os, camStats.getResStat()); writeFlat(os, camStats.getAspectRatioStat()); writeFlat(os, camStats.getPhaseStat()); writeFlat(os, camStats.getEmissionStat()); writeFlat(os, camStats.getIncidenceStat()); writeFlat(os, camStats.getLocalSolarTimeStat()); writeFlat(os, camStats.getLocalRaduisStat()); writeFlat(os, camStats.getNorthAzimuthStat()); os << endl; } } if(ui.GetBoolean("ATTACH")) { QString cam_name = "CameraStatistics"; //Creates new CameraStatistics Table TableField fname("Name", Isis::TableField::Text, 20); TableField fmin("Minimum", Isis::TableField::Double); TableField fmax("Maximum", Isis::TableField::Double); TableField favg("Average", Isis::TableField::Double); TableField fstd("StandardDeviation", Isis::TableField::Double); TableRecord record; record += fname; record += fmin; record += fmax; record += favg; record += fstd; Table table(cam_name, record); // Place all the gathered camera statistics in a table and attach it to the // cube. Skip "User Parameters" group. for (int i = 1; i < statsPvl.groups(); i++) { PvlGroup &group = statsPvl.group(i); int entry = 0; record[entry] = group.name(); entry++; for (int j = 0; j < group.keywords(); j++) { record[entry] = toDouble(group[j][0]); entry++; } table += record; } icube->reopen("rw"); icube->write(table); p.WriteHistory(*icube); icube->close(); } }
void IsisMain() { // Use a regular Process Process p; // Get user parameters and error check UserInterface &ui = Application::GetUserInterface(); QString from = ui.GetFileName("FROM"); QString to = FileName(ui.GetFileName("TO")).expanded(); //TO DO: UNCOMMENT THIS LINE ONCE HRSC IS WORKING IN SS // double HRSCNadirCenterTime = ui.GetDouble("HRSC_NADIRCENTERTIME"); // Open input cube and Make sure this is a lev1 image (ie, not map projected) Cube cube; cube.open(from); if (cube.isProjected()) { QString msg = "Input images is a map projected cube ... not a level 1 image"; throw IException(IException::User, msg, _FILEINFO_); } // Initialize the camera Cube *input = p.SetInputCube("FROM"); Pvl *cubeHeader = input->label(); Camera *cam = input->camera(); CameraDetectorMap *detectorMap = cam->DetectorMap(); CameraFocalPlaneMap *focalMap = cam->FocalPlaneMap(); CameraDistortionMap *distortionMap = cam->DistortionMap(); CameraGroundMap *groundMap = cam->GroundMap(); // Make sure the image contains the InstrumentPointing (aka CK) blob/table PvlGroup test = cube.label()->findGroup("Kernels", Pvl::Traverse); QString InstrumentPointing = (QString) test["InstrumentPointing"]; if (InstrumentPointing != "Table") { QString msg = "Input image does not contain needed SPICE blobs...run spiceinit with attach=yes."; throw IException(IException::User, msg, _FILEINFO_); } // Open output line scanner keyword file ofstream toStrm; toStrm.open(to.toAscii().data(), ios::trunc); if (toStrm.bad()) { QString msg = "Unable to open output TO file"; throw IException(IException::User, msg, _FILEINFO_); } // Get required keywords from instrument and band groups PvlGroup inst = cube.label()->findGroup("Instrument", Pvl::Traverse); QString instrumentId = (QString) inst["InstrumentId"]; bool isMocNA = false; //TO DO: UNCOMMENT THIS LINES ONCE MOC IS WORKING IN SS // bool isMocWARed = false; bool isHiRise = false; bool isCTX = false; bool isLroNACL = false; bool isLroNACR = false; bool isHRSC = false; //TO DO: UNCOMMENT THESE LINE ONCE MOC IS WORKING IN SS // if (instrumentId == "MOC") { // PvlGroup band = cube.label()->findGroup("BandBin", Pvl::Traverse); // QString filter = (QString) band["FilterName"]; // // if (strcmp(filter.toAscii().data(), "BROAD_BAND") == 0) // isMocNA = true; // else if (strcmp(filter.toAscii().data(), "RED") == 0) // isMocWARed = true; // else if (strcmp(filter.toAscii().data(), "BLUE") == 0) { // QString msg = "MOC WA Blue filter images not supported for Socet Set mapping"; // throw IException(IException::User, msg, _FILEINFO_); // } // } // else if (instrumentId == "IdealCamera") { //TO DO: DELETE THIS LINE ONCE MOC IS WORKING IN SS if (instrumentId == "IdealCamera") { PvlGroup orig = cube.label()->findGroup("OriginalInstrument", Pvl::Traverse); QString origInstrumentId = (QString) orig["InstrumentId"]; if (origInstrumentId == "HIRISE") { isHiRise = true; } else { QString msg = "Unsupported instrument: " + origInstrumentId; throw IException(IException::User, msg, _FILEINFO_); } } else if (instrumentId == "HIRISE") { isHiRise = true; } else if (instrumentId == "CTX") { isCTX = true; } else if (instrumentId == "NACL") { isLroNACL = true; } else if (instrumentId == "NACR") { isLroNACR = true; } //TO DO: UNCOMMENT THIS LINE ONCE HRSC IS WORKING IN SS // else if (instrumentId == "HRSC") isHRSC = true; else { QString msg = "Unsupported instrument: " + instrumentId; throw IException(IException::User, msg, _FILEINFO_); } int ikCode = cam->naifIkCode(); // Get Focal Length. // NOTE: // For MOC Wide Angle, cam->focal_length returns the focal length // in pixels, so we must convert from pixels to mm using the PIXEL_SIZE // of 0.007 mm gotten from $ISIS3DATA/mgs/kernels/ik/moc20.ti. (The // PIXEL_PITCH value gotten from cam->PixelPitch is 1.0 since the // focal length used by ISIS in this case is in pixels) // For reference: the MOC WA blue filter pixel size needs an adjustment // of 1.000452 (see p_scale in MocWideAngleDistortionMap.cpp), so that // the final blue filter pixel size = (0.007 / 1.000452) // // For all other cameras, cam->focal_length returns the focal // length in mm, as needed by Socet Set double focal = cam->FocalLength(); // focal length returned in mm //TO DO: UNCOMMENT THESE LINES ONCE HRSC and MOC IS WORKING IN SS // if (isMocWARed) // focal = focal * 0.007; // pixel to mm conversion // else if (isHRSC) // { // switch (ikCode) { // case -41219: //S1: fwd stereo // focal = 184.88; // break; // case -41218: //IR: infra-red // focal = 181.57; // break; // case -41217: //P1: fwd photo // focal = 179.16; // break; // case -41216: // GREEN // focal = 175.31; // break; // case -41215: // NADIR // focal = 175.01; // break; // case -41214: // BLUE // focal = 175.53; // break; // case -41213: // P2: aft photo // focal = 179.19; // break; // case -41212: // RED // focal = 181.77; // break; // case -41211: // S2: aft stereo // focal = 184.88; // break; // default: // break; // } // } // Get instrument summing modes int csum = (int) detectorMap->SampleScaleFactor(); int dsum = (int) detectorMap->LineScaleFactor(); if (isLroNACL || isLroNACR || isHRSC) dsum = csum; // Calculate location of boresight in image space, these are zero-based values // // Note: For MOC NA, the boresight is at the image center // For MOC WA, MRO HiRISE, MRO CTX, LRO_NACL, LRO_NACR and HRSC the // boresight is not at the detector center, but the boresight is at the // center of a NOPROJ'ED MRO HIRISE image // Get line/samp of boresight pixel in detector space (summing == 1) focalMap->SetFocalPlane(0.0, 0.0); double detectorBoresightSample = focalMap->DetectorSample(); double detectorBoresightLine = focalMap->DetectorLine(); // Convert sample of boresight pixel in detector into image space // (summing, etc., is accounted for.) detectorMap->SetDetector(detectorBoresightSample, detectorBoresightLine); double boresightSample = detectorMap->ParentSample(); // Set Atmospheric correction coefficients to 0 double atmco[4] = {0.0, 0.0, 0.0, 0.0}; // Get totalLines, totalSamples and account for summed images int totalLines = cube.lineCount(); int totalSamples = cube.sampleCount(); // Get the Interval Time in seconds and calculate // scan duration in seconds double scanDuration = 0.0; double intTime = 0.0; //TO DO: UNCOMMENT THESE LINES ONCE HRSC IS WORKING IN SS // int numIntTimes = 0.0; // vector<LineRateChange> lineRates; // if (isHRSC) { // numIntTimes = GetHRSCLineRates(&cube, lineRates, totalLines, HRSCNadirCenterTime); // if (numIntTimes == 1) { // LineRateChange lrc = lineRates.at(0); // intTime = lrc.GetLineScanRate(); // } // if (numIntTimes <= 0) { // QString msg = "HRSC: Invalid number of scan times"; // throw IException(IException::Programmer, msg, _FILEINFO_); // } // else // scanDuration = GetHRSCScanDuration(lineRates, totalLines); // } // else { // // TO DO: indent the following two lines when HRSC is working in SS intTime = detectorMap->LineRate(); //LineRate is in seconds scanDuration = intTime * totalLines; //TO DO: UNCOMMENT THIS LINE ONCE HRSC IS WORKING IN SS // } // For reference, this is the code if calculating interval time // via LineExposureDuration keyword off image labels: // // if (isMocNA || isMocWARed) // intTime = exposureDuration * (double) dsum / 1000.0; // else if (isHiRise) // intTime = exposureDuration * (double) dsum / 1000000.0; // Get along and cross scan pixel size for NA and WA sensors. // NOTE: // 1) The MOC WA pixel size is gotten from moc20.ti and is 7 microns // HRSC pixel size is from the Instrument Addendum file // 2) For others, cam->PixelPitch() returns the pixel pitch (size) in mm. double alongScanPxSize = 0.0; double crossScanPxSize = 0.0; //TO DO: UNCOMMENT THESE LINES ONCE MOC IS WORKING IN SS // if (isMocWARed || isHRSC) { // alongScanPxSize = csum * 0.007; // crossScanPxSize = dsum * 0.007; // } // else { // // TO DO: indent the following 24 lines when HRSC is working in SS crossScanPxSize = dsum * cam->PixelPitch(); // Get the ephemeris time, ground position and undistorted focal plane X // coordinate at the center line/samp of image cam->SetImage(cube.sampleCount() / 2.0, cube.lineCount() / 2.0); double tMid = cam->time().Et(); const double latCenter = cam->UniversalLatitude(); const double lonCenter = cam->UniversalLongitude(); const double radiusCenter = cam->LocalRadius().meters(); double uXCenter = distortionMap->UndistortedFocalPlaneX(); // from the ground position at the image center, increment the ephemeris // time by the line rate and map the ground position into the sensor in // undistorted focal plane coordinates cam->setTime(iTime(tMid + intTime)); double uX, uY; groundMap->GetXY(latCenter, lonCenter, radiusCenter, &uX, &uY); // the along scan pixel size is the difference in focal plane X coordinates alongScanPxSize = abs(uXCenter - uX); //TO DO: UNCOMMENT THIS LINE ONCE MOC and HRSC IS WORKING IN SS // } // Now that we have totalLines, totalSamples, alongScanPxSize and // crossScanPxSize, fill the Interior Orientation Coefficient arrays double ioCoefLine[10]; double ioCoefSample[10]; for (int i = 0; i <= 9; i++) { ioCoefLine[i] = 0.0; ioCoefSample[i] = 0.0; } ioCoefLine[0] = totalLines / 2.0; ioCoefLine[1] = 1.0 / alongScanPxSize; ioCoefSample[0] = totalSamples / 2.0; ioCoefSample[2] = 1.0 / crossScanPxSize; // Update the Rectification Terms found in the base sensor class double rectificationTerms[6]; rectificationTerms[0] = totalLines / 2.0; rectificationTerms[1] = 0.0; rectificationTerms[2] = 1.0; rectificationTerms[3] = totalSamples / 2.0; rectificationTerms[4] = 1.0; rectificationTerms[5] = 0.0; // Fill the triangulation parameters array double triParams[18]; for (int i = 0; i <= 17; i++) triParams[i] = 0.0; triParams[15] = focal; // Set the Center Ground Point at the SOCET Set image, in radians double centerGp[3]; double radii[3] = {0.0, 0.0, 0.0}; Distance Dradii[3]; cam->radii(Dradii); radii[0] = Dradii[0].kilometers(); radii[1] = Dradii[1].kilometers(); radii[2] = Dradii[2].kilometers(); cam->SetImage(boresightSample, totalLines / 2.0); centerGp[0] = DEG2RAD * TProjection::ToPlanetographic(cam->UniversalLatitude(), radii[0], radii[2]); centerGp[1] = DEG2RAD * TProjection::To180Domain(cam->UniversalLongitude()); centerGp[2] = 0.0; //**** NOTE: in the import_pushbroom SOCET SET program, centerGp[2] will be set to the SS //**** project's gp_origin_z // Now get keyword values that depend on ephemeris data. // First get the ephemeris time and camera Lat Lon at image center line, boresight sample. double centerLine = double(totalLines) / 2.0; cam->SetImage(boresightSample, centerLine); //set to boresight of image double etCenter = cam->time().Et(); // Get the sensor position at the image center in ographic lat, // +E lon domain 180 coordinates, radians, height in meters double sensorPosition[3] = {0.0, 0.0, 0.0}; double ocentricLat, e360Lon; cam->subSpacecraftPoint(ocentricLat, e360Lon); sensorPosition[0] = DEG2RAD * TProjection::ToPlanetographic(ocentricLat, radii[0], radii[2]); sensorPosition[1] = DEG2RAD * TProjection::To180Domain(e360Lon); sensorPosition[2] = cam->SpacecraftAltitude() * 1000.0; // Build the ephem data. If the image label contains the InstrumentPosition // table, use it as a guide for number and spacing of Ephem points. // Otherwise (i.e, for dejittered HiRISE images), the number and spacing of // ephem points based on hardcoded dtEphem value // Using the InstrumentPosition table as a guide build the ephem data QList< QList<double> > ephemPts; QList< QList<double> > ephemRates; PvlGroup kernels = cube.label()->findGroup("Kernels", Pvl::Traverse); QString InstrumentPosition = (QString) kernels["InstrumentPosition"]; int numEphem = 0; // number of ephemeris points double dtEphem = 0.0; // delta time of ephemeris points, seconds if (InstrumentPosition == "Table") { // Labels contain SPK blob // set up Ephem pts/rates number and spacing Table tablePosition("InstrumentPosition", cubeHeader->fileName()); numEphem = tablePosition.Records(); // increase the number of ephem nodes by 20%. This is somewhat random but // generally intended to compensate for having equally time spaced nodes // instead of of the potentially more efficient placement used by spiceinit numEphem = int(double(numEphem) * 1.2); // if numEphem calcutated from SPICE blobs is too sparse for SOCET Set, // mulitiply it by a factor of 30 // (30X was settled upon emperically. In the future, make this an input parameter) if (numEphem <= 10) numEphem = tablePosition.Records() * 30; // make the number of nodes odd numEphem = (numEphem % 2) == 1 ? numEphem : numEphem + 1; // SOCET has a max number of ephem pts of 10000, and we're going to add twenty... if (numEphem > 10000 - 20) numEphem = 9979; dtEphem = scanDuration / double(numEphem); //build the tables of values double et = etCenter - (((numEphem - 1) / 2) * dtEphem); for (int i = 0; i < numEphem; i++) { cam->setTime(iTime(et)); SpiceRotation *bodyRot = cam->bodyRotation(); vector<double> pos = bodyRot->ReferenceVector(cam->instrumentPosition()->Coordinate()); //TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS //vector<double> vel = bodyRot->ReferenceVector(cam->instrumentPosition()->Velocity()); //Add the ephemeris position and velocity to their respective lists, in meters and meters/sec QList<double> ephemPt; QList<double> ephemRate; ephemPts.append(ephemPt << pos[0] * 1000 << pos[1] * 1000 << pos[2] * 1000); //TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS //ephemRates.append(ephemRate << vel[0] * 1000 << vel[1] * 1000 << vel[2] * 1000); et += dtEphem; } //TO DO: WHEN VELOCITY BLOBS ARE CORRECT IN ISIS, linearlly interpolate 10 nodes rather than 11 // (need 11 now for computation of velocity at first and last ephemeris point) // linearlly interpolate 11 additional nodes before line 1 (SOCET requires this) for (int i = 0; i < 11; i++) { double vec[3] = {0.0, 0.0, 0.0}; vec[0] = ephemPts[0][0] + (ephemPts[0][0] - ephemPts[1][0]); vec[1] = ephemPts[0][1] + (ephemPts[0][1] - ephemPts[1][1]); vec[2] = ephemPts[0][2] + (ephemPts[0][2] - ephemPts[1][2]); QList<double> ephemPt; ephemPts.prepend (ephemPt << vec[0] << vec[1] << vec[2]); //TO DO: UNCOMMENT THE FOLLOWING LINES WHEN VELOCITY BLOBS ARE CORRECT IN ISIS //vec[0] = ephemRates[0][0] + (ephemRates[0][0] - ephemRates[1][0]); //vec[1] = ephemRates[0][1] + (ephemRates[0][1] - ephemRates[1][1]); //vec[2] = ephemRates[0][2] + (ephemRates[0][2] - ephemRates[1][2]); //QList<double> ephemRate; //ephemRates.prepend (ephemRate << vec[0] << vec[1] << vec[2]); } //TO DO: WHEN VELOCITY BLOBS ARE CORRECT IN ISIS, linearlly interpolate 10 nodes rather than 11 // (need 11 now for computation of velocity at first and last ephemeris point) // linearlly interpolate 11 additional nodes after the last line (SOCET requires this) for (int i = 0; i < 11; i++) { double vec[3] = {0.0, 0.0, 0.0}; int index = ephemPts.size() - 1; vec[0] = ephemPts[index][0] + (ephemPts[index][0] - ephemPts[index - 1][0]); vec[1] = ephemPts[index][1] + (ephemPts[index][1] - ephemPts[index - 1][1]); vec[2] = ephemPts[index][2] + (ephemPts[index][2] - ephemPts[index - 1][2]); QList<double> ephemPt; ephemPts.append(ephemPt << vec[0] << vec[1] << vec[2]); //TO DO: UNCOMMENT THE FOLLOWING LINES WHEN VELOCITY BLOBS ARE CORRECT IN ISIS //vec[0] = ephemRates[index][0] + (ephemRates[index][0] - ephemRates[index - 1][0]); //vec[1] = ephemRates[index][1] + (ephemRates[index][1] - ephemRates[index - 1][1]); //vec[2] = ephemRates[index][2] + (ephemRates[index][2] - ephemRates[index - 1][2]); //QList<double> ephemRate; //ephemRates.append(ephemRate << vec[0] << vec[1] << vec[2]); } numEphem += 20; //TO DO: DELETE THE FOLLOWING LINES WHEN VELOCITY BLOBS ARE CORRECT IN ISIS // Compute the spacecraft velocity at each ephemeris point double deltaTime = 2.0 * dtEphem; for (int i = 0; i < numEphem; i++) { double vec[3] = {0.0, 0.0, 0.0}; vec[0] = (ephemPts[i+2][0] - ephemPts[i][0]) / deltaTime; vec[1] = (ephemPts[i+2][1] - ephemPts[i][1]) / deltaTime; vec[2] = (ephemPts[i+2][2] - ephemPts[i][2]) / deltaTime; QList<double> ephemRate; ephemRates.append(ephemRate << vec[0] << vec[1] << vec[2]); } } else { // Calculate the number of ephemeris points that are needed, based on the // value of dtEphem (Delta-Time-Ephemeris). SOCET SET needs the ephemeris // points to exceed the image range for interpolation. For now, attempt a // padding of 10 ephemeris points on either side of the image. if (isMocNA || isHiRise || isCTX || isLroNACL || isLroNACR || isHRSC) // Try increment of every 300 image lines dtEphem = 300 * intTime; // Make this a user definable increment? else // Set increment for WA images to one second dtEphem = 1.0; // Pad by 10 ephem pts on each side of the image numEphem = (int)(scanDuration / dtEphem) + 20; // if numEphem is even, make it odd so that the number of ephemeris points // is equal on either side of T_CENTER if ((numEphem % 2) == 0) numEphem++; //TO DO: DELETE THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS numEphem = numEphem + 2; // Add two for calcuation of velocity vectors... // Find the ephemeris time for the first ephemeris point, and from that, get // to_ephem needed by SOCET (to_ephem is relative to etCenter) double et = etCenter - (((numEphem - 1) / 2) * dtEphem); for (int i = 0; i < numEphem; i++) { cam->setTime(iTime(et)); SpiceRotation *bodyRot = cam->bodyRotation(); vector<double> pos = bodyRot->ReferenceVector(cam->instrumentPosition()->Coordinate()); //TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS //vector<double> vel = bodyRot->ReferenceVector(cam->instrumentPosition()->Velocity()); //Add the ephemeris position and velocity to their respective lists, in meters and meters/sec QList<double> ephemPt; QList<double> ephemRate; ephemPts.append(ephemPt << pos[0] * 1000 << pos[1] * 1000 << pos[2] * 1000); //TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS //ephemRates.append(ephemRate << vel[0] * 1000 << vel[1] * 1000 << vel[2] * 1000); et += dtEphem; } //TO DO: DELETE THE FOLLOWING LINES WHEN VELOCITY BLOBS ARE CORRECT IN ISIS // Compute the spacecraft velocity at each ephemeris point // (We must do this when blobs are not attached because the Spice Class // stores in memory the same data that would be in a blob...even when reading NAIF kernels) double deltaTime = 2.0 * dtEphem; numEphem = numEphem - 2; // set numEphem back to the number we need output for (int i = 0; i < numEphem; i++) { double vec[3] = {0.0, 0.0, 0.0}; vec[0] = (ephemPts[i+2][0] - ephemPts[i][0]) / deltaTime; vec[1] = (ephemPts[i+2][1] - ephemPts[i][1]) / deltaTime; vec[2] = (ephemPts[i+2][2] - ephemPts[i][2]) / deltaTime; QList<double> ephemRate; ephemRates.append(ephemRate << vec[0] << vec[1] << vec[2]); } } //update ephem stats double etFirstEphem = etCenter - (((numEphem - 1) / 2) * dtEphem); double t0Ephem = etFirstEphem - etCenter; // Using the intrumentPointing table as a guide build the quarternions // for simplicity sake we'll leave the mountingAngles as identity // and store the complete rotation from body fixed to camera in the // quarternions //set up quaternions number and spacing Table tablePointing("InstrumentPointing", cubeHeader->fileName()); //number of quaternions int numQuaternions = tablePointing.Records(); // increase the number of quaternions nodes by 20%. This is somewhat random but // generally intended to compensate for having equally time spaced nodes // instead of of the potentially more efficient placement used by spiceinit numQuaternions = (int)(numQuaternions * 1.2); // if numQuaternions calcutated from SPICE blobs is too sparse for SOCET Set, // mulitiply it by a factor of 30 // (30X was settled upon emperically. In the future, make this an input parameter) if (numQuaternions <= 10) numQuaternions = tablePointing.Records() * 30; //make the number of nodes odd numQuaternions = (numQuaternions % 2) == 1 ? numQuaternions : numQuaternions + 1; // SOCET has a max number of quaternions of 20000, and we're going to add twenty... if (numQuaternions > 20000 - 20) numQuaternions = 19179; double dtQuat = scanDuration / double(numQuaternions); // build the tables of values QList< QList<double> > quaternions; double et = etCenter - (((numQuaternions - 1) / 2) * dtQuat); for (int i = 0; i < numQuaternions; i++) { cam->setTime(iTime(et)); vector<double> j2000ToBodyFixedMatrixVector = cam->bodyRotation()->Matrix(); vector<double> j2000ToCameraMatrixVector = cam->instrumentRotation()->Matrix(); double quaternion[4] = {0.0, 0.0, 0.0, 0.0}; double j2000ToBodyFixedRotationMatrix[3][3], //rotation from J2000 to target (aka body, planet) j2000ToCameraRotationMatrix[3][3], //rotation from J2000 to spacecraft cameraToBodyFixedRotationMatrix[3][3]; //rotation from camera to target // reformat vectors to 3x3 rotation matricies for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { j2000ToBodyFixedRotationMatrix[j][k] = j2000ToBodyFixedMatrixVector[3 * j + k]; j2000ToCameraRotationMatrix[j][k] = j2000ToCameraMatrixVector[3 * j + k]; } } // get the quaternion mxmt_c(j2000ToBodyFixedRotationMatrix, j2000ToCameraRotationMatrix, cameraToBodyFixedRotationMatrix); m2q_c(cameraToBodyFixedRotationMatrix, quaternion); // add the quaternion to the list of quaternions QList<double> quat; quaternions.append(quat << quaternion[1] << quaternion[2] << quaternion[3] << quaternion[0]); //note also that the order is changed to match socet et += dtQuat; } // linearlly interpolate 10 additional nodes before the first quaternion (SOCET requires this) for (int i = 0; i < 10; i++) { double vec[4] = {0.0, 0.0, 0.0, 0.0}; vec[0] = quaternions[0][0] + (quaternions[0][0] - quaternions[1][0]); vec[1] = quaternions[0][1] + (quaternions[0][1] - quaternions[1][1]); vec[2] = quaternions[0][2] + (quaternions[0][2] - quaternions[1][2]); vec[3] = quaternions[0][3] + (quaternions[0][3] - quaternions[1][3]); QList<double> quat; quaternions.prepend (quat << vec[0] << vec[1] << vec[2] << vec[3]); } // linearlly interpolate 10 additional nodes after the last quaternion (SOCET requires this) for (int i = 0; i < 10; i++) { double vec[4] = {0.0, 0.0, 0.0, 0.0}; int index = quaternions.size() - 1; vec[0] = quaternions[index][0] + (quaternions[index][0] - quaternions[index - 1][0]); vec[1] = quaternions[index][1] + (quaternions[index][1] - quaternions[index - 1][1]); vec[2] = quaternions[index][2] + (quaternions[index][2] - quaternions[index - 1][2]); vec[3] = quaternions[index][3] + (quaternions[index][3] - quaternions[index - 1][3]); QList<double> quat; quaternions.append(quat << vec[0] << vec[1] << vec[2] << vec[3]); } //update quaternions stats numQuaternions += 20; //ephemeris time of the first quarternion double et0Quat = etCenter - (((numQuaternions - 1) / 2) * dtQuat); //quadrtic time of the first quarternion double qt0Quat = et0Quat - etCenter; //query remaing transformation parameters from Camera Classes //transformation to distortionless focal plane double zDirection = distortionMap->ZDirection(); //transformation from DistortionlessFocalPlane to FocalPlane vector<double> opticalDistCoefs = distortionMap->OpticalDistortionCoefficients(); // For instruments with less than 3 distortion coefficients, set the // unused ones to 0.0 opticalDistCoefs.resize(3, 0); //transformation from focal plane to detector const double *iTransS = focalMap->TransS(); const double *iTransL = focalMap->TransL(); double detectorSampleOrigin = focalMap->DetectorSampleOrigin(); double detectorLineOrigin = focalMap->DetectorLineOrigin(); //transformation from dectector to cube double startingSample = detectorMap->AdjustedStartingSample(); double startingLine = detectorMap->AdjustedStartingLine(); double sampleSumming = detectorMap->SampleScaleFactor(); double etStart = ((LineScanCameraDetectorMap *)detectorMap)->StartTime(); double lineOffset = focalMap->DetectorLineOffset(); // We are done with computing keyword values, so output the Line Scanner // Keyword file. // This is the SOCET SET base sensor class keywords portion of support file: toStrm.setf(ios::scientific); toStrm << "RECTIFICATION_TERMS" << endl; toStrm << " " << setprecision(14) << rectificationTerms[0] << " " << rectificationTerms[1] << " " << rectificationTerms[2] << endl; toStrm << " " << rectificationTerms[3] << " " << rectificationTerms[4] << " " << rectificationTerms[5] << endl; toStrm << "GROUND_ZERO "; toStrm << centerGp[0] << " " << centerGp[1] << " " << centerGp[2] << endl; toStrm << "LOAD_PT "; toStrm << centerGp[0] << " " << centerGp[1] << " " << centerGp[2] << endl; toStrm << "COORD_SYSTEM 1" << endl; toStrm << "IMAGE_MOTION 0" << endl; // This is the line scanner sensor model portion of support file: toStrm << "SENSOR_TYPE USGSAstroLineScanner" << endl; toStrm << "SENSOR_MODE UNKNOWN" << endl; toStrm << "FOCAL " << focal << endl; toStrm << "ATMCO"; for (int i = 0; i < 4; i++) toStrm << " " << atmco[i]; toStrm << endl; toStrm << "IOCOEF_LINE"; for (int i = 0; i < 10; i++) toStrm << " " << ioCoefLine[i]; toStrm << endl; toStrm << "IOCOEF_SAMPLE"; for (int i = 0; i < 10; i++) toStrm << " " << ioCoefSample[i]; toStrm << endl; toStrm << "ABERR 0" << endl; toStrm << "ATMREF 0" << endl; toStrm << "PLATFORM 1" << endl; toStrm << "SOURCE_FLAG 1" << endl; toStrm << "SINGLE_EPHEMERIDE 0" << endl; //Note, for TRI_PARAMETERS, we print the first element separate from the rest so that the array //starts in the first column. Otherwise, SOCET Set will treat the array as a comment toStrm << "TRI_PARAMETERS" << endl; toStrm << triParams[0]; for (int i = 1; i < 18; i++) toStrm << " " << triParams[i]; toStrm << endl; toStrm << setprecision(25) << "T_CENTER "; double tCenter = 0.0; //TO DO: UNCOMMENT THESE LINES ONCE HRSC IS WORKING IN SS // if (isHRSC) { // tCenter = etCenter - HRSCNadirCenterTime; // toStrm << tCenter << endl; // } // else toStrm << tCenter << endl; toStrm << "DT_EPHEM " << dtEphem << endl; toStrm << "T0_EPHEM "; //TO DO: UNCOMMENT THESE LINES ONCE HRSC IS WORKING IN SS // if (isHRSC) { // double t = tCenter + t0Ephem; // toStrm << t << endl; // } // else toStrm << t0Ephem << endl; toStrm << "NUMBER_OF_EPHEM " << numEphem << endl; toStrm << "EPHEM_PTS" << endl; //TO DO: DELETE THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS for (int i = 1; i <= numEphem; i++) { //TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS //for (int i = 0; i < numEphem; i++) { toStrm << " " << ephemPts[i][0]; toStrm << " " << ephemPts[i][1]; toStrm << " " << ephemPts[i][2] << endl; } toStrm << "\n\nEPHEM_RATES" << endl; for (int i = 0; i < numEphem; i++) { toStrm << " " << ephemRates[i][0]; toStrm << " " << ephemRates[i][1]; toStrm << " " << ephemRates[i][2] << endl; } toStrm << "\n\nDT_QUAT " << dtQuat << endl; toStrm << "T0_QUAT " << qt0Quat << endl; toStrm << "NUMBER_OF_QUATERNIONS " << numQuaternions << endl; toStrm << "QUATERNIONS" << endl; for (int i = 0; i < numQuaternions; i++) { toStrm << " " << quaternions[i][0]; toStrm << " " << quaternions[i][1]; toStrm << " " << quaternions[i][2]; toStrm << " " << quaternions[i][3] << endl; } toStrm << "\n\nSCAN_DURATION " << scanDuration << endl; // UNCOMMENT toStrm << "\nNUMBER_OF_INT_TIMES " << numIntTimes << endl; // // if (isHRSC) { // toStrm << "INT_TIMES" << endl; // for (int i = 0; i < numIntTimes; i++) { // LineRateChange lr = lineRates.at(i); // toStrm << " " << lr.GetStartEt(); // toStrm << " " << lr.GetLineScanRate(); // toStrm << " " << lr.GetStartLine() << endl; // } // } // else toStrm << "INT_TIME " << intTime << endl; toStrm << "\nALONG_SCAN_PIXEL_SIZE " << alongScanPxSize << endl; toStrm << "CROSS_SCAN_PIXEL_SIZE " << crossScanPxSize << endl; toStrm << "\nCENTER_GP"; for (int i = 0; i < 3; i++) toStrm << " " << centerGp[i]; toStrm << endl; toStrm << "SENSOR_POSITION"; for (int i = 0; i < 3; i++) toStrm << " " << sensorPosition[i]; toStrm << endl; toStrm << "MOUNTING_ANGLES"; double mountingAngles[3] = {0.0, 0.0, 0.0}; for (int i = 0; i < 3; i++) toStrm << " " << mountingAngles[i]; toStrm << endl; toStrm << "\nTOTAL_LINES " << totalLines << endl; toStrm << "TOTAL_SAMPLES " << totalSamples << endl; toStrm << "\n\n\n" << endl; toStrm << "IKCODE " << ikCode << endl; toStrm << "ISIS_Z_DIRECTION " << zDirection << endl; toStrm << "OPTICAL_DIST_COEF"; for (int i = 0; i < 3; i++) toStrm << " " << opticalDistCoefs[i]; toStrm << endl; toStrm << "ITRANSS"; for (int i = 0; i < 3; i++) toStrm << " " << iTransS[i]; toStrm << endl; toStrm << "ITRANSL"; for (int i = 0; i < 3; i++) toStrm << " " << iTransL[i]; toStrm << endl; toStrm << "DETECTOR_SAMPLE_ORIGIN " << detectorSampleOrigin << endl; toStrm << "DETECTOR_LINE_ORIGIN " << detectorLineOrigin << endl; toStrm << "DETECTOR_LINE_OFFSET " << lineOffset << endl; toStrm << "DETECTOR_SAMPLE_SUMMING " << sampleSumming << endl; toStrm << "STARTING_SAMPLE " << startingSample << endl; toStrm << "STARTING_LINE " << startingLine << endl; toStrm << "STARTING_EPHEMERIS_TIME " << setprecision(25) << etStart << endl; toStrm << "CENTER_EPHEMERIS_TIME " << etCenter << endl; } // end main
/** 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(); }
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(){ Process p; // Reset all the stats objects because they are global latStat.Reset(); lonStat.Reset(); resStat.Reset(); sampleResStat.Reset(); lineResStat.Reset(); aspectRatioStat.Reset(); phaseStat.Reset(); emissionStat.Reset(); incidenceStat.Reset(); localSolarTimeStat.Reset(); localRaduisStat.Reset(); northAzimuthStat.Reset(); UserInterface &ui = Application::GetUserInterface(); Cube *icube = p.SetInputCube("FROM"); Camera *cam = icube->Camera(); // Cube cube; // cube.Open(ui.GetFilename("FROM")); // Camera *cam = cube.Camera(); int eband = cam->Bands(); // if the camera is band independent that only run one band if (cam->IsBandIndependent()) eband = 1; int linc = ui.GetInteger("LINC"); int sinc = ui.GetInteger("SINC"); int pTotal = eband * ((cam->Lines()-2) / linc + 2) ; Progress progress; progress.SetMaximumSteps(pTotal); progress.CheckStatus(); for (int band=1; band<=eband; band++) { cam->SetBand(band); for (int line=1; line<(int)cam->Lines(); line=line+linc) { for (int sample=1; sample< cam->Samples(); sample=sample+sinc) { buildStats(cam, sample, line); } //set the sample value to the last sample and run buildstats int sample = cam->Samples(); buildStats(cam, sample, line); progress.CheckStatus(); } //set the line value to the last line and run on all samples(sample + sinc) int line = cam->Lines(); for (int sample=1; sample< cam->Samples(); sample=sample+sinc) { buildStats(cam, sample, line); } //set last sample and run with last line int sample = cam->Samples(); buildStats(cam, sample, line); progress.CheckStatus(); } //Set up the Pvl groups and get min, max, avg, and sd for each statstics object PvlGroup pUser("User Parameters"); pUser += PvlKeyword("Filename",ui.GetFilename("FROM")); pUser += PvlKeyword("Linc",ui.GetInteger("LINC")); pUser += PvlKeyword("Sinc",ui.GetInteger("SINC")); PvlGroup pLat("Latitude"); pLat += ValidateKey("LatitudeMinimum",latStat.Minimum()); pLat += ValidateKey("LatitudeMaximum",latStat.Maximum()); pLat += ValidateKey("LatitudeAverage",latStat.Average()); pLat += ValidateKey("LatitudeStandardDeviation",latStat.StandardDeviation()); PvlGroup pLon("Longitude"); pLon += ValidateKey("LongitudeMinimum",lonStat.Minimum()); pLon += ValidateKey("LongitudeMaximum",lonStat.Maximum()); pLon += ValidateKey("LongitudeAverage",lonStat.Average()); pLon += ValidateKey("LongitudeStandardDeviation",lonStat.StandardDeviation()); PvlGroup pSampleRes("SampleResolution"); pSampleRes += ValidateKey("SampleResolutionMinimum",sampleResStat.Minimum(), "meters/pixel"); pSampleRes += ValidateKey("SampleResolutionMaximum",sampleResStat.Maximum(), "meters/pixel"); pSampleRes += ValidateKey("SampleResolutionAverage",sampleResStat.Average(), "meters/pixel"); pSampleRes += ValidateKey("SampleResolutionStandardDeviation", sampleResStat.StandardDeviation(),"meters/pixel"); PvlGroup pLineRes("LineResolution"); pLineRes += ValidateKey("LineResolutionMinimum",lineResStat.Minimum(), "meters/pixel"); pLineRes += ValidateKey("LineResolutionMaximum",lineResStat.Maximum(), "meters/pixel"); pLineRes += ValidateKey("LineResolutionAverage",lineResStat.Average(), "meters/pixel"); pLineRes += ValidateKey("LineResolutionStandardDeviation", lineResStat.StandardDeviation(),"meters/pixel"); PvlGroup pResolution("Resolution"); pResolution += ValidateKey("ResolutionMinimum",resStat.Minimum(), "meters/pixel"); pResolution += ValidateKey("ResolutionMaximum",resStat.Maximum(), "meters/pixel"); pResolution += ValidateKey("ResolutionAverage",resStat.Average(), "meters/pixel"); pResolution += ValidateKey("ResolutionStandardDeviation", resStat.StandardDeviation(),"meters/pixel"); PvlGroup pAspectRatio("AspectRatio"); pAspectRatio += ValidateKey("AspectRatioMinimum",aspectRatioStat.Minimum()); pAspectRatio += ValidateKey("AspectRatioMaximun",aspectRatioStat.Maximum()); pAspectRatio += ValidateKey("AspectRatioAverage",aspectRatioStat.Average()); pAspectRatio += ValidateKey("AspectRatioStandardDeviation", aspectRatioStat.StandardDeviation()); PvlGroup pPhase("PhaseAngle"); pPhase += ValidateKey("PhaseMinimum",phaseStat.Minimum()); pPhase += ValidateKey("PhaseMaximum",phaseStat.Maximum()); pPhase += ValidateKey("PhaseAverage",phaseStat.Average()); pPhase += ValidateKey("PhaseStandardDeviation",phaseStat.StandardDeviation()); PvlGroup pEmission("EmissionAngle"); pEmission += ValidateKey("EmissionMinimum",emissionStat.Minimum()); pEmission += ValidateKey("EmissionMaximum",emissionStat.Maximum()); pEmission += ValidateKey("EmissionAverage",emissionStat.Average()); pEmission += ValidateKey("EmissionStandardDeviation", emissionStat.StandardDeviation()); PvlGroup pIncidence("IncidenceAngle"); pIncidence += ValidateKey("IncidenceMinimum",incidenceStat.Minimum()); pIncidence += ValidateKey("IncidenceMaximum",incidenceStat.Maximum()); pIncidence += ValidateKey("IncidenceAverage",incidenceStat.Average()); pIncidence += ValidateKey("IncidenceStandardDeviation", incidenceStat.StandardDeviation()); PvlGroup pTime("LocalSolarTime"); pTime += ValidateKey("LocalSolarTimeMinimum",localSolarTimeStat.Minimum(), "hours"); pTime += ValidateKey("LocalSolarTimeMaximum",localSolarTimeStat.Maximum(), "hours"); pTime += ValidateKey("LocalSolarTimeAverage",localSolarTimeStat.Average(), "hours"); pTime += ValidateKey("LocalSolarTimeStandardDeviation", localSolarTimeStat.StandardDeviation(),"hours"); PvlGroup pLocalRadius("LocalRadius"); pLocalRadius += ValidateKey("LocalRadiusMinimum",localRaduisStat.Minimum()); pLocalRadius += ValidateKey("LocalRadiusMaximum",localRaduisStat.Maximum()); pLocalRadius += ValidateKey("LocalRadiusAverage",localRaduisStat.Average()); pLocalRadius += ValidateKey("LocalRadiusStandardDeviation", localRaduisStat.StandardDeviation()); PvlGroup pNorthAzimuth("NorthAzimuth"); pNorthAzimuth += ValidateKey("NorthAzimuthMinimum",northAzimuthStat.Minimum()); pNorthAzimuth += ValidateKey("NorthAzimuthMaximum",northAzimuthStat.Maximum()); pNorthAzimuth += ValidateKey("NorthAzimuthAverage",northAzimuthStat.Average()); pNorthAzimuth += ValidateKey("NorthAzimuthStandardDeviation", northAzimuthStat.StandardDeviation()); // Send the Output to the log area Application::Log(pUser); Application::Log(pLat); Application::Log(pLon); Application::Log(pSampleRes); Application::Log(pLineRes); Application::Log(pResolution); Application::Log(pAspectRatio); Application::Log(pPhase); Application::Log(pEmission); Application::Log(pIncidence); Application::Log(pTime); Application::Log(pLocalRadius); Application::Log(pNorthAzimuth); if (ui.WasEntered("TO")) { string from = ui.GetFilename("FROM"); string outfile = Filename(ui.GetFilename("TO")).Expanded(); bool exists = Filename(outfile).Exists(); bool append = ui.GetBoolean("APPEND"); //If the user chooses a fromat of PVL then write to the output file ("TO") if (ui.GetString("FORMAT") == "PVL") { Pvl temp; temp.SetTerminator(""); temp.AddGroup(pUser); temp.AddGroup(pLat); temp.AddGroup(pLon); temp.AddGroup(pSampleRes); temp.AddGroup(pLineRes); temp.AddGroup(pResolution); temp.AddGroup(pAspectRatio); temp.AddGroup(pPhase); temp.AddGroup(pEmission); temp.AddGroup(pIncidence); temp.AddGroup(pTime); temp.AddGroup(pLocalRadius); temp.AddGroup(pNorthAzimuth); if (append) { temp.Append(outfile); } else { temp.Write(outfile); } } //Create a flatfile of the data with columhn headings // the flatfile is comma delimited and can be imported in to spreadsheets else { ofstream os; bool writeHeader = true; if (append) { os.open(outfile.c_str(),ios::app); if (exists) { writeHeader = false; } } else { os.open(outfile.c_str(),ios::out); } // if new file or append and no file exists then write header if(writeHeader){ os << "Filename,"<< "LatitudeMinimum,"<< "LatitudeMaximum,"<< "LatitudeAverage,"<< "LatitudeStandardDeviation,"<< "LongitudeMinimum,"<< "LongitudeMaximum,"<< "LongitudeAverage,"<< "LongitudeStandardDeviation,"<< "SampleResolutionMinimum,"<< "SampleResolutionMaximum,"<< "SampleResolutionAverage,"<< "SampleResolutionStandardDeviation,"<< "LineResolutionMinimum,"<< "LineResolutionMaximum,"<< "LineResolutionAverage,"<< "LineResolutionStandardDeviation,"<< "ResolutionMinimum,"<< "ResolutionMaximum,"<< "ResolutionAverage,"<< "ResolutionStandardDeviation,"<< "AspectRatioMinimum,"<< "AspectRatioMaximum,"<< "AspectRatioAverage,"<< "AspectRatioStandardDeviation,"<< "PhaseMinimum,"<< "PhaseMaximum,"<< "PhaseAverage,"<< "PhaseStandardDeviation,"<< "EmissionMinimum,"<< "EmissionMaximum,"<< "EmissionAverage,"<< "EmissionStandardDeviation,"<< "IncidenceMinimum,"<< "IncidenceMaximum,"<< "IncidenceAverage,"<< "IncidenceStandardDeviation,"<< "LocalSolarTimeMinimum,"<< "LocalSolarTimeMaximum,"<< "LocalSolarTimeAverage,"<< "LocalSolarTimeStandardDeviation,"<< "LocalRadiusMaximum,"<< "LocalRadiusMaximum,"<< "LocalRadiusAverage,"<< "LocalRadiusStandardDeviation,"<< "NorthAzimuthMinimum,"<< "NorthAzimuthMaximum,"<< "NorthAzimuthAverage,"<< "NorthAzimuthStandardDeviation,"<<endl; } os << Filename(from).Expanded() <<","; //call the function to write out the values for each group writeFlat(os, latStat); writeFlat(os, lonStat); writeFlat(os, sampleResStat); writeFlat(os, lineResStat); writeFlat(os, resStat); writeFlat(os, aspectRatioStat); writeFlat(os, phaseStat); writeFlat(os, emissionStat); writeFlat(os, incidenceStat); writeFlat(os, localSolarTimeStat); writeFlat(os, localRaduisStat); writeFlat(os, northAzimuthStat); os << endl; } } if( ui.GetBoolean("ATTACH") ) { string cam_name = "CameraStatistics"; //Creates new CameraStatistics Table TableField fname( "Name", Isis::TableField::Text, 20 ); TableField fmin( "Minimum", Isis::TableField::Double ); TableField fmax( "Maximum", Isis::TableField::Double ); TableField favg( "Average", Isis::TableField::Double ); TableField fstd( "StandardDeviation", Isis::TableField::Double ); TableRecord record; record += fname; record += fmin; record += fmax; record += favg; record += fstd; Table table( cam_name, record ); vector<PvlGroup> grps; grps.push_back( pLat ); grps.push_back( pLon ); grps.push_back( pSampleRes ); grps.push_back( pLineRes ); grps.push_back( pResolution ); grps.push_back( pAspectRatio ); grps.push_back( pPhase ); grps.push_back( pEmission ); grps.push_back( pIncidence ); grps.push_back( pTime ); grps.push_back( pLocalRadius ); grps.push_back( pNorthAzimuth ); for( vector<PvlGroup>::iterator g = grps.begin(); g != grps.end(); g++ ) { int i = 0; record[i++] = g->Name(); record[i++] = (double) (*g)[0][0]; record[i++] = (double) (*g)[1][0]; record[i++] = (double) (*g)[2][0]; record[i++] = (double) (*g)[3][0]; table += record; } icube->ReOpen( "rw" ); icube->Write( table ); p.WriteHistory(*icube); icube->Close(); } }
//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; } }
void IsisMain() { const QString caminfo_program = "caminfo"; UserInterface &ui = Application::GetUserInterface(); QList< QPair<QString, QString> > *general = NULL, *camstats = NULL, *statistics = NULL; BandGeometry *bandGeom = NULL; // Get input filename FileName in = ui.GetFileName("FROM"); // Get the format QString sFormat = ui.GetAsString("FORMAT"); // if true then run spiceinit, xml default is FALSE // spiceinit will use system kernels if(ui.GetBoolean("SPICE")) { QString parameters = "FROM=" + in.expanded(); ProgramLauncher::RunIsisProgram("spiceinit", parameters); } Process p; Cube *incube = p.SetInputCube("FROM"); // General data gathering general = new QList< QPair<QString, QString> >; general->append(MakePair("Program", caminfo_program)); general->append(MakePair("IsisVersion", Application::Version())); general->append(MakePair("RunDate", iTime::CurrentGMT())); general->append(MakePair("IsisId", SerialNumber::Compose(*incube))); general->append(MakePair("From", in.baseName() + ".cub")); general->append(MakePair("Lines", toString(incube->lineCount()))); general->append(MakePair("Samples", toString(incube->sampleCount()))); general->append(MakePair("Bands", toString(incube->bandCount()))); // Run camstats on the entire image (all bands) // another camstats will be run for each band and output // for each band. if(ui.GetBoolean("CAMSTATS")) { camstats = new QList< QPair<QString, QString> >; QString filename = ui.GetAsString("FROM"); int sinc = ui.GetInteger("SINC"); int linc = ui.GetInteger("LINC"); CameraStatistics stats(filename, sinc, linc); Pvl camPvl = stats.toPvl(); PvlGroup cg = camPvl.findGroup("Latitude", Pvl::Traverse); camstats->append(MakePair("MinimumLatitude", cg["latitudeminimum"][0])); camstats->append(MakePair("MaximumLatitude", cg["latitudemaximum"][0])); cg = camPvl.findGroup("Longitude", Pvl::Traverse); camstats->append(MakePair("MinimumLongitude", cg["longitudeminimum"][0])); camstats->append(MakePair("MaximumLongitude", cg["longitudemaximum"][0])); cg = camPvl.findGroup("Resolution", Pvl::Traverse); camstats->append(MakePair("MinimumResolution", cg["resolutionminimum"][0])); camstats->append(MakePair("MaximumResolution", cg["resolutionmaximum"][0])); cg = camPvl.findGroup("PhaseAngle", Pvl::Traverse); camstats->append(MakePair("MinimumPhase", cg["phaseminimum"][0])); camstats->append(MakePair("MaximumPhase", cg["phasemaximum"][0])); cg = camPvl.findGroup("EmissionAngle", Pvl::Traverse); camstats->append(MakePair("MinimumEmission", cg["emissionminimum"][0])); camstats->append(MakePair("MaximumEmission", cg["emissionmaximum"][0])); cg = camPvl.findGroup("IncidenceAngle", Pvl::Traverse); camstats->append(MakePair("MinimumIncidence", cg["incidenceminimum"][0])); camstats->append(MakePair("MaximumIncidence", cg["incidencemaximum"][0])); cg = camPvl.findGroup("LocalSolarTime", Pvl::Traverse); camstats->append(MakePair("LocalTimeMinimum", cg["localsolartimeMinimum"][0])); camstats->append(MakePair("LocalTimeMaximum", cg["localsolartimeMaximum"][0])); } // Compute statistics for entire cube if(ui.GetBoolean("STATISTICS")) { statistics = new QList< QPair<QString, QString> >; LineManager iline(*incube); Statistics stats; Progress progress; progress.SetText("Statistics..."); progress.SetMaximumSteps(incube->lineCount()*incube->bandCount()); progress.CheckStatus(); iline.SetLine(1); for(; !iline.end() ; iline.next()) { incube->read(iline); stats.AddData(iline.DoubleBuffer(), iline.size()); progress.CheckStatus(); } // Compute stats of entire cube double nPixels = stats.TotalPixels(); double nullpercent = (stats.NullPixels() / (nPixels)) * 100; double hispercent = (stats.HisPixels() / (nPixels)) * 100; double hrspercent = (stats.HrsPixels() / (nPixels)) * 100; double lispercent = (stats.LisPixels() / (nPixels)) * 100; double lrspercent = (stats.LrsPixels() / (nPixels)) * 100; // Statitics output for band statistics->append(MakePair("MeanValue", toString(stats.Average()))); statistics->append(MakePair("StandardDeviation", toString(stats.StandardDeviation()))); statistics->append(MakePair("MinimumValue", toString(stats.Minimum()))); statistics->append(MakePair("MaximumValue", toString(stats.Maximum()))); statistics->append(MakePair("PercentHIS", toString(hispercent))); statistics->append(MakePair("PercentHRS", toString(hrspercent))); statistics->append(MakePair("PercentLIS", toString(lispercent))); statistics->append(MakePair("PercentLRS", toString(lrspercent))); statistics->append(MakePair("PercentNull", toString(nullpercent))); statistics->append(MakePair("TotalPixels", toString(stats.TotalPixels()))); } bool getFootBlob = ui.GetBoolean("USELABEL"); bool doGeometry = ui.GetBoolean("GEOMETRY"); bool doPolygon = ui.GetBoolean("POLYGON"); if(doGeometry || doPolygon || getFootBlob) { Camera *cam = incube->camera(); QString incType = ui.GetString("INCTYPE"); int polySinc, polyLinc; if(doPolygon && incType.toUpper() == "VERTICES") { ImagePolygon poly; poly.initCube(*incube); polySinc = polyLinc = (int)(0.5 + (((poly.validSampleDim() * 2) + (poly.validLineDim() * 2) - 3.0) / ui.GetInteger("NUMVERTICES"))); } else if (incType.toUpper() == "LINCSINC"){ if(ui.WasEntered("POLYSINC")) { polySinc = ui.GetInteger("POLYSINC"); } else { polySinc = (int)(0.5 + 0.10 * incube->sampleCount()); if(polySinc == 0) polySinc = 1; } if(ui.WasEntered("POLYLINC")) { polyLinc = ui.GetInteger("POLYLINC"); } else { polyLinc = (int)(0.5 + 0.10 * incube->lineCount()); if(polyLinc == 0) polyLinc = 1; } } else { QString msg = "Invalid INCTYPE option[" + incType + "]"; throw IException(IException::Programmer, msg, _FILEINFO_); } bandGeom = new BandGeometry(); bandGeom->setSampleInc(polySinc); bandGeom->setLineInc(polyLinc); bandGeom->setMaxIncidence(ui.GetDouble("MAXINCIDENCE")); bandGeom->setMaxEmission(ui.GetDouble("MAXEMISSION")); bool precision = ui.GetBoolean("INCREASEPRECISION"); if (getFootBlob) { // Need to read history to obtain parameters that were used to // create the footprint History hist("IsisCube", in.expanded()); Pvl pvl = hist.ReturnHist(); PvlObject::PvlObjectIterator objIter; bool found = false; PvlGroup fpgrp; for (objIter=pvl.endObject()-1; objIter>=pvl.beginObject(); objIter--) { if (objIter->name().toUpper() == "FOOTPRINTINIT") { found = true; fpgrp = objIter->findGroup("UserParameters"); break; } } if (!found) { QString msg = "Footprint blob was not found in input image history"; throw IException(IException::User, msg, _FILEINFO_); } QString prec = (QString)fpgrp.findKeyword("INCREASEPRECISION"); prec = prec.toUpper(); if (prec == "TRUE") { precision = true; } else { precision = false; } QString inctype = (QString)fpgrp.findKeyword("INCTYPE"); inctype = inctype.toUpper(); if (inctype == "LINCSINC") { int linc = fpgrp.findKeyword("LINC"); int sinc = fpgrp.findKeyword("SINC"); bandGeom->setSampleInc(sinc); bandGeom->setLineInc(linc); } else { int vertices = fpgrp.findKeyword("NUMVERTICES"); int lincsinc = (int)(0.5 + (((incube->sampleCount() * 2) + (incube->lineCount() * 2) - 3.0) / vertices)); bandGeom->setSampleInc(lincsinc); bandGeom->setLineInc(lincsinc); } if (fpgrp.hasKeyword("MAXINCIDENCE")) { double maxinc = fpgrp.findKeyword("MAXINCIDENCE"); bandGeom->setMaxIncidence(maxinc); } if (fpgrp.hasKeyword("MAXEMISSION")) { double maxema = fpgrp.findKeyword("MAXEMISSION"); bandGeom->setMaxEmission(maxema); } } bandGeom->collect(*cam, *incube, doGeometry, doPolygon, getFootBlob, precision); // Check if the user requires valid image center geometry if(ui.GetBoolean("VCAMERA") && (!bandGeom->hasCenterGeometry())) { QString msg = "Image center does not project in camera model"; throw IException(IException::Unknown, msg, _FILEINFO_); } } if(sFormat.toUpper() == "PVL") GeneratePVLOutput(incube, general, camstats, statistics, bandGeom); else GenerateCSVOutput(incube, general, camstats, statistics, bandGeom); // Clean the data delete general; general = NULL; if(camstats) { delete camstats; camstats = NULL; } if(statistics) { delete statistics; statistics = NULL; } if(bandGeom) { delete bandGeom; bandGeom = NULL; } }
void IsisMain() { UserInterface &ui = Application::GetUserInterface(); Process p; // Get the histogram Cube *icube = p.SetInputCube("FROM"); double validMin = Isis::ValidMinimum; double validMax = Isis::ValidMaximum; if(ui.WasEntered("VALIDMIN")) { validMin = ui.GetDouble("VALIDMIN"); } if(ui.WasEntered("VALIDMAX")) { validMax = ui.GetDouble("VALIDMAX"); } // Set a global Pvl for storing results Pvl mainpvl; // Get the number of bands to process int bandcount = icube->bandCount(); for (int i = 1; i <= bandcount; i++) { Histogram *stats = icube->histogram(i, validMin, validMax); // Construct a label with the results PvlGroup results("Results"); results += PvlKeyword("From", icube->fileName()); results += PvlKeyword("Band", toString(icube->physicalBand(i))); if(stats->ValidPixels() != 0) { results += PvlKeyword("Average", toString(stats->Average())); results += PvlKeyword("StandardDeviation", toString(stats->StandardDeviation())); results += PvlKeyword("Variance", toString(stats->Variance())); // These statistics only worked on a histogram results += PvlKeyword("Median", toString(stats->Median())); results += PvlKeyword("Mode", toString(stats->Mode())); results += PvlKeyword("Skew", toString(stats->Skew())); results += PvlKeyword("Minimum", toString(stats->Minimum())); results += PvlKeyword("Maximum", toString(stats->Maximum())); results += PvlKeyword("Sum", toString(stats->Sum())); } results += PvlKeyword("TotalPixels", toString(stats->TotalPixels())); results += PvlKeyword("ValidPixels", toString(stats->ValidPixels())); results += PvlKeyword("OverValidMaximumPixels", toString(stats->OverRangePixels())); results += PvlKeyword("UnderValidMinimumPixels", toString(stats->UnderRangePixels())); results += PvlKeyword("NullPixels", toString(stats->NullPixels())); results += PvlKeyword("LisPixels", toString(stats->LisPixels())); results += PvlKeyword("LrsPixels", toString(stats->LrsPixels())); results += PvlKeyword("HisPixels", toString(stats->HisPixels())); results += PvlKeyword("HrsPixels", toString(stats->HrsPixels())); mainpvl.addGroup(results); delete stats; // Write the results to the log Application::Log(results); } // Write the results to the output file if the user specified one if(ui.WasEntered("TO")) { QString outFile = FileName(ui.GetFileName("TO")).expanded(); bool exists = FileName(outFile).fileExists(); bool append = ui.GetBoolean("APPEND"); ofstream os; bool writeHeader = false; //write the results in the requested format. if(ui.GetString("FORMAT") == "PVL") { if(append) { mainpvl.append(outFile); } else { mainpvl.write(outFile); } } else { //if the format was not PVL, write out a flat file. if(append) { os.open(outFile.toAscii().data(), ios::app); if(!exists) { writeHeader = true; } } else { os.open(outFile.toAscii().data(), ios::out); writeHeader = true; } if(writeHeader) { for(int i = 0; i < mainpvl.group(0).keywords(); i++) { os << mainpvl.group(0)[i].name(); if( i < mainpvl.group(0).keywords() - 1 ) { os << ","; } } os << endl; } for(int i = 0; i < mainpvl.groups(); i++) { for (int j = 0; j < mainpvl.group(i).keywords(); j++) { os << (QString)mainpvl.group(i)[j]; if(j < mainpvl.group(i).keywords() - 1) { os << ","; } } os << endl; } } } }
void IsisMain() { // Use a regular Process Process p; UserInterface &ui = Application::GetUserInterface(); QString from = ui.GetFileName("FROM"); QString to = FileName(ui.GetFileName("TO")).expanded(); QString socetProject = ui.GetString("SS_PROJECT"); QString socetImageLocation = ui.GetString("SS_IMG_LOC"); QString socetInputDataPath = ui.GetString("SS_INPUT_PATH"); QString socetCameraCalibrationPath = ui.GetString("SS_CAM_CALIB_PATH"); // Open input cube and make sure this is a lev1 image (ie, not map projected) Cube cube; cube.open(from); if (cube.isProjected()) { QString msg = QString("You can only create a SOCET Set Framing Camera or FrameOffAxis settings " "file for level 1 images. The input image [%1] is a map projected, level " "2, cube.").arg(from); throw IException(IException::User, msg, _FILEINFO_); } // Initialize the camera Cube *input = p.SetInputCube("FROM"); Camera *cam = input->camera(); CameraDetectorMap *detectorMap = cam->DetectorMap(); CameraFocalPlaneMap *focalMap = cam->FocalPlaneMap(); // Make sure the image contains the SPICE blobs/tables PvlGroup test = cube.label()->findGroup("Kernels", Pvl::Traverse); QString instrumentPointing = (QString) test["InstrumentPointing"]; if (instrumentPointing != "Table") { QString msg = QString("Input image [%1] does not contain needed SPICE blobs. Please run " "spiceinit on the image with attach=yes.").arg(from); throw IException(IException::User, msg, _FILEINFO_); } // Set the image at the boresight pixel to get the ephemeris time and SPICE data at that image // location double detectorSampleOrigin = focalMap->DetectorSampleOrigin(); double detectorLineOrigin = focalMap->DetectorSampleOrigin(); cam->SetImage(detectorSampleOrigin, detectorLineOrigin); double et = cam->time().Et(); Spice spice(*input); spice.setTime(et); // Get required keywords from instrument and band groups PvlGroup inst = cube.label()->findGroup("Instrument", Pvl::Traverse); QString instrumentId = (QString) inst["InstrumentId"]; QString spacecraftName = (QString) inst["SpacecraftName"]; // Compensate for noproj altering cube labels if (instrumentId == "IdealCamera") { PvlGroup orig = cube.label()->findGroup("OriginalInstrument", Pvl::Traverse); instrumentId = (QString) orig["InstrumentId"]; spacecraftName = (QString) orig["SpacecraftName"]; } // Get sensor position and orientation (opk) angles double ographicCamPos[3] = {0.0, 0.0, 0.0}; double omegaPhiKappa[3] = {0.0, 0.0, 0.0}; double isisFocalPlane2SocetPlateTranspose[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; getCamPosOPK(spice, spacecraftName, et, cam, ographicCamPos, omegaPhiKappa,isisFocalPlane2SocetPlateTranspose); // Determine the SOCET Set camera calibration file QString socetCamFile = socetCameraCalibrationPath; if (spacecraftName == "VIKING_ORBITER_1") { if (instrumentId == "VISUAL_IMAGING_SUBSYSTEM_CAMERA_A") { socetCamFile += "VIK1A.cam"; } else { socetCamFile += "VIK1B.cam"; } } else if (spacecraftName == "VIKING_ORBITER_2") { if (instrumentId == "VISUAL_IMAGING_SUBSYSTEM_CAMERA_A") { socetCamFile += "VIK2A.cam"; } else { socetCamFile += "VIK2B.cam"; } } //----------------------------------------.------------- //TO DO: Uncomment these lines when MEX SRC is supported //----------------------------------------.------------- // // Mars Express // else if (spacecraftName == "MARS_EXPRESS") { // socetCamFile += "SRC.cam"; // } //----------------------------------------------------- //TO DO: Uncomment these lines when Themis is supported //----------------------------------------------------- // // THEMIS VIS images (MARS Odyssey) // else if (spacecraftName == "MARS_ODYSSEY") { // socetCamFile += "THEMIS_VIS_F3.cam"; // } //----------------------------------------------------- //TO DO: Uncomment these lines when Apollo is supported //----------------------------------------------------- // else if (spacecraftName == "APOLLO 15") { // socetCamFile += "Apollo15_M_ASU.cam"; // } // else if (spacecraftName == "APOLLO 16") { // socetCamFile += "Apollo16_M_ASU.cam"; // } // else if (spacecraftName == "APOLLO 17") { // socetCamFile += "Apollo17_M_ASU.cam"; // } else if (spacecraftName == "Galileo Orbiter") { //Check if this image was aquired with the cover on or off iTime removeCoverDate("1994/04/01 00:00:00"); iTime imageDate((QString) inst["StartTime"]); if (imageDate < removeCoverDate) { socetCamFile += "Galileo_SSI_Cover.cam"; } else { socetCamFile += "Galileo_SSI.cam"; } } else if (spacecraftName == "Cassini-Huygens") { // Get the image filter and replace "/" with "_" PvlGroup bandBin = cube.label()->findGroup("BandBin", Pvl::Traverse); QString filter = (QString) bandBin["FilterName"]; filter.replace("/", "_"); socetCamFile += "Cassini_ISSNA_"; socetCamFile += filter; socetCamFile += ".cam"; } else if (spacecraftName == "Messenger") { if (instrumentId == "MDIS-NAC") { socetCamFile += "MDIS_NAC.cam"; } else { socetCamFile += "MDIS_WAC.cam"; } } else if (spacecraftName == "CLEMENTINE 1") { if (instrumentId == "UVVIS") { socetCamFile += "ClemUVVIS.cam"; } } // Throw exception for unsupported camera else { QString msg = QString("The ISIS to SOCET Set translation of input image [%1] is currently " "not supported for instrument [%2].").arg(from).arg(instrumentId); throw IException(IException::User, msg, _FILEINFO_); } // For THEMIS VIS, Galileo SSI, Cassini ISS get the image summation mode int summation = 1; //----------------------------------------------------- //TO DO: Uncomment these lines when Themis is supported //----------------------------------------------------- // if (spacecraftName == "MARS_ODYSSEY") { // try { // summation = (int) detectorMap->SampleScaleFactor(); // } // catch (IException &e) { // QString msg = "Error reading SpatialSumming from Instrument label"; // throw IException(IException::User, msg, _FILEINFO_); // } // } if (spacecraftName == "Galileo Orbiter") { try { summation = (int) detectorMap->SampleScaleFactor(); } catch (IException &e) { QString msg = "Error reading Summing from Instrument label"; throw IException(IException::User, msg, _FILEINFO_); } } if (spacecraftName == "Cassini-Huygens") { try { summation = (int) detectorMap->SampleScaleFactor(); } catch (IException &e) { QString msg = "Error reading Summing from Instrument label"; throw IException(IException::User, msg, _FILEINFO_); } } // Get NL/NS of image and calculate the size in x/y dimensions, in mm // Note: for THEMIS VIS, Galileo SSI and Cassini ISS summed images, calculate the size of the full // resolution image because our "isis2socet" scripts will enlarge the summed image for import into // Socet Set double pixelSize = 1.0 / cam->PixelPitch(); int numLines = cube.lineCount(); int numSamples = cube.sampleCount(); if (summation > 1) { // For Themis VIS, Galileo SSI, Cassini ISS: numLines *= summation; numSamples *= summation; } double sizeX = numSamples / pixelSize; double sizeY = numLines / pixelSize; // Make sure the Socet Set project name has the .prj extension if (socetProject.endsWith(".prj", Qt::CaseInsensitive) == FALSE) socetProject += ".prj"; // Find cube base name w/o extensions & establish the Socet Set support file name // Note: I'm using the QFileInfo class because the baseName method in the ISIS // FileName class only strips the last extension, and we need the core name // of the file without any extensions, or path QString baseName = QFileInfo(from).baseName(); QString socetSupFile = baseName + ".sup"; // Open and write to the SOCET Set Framing Camera settings file keywords and values // If this is a Messenger image, add the temperature-dependent focal length so as to overrride // the nominal focal lenghth stored in the SOCET Set camera calibration files ofstream toStrm; toStrm.open (to.toAscii().data(), ios::trunc); if (toStrm.bad()) { QString msg = "Unable to open output settings file"; throw IException(IException::User, msg, _FILEINFO_); } toStrm << "setting_file 1.1\n"; toStrm << "multi_frame.project " << socetProject << endl; toStrm << "multi_frame.cam_calib_filename " << socetCamFile << endl; toStrm << "multi_frame.create_files IMAGE_AND_SUPPORT\n"; toStrm << "multi_frame.atmos_ref 0\n"; toStrm << "multi_frame.auto_min YES\n"; toStrm << "multi_frame.digital_cam NO\n"; toStrm << "multi_frame.input_image_filename " << socetInputDataPath + baseName + ".raw" << endl; toStrm << "multi_frame.output_format img_type_vitec\n"; toStrm << "multi_frame.output_name " << socetSupFile << endl; toStrm << "multi_frame.output_location " << socetImageLocation << endl; toStrm << "multi_frame.cam_loc_ang_sys OPK\n"; toStrm << "multi_frame.cam_loc_ang_units UNIT_DEGREES\n"; toStrm << "multi_frame.cam_loc_xy_units UNIT_DEGREES\n"; if (spacecraftName == "Messenger") { // Overide the nominal focal length in the SOCET SET camera calibration file with the // Temperature Dependent Focal Length used in ISIS double focalLength = cam->FocalLength(); toStrm << "multi_frame.cam_loc_focal " << setprecision(17) << focalLength << endl; } toStrm << "multi_frame.cam_loc_y_or_lat " << setprecision(17) << ographicCamPos[0] << endl; toStrm << "multi_frame.cam_loc_x_or_lon " << ographicCamPos[1] << endl; toStrm << "multi_frame.cam_loc_elev " << ographicCamPos[2] << endl; toStrm << "multi_frame.cam_loc_omega " << omegaPhiKappa[0] << endl; toStrm << "multi_frame.cam_loc_phi " << omegaPhiKappa[1] << endl; toStrm << "multi_frame.cam_loc_kappa " << omegaPhiKappa[2] << endl; toStrm << "multi_frame.img_size_lines " << numLines << endl; toStrm << "multi_frame.img_size_samps " << numSamples << endl; toStrm << "multi_frame.sizex " << setprecision(6) << sizeX << endl; toStrm << "multi_frame.sizey " << sizeY << endl; toStrm << "multi_frame.orientation 1\n"; // Furthermore, if this is a Messenger image, get the needed keywords values needed for the // USGSAstro FrameOffAxis *support* file, and add them to the output settings file. // During frame import in SOCET Set, these values will be ignored, but then later accessed by // the USGSAstro import_frame SOCET Set program. // // Note: Summed Messenger images are handled in the FrameOffAxis sensor model, so no need to // account for enlarging Messenger images in the "socet2isis" scripts if (spacecraftName == "Messenger") { double originalHalfLines = numLines / 2.0; double originalHalfSamples = numSamples / 2.0; // Set the lens distortion coefficients // Note: These values were calculated for SOCET Set by Orrin Thomas in an MSExcel spreadsheet, // and are hardcoded here QString lenscoX; QString lenscoY; if (instrumentId == "MDIS-WAC") { lenscoX = QString("1.0913499678359500E-06 1.0000181809155400E+00 5.2705094712778700E-06 " "7.3086112844249500E-05 -2.1503011755973800E-06 -3.5311655893430800E-08 " "-5.3312743384716000E-06 -1.4642661005550900E-07 -5.4770856997706100E-06 " "-1.2364567692453900E-07 0.0000000000000000E+00 0.0000000000000000E+00 " "0.0000000000000000E+00 0.0000000000000000E+00 0.0000000000000000E+00"); lenscoY = QString("-4.8524316760252900E-08 -5.2704844291112000E-06 1.0000181808487100E+00 " "2.4702140905559800E-09 7.3084305868732200E-05 -2.1478354889239300E-06 " "1.2364567791040000E-07 -5.4663905009059100E-06 1.4516772126792600E-07 " "-5.3419626374895400E-06 0.0000000000000000E+00 0.0000000000000000E+00 " "0.0000000000000000E+00 0.0000000000000000E+00 0.0000000000000000E+00"); } else { //MDIS-NAC lens distortion coefficients: lenscoX = QString("-0.000000000000005 0.997948053760188 0.000000000000000 0.000000000000000 " "0.000542184519158 0.000000000000000 -0.000007008182254 0.000000000000000 " "-0.000006526474815 0.000000000000000 0.000000000000000 0.000000000000000 " "0.000000000000000 0.000000000000000 0.000000000000000"); lenscoY = QString("-0.000003746900328 0.000000000000000 0.999999575428613 -0.000880501428960 " "0.000000000000000 -0.000332760373453 0.000000000000000 -0.000008067196812 " "0.000000000000000 -0.000007553955548 0.000000000000000 0.000000000000000 " "0.000000000000000 0.000000000000000 0.000000000000000"); } // Get the image summation double sampleSumming = (int) detectorMap->SampleScaleFactor(); double lineSumming = (int) detectorMap->LineScaleFactor(); // Get the Starting Detector Line/Sample double startingSample = detectorMap->AdjustedStartingSample(); double startingLine = detectorMap->AdjustedStartingLine(); // Get the image plane corrdinates to pixel coordinates transformation matrices const double *iTransS = focalMap->TransS(); const double *iTransL = focalMap->TransL(); // Because of the options for applying light-time correction, capture the pertinent // ISIS keywords as a record to be stored in the settingsfile // Note: these values will not go into the Socet Set support file) QString ikCode; QString swapObserverTarget; QString lightTimeCorrection; QString ltSurfaceCorrect; PvlObject naifKeywordsObject = cube.label()->findObject("NaifKeywords"); if (instrumentId == "MDIS-NAC") { ikCode = "236820"; swapObserverTarget = (QString) naifKeywordsObject["INS-236820_SWAP_OBSERVER_TARGET"]; lightTimeCorrection = (QString) naifKeywordsObject["INS-236820_LIGHTTIME_CORRECTION"]; ltSurfaceCorrect = (QString) naifKeywordsObject["INS-236820_LT_SURFACE_CORRECT"]; } else { ikCode = "236800"; swapObserverTarget = (QString) naifKeywordsObject["INS-236800_SWAP_OBSERVER_TARGET"]; lightTimeCorrection = (QString) naifKeywordsObject["INS-236800_LIGHTTIME_CORRECTION"]; ltSurfaceCorrect = (QString) naifKeywordsObject["INS-236800_LT_SURFACE_CORRECT"]; } toStrm << "\nSENSOR_TYPE FrameOffAxis" << endl; toStrm << "USE_LENS_DISTORTION 1" << endl; toStrm << "ORIGINAL_HALF_LINES " << originalHalfLines << endl; toStrm << "ORIGINAL_HALF_SAMPLES " << originalHalfSamples << endl; toStrm << "LENSCOX " << lenscoX << endl; toStrm << "LENSCOY " << lenscoY << endl; toStrm << "SAMPLE_SUMMING " << sampleSumming << endl; toStrm << "LINE_SUMMING " << lineSumming << endl; toStrm << "STARTING_DETECTOR_SAMPLE " << setprecision(17) << startingSample << endl; toStrm << "STARTING_DETECTOR_LINE " << startingLine << endl; toStrm << "SAMPLE_BORESIGHT " << detectorSampleOrigin << endl; toStrm << "LINE_BORESIGHT " << detectorLineOrigin << endl; toStrm << "INS_ITRANSS"; for (int i = 0; i < 3; i++) toStrm << " " << setprecision(14) << iTransS[i]; toStrm << endl; toStrm << "INS_ITRANSL"; for (int i = 0; i < 3; i++) toStrm << " " << iTransL[i]; toStrm << endl; toStrm << "M_SOCET2ISIS_FOCALPLANE " << setprecision(2) << isisFocalPlane2SocetPlateTranspose[0][0] << " " << isisFocalPlane2SocetPlateTranspose[0][1] << " " << isisFocalPlane2SocetPlateTranspose[0][2] << endl; toStrm << " " << isisFocalPlane2SocetPlateTranspose[1][0] << " " << isisFocalPlane2SocetPlateTranspose[1][1] << " " << isisFocalPlane2SocetPlateTranspose[1][2] << endl; toStrm << " " << isisFocalPlane2SocetPlateTranspose[2][0] << " " << isisFocalPlane2SocetPlateTranspose[2][1] << " " << isisFocalPlane2SocetPlateTranspose[2][2] << endl; toStrm << "INS-" << ikCode << "_SWAP_OBSERVER_TARGET = '" << swapObserverTarget << "'\n"; toStrm << "INS-" << ikCode << "_LIGHTTIME_CORRECTION = '" << lightTimeCorrection << "'\n"; toStrm << "INS-" << ikCode << "_LT_SURFACE_CORRECT = '" << ltSurfaceCorrect <<"'\n"; } } //End IsisMain
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() { 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(); }
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() { UserInterface &ui = Application::GetUserInterface(); Isis::FileName fromFile = ui.GetFileName("FROM"); Isis::Cube inputCube; inputCube.open(fromFile.expanded()); //Check to make sure we got the cube properly if(!inputCube.isOpen()) { QString msg = "Could not open FROM cube" + fromFile.expanded(); throw IException(IException::User, msg, _FILEINFO_); } Process p; Cube *icube = p.SetInputCube("FROM"); int totalSamples = icube->sampleCount(); int totalLines = icube->lineCount(); Isis::LineManager lineManager(inputCube); lineManager.begin(); int leftFringe, rightFringe; int binningMode = icube->group("Instrument")["Summing"]; //determine the edges between which no statistics should be gathered leftFringe = 48 / binningMode; rightFringe = totalSamples - leftFringe; int numSections = ui.GetInteger("SECTIONS"); if(numSections > 9) { QString msg = "You may have no more than 9 sections per side"; throw IException(IException::User, msg, _FILEINFO_); } int sectionLength = 0; if(!ui.WasEntered("LINESIZE")) { //User didn't enter number of lines if(numSections == 0) { sectionLength = 0; } else { sectionLength = totalLines / numSections; } } else { sectionLength = ui.GetInteger("LINESIZE"); if((sectionLength * numSections > totalLines) || sectionLength < 1) { sectionLength = totalLines / numSections; } } Statistics sections[numSections][2]; Statistics leftTotal, rightTotal; int sectionStarts[numSections]; sectionStarts[0] = 0; for(int i = 1 ; i < numSections - 1 ; i ++) { sectionStarts[i] = (totalLines / numSections) * i; } if(numSections > 0) { sectionStarts[numSections -1] = totalLines - sectionLength; } int currentSection = 0; Buffer leftFringeBuf(leftFringe, 1, 1, lineManager.PixelType()); Buffer rightFringeBuf(leftFringe, 1, 1, lineManager.PixelType()); //Walk down the cube for(int lineCount = 0 ; lineCount < totalLines ; lineCount++) { inputCube.read(lineManager); //Read the edges into the fringe buffers for(int i = 0 ; i < leftFringe ; i++) { leftFringeBuf[i] = lineManager[i]; } for(int i = rightFringe ; i < totalSamples ; i++) { rightFringeBuf[i - rightFringe] = lineManager[i]; } //No matter what, add the fringe buffers to the totals for that side leftTotal.AddData(leftFringeBuf.DoubleBuffer(), leftFringeBuf.size()); rightTotal.AddData(rightFringeBuf.DoubleBuffer(), rightFringeBuf.size()); if(numSections == 0) { continue; } //Index is not too large for this fringe section if(lineCount < sectionStarts[currentSection] + sectionLength) { //Index is not too small for this fringe section if(lineCount >= sectionStarts[currentSection]) { sections[currentSection][0].AddData(leftFringeBuf.DoubleBuffer(), leftFringeBuf.size()); sections[currentSection][1].AddData(rightFringeBuf.DoubleBuffer(), rightFringeBuf.size()); } } else { currentSection++; //Since sections may butt up against each other, it is possible that // we have to add this data to the next section. if(lineCount >= sectionStarts[currentSection]) { sections[currentSection][0].AddData(leftFringeBuf.DoubleBuffer(), leftFringeBuf.size()); sections[currentSection][1].AddData(rightFringeBuf.DoubleBuffer(), rightFringeBuf.size()); } } } // Write the results to the output file if the user specified one PvlObject leftSide("LeftSide"), rightSide("RightSide"); for(int i = 0 ; i < numSections ; i++) { QString sectionName = "Section" + toString(i + 1); pvlOut(sections[i][0], //Stats to add to the left Object sections[i][1], //Stats to add to the right Object sectionName, //Name for the new groups sectionStarts[i], //start line sectionStarts[i] + sectionLength, //end line &leftSide, //Object to add left group to &rightSide //Object to add right group to ); } pvlOut(leftTotal, //Stats to add to the left Object rightTotal, //Stats to add to the right Object "Total", //Name for the new groups 0, //start line totalLines, //end line &leftSide, //Object to add left group to &rightSide //Object to add right group to ); Pvl outputPvl; PvlGroup sourceInfo("SourceInfo"); sourceInfo += PvlKeyword("From", fromFile.expanded()); sourceInfo += icube->group("Archive")["ProductId"]; outputPvl.addGroup(sourceInfo); if(numSections > 0) { outputPvl.addObject(leftSide); outputPvl.addObject(rightSide); } else { PvlGroup leftGroup = leftSide.findGroup("Total"); PvlGroup rightGroup = rightSide.findGroup("Total"); leftGroup.setName("LeftSide"); rightGroup.setName("RightSide"); outputPvl.addGroup(leftGroup); outputPvl.addGroup(rightGroup); } outputPvl.write(ui.GetFileName("TO")); }