/** * Calculates the lat/lon of the ControlNet. * * @param incubes The filename of the list of cubes in the ControlNet * @param cnet The filename of the ControlNet */ void setControlPointLatLon(SerialNumberList &snl, ControlNet &cnet) { CubeManager manager; manager.SetNumOpenCubes(50); //Should keep memory usage to around 1GB Progress progress; progress.SetText("Calculating Lat/Lon"); progress.SetMaximumSteps(cnet.GetNumPoints()); progress.CheckStatus(); for (int cp = 0; cp < cnet.GetNumPoints(); cp++) { ControlPoint *point = cnet.GetPoint(cp); ControlMeasure *cm = point->GetRefMeasure(); Cube *cube = manager.OpenCube(snl.FileName(cm->GetCubeSerialNumber())); try { cube->camera()->SetImage(cm->GetSample(), cm->GetLine()); g_surfacePoints[point->GetId()] = cube->camera()->GetSurfacePoint(); } catch (IException &e) { QString msg = "Unable to create camera for cube file ["; msg += snl.FileName(cm->GetCubeSerialNumber()) + "]"; throw IException(e, IException::Unknown, msg, _FILEINFO_); } cube = NULL; //Do not delete, manager still has ownership progress.CheckStatus(); } manager.CleanCubes(); }
/** * This method performs pass1 on one image. It analyzes each framelet's * statistics and populates the necessary global variable. * * @param progress Progress message * @param theCube Current cube that needs processing * * @return bool True if the file contains a valid framelet */ bool CheckFramelets(string progress, Cube &theCube) { bool foundValidFramelet = false; LineManager mgr(theCube); Progress prog; prog.SetText(progress); prog.SetMaximumSteps(theCube.Lines()); prog.CheckStatus(); vector<double> frameletAvgs; // We need to store off the framelet information, because if no good // framelets were found then no data should be added to the // global variable for framelets, just files. vector< pair<int,double> > excludedFrameletsTmp; Statistics frameletStats; for(int line = 1; line <= theCube.Lines(); line++) { if((line-1) % numFrameLines == 0) { frameletStats.Reset(); } mgr.SetLine(line); theCube.Read(mgr); frameletStats.AddData(mgr.DoubleBuffer(), mgr.size()); if((line-1) % numFrameLines == numFrameLines-1) { if(IsSpecial(frameletStats.StandardDeviation()) || frameletStats.StandardDeviation() > maxStdev) { excludedFrameletsTmp.push_back( pair<int,double>((line-1)/numFrameLines, frameletStats.StandardDeviation()) ); } else { foundValidFramelet = true; } frameletAvgs.push_back(frameletStats.Average()); } prog.CheckStatus(); } inputFrameletAverages.push_back(frameletAvgs); if(foundValidFramelet) { for(unsigned int i = 0; i < excludedFrameletsTmp.size(); i++) { excludedFramelets.insert(pair< pair<int,int>, double>( pair<int,int>(currImage, excludedFrameletsTmp[i].first), excludedFrameletsTmp[i].second ) ); } } return foundValidFramelet; }
/** * Finds and writes all input cubes contained within the given Control Network * to the output file list * * @param cnet The Control Network to list the filenames contained within * @param sn2file The map for converting the Control Network's serial numbers * to filenames */ void WriteCubeOutList( ControlNet cnet, map<iString,iString> sn2file ) { UserInterface &ui = Application::GetUserInterface(); if( ui.WasEntered("TOLIST") ) { Progress p; p.SetText("Writing Cube List"); try { p.SetMaximumSteps(cnet.Size()); p.CheckStatus(); } catch( iException &e ) { e.Clear(); string msg = "The provided filters have resulted in an empty Control Network."; throw Isis::iException::Message(Isis::iException::User,msg, _FILEINFO_); } set<iString> outputsn; for( int cp = 0; cp < cnet.Size(); cp ++ ) { for( int cm = 0; cm < cnet[cp].Size(); cm ++ ) { outputsn.insert( cnet[cp][cm].CubeSerialNumber() ); } p.CheckStatus(); } std::string toList = ui.GetFilename("TOLIST"); ofstream out_stream; out_stream.open(toList.c_str(), std::ios::out); out_stream.seekp(0,std::ios::beg); //Start writing from beginning of file for( set<iString>::iterator sn = outputsn.begin(); sn != outputsn.end(); sn ++ ) { if( !sn2file[(*sn)].empty() ) { out_stream << sn2file[(*sn)] << endl; } } out_stream.close(); } }
void IsisMain() { // Get user interface UserInterface &ui = Application::GetUserInterface(); // Open the shift definitions file Pvl shiftdef; if (ui.WasEntered("SHIFTDEF")) { shiftdef.Read(ui.GetFilename("SHIFTDEF")); } else { shiftdef.AddObject(PvlObject("Hiccdstitch")); } PvlObject &stitch = shiftdef.FindObject("Hiccdstitch", Pvl::Traverse); // Open the first cube. It will be matched to the second input cube. HiJitCube trans; CubeAttributeInput &attTrans = ui.GetInputAttribute("FROM"); vector<string> bandTrans = attTrans.Bands(); trans.SetVirtualBands(bandTrans); trans.OpenCube(ui.GetFilename("FROM"), stitch); // Open the second cube, it is held in place. We will be matching the // first to this one by attempting to compute a sample/line translation HiJitCube match; CubeAttributeInput &attMatch = ui.GetInputAttribute("MATCH"); vector<string> bandMatch = attMatch.Bands(); match.SetVirtualBands(bandMatch); match.OpenCube(ui.GetFilename("MATCH"), stitch); // Ensure only one band if ((trans.Bands() != 1) || (match.Bands() != 1)) { string msg = "Input Cubes must have only one band!"; throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); } // Now test compatability (basically summing) trans.Compatable(match); // Determine intersection if (!trans.intersects(match)) { string msg = "Input Cubes do not overlap!"; throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); } // Get overlapping regions of each cube HiJitCube::Corners fcorns, mcorns; trans.overlap(match, fcorns); match.overlap(trans, mcorns); #if defined(ISIS_DEBUG) cout << "FROM Poly: " << trans.PolyToString() << std::endl; cout << "MATCH Poly: " << match.PolyToString() << std::endl; cout << "From Overlap: (" << fcorns.topLeft.sample << "," << fcorns.topLeft.line << "), (" << fcorns.lowerRight.sample << "," << fcorns.lowerRight.line << ")\n" ; cout << "Match Overlap: (" << mcorns.topLeft.sample << "," << mcorns.topLeft.line << "), (" << mcorns.lowerRight.sample << "," << mcorns.lowerRight.line << ")\n" ; #endif // We need to get a user definition of how to auto correlate around each // of the grid points. Pvl regdef; Filename regFile(ui.GetFilename("REGDEF")); regdef.Read(regFile.Expanded()); AutoReg *ar = AutoRegFactory::Create(regdef); double flines(fcorns.lowerRight.line - fcorns.topLeft.line + 1.0); double fsamps(fcorns.lowerRight.sample - fcorns.topLeft.sample + 1.0); // We want to create a grid of control points that is N rows by M columns. // Get row and column variables, if not entered, default to 1% of the input // image size int rows(1), cols(1); if (ui.WasEntered("ROWS")) { rows = ui.GetInteger("ROWS"); } else { rows = (int)(((flines - 1.0) / ar->SearchChip()->Lines()) + 1); } cols = ui.GetInteger("COLUMNS"); if (cols == 0) { cols = (int)(((fsamps - 1.0) / ar->SearchChip()->Samples()) + 1); } // Calculate spacing for the grid of points double lSpacing = floor(flines / rows); double sSpacing = floor(fsamps / cols); #if defined(ISIS_DEBUG) cout << "# Samples in Overlap: " << fsamps << endl; cout << "# Lines in Overlap : " << flines << endl; cout << "# Rows: " << rows << endl; cout << "# Columns: " << cols << endl; cout << "Line Spacing: " << lSpacing << endl; cout << "Sample Spacing: " << sSpacing << endl; #endif // Display the progress...10% 20% etc. Progress prog; prog.SetMaximumSteps(rows * cols); prog.CheckStatus(); // Initialize control point network ControlNet cn; cn.SetType(ControlNet::ImageToImage); cn.SetUserName(Application::UserName()); cn.SetCreatedDate(iTime::CurrentLocalTime()); // Get serial numbers for input cubes string transSN = SerialNumber::Compose(trans, true); string matchSN = SerialNumber::Compose(match, true); cn.SetTarget(transSN); cn.SetDescription("Records s/c jitter between two adjacent HiRISE images"); // Set up results parameter saves JitterParms jparms; jparms.fromCorns = fcorns; jparms.fromJit = trans.GetInfo(); jparms.matchCorns = mcorns; jparms.matchJit = match.GetInfo(); jparms.regFile = regFile.Expanded(); jparms.cols = cols; jparms.rows = rows; jparms.lSpacing = lSpacing; jparms.sSpacing = sSpacing; jparms.nSuspects = 0; // Loop through grid of points and get statistics to compute // translation values RegList reglist; double fline0(fcorns.topLeft.line-1.0), fsamp0(fcorns.topLeft.sample-1.0); double mline0(mcorns.topLeft.line-1.0), msamp0(mcorns.topLeft.sample-1.0); for (int r=0; r<rows; r++) { int line = (int)(lSpacing / 2.0 + lSpacing * r + 0.5); for (int c=0; c<cols; c++) { int samp = (int)(sSpacing / 2.0 + sSpacing * c + 0.5); ar->PatternChip()->TackCube(msamp0+samp, mline0+line); ar->PatternChip()->Load(match); ar->SearchChip()->TackCube(fsamp0+samp, fline0+line); ar->SearchChip()->Load(trans); // Set up ControlMeasure for cube to translate ControlMeasure cmTrans; cmTrans.SetCubeSerialNumber(transSN); cmTrans.SetCoordinate(msamp0+samp, mline0+line, ControlMeasure::Unmeasured); cmTrans.SetChooserName("hijitreg"); cmTrans.SetReference(false); // Set up ControlMeasure for the pattern/Match cube ControlMeasure cmMatch; cmMatch.SetCubeSerialNumber(matchSN); cmMatch.SetCoordinate(fsamp0+samp, fline0+line, ControlMeasure::Automatic); cmMatch.SetChooserName("hijitreg"); cmMatch.SetReference(true); // Match found if (ar->Register()==AutoReg::Success) { RegData reg; reg.fLine = fline0 + line; reg.fSamp = fsamp0 + samp; reg.fLTime = trans.getLineTime(reg.fLine); reg.mLine = mline0 + line; reg.mSamp = msamp0 + samp; reg.mLTime = match.getLineTime(reg.mLine); reg.regLine = ar->CubeLine(); reg.regSamp = ar->CubeSample(); reg.regCorr = ar->GoodnessOfFit(); if (fabs(reg.regCorr) > 1.0) jparms.nSuspects++; double sDiff = reg.fSamp - reg.regSamp; double lDiff = reg.fLine - reg.regLine; jparms.sStats.AddData(&sDiff,(unsigned int)1); jparms.lStats.AddData(&lDiff,(unsigned int)1); // Record the translation in the control point cmTrans.SetCoordinate(ar->CubeSample(), ar->CubeLine(), ControlMeasure::Automatic); cmTrans.SetError(sDiff, lDiff); cmTrans.SetGoodnessOfFit(ar->GoodnessOfFit()); // Reread the chip location centering the offset and compute // linear regression statistics try { Chip &pchip(*ar->PatternChip()); Chip fchip(pchip.Samples(), pchip.Lines()); fchip.TackCube(ar->CubeSample(), ar->CubeLine()); fchip.Load(trans); // Writes correlated chips to files for visual inspection #if defined(ISIS_DEBUG) ostringstream tstr; tstr << "R" << r << "C" << c << "_chip.cub"; string fcname("from" + tstr.str()); string mcname("match" + tstr.str()); pchip.Write(mcname); fchip.Write(fcname); #endif MultivariateStatistics mstats; for (int line = 1 ; line <= fchip.Lines() ; line++) { for(int sample = 1; sample < fchip.Samples(); sample++) { double fchipValue = fchip.GetValue(sample,line); double pchipValue = pchip.GetValue(sample,line); mstats.AddData(&fchipValue, &pchipValue, 1); } } // Get regression and correlation values mstats.LinearRegression(reg.B0, reg.B1); reg.Bcorr = mstats.Correlation(); if (IsSpecial(reg.B0)) throw 1; if (IsSpecial(reg.B1)) throw 2; if (IsSpecial(reg.Bcorr)) throw 3; } catch (...) { // If fails, flag this condition reg.B0 = 0.0; reg.B1= 0.0; reg.Bcorr = 0.0; } reglist.push_back(reg); } // Add the measures to a control point string str = "Row " + iString(r) + " Column " + iString(c); ControlPoint cp(str); cp.SetType(ControlPoint::Tie); cp.Add(cmTrans); cp.Add(cmMatch); if (!cmTrans.IsMeasured()) cp.SetIgnore(true); cn.Add(cp); prog.CheckStatus(); } } // If flatfile was entered, create the flatfile // The flatfile is comma seperated and can be imported into an excel // spreadsheet if (ui.WasEntered("FLATFILE")) { string fFile = ui.GetFilename("FLATFILE"); ofstream os; string fFileExpanded = Filename(fFile).Expanded(); os.open(fFileExpanded.c_str(),ios::out); dumpResults(os, reglist, jparms, *ar); } // If a cnet file was entered, write the ControlNet pvl to the file if (ui.WasEntered("CNETFILE")) { cn.Write(ui.GetFilename("CNETFILE")); } // Don't need the cubes opened anymore trans.Close(); match.Close(); // Write translation to log PvlGroup results("AverageTranslation"); if (jparms.sStats.ValidPixels() > 0) { double sTrans = (int)(jparms.sStats.Average() * 100.0) / 100.0; double lTrans = (int)(jparms.lStats.Average() * 100.0) / 100.0; results += PvlKeyword ("Sample",sTrans); results += PvlKeyword ("Line",lTrans); results += PvlKeyword ("NSuspects",jparms.nSuspects); } else { results += PvlKeyword ("Sample","NULL"); results += PvlKeyword ("Line","NULL"); } Application::Log(results); // add the auto registration information to print.prt PvlGroup autoRegTemplate = ar->RegTemplate(); Application::Log(autoRegTemplate); return; }
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() { UserInterface &ui = Application::GetUserInterface(); FileList addList(ui.GetFileName("ADDLIST")); bool log = false; FileName logFile; if (ui.WasEntered("LOG")) { log = true; logFile = ui.GetFileName("LOG"); } Pvl results; results.setName("cnetadd_Results"); PvlKeyword added("FilesAdded"); PvlKeyword omitted("FilesOmitted"); PvlKeyword pointsModified("PointsModified"); bool checkMeasureValidity = ui.WasEntered("DEFFILE"); ControlNetValidMeasure validator; if (checkMeasureValidity) { Pvl deffile(ui.GetFileName("DEFFILE")); validator = ControlNetValidMeasure(deffile); } SerialNumberList *fromSerials = ui.WasEntered("FROMLIST") ? new SerialNumberList(ui.GetFileName("FROMLIST")) : new SerialNumberList(); ControlNet inNet = ControlNet(ui.GetFileName("CNET")); inNet.SetUserName(Application::UserName()); inNet.SetModifiedDate(iTime::CurrentLocalTime()); //This should be done in ControlNet's Write fn QString retrievalOpt = ui.GetString("RETRIEVAL"); PvlKeyword duplicates("DupSerialNumbers"); if (retrievalOpt == "REFERENCE") { FileList list1(ui.GetFileName("FROMLIST")); SerialNumberList addSerials(ui.GetFileName("ADDLIST")); //Check for duplicate files in the lists by serial number for (int i = 0; i < addSerials.Size(); i++) { // Check for duplicate SNs accross the lists if (fromSerials->HasSerialNumber(addSerials.SerialNumber(i))) { duplicates.addValue(addSerials.FileName(i)); } // Check for duplicate SNs within the addlist for (int j = i + 1; j < addSerials.Size(); j++) { if (addSerials.SerialNumber(i) == addSerials.SerialNumber(j)) { QString msg = "Add list files [" + addSerials.FileName(i) + "] and ["; msg += addSerials.FileName(j) + "] share the same serial number."; throw IException(IException::User, msg, _FILEINFO_); } } } // Get the lat/long coords from the existing reference measure setControlPointLatLon(*fromSerials, inNet); } else { for (int cp = 0; cp < inNet.GetNumPoints(); cp++) { // Get the surface point from the current control point ControlPoint *point = inNet.GetPoint(cp); SurfacePoint surfacePoint = point->GetBestSurfacePoint(); if (!surfacePoint.Valid()) { QString msg = "Unable to retreive lat/lon from Control Point ["; msg += point->GetId() + "]. RETREIVAL=POINT cannot be used unless "; msg += "all Control Points have Latitude/Longitude keywords."; throw IException(IException::User, msg, _FILEINFO_); } g_surfacePoints[point->GetId()] = surfacePoint; } } FileName outNetFile(ui.GetFileName("ONET")); Progress progress; progress.SetText("Adding Images"); progress.SetMaximumSteps(addList.size()); progress.CheckStatus(); STRtree coordTree; QList<ControlPoint *> pointList; bool usePolygon = ui.GetBoolean("POLYGON"); if (usePolygon) { for (int cp = 0; cp < inNet.GetNumPoints(); cp++) { ControlPoint *point = inNet.GetPoint(cp); SurfacePoint surfacePoint = g_surfacePoints[point->GetId()]; Longitude lon = surfacePoint.GetLongitude(); Latitude lat = surfacePoint.GetLatitude(); Coordinate *coord = new Coordinate(lon.degrees(), lat.degrees()); Envelope *envelope = new Envelope(*coord); coordTree.insert(envelope, point); } } else { for (int cp = 0; cp < inNet.GetNumPoints(); cp++) { pointList.append(inNet.GetPoint(cp)); } } // Loop through all the images for (int img = 0; img < addList.size(); img++) { Cube cube; cube.open(addList[img].toString()); Pvl *cubepvl = cube.label(); QString sn = SerialNumber::Compose(*cubepvl); Camera *cam = cube.camera(); // Loop through all the control points QList<ControlPoint *> validPoints = usePolygon ? getValidPoints(cube, coordTree) : pointList; bool imageAdded = false; for (int cp = 0; cp < validPoints.size(); cp++) { ControlPoint *point = validPoints[cp]; // If the point is locked and Apriori source is "AverageOfMeasures" // then do not add the measures. if (point->IsEditLocked() && point->GetAprioriSurfacePointSource() == ControlPoint::SurfacePointSource::AverageOfMeasures) { continue; } if (point->HasSerialNumber(sn)) continue; // Only use the surface point's latitude and longitude, rely on the DEM // for computing the radius. We do this because otherwise we will receive // inconsistent results from successive runs of this program if the // different DEMs are used, or the point X, Y, Z was generated from the // ellipsoid. SurfacePoint surfacePoint = g_surfacePoints[point->GetId()]; if (cam->SetGround( surfacePoint.GetLatitude(), surfacePoint.GetLongitude())) { // Make sure the samp & line are inside the image if (cam->InCube()) { ControlMeasure *newCm = new ControlMeasure(); newCm->SetCoordinate(cam->Sample(), cam->Line(), ControlMeasure::Candidate); newCm->SetAprioriSample(cam->Sample()); newCm->SetAprioriLine(cam->Line()); newCm->SetCubeSerialNumber(sn); newCm->SetDateTime(); newCm->SetChooserName("Application cnetadd"); // Check the measure for DEFFILE validity if (checkMeasureValidity) { if (!validator.ValidEmissionAngle(cam->EmissionAngle())) { //TODO: log that it was Emission Angle that failed the check newCm->SetIgnored(true); } else if (!validator.ValidIncidenceAngle(cam->IncidenceAngle())) { //TODO: log that it was Incidence Angle that failed the check newCm->SetIgnored(true); } else if (!validator.ValidResolution(cam->resolution())) { //TODO: log that it was Resolution that failed the check newCm->SetIgnored(true); } else if (!validator.PixelsFromEdge((int)cam->Sample(), (int)cam->Line(), &cube)) { //TODO: log that it was Pixels from Edge that failed the check newCm->SetIgnored(true); } else { Portal portal(1, 1, cube.pixelType()); portal.SetPosition(cam->Sample(), cam->Line(), 1); cube.read(portal); if (!validator.ValidDnValue(portal[0])) { //TODO: log that it was DN that failed the check newCm->SetIgnored(true); } } } point->Add(newCm); // Point takes ownership // Record the modified Point and Measure g_modifications[point->GetId()].insert(newCm->GetCubeSerialNumber()); newCm = NULL; // Do not delete because the point has ownership if (retrievalOpt == "POINT" && point->GetNumMeasures() == 1) point->SetIgnored(false); imageAdded = true; } } } cubepvl = NULL; cam = NULL; if (log) { PvlKeyword &logKeyword = (imageAdded) ? added : omitted; logKeyword.addValue(addList[img].baseName()); } progress.CheckStatus(); } if (log) { // Add the list of modified points to the output log file QList<QString> modifiedPointsList = g_modifications.keys(); for (int i = 0; i < modifiedPointsList.size(); i++) pointsModified += modifiedPointsList[i]; results.addKeyword(added); results.addKeyword(omitted); results.addKeyword(pointsModified); if (duplicates.size() > 0) { results.addKeyword(duplicates); } results.write(logFile.expanded()); } // List the modified points if (ui.WasEntered("MODIFIEDPOINTS")) { FileName pointList(ui.GetFileName("MODIFIEDPOINTS")); // Set up the output file for writing std::ofstream out_stream; out_stream.open(pointList.expanded().toAscii().data(), std::ios::out); out_stream.seekp(0, std::ios::beg); //Start writing from beginning of file QList<QString> modifiedPointsList = g_modifications.keys(); for (int i = 0; i < modifiedPointsList.size(); i++) out_stream << modifiedPointsList[i].toStdString() << std::endl; out_stream.close(); } // Modify the inNet to only have modified points/measures if (ui.GetString("EXTRACT") == "MODIFIED") { for (int cp = inNet.GetNumPoints() - 1; cp >= 0; cp--) { ControlPoint *point = inNet.GetPoint(cp); // If the point was not modified, delete // Even get rid of edit locked points in this case if (!g_modifications.contains(point->GetId())) { point->SetEditLock(false); inNet.DeletePoint(cp); } // Else, remove the unwanted measures from the modified point else { for (int cm = point->GetNumMeasures() - 1; cm >= 0; cm--) { ControlMeasure *measure = point->GetMeasure(cm); // Even get rid of edit locked measures in this case if (point->GetRefMeasure() != measure && !g_modifications[point->GetId()].contains( measure->GetCubeSerialNumber())) { measure->SetEditLock(false); point->Delete(cm); } } } } } // Generate the TOLIST if wanted if (ui.WasEntered("TOLIST")) { SerialNumberList toList; SerialNumberList addSerials(ui.GetFileName("ADDLIST")); const QList<QString> snList = inNet.GetCubeSerials(); for (int i = 0; i < snList.size(); i++) { QString sn = snList[i]; if (addSerials.HasSerialNumber(sn)) toList.Add(addSerials.FileName(sn)); else if (fromSerials->HasSerialNumber(sn)) toList.Add(fromSerials->FileName(sn)); } IString name(ui.GetFileName("TOLIST")); std::fstream out_stream; out_stream.open(name.c_str(), std::ios::out); out_stream.seekp(0, std::ios::beg); //Start writing from beginning of file for (int f = 0; f < (int) toList.Size(); f++) out_stream << toList.FileName(f) << std::endl; out_stream.close(); } inNet.Write(outNetFile.expanded()); delete fromSerials; }
void IsisMain() { // Get user interface UserInterface &ui = Application::GetUserInterface(); // Get necessary variables from the user double latStart = ui.GetDouble("STARTLAT"); double lonStart = ui.GetDouble("STARTLON"); double latEnd = ui.GetDouble("ENDLAT"); double lonEnd = ui.GetDouble("ENDLON"); double latSpacing = ui.GetDouble("LATSPACING"); double lonSpacing = ui.GetDouble("LONSPACING"); double latInc = ui.GetDouble("LATINCREMENT"); double lonInc = ui.GetDouble("LONINCREMENT"); // Get mapfile, add values for range and create projection QString mapFile = ui.GetFileName("MAPFILE"); Pvl p(mapFile); PvlGroup &mapping = p.findGroup("Mapping", Pvl::Traverse); if(mapping.hasKeyword("MinimumLatitude")) { mapping.deleteKeyword("MinimumLatitude"); } if(mapping.hasKeyword("MaximumLatitude")) { mapping.deleteKeyword("MaximumLatitude"); } if(mapping.hasKeyword("MinimumLongitude")) { mapping.deleteKeyword("MinimumLongitude"); } if(mapping.hasKeyword("MaximumLongitude")) { mapping.deleteKeyword("MaximumLongitude"); } mapping += PvlKeyword("MinimumLatitude", toString(latStart)); mapping += PvlKeyword("MaximumLatitude", toString(latEnd)); mapping += PvlKeyword("MinimumLongitude", toString(lonStart)); mapping += PvlKeyword("MaximumLongitude", toString(lonEnd)); TProjection *proj; try { proj = (TProjection *) ProjectionFactory::Create(p); } catch(IException &e) { QString msg = "Cannot create grid - MapFile [" + mapFile + "] does not contain necessary information to create a projection"; throw IException(e, IException::User, msg, _FILEINFO_); } // Write grid to well known text output QString out = FileName(ui.GetFileName("TO")).expanded(); std::ofstream os; os.open(out.toAscii().data(), std::ios::out); // Display the progress...10% 20% etc. Progress prog; int steps = (int)(abs((latEnd - latStart) / latSpacing) + abs((lonEnd - lonStart) / lonSpacing) + 0.5) + 3; prog.SetMaximumSteps(steps); prog.CheckStatus(); /** * Initialize document. GML is XML-based, so we need the necessary XML headers. These * are necessary for the GML file to be recognized. */ os << "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" << endl; os << "<ogr:FeatureCollection " << endl << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" << endl << "xsi:schemaLocation=\"http://org.maptools.org/\"" << endl << "xmlns:ogr=\"http://org.maptools.org/\"" << endl << "xmlns:gml=\"http://www.opengis.net/gml\">" << endl; /** * Draw the interior longitude lines by looping through the longitude * range and drawing across each latitude line using the longitude increment. The first * and last line will be skipped for now. */ for(double j = lonStart + lonSpacing; j < lonEnd; j += lonSpacing) { StartNewLine(os); for(double k = latStart; k <= latEnd; k += lonInc) { proj->SetGround(k, j); AddPointToLine(os, proj->XCoord(), proj->YCoord()); } EndLine(os); prog.CheckStatus(); } /** * Draw the exterior longitude boundary lines. This happens by drawing just the first and * last longitude lines. */ for(double r = lonStart; r <= lonEnd; r += (lonEnd - lonStart)) { StartNewLine(os); for(double s = latStart; s <= latEnd; s += lonInc) { proj->SetGround(s, r); AddPointToLine(os, proj->XCoord(), proj->YCoord()); } EndLine(os); prog.CheckStatus(); } /** * Draw the interior latitude lines by looping through the latitude * range and drawing across each longitude line using the latitude increment. The first * and last line will be skipped for now. */ for(double i = latStart + latSpacing; i < latEnd; i += latSpacing) { // Get Latitude Line StartNewLine(os); for(double l = lonStart; l <= lonEnd; l += latInc) { proj->SetGround(i, l); AddPointToLine(os, proj->XCoord(), proj->YCoord()); } EndLine(os); prog.CheckStatus(); } /** * Draw the exterior latitude boundary lines. This happens by drawing just the first and * last longitude lines. */ for(double m = latStart; m <= latEnd; m += (latEnd - latStart)) { StartNewLine(os); for(double n = lonStart; n <= lonEnd; n += latInc) { proj->SetGround(m, n); AddPointToLine(os, proj->XCoord(), proj->YCoord()); } EndLine(os); prog.CheckStatus(); } /** * Draw the bounding box using a series of lines. */ if(ui.GetBoolean("BOUNDED")) { double minX, maxX, minY, maxY; proj->XYRange(minX, maxX, minY, maxY); StartNewLine(os); AddPointToLine(os, minX, minY); AddPointToLine(os, minX, maxY); EndLine(os); StartNewLine(os); AddPointToLine(os, minX, maxY); AddPointToLine(os, maxX, maxY); EndLine(os); StartNewLine(os); AddPointToLine(os, maxX, minY); AddPointToLine(os, maxX, maxY); EndLine(os); StartNewLine(os); AddPointToLine(os, minX, minY); AddPointToLine(os, maxX, minY); EndLine(os); } os << "</ogr:FeatureCollection>" << endl; // add mapping to print.prt PvlGroup projMapping = proj->Mapping(); Application::Log(projMapping); }
/** * Constructs an OverlapStatistics object. Compares the two input cubes and * finds where they overlap. * * @param x The first input cube * @param y The second input cube * @param progressMsg (Default value of "Gathering Overlap Statistics") Text * for indicating progress during statistic gathering * @param sampPercent (Default value of 100.0) Sampling percent, or the percentage * of lines to consider during the statistic gathering procedure * * @throws Isis::iException::User - All images must have the same number of * bands */ OverlapStatistics::OverlapStatistics(Isis::Cube &x, Isis::Cube &y, std::string progressMsg, double sampPercent) { // Test to ensure sampling percent in bound if (sampPercent <= 0.0 || sampPercent > 100.0) { string msg = "The sampling percent must be a decimal (0.0, 100.0]"; throw iException::Message(iException::Programmer,msg,_FILEINFO_); } p_sampPercent = sampPercent; // Extract filenames and band number from cubes p_xFile = x.Filename(); p_yFile = y.Filename(); // Make sure number of bands match if (x.Bands() != y.Bands()) { string msg = "Number of bands do not match between cubes [" + p_xFile.Name() + "] and [" + p_yFile.Name() + "]"; throw iException::Message(iException::User,msg,_FILEINFO_); } p_bands = x.Bands(); p_stats.resize(p_bands); //Create projection from each cube Projection *projX = x.Projection(); Projection *projY = y.Projection(); // Test to make sure projection parameters match if (*projX != *projY) { string msg = "Mapping groups do not match between cubes [" + p_xFile.Name() + "] and [" + p_yFile.Name() + "]"; throw iException::Message(iException::Programmer,msg,_FILEINFO_); } // Figure out the x/y range for both images to find the overlap double Xmin1 = projX->ToProjectionX(0.5); double Ymax1 = projX->ToProjectionY(0.5); double Xmax1 = projX->ToProjectionX(x.Samples()+0.5); double Ymin1 = projX->ToProjectionY(x.Lines()+0.5); double Xmin2 = projY->ToProjectionX(0.5); double Ymax2 = projY->ToProjectionY(0.5); double Xmax2 = projY->ToProjectionX(y.Samples()+0.5); double Ymin2 = projY->ToProjectionY(y.Lines()+0.5); // Find overlap if ((Xmin1<Xmax2) && (Xmax1>Xmin2) && (Ymin1<Ymax2) && (Ymax1>Ymin2)) { double minX = Xmin1 > Xmin2 ? Xmin1 : Xmin2; double minY = Ymin1 > Ymin2 ? Ymin1 : Ymin2; double maxX = Xmax1 < Xmax2 ? Xmax1 : Xmax2; double maxY = Ymax1 < Ymax2 ? Ymax1 : Ymax2; // Find Sample range of the overlap p_minSampX = (int)(projX->ToWorldX(minX) + 0.5); p_maxSampX = (int)(projX->ToWorldX(maxX) + 0.5); p_minSampY = (int)(projY->ToWorldX(minX) + 0.5); p_maxSampY = (int)(projY->ToWorldX(maxX) + 0.5); p_sampRange = p_maxSampX - p_minSampX + 1; // Test to see if there was only sub-pixel overlap if (p_sampRange <= 0) return; // Find Line range of overlap p_minLineX = (int)(projX->ToWorldY(maxY) + 0.5); p_maxLineX = (int)(projX->ToWorldY(minY) + 0.5); p_minLineY = (int)(projY->ToWorldY(maxY) + 0.5); p_maxLineY = (int)(projY->ToWorldY(minY) + 0.5); p_lineRange = p_maxLineX - p_minLineX + 1; // Print percent processed Progress progress; progress.SetText(progressMsg); int linc = (int)(100.0 / sampPercent + 0.5); // Calculate our line increment // Define the maximum number of steps to be our line range divided by the // line increment, but if they do not divide evenly, then because of // rounding, we need to do an additional step for each band int maxSteps = (int)(p_lineRange / linc + 0.5); if (p_lineRange % linc != 0) maxSteps += 1; maxSteps *= p_bands; progress.SetMaximumSteps(maxSteps); progress.CheckStatus(); // Collect and store off the overlap statistics for (int band=1; band<=p_bands; band++) { Brick b1(p_sampRange,1,1,x.PixelType()); Brick b2(p_sampRange,1,1,y.PixelType()); int i=0; while (i<p_lineRange) { b1.SetBasePosition(p_minSampX,(i+p_minLineX),band); b2.SetBasePosition(p_minSampY,(i+p_minLineY),band); x.Read(b1); y.Read(b2); p_stats[band-1].AddData(b1.DoubleBuffer(), b2.DoubleBuffer(), p_sampRange); // Make sure we consider the last line if (i+linc > p_lineRange-1 && i != p_lineRange-1) { i = p_lineRange-1; progress.AddSteps(1); } else i+=linc; // Increment the current line by our incrementer progress.CheckStatus(); } } } }
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(); } }
/** * This is the main method. Makeflat runs in three steps: * * 1) Calculate statistics * - For all cameras, this checks for one band and matching * sample counts. * - For framing cameras, this checks the standard deviation of * the images and records the averages of each image * - For push frame cameras, this calls CheckFramelets for each * image. * * 2) Create the temporary file, collect more detailed statistics * - For all cameras, this generates the temporary file and calculates * the final exclusion list * - For framing/push frame cameras, the temporary file is * 2 bands, where the first is a sum of DNs from each image/framelet * and the second band is a count of valid DNs that went into each sum * * 3) Create the final flat field file * - For all cameras, this processes the temporary file to create the final flat * field file. */ void IsisMain() { // Initialize variables ResetGlobals(); UserInterface &ui = Application::GetUserInterface(); maxStdev = ui.GetDouble("STDEVTOL"); if(ui.GetString("IMAGETYPE") == "FRAMING") { cameraType = Framing; // framing cameras need to figure this out automatically // during step 1 numFrameLines = -1; } else if(ui.GetString("IMAGETYPE") == "LINESCAN") { cameraType = LineScan; numFrameLines = ui.GetInteger("NUMLINES"); } else { cameraType = PushFrame; numFrameLines = ui.GetInteger("FRAMELETHEIGHT"); } FileList inList(ui.GetFilename("FROMLIST")); Progress progress; tempFileLength = 0; numOutputSamples = 0; /** * Line scan progress is based on the input list, whereas * the other cameras take much longer and are based on the * images themselves. Prepare the progress if we're doing * line scan. */ if(cameraType == LineScan) { progress.SetText("Calculating Number of Image Lines"); progress.SetMaximumSteps(inList.size()); progress.CheckStatus(); } /** * For a push frame camera, the temp file is one framelet. * Technically this is the same for the framing, but we * don't know the height of a framelet yet. */ if(cameraType == PushFrame) { tempFileLength = numFrameLines; } /** * Start pass 1, use global currImage so that methods called * know the image we're processing. */ for(currImage = 0; currImage < inList.size(); currImage++) { /** * Read the current cube into memory */ Cube tmp; tmp.Open(Filename(inList[currImage]).Expanded()); /** * If we haven't determined how many samples the output * should have, we can do so now */ if(numOutputSamples == 0 && tmp.Bands() == 1) { numOutputSamples = tmp.Samples(); } /** * Try and validate the image, quick tests first! * * (imageValid &= means imageValid = imageValid && ...) */ bool imageValid = true; // Only single band images are acceptable imageValid &= (tmp.Bands() == 1); // Sample sizes must always match imageValid &= (numOutputSamples == tmp.Samples()); // For push frame cameras, there must be valid all framelets if(cameraType == PushFrame) { imageValid &= (tmp.Lines() % numFrameLines == 0); } // For framing cameras, we need to figure out the size... // setTempFileLength is used to revert if the file // is decided to be invalid bool setTempFileLength = false; if(cameraType == Framing) { if(tempFileLength == 0 && imageValid) { tempFileLength = tmp.Lines(); numFrameLines = tempFileLength; setTempFileLength = true; } imageValid &= (tempFileLength == tmp.Lines()); } // Statistics are necessary at this point for push frame and framing cameras // because the framing camera standard deviation tolerance is based on // entire images, and push frame framelet exclusion stats can not be collected // during pass 2 cleanly if((cameraType == Framing || cameraType == PushFrame) && imageValid) { string prog = "Calculating Standard Deviation " + iString((int)currImage+1) + "/"; prog += iString((int)inList.size()) + " (" + Filename(inList[currImage]).Name() + ")"; if(cameraType == Framing) { Statistics *stats = tmp.Statistics(1, prog); imageValid &= !IsSpecial(stats->StandardDeviation()); imageValid &= !IsSpecial(stats->Average()); imageValid &= stats->StandardDeviation() <= maxStdev; vector<double> fileStats; fileStats.push_back(stats->Average()); inputFrameletAverages.push_back(fileStats); delete stats; } else if(cameraType == PushFrame) { imageValid &= CheckFramelets(prog, tmp); } if(setTempFileLength && !imageValid) { tempFileLength = 0; } } // The line scan camera needs to actually count the number of lines in each image to know // how many total frames there are before beginning pass 2. if(imageValid && (cameraType == LineScan)) { int lines = (tmp.Lines() / numFrameLines); // partial frame? if(tmp.Lines() % numFrameLines != 0) { lines ++; } tempFileLength += lines; } else if(!imageValid) { excludedFiles.insert(pair<int, bool>(currImage, true)); } tmp.Close(); if(cameraType == LineScan) { progress.CheckStatus(); } } /** * If the number of output samples could not be determined, we never * found a legitimate cube. */ if(numOutputSamples <= 0) { string msg = "No valid input cubes were found"; throw iException::Message(iException::User,msg,_FILEINFO_); } /** * If theres no temp file length, which is based off of valid data in * the input cubes, then we havent found any valid data. */ if(tempFileLength <= 0) { string msg = "No valid input data was found"; throw iException::Message(iException::User,msg,_FILEINFO_); } /** * ocube is now the temporary file (for pass 2). */ ocube = new Cube(); ocube->SetDimensions(numOutputSamples, tempFileLength, 2); PvlGroup &prefs = Preference::Preferences().FindGroup("DataDirectory", Pvl::Traverse); iString outTmpName = (string)prefs["Temporary"][0] + "/"; outTmpName += Filename(ui.GetFilename("TO")).Basename() + ".tmp.cub"; ocube->Create(outTmpName); oLineMgr = new LineManager(*ocube); oLineMgr->SetLine(1); ProcessByBrick p; int excludedCnt = 0; if(cameraType == LineScan) { outputTmpAverages.resize(numOutputSamples); outputTmpCounts.resize(numOutputSamples); numInputDns.resize(numOutputSamples); } cubeInitialized = false; for(currImage = 0; currImage < inList.size(); currImage++) { if(Excluded(currImage)) { excludedCnt ++; continue; } PvlObject currFile("Exclusions"); currFile += PvlKeyword("Filename", inList[currImage]); currFile += PvlKeyword("Tolerance", maxStdev); if(cameraType == LineScan) { currFile += PvlKeyword("FrameLines", numFrameLines); } else if(cameraType == PushFrame) { currFile += PvlKeyword("FrameletLines", numFrameLines); } excludedDetails.push_back(currFile); CubeAttributeInput inAtt; // This needs to be set constantly because ClearInputCubes // seems to be removing the input brick size. if(cameraType == LineScan) { p.SetBrickSize(1, numFrameLines, 1); } else if(cameraType == Framing || cameraType == PushFrame) { p.SetBrickSize(numOutputSamples, 1, 1); } p.SetInputCube(inList[currImage], inAtt); iString progText = "Calculating Averages " + iString((int)currImage+1); progText += "/" + iString((int)inList.size()); progText += " (" + Filename(inList[currImage]).Name() + ")"; p.Progress()->SetText(progText); p.StartProcess(CreateTemporaryData); p.EndProcess(); p.ClearInputCubes(); if(excludedDetails[excludedDetails.size()-1].Groups() == 0) { excludedDetails.resize(excludedDetails.size()-1); } } /** * Pass 2 completed. The processing methods were responsible for writing * the entire temporary cube. */ if(oLineMgr) { delete oLineMgr; oLineMgr = NULL; } if(ocube) { ocube->Close(); delete ocube; } /** * ocube is now the final output */ ocube = new Cube(); if(cameraType == LineScan) { ocube->SetDimensions(numOutputSamples, 1, 1); } else if(cameraType == Framing || cameraType == PushFrame) { ocube->SetDimensions(numOutputSamples, tempFileLength, 1); } ocube->Create(Filename(ui.GetFilename("TO")).Expanded()); oLineMgr = new LineManager(*ocube); oLineMgr->SetLine(1); // We now have the necessary temp file, let's go ahead and combine it into // the final output! p.SetInputBrickSize(numOutputSamples, 1, 2); p.SetOutputBrickSize(numOutputSamples, 1, 1); cubeInitialized = false; CubeAttributeInput inAtt; p.Progress()->SetText("Calculating Final Flat Field"); p.SetInputCube(outTmpName, inAtt); p.StartProcess(ProcessTemporaryData); p.EndProcess(); if(cameraType == LineScan) { ocube->Write(*oLineMgr); } if(oLineMgr) { delete oLineMgr; oLineMgr = NULL; } if(ocube) { ocube->Close(); delete ocube; ocube = NULL; } /** * Build a list of excluded files */ PvlGroup excludedFiles("ExcludedFiles"); for(currImage = 0; currImage < inList.size(); currImage++) { if(Excluded(currImage)) { excludedFiles += PvlKeyword("File", inList[currImage]); } } // log the results Application::Log(excludedFiles); if(ui.WasEntered("EXCLUDE")) { Pvl excludeFile; // Find excluded files excludeFile.AddGroup(excludedFiles); for(unsigned int i = 0; i < excludedDetails.size(); i++) { excludeFile.AddObject(excludedDetails[i]); } excludeFile.Write(Filename(ui.GetFilename("EXCLUDE")).Expanded()); } remove(outTmpName.c_str()); // Clean up settings ResetGlobals(); }
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() { // Get user interface UserInterface &ui = Application::GetUserInterface(); bool register_ignored = ui.GetBoolean("REGISTERIGNOREDONLY"); // Open the files list in a SerialNumberList for // reference by SerialNumber SerialNumberList files(ui.GetFilename("FILES")); // Create a ControlNet from the input file ControlNet inNet(ui.GetFilename("CNET")); // Create an AutoReg from the template file Pvl pvl(ui.GetFilename("TEMPLATE")); AutoReg *ar = AutoRegFactory::Create(pvl); // Create the output ControlNet ControlNet outNet; outNet.SetType(inNet.Type()); outNet.SetUserName(Application::UserName()); outNet.SetDescription(inNet.Description()); outNet.SetCreatedDate(iTime::CurrentLocalTime()); outNet.SetTarget(inNet.Target()); outNet.SetNetworkId(inNet.NetworkId()); Progress progress; progress.SetMaximumSteps(inNet.Size()); progress.CheckStatus(); int ignored=0, unmeasured=0, registered=0, unregistered=0, validated=0; CubeManager cubeMgr; cubeMgr.SetNumOpenCubes(50); // Register the points and create a new // ControlNet containing the refined measurements for (int i=0; i<inNet.Size(); i++) { ControlPoint &inPoint = inNet[i]; ControlPoint outPoint; outPoint.SetType(inPoint.Type()); outPoint.SetId(inPoint.Id()); outPoint.SetUniversalGround(inPoint.UniversalLatitude(), inPoint.UniversalLongitude(), inPoint.Radius()); outPoint.SetHeld(inPoint.Held()); outPoint.SetIgnore(inPoint.Ignore()); // CHECK TO SEE IF THE CONTROL POINT SHOULD BE REGISTERED // "Ignore" point and we are not registering ignored if (inPoint.Ignore() && !register_ignored){ ignored++; // add "Ignored" to network only if indicated if (ui.GetBoolean("OUTPUTIGNORED")) { // only include appropriate control measures for (int j = 0; j < inPoint.Size(); j++) { if (inPoint[j].IsMeasured()){ outPoint.Add(inPoint[j]); } else{ unmeasured++; if (ui.GetBoolean("OUTPUTUNMEASURED")){ outPoint.Add(inPoint[j]); } } } // only add this point if OUTPUTIGNORED outNet.Add(outPoint); } // go to next control point continue; } // Not "Ignore" point (i.e. "valid") and we are only registering "Ignored" else if (!inPoint.Ignore() && register_ignored) { // add all "valid" points to network // only include appropriate control measures for (int j = 0; j < inPoint.Size(); j++) { if (inPoint[j].IsMeasured()){ outPoint.Add(inPoint[j]); } else{ unmeasured++; if (ui.GetBoolean("OUTPUTUNMEASURED")) { outPoint.Add(inPoint[j]); } } } // add this point since it is not ignored outNet.Add(outPoint); // go to next control point continue; } // "Ignore" point or "valid" point to be registered else { // if ( (inPoint.Ignore() && register_ignored) || (!inPoint.Ignore() && !register_ignored ) ) { if (inPoint.Ignore()) { outPoint.SetIgnore(false); } ControlMeasure &patternCM = inPoint[inPoint.ReferenceIndex()]; Cube &patternCube = *cubeMgr.OpenCube(files.Filename(patternCM.CubeSerialNumber())); ar->PatternChip()->TackCube(patternCM.Sample(), patternCM.Line()); ar->PatternChip()->Load(patternCube); if (patternCM.IsValidated()) validated++; if (!patternCM.IsMeasured()) continue; if(!patternCM.IsReference()) { patternCM.SetReference(true); patternCM.SetChooserName("Application pointreg"); patternCM.SetDateTime(); } outPoint.Add(patternCM); // reset goodMeasureCount for this point before looping measures int goodMeasureCount = 0; // Register all the unvalidated measurements for (int j = 0; j < inPoint.Size(); j++) { // don't register the reference, go to next measure if (j == inPoint.ReferenceIndex()){ if (!inPoint[j].Ignore()) goodMeasureCount++; continue; } // if the measurement is valid, keep it as is and go to next measure if (inPoint[j].IsValidated()) { validated++; outPoint.Add(inPoint[j]); if (!inPoint[j].Ignore()) goodMeasureCount++; continue; } // if the point is unmeasured, add to output only if necessary and go to next measure if (!inPoint[j].IsMeasured()) { unmeasured++; if (ui.GetBoolean("OUTPUTUNMEASURED")) { outPoint.Add(inPoint[j]); } continue; } ControlMeasure searchCM = inPoint[j]; // refresh pattern cube pointer to ensure it stays valid Cube &patternCube = *cubeMgr.OpenCube(files.Filename(patternCM.CubeSerialNumber())); Cube &searchCube = *cubeMgr.OpenCube(files.Filename(searchCM.CubeSerialNumber())); ar->SearchChip()->TackCube(searchCM.Sample(), searchCM.Line()); try { ar->SearchChip()->Load(searchCube,*(ar->PatternChip()),patternCube); // If the measurements were correctly registered // Write them to the new ControlNet AutoReg::RegisterStatus res = ar->Register(); double score1, score2; ar->ZScores(score1, score2); searchCM.SetZScores(score1, score2); if(res == AutoReg::Success) { registered++; searchCM.SetType(ControlMeasure::Automatic); searchCM.SetError(searchCM.Sample() - ar->CubeSample(), searchCM.Line() - ar->CubeLine()); searchCM.SetCoordinate(ar->CubeSample(),ar->CubeLine()); searchCM.SetGoodnessOfFit(ar->GoodnessOfFit()); searchCM.SetChooserName("Application pointreg"); searchCM.SetDateTime(); searchCM.SetIgnore(false); outPoint.Add(searchCM); goodMeasureCount++; } // Else use the original marked as "Estimated" else { unregistered++; searchCM.SetType(ControlMeasure::Estimated); if(res == AutoReg::FitChipToleranceNotMet) { searchCM.SetError(inPoint[j].Sample() - ar->CubeSample(), inPoint[j].Line() - ar->CubeLine()); searchCM.SetGoodnessOfFit(ar->GoodnessOfFit()); } searchCM.SetChooserName("Application pointreg"); searchCM.SetDateTime(); searchCM.SetIgnore(true); outPoint.Add(searchCM); } } catch (iException &e) { e.Clear(); unregistered++; searchCM.SetType(ControlMeasure::Estimated); searchCM.SetChooserName("Application pointreg"); searchCM.SetDateTime(); searchCM.SetIgnore(true); outPoint.Add(searchCM); } } // Jeff Anderson put in this test (Dec 2, 2008) to allow for control // points to be good so long as at least two measure could be // registered. When a measure can't be registered to the reference then // that measure is set to be ignored where in the past the whole point // was ignored if (goodMeasureCount < 2) { if (!outPoint.Held() && outPoint.Type() != ControlPoint::Ground) { outPoint.SetIgnore(true); } } // Otherwise, ignore=false. This is already set at the beginning of the registration process // Check to see if the control point has now been assigned // to "ignore". If not, add it to the network. If so, only // add it to the output if the OUTPUTIGNORED parameter is selected // 2008-11-14 Jeannie Walldren if (!outPoint.Ignore()) { outNet.Add(outPoint); } else{ ignored++; if (ui.GetBoolean("OUTPUTIGNORED")) outNet.Add(outPoint); } } progress.CheckStatus(); } // If flatfile was entered, create the flatfile // The flatfile is comma seperated and can be imported into an excel // spreadsheet if (ui.WasEntered("FLATFILE")) { string fFile = Filename(ui.GetFilename("FLATFILE")).Expanded(); ofstream os; os.open(fFile.c_str(),ios::out); os << "PointId,OriginalMeasurementSample,OriginalMeasurementLine," << "RegisteredMeasurementSample,RegisteredMeasurementLine,SampleDifference," << "LineDifference,ZScoreMin,ZScoreMax,GoodnessOfFit" << endl; os << NULL8 << endl; for (int i=0; i<outNet.Size(); i++) { // get point from output control net and its // corresponding point from input control net ControlPoint outPoint = outNet[i]; ControlPoint *inPoint = inNet.Find(outPoint.Id()); if (outPoint.Ignore()) continue; for (int i = 0; i<outPoint.Size();i++) { // get measure and find its corresponding measure from input net ControlMeasure cmTrans = outPoint[i]; ControlMeasure cmOrig = (*inPoint)[cmTrans.CubeSerialNumber()]; double inSamp = cmOrig.Sample(); double inLine = cmOrig.Line(); double outSamp = cmTrans.Sample(); double outLine = cmTrans.Line(); double sampErr = cmTrans.SampleError(); double lineErr = cmTrans.LineError(); double zScoreMin = cmTrans.GetZScoreMin(); if (fabs(zScoreMin) <= DBL_EPSILON || zScoreMin == NULL8) zScoreMin = 0; double zScoreMax = cmTrans.GetZScoreMax(); if (fabs(zScoreMax) <= DBL_EPSILON || zScoreMax == NULL8) zScoreMax = 0; double goodnessOfFit = cmTrans.GoodnessOfFit(); if (fabs(goodnessOfFit) <= DBL_EPSILON || goodnessOfFit == NULL8) goodnessOfFit = 0; string pointId = outPoint.Id(); os << pointId << "," << inSamp << "," << inLine << "," << outSamp << "," << outLine << "," << sampErr << "," << lineErr << "," << zScoreMin << "," << zScoreMax << "," << goodnessOfFit << endl; } } } PvlGroup pLog("Points"); pLog+=PvlKeyword("Ignored", ignored); Application::Log(pLog); PvlGroup mLog("Measures"); mLog+=PvlKeyword("Validated", validated); mLog+=PvlKeyword("Registered", registered); mLog+=PvlKeyword("Unregistered", unregistered); mLog+=PvlKeyword("Unmeasured", unmeasured); Application::Log(mLog); // Log Registration Statistics Pvl arPvl = ar->RegistrationStatistics(); for(int i = 0; i < arPvl.Groups(); i++) { Application::Log(arPvl.Group(i)); } // add the auto registration information to print.prt PvlGroup autoRegTemplate = ar->RegTemplate(); Application::Log(autoRegTemplate); outNet.Write(ui.GetFilename("TO")); delete ar; }
/** 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(); }
// Main program void IsisMain() { UserInterface &ui = Application::GetUserInterface(); if( !ui.WasEntered("FROMLIST") && ui.WasEntered("TOLIST") ) { std::string msg = "To create a [TOLIST] the [FROMLIST] parameter must be provided."; throw iException::Message(iException::User,msg,_FILEINFO_); } // Gets the input parameters ControlNet outNet( ui.GetFilename("CNET") ); FileList inList; if( ui.WasEntered("FROMLIST") ) { inList = ui.GetFilename("FROMLIST"); } bool noIgnore = ui.GetBoolean("NOIGNORE"); bool noHeld = ui.GetBoolean("NOHELD"); bool noSingleMeasure = ui.GetBoolean("NOSINGLEMEASURES"); bool noMeasureless = ui.GetBoolean("NOMEASURELESS"); bool noTolerancePoints = ui.GetBoolean("TOLERANCE"); bool reference = ui.GetBoolean("REFERENCE"); bool ground = ui.GetBoolean("GROUND"); bool cubePoints = ui.WasEntered("CUBEPOINTS"); bool cubeMeasures = ui.GetBoolean("CUBEMEASURES"); bool pointsEntered = ui.WasEntered("POINTLIST"); bool latLon = ui.GetBoolean("LATLON"); if( !(noIgnore || noHeld || noSingleMeasure || noMeasureless || noTolerancePoints || reference || ground || cubePoints || pointsEntered || latLon) ) { std::string msg = "At least one filter must be selected ["; msg += "NOIGNORE,NOHELD,NOSINGLEMEASURE,TOLERANCE,REFERENCE,GROUND,CUBEPOINTS,"; msg += "CUBEMEASURES,POINTLIST,LATLON]"; throw iException::Message(iException::User,msg,_FILEINFO_); } else if( cubeMeasures && !cubePoints ) { std::string msg = "When CUBEMEASURES is selected, CUBEPOINTS must be given"; msg += " a list of cubes."; throw iException::Message(iException::User,msg,_FILEINFO_); } // Set up the Serial Number to Filename mapping map<iString,iString> sn2filename; for( int cubeIndex=0; cubeIndex < (int)inList.size(); cubeIndex ++ ) { iString sn = SerialNumber::Compose( inList[cubeIndex] ); sn2filename[sn] = inList[cubeIndex]; } Progress progress; progress.SetMaximumSteps(outNet.Size()); progress.CheckStatus(); // Set up verctor records of how points/measures are removed PvlKeyword ignoredPoints( "IgnoredPoints" ); PvlKeyword ignoredMeasures( "IgnoredMeasures" ); PvlKeyword heldPoints( "HeldPoints" ); PvlKeyword singleMeasurePoints( "SingleMeasurePoints" ); PvlKeyword measurelessPoints( "MeasurelessPoints" ); PvlKeyword tolerancePoints( "TolerancePoints" ); PvlKeyword nonReferenceMeasures( "NonReferenseMeasures" ); PvlKeyword nonGroundPoints( "NonGroundPoints" ); PvlKeyword nonCubePoints( "NonCubePoints" ); PvlKeyword nonCubeMeasures( "NonCubeMeasures" ); PvlKeyword noMeasurePoints( "NoMeasurePoints" ); PvlKeyword nonListedPoints( "NonListedPoints" ); PvlKeyword nonLatLonPoints( "LatLonOutOfRangePoints" ); PvlKeyword cannotGenerateLatLonPoints( "NoLatLonPoints" ); // Set up comparison data vector<iString> serialNumbers; if( cubePoints ) { FileList cubeList( ui.GetFilename("CUBEPOINTS") ); for( int cubeIndex=0; cubeIndex < (int)cubeList.size(); cubeIndex ++ ) { iString sn = SerialNumber::Compose( cubeList[cubeIndex] ); serialNumbers.push_back( sn ); } } double tolerance = 0.0; if( noTolerancePoints ) { tolerance = ui.GetDouble("PIXELTOLERANCE"); } // Set up extracted network values if( ui.WasEntered("NETWORKID") ) outNet.SetNetworkId( ui.GetString("NETWORKID") ); outNet.SetUserName( Isis::Application::UserName() ); outNet.SetDescription( ui.GetString("DESCRIPTION") ); for(int cp=outNet.Size()-1; cp >= 0; cp --) { progress.CheckStatus(); // Do preliminary exclusion checks if( noIgnore && outNet[cp].Ignore() ) { ignoredPoints += outNet[cp].Id(); outNet.Delete(cp); continue; } if( noHeld && outNet[cp].Held() ) { heldPoints += outNet[cp].Id(); outNet.Delete(cp); continue; } if( ground && !(outNet[cp].Type() == ControlPoint::Ground) ) { nonGroundPoints += outNet[cp].Id(); outNet.Delete(cp); continue; } if( noSingleMeasure ) { bool invalidPoint = false; invalidPoint |= noIgnore && (outNet[cp].NumValidMeasures() < 2); invalidPoint |= outNet[cp].Size() < 2 && (outNet[cp].Type() != ControlPoint::Ground); if( invalidPoint ) { singleMeasurePoints += outNet[cp].Id(); outNet.Delete(cp); continue; } } // Change the current point into a new point by manipulation of its control measures ControlPoint & newPoint = outNet[cp]; for( int cm = newPoint.Size()-1; cm >= 0; cm --) { if(noIgnore && newPoint[cm].Ignore()) { ignoredMeasures += "(" + newPoint.Id() + "," + newPoint[cm].CubeSerialNumber() + ")"; newPoint.Delete( cm ); } else if( reference && !newPoint[cm].IsReference() ) { nonReferenceMeasures += "(" + newPoint.Id() + "," + newPoint[cm].CubeSerialNumber() + ")"; newPoint.Delete( cm ); } else if( cubeMeasures ) { bool hasSerialNumber = false; for( unsigned int sn = 0; sn < serialNumbers.size() && !hasSerialNumber; sn ++) { if(serialNumbers[sn] == newPoint[cm].CubeSerialNumber()) hasSerialNumber = true; } if( !hasSerialNumber ) { nonCubeMeasures += "(" + newPoint.Id() + "," + newPoint[cm].CubeSerialNumber() + ")"; newPoint.Delete( cm ); } } } // Check for line/sample errors above provided tolerance if( noTolerancePoints ) { bool hasLowTolerance = true; for( int cm = 0; cm < newPoint.Size() && hasLowTolerance; cm ++ ) { if( newPoint[cm].SampleError() >= tolerance || newPoint[cm].LineError() >= tolerance ) { hasLowTolerance = false; } } if( hasLowTolerance ) { tolerancePoints += newPoint.Id(); outNet.Delete(cp); continue; } } // Do not add outPoint if it has too few measures if( noSingleMeasure ) { bool invalidPoint = false; invalidPoint |= noIgnore && (newPoint.NumValidMeasures() < 2); invalidPoint |= newPoint.Size() < 2 && newPoint.Type() != ControlPoint::Ground; if( invalidPoint ) { singleMeasurePoints += outNet[cp].Id(); outNet.Delete(cp); continue; } } // Do not add outPoint if it does not have a cube in CUBEPOINTS as asked if( cubePoints && !cubeMeasures ) { bool hasSerialNumber = false; for( int cm = 0; cm < newPoint.Size() && !hasSerialNumber; cm ++) { for( unsigned int sn = 0; sn < serialNumbers.size() && !hasSerialNumber; sn ++) { if(serialNumbers[sn] == newPoint[cm].CubeSerialNumber()) hasSerialNumber = true; } } if( !hasSerialNumber ) { nonCubePoints += newPoint.Id(); outNet.Delete(cp); continue; } } if( noMeasureless && newPoint.Size() == 0 ) { noMeasurePoints += newPoint.Id(); outNet.Delete(cp); continue; } } //! Finished with simple comparisons /** * Use another pass to check for Ids */ if( pointsEntered ) { ExtractPointList( outNet, nonListedPoints ); } /** * Use another pass on outNet, because this is by far the most time consuming * process, and time could be saved by using the reduced size of outNet */ if( latLon ) { ExtractLatLonRange( outNet, nonLatLonPoints, cannotGenerateLatLonPoints, sn2filename ); } // Write the filenames associated with outNet WriteCubeOutList( outNet, sn2filename ); Progress outProgress; outProgress.SetText("Writing Control Network"); outProgress.SetMaximumSteps( 5 ); outProgress.CheckStatus(); // Create the points included file PvlGroup included("NewControlNet"); included.AddKeyword( PvlKeyword( "Size", outNet.Size() ) ); PvlKeyword newPoints( "Points" ); for( int cp = 0; cp < outNet.Size(); cp ++ ) { newPoints.AddValue( outNet[cp].Id() ); } included.AddKeyword( newPoints ); outProgress.CheckStatus(); // Write the extracted Control Network outNet.Write( ui.GetFilename("OUTNET") ); outProgress.CheckStatus(); // Adds the remove history to the summary and results group PvlGroup summary("ResultSummary"); PvlGroup results("Results"); if( noIgnore ) { summary.AddKeyword( PvlKeyword( "IgnoredPoints", ignoredPoints.Size() ) ); results.AddKeyword( ignoredPoints ); summary.AddKeyword( PvlKeyword( "IgnoredMeasures", ignoredMeasures.Size() ) ); results.AddKeyword( ignoredMeasures ); } if( noHeld ) { summary.AddKeyword( PvlKeyword( "HeldPoints", heldPoints.Size() ) ); results.AddKeyword( heldPoints ); } if( noSingleMeasure ) { summary.AddKeyword( PvlKeyword( "SingleMeasurePoints", singleMeasurePoints.Size() ) ); results.AddKeyword( singleMeasurePoints ); } if( noMeasureless ) { summary.AddKeyword( PvlKeyword( "MeasurelessPoints", measurelessPoints.Size() ) ); results.AddKeyword( measurelessPoints ); } if( noTolerancePoints ) { summary.AddKeyword( PvlKeyword( "TolerancePoints", tolerancePoints.Size() ) ); results.AddKeyword( tolerancePoints ); } if( reference ) { summary.AddKeyword( PvlKeyword( "NonReferenceMeasures", nonReferenceMeasures.Size() ) ); results.AddKeyword( nonReferenceMeasures ); } if( ground ) { summary.AddKeyword( PvlKeyword( "NonGroundPoints", nonGroundPoints.Size() ) ); results.AddKeyword( nonGroundPoints ); } if( cubePoints ) { summary.AddKeyword( PvlKeyword( "NonCubePoints", nonCubePoints.Size() ) ); results.AddKeyword( nonCubePoints ); } if( noMeasurePoints.Size() != 0 ) { summary.AddKeyword( PvlKeyword( "NonCubeMeasure", noMeasurePoints.Size() ) ); results.AddKeyword( noMeasurePoints ); } if( cubeMeasures ) { summary.AddKeyword( PvlKeyword( "NoMeasurePoints", nonCubeMeasures.Size() ) ); results.AddKeyword( nonCubeMeasures ); } if( pointsEntered ) { summary.AddKeyword( PvlKeyword( "NonListedPoints", nonListedPoints.Size() ) ); results.AddKeyword( nonListedPoints ); } if( latLon ) { summary.AddKeyword( PvlKeyword( "LatLonOutOfRange", nonLatLonPoints.Size() ) ); results.AddKeyword( nonLatLonPoints ); summary.AddKeyword( PvlKeyword( "NoLatLonPoints", cannotGenerateLatLonPoints.Size() ) ); results.AddKeyword( cannotGenerateLatLonPoints ); } outProgress.CheckStatus(); // Log Control Net results Application::Log(included); Application::Log(summary); results.AddComment( "Each keyword represents a filter parameter used." \ " Check the documentation for specific keyword descriptions." ); Application::Log(results); outProgress.CheckStatus(); }
void IsisMain() { Process p; // Get the list of names of input CCD cubes to stitch together FileList flist; UserInterface &ui = Application::GetUserInterface(); flist.Read(ui.GetFilename("FROMLIST")); if (flist.size() < 1) { string msg = "The list file[" + ui.GetFilename("FROMLIST") + " does not contain any filenames"; throw iException::Message(iException::User,msg,_FILEINFO_); } string projection("Equirectangular"); if(ui.WasEntered("MAP")) { Pvl mapfile(ui.GetFilename("MAP")); projection = (string) mapfile.FindGroup("Mapping")["ProjectionName"]; } if(ui.WasEntered("PROJECTION")) { projection = ui.GetString("PROJECTION"); } // Gather other user inputs to projection string lattype = ui.GetString("LATTYPE"); string londir = ui.GetString("LONDIR"); string londom = ui.GetString("LONDOM"); int digits = ui.GetInteger("PRECISION"); // Fix them for mapping group lattype = (lattype == "PLANETOCENTRIC") ? "Planetocentric" : "Planetographic"; londir = (londir == "POSITIVEEAST") ? "PositiveEast" : "PositiveWest"; Progress prog; prog.SetMaximumSteps(flist.size()); prog.CheckStatus(); Statistics scaleStat; Statistics longitudeStat; Statistics latitudeStat; Statistics equiRadStat; Statistics poleRadStat; PvlObject fileset("FileSet"); // Save major equitorial and polar radii for last occuring double eqRad; double eq2Rad; double poleRad; string target("Unknown"); for (unsigned int i = 0 ; i < flist.size() ; i++) { // Set the input image, get the camera model, and a basic mapping // group Cube cube; cube.Open(flist[i]); int lines = cube.Lines(); int samples = cube.Samples(); PvlObject fmap("File"); fmap += PvlKeyword("Name",flist[i]); fmap += PvlKeyword("Lines", lines); fmap += PvlKeyword("Samples", samples); Camera *cam = cube.Camera(); Pvl mapping; cam->BasicMapping(mapping); PvlGroup &mapgrp = mapping.FindGroup("Mapping"); mapgrp.AddKeyword(PvlKeyword("ProjectionName",projection),Pvl::Replace); mapgrp.AddKeyword(PvlKeyword("LatitudeType",lattype),Pvl::Replace); mapgrp.AddKeyword(PvlKeyword("LongitudeDirection",londir),Pvl::Replace); mapgrp.AddKeyword(PvlKeyword("LongitudeDomain",londom),Pvl::Replace); // Get the radii double radii[3]; cam->Radii(radii); eqRad = radii[0] * 1000.0; eq2Rad = radii[1] * 1000.0; poleRad = radii[2] * 1000.0; target = cam->Target(); equiRadStat.AddData(&eqRad, 1); poleRadStat.AddData(&poleRad, 1); // Get resolution double lowres = cam->LowestImageResolution(); double hires = cam->HighestImageResolution(); scaleStat.AddData(&lowres, 1); scaleStat.AddData(&hires, 1); double pixres = (lowres+hires)/2.0; double scale = Scale(pixres, poleRad, eqRad); mapgrp.AddKeyword(PvlKeyword("PixelResolution",pixres),Pvl::Replace); mapgrp.AddKeyword(PvlKeyword("Scale",scale,"pixels/degree"),Pvl::Replace); mapgrp += PvlKeyword("MinPixelResolution",lowres,"meters"); mapgrp += PvlKeyword("MaxPixelResolution",hires,"meters"); // Get the universal ground range double minlat,maxlat,minlon,maxlon; cam->GroundRange(minlat,maxlat,minlon,maxlon,mapping); mapgrp.AddKeyword(PvlKeyword("MinimumLatitude",minlat),Pvl::Replace); mapgrp.AddKeyword(PvlKeyword("MaximumLatitude",maxlat),Pvl::Replace); mapgrp.AddKeyword(PvlKeyword("MinimumLongitude",minlon),Pvl::Replace); mapgrp.AddKeyword(PvlKeyword("MaximumLongitude",maxlon),Pvl::Replace); fmap.AddGroup(mapgrp); fileset.AddObject(fmap); longitudeStat.AddData(&minlon, 1); longitudeStat.AddData(&maxlon, 1); latitudeStat.AddData(&minlat, 1); latitudeStat.AddData(&maxlat, 1); p.ClearInputCubes(); prog.CheckStatus(); } // Construct the output mapping group with statistics PvlGroup mapping("Mapping"); double avgPixRes((scaleStat.Minimum()+scaleStat.Maximum())/2.0); double avgLat((latitudeStat.Minimum()+latitudeStat.Maximum())/2.0); double avgLon((longitudeStat.Minimum()+longitudeStat.Maximum())/2.0); double avgEqRad((equiRadStat.Minimum()+equiRadStat.Maximum())/2.0); double avgPoleRad((poleRadStat.Minimum()+poleRadStat.Maximum())/2.0); double scale = Scale(avgPixRes, avgPoleRad, avgEqRad); mapping += PvlKeyword("ProjectionName",projection); mapping += PvlKeyword("TargetName", target); mapping += PvlKeyword("EquatorialRadius",eqRad,"meters"); mapping += PvlKeyword("PolarRadius",poleRad,"meters"); mapping += PvlKeyword("LatitudeType",lattype); mapping += PvlKeyword("LongitudeDirection",londir); mapping += PvlKeyword("LongitudeDomain",londom); mapping += PvlKeyword("PixelResolution", SetRound(avgPixRes, digits), "meters/pixel"); mapping += PvlKeyword("Scale", SetRound(scale, digits), "pixels/degree"); mapping += PvlKeyword("MinPixelResolution",scaleStat.Minimum(),"meters"); mapping += PvlKeyword("MaxPixelResolution",scaleStat.Maximum(),"meters"); mapping += PvlKeyword("CenterLongitude", SetRound(avgLon,digits)); mapping += PvlKeyword("CenterLatitude", SetRound(avgLat,digits)); mapping += PvlKeyword("MinimumLatitude", MAX(SetFloor(latitudeStat.Minimum(),digits), -90.0)); mapping += PvlKeyword("MaximumLatitude", MIN(SetCeil(latitudeStat.Maximum(),digits), 90.0)); mapping += PvlKeyword("MinimumLongitude",MAX(SetFloor(longitudeStat.Minimum(),digits), -180.0)); mapping += PvlKeyword("MaximumLongitude",MIN(SetCeil(longitudeStat.Maximum(),digits), 360.0)); PvlKeyword clat("PreciseCenterLongitude", avgLon); clat.AddComment("Actual Parameters without precision applied"); mapping += clat; mapping += PvlKeyword("PreciseCenterLatitude", avgLat); mapping += PvlKeyword("PreciseMinimumLatitude", latitudeStat.Minimum()); mapping += PvlKeyword("PreciseMaximumLatitude", latitudeStat.Maximum()); mapping += PvlKeyword("PreciseMinimumLongitude",longitudeStat.Minimum()); mapping += PvlKeyword("PreciseMaximumLongitude",longitudeStat.Maximum()); Application::GuiLog(mapping); // Write the output file if requested if (ui.WasEntered("TO")) { Pvl temp; temp.AddGroup(mapping); temp.Write(ui.GetFilename("TO","map")); } if (ui.WasEntered("LOG")) { Pvl temp; temp.AddObject(fileset); temp.Write(ui.GetFilename("LOG","log")); } p.EndProcess(); }
/** * Removes control points not in the lat/lon range provided in the unput * parameters. * * @param outNet The output control net being removed from * @param noLanLonPoint The keyword recording all of the control points removed * due to the provided lat/lon range * @param noLanLonPoint The keyword recording all of the control points removed * due to the inability to calculate the lat/lon for that * point */ void ExtractLatLonRange( ControlNet & outNet, PvlKeyword & nonLatLonPoints, PvlKeyword & cannotGenerateLatLonPoints, map<iString,iString> sn2filename ) { if( outNet.Size() == 0 ) { return; } UserInterface &ui = Application::GetUserInterface(); // Get the lat/lon and fix the range for the internal 0/360 double minlat = ui.GetDouble("MINLAT"); double maxlat = ui.GetDouble("MAXLAT"); double minlon = ui.GetDouble("MINLON"); if( minlon < 0.0 ) { minlon += 360; } double maxlon = ui.GetDouble("MAXLON"); if( maxlon < 0.0 ) { minlon += 360; } bool useNetwork = ui.GetBoolean("USENETWORK"); Progress progress; progress.SetText("Calculating lat/lon"); progress.SetMaximumSteps(outNet.Size()); progress.CheckStatus(); CubeManager manager; manager.SetNumOpenCubes( 50 ); //Should keep memory usage to around 1GB for( int cp = outNet.Size()-1; cp >= 0; cp --) { progress.CheckStatus(); // If the Contorl Network takes priority, use it double pointLat = outNet[cp].UniversalLatitude(); double pointLon = outNet[cp].UniversalLongitude(); bool useControlNet = useNetwork && pointLat > -1000 && pointLon > -1000; if( outNet[cp].Type() == Isis::ControlPoint::Ground || useControlNet ) { if( NotInLatLonRange( outNet[cp].UniversalLatitude(), outNet[cp].UniversalLongitude(), minlat, maxlat, minlon, maxlon ) ) { nonLatLonPoints += outNet[cp].Id(); outNet.Delete( cp ); } } /** * If the lat/lon cannot be determined from the point, then we need to calculate * lat/lon on our own */ else if( ui.WasEntered("FROMLIST") ) { // Find a cube in the Control Point to get the lat/lon from int cm = 0; iString sn = ""; double lat = 0.0; double lon = 0.0; double radius = 0.0; // First check the reference Measure if( outNet[cp].HasReference() ) { cm = outNet[cp].ReferenceIndex(); if( !sn2filename[outNet[cp][cm].CubeSerialNumber()].empty() ) { sn = outNet[cp][cm].CubeSerialNumber(); } } // Search for other Control Measures if needed if( sn.empty() ) { // Find the Serial Number if it exists for( int cm = 0; (cm < outNet[cp].Size()) && sn.empty(); cm ++ ) { if( !sn2filename[outNet[cp][cm].CubeSerialNumber()].empty() ) { sn = outNet[cp][cm].CubeSerialNumber(); } } } // Connot fine a cube to get the lat/lon from if( sn.empty() ) { cannotGenerateLatLonPoints += outNet[cp].Id(); outNet.Delete( cp ); } // Calculate the lat/lon and check for validity else { bool remove = false; Cube *cube = manager.OpenCube( sn2filename[sn] ); Camera *camera = cube->Camera(); if (camera == NULL) { try { Projection *projection = ProjectionFactory::Create( (*(cube->Label())) ); if(!projection->SetCoordinate(outNet[cp][cm].Sample(),outNet[cp][cm].Line())) { nonLatLonPoints += outNet[cp].Id(); remove = true; } lat = projection->Latitude(); lon = projection->Longitude(); radius = projection->LocalRadius(); delete projection; projection = NULL; } catch ( iException &e ) { remove = true; e.Clear(); } } else { if(!camera->SetImage(outNet[cp][cm].Sample(),outNet[cp][cm].Line())) { nonLatLonPoints += outNet[cp].Id(); remove = true; } lat = camera->UniversalLatitude(); lon = camera->UniversalLongitude(); radius = camera->LocalRadius(); camera = NULL; } cube = NULL; if( remove || NotInLatLonRange( lat, lon, minlat, maxlat, minlon, maxlon ) ) { nonLatLonPoints += outNet[cp].Id(); outNet.Delete( cp ); } else { // Add the reference lat/lon/radius to the Control Point outNet[cp].SetUniversalGround( lat, lon, radius ); } } } else { cannotGenerateLatLonPoints += outNet[cp].Id(); outNet.Delete( cp ); } } manager.CleanCubes(); }
void IsisMain() { const QString mdisddr_program = "mdisddr"; const QString mdisddr_version = "1.0"; const QString mdisddr_revision = "$Revision: 5086 $"; const QString mdisddr_runtime = Application::DateTime(); const QString dataSetID = "MESS-E/V/H-MDIS-6-DDR-GEOMDATA-V1.0"; UserInterface &ui = Application::GetUserInterface(); FileName input(ui.GetFileName("FROM")); QString to(""); bool toEntered = ui.WasEntered("TO"); if(toEntered) { to = ui.GetAsString("TO"); } QString opath("."); // Set default to local directory if(ui.WasEntered("OPATH")) { opath = ui.GetString("OPATH"); } else { ui.PutAsString("OPATH", opath); } // Generate the image cube that phocube produces for the DDR data FileName phoFile = FileName::createTempFile("$TEMPORARY/" + input.baseName() + "_phocube.cub"); QString pfile = phoFile.expanded(); QString parameters = "FROM=" + input.expanded() + " TO=" + pfile + " LATITUDE=TRUE LONGITUDE=TRUE PHASE=TRUE EMISSION=TRUE INCIDENCE=TRUE"; ProgramLauncher::RunIsisProgram("phocube", parameters); // Wrap a try clause so that if anything goes wrong below, we can remove // the phocube file. try { Pvl phoLabel(pfile); BandMap bandmap; PvlKeyword bn = phoLabel.findGroup("BandBin", Pvl::Traverse)["Name"]; for(int i = 0 ; i < bn.size() ; i++) { bandmap.add(bn[i], i + 1); } // Set up the export. Note that the attributes selects 5 bands from the // output of the phocube run. It doesn't matter at this time which 5 // bands it is, just so that we have this established so the right labels // and file size is created. ProcessExportPds processPds; (void) processPds.SetInputCube(pfile, CubeAttributeInput("+1-5")); // Due to the nature of the phocube file, we cannot compute a histogram // of the data (it includes lots of data we don't need). So we will // fix the range to the expected well defined angle ranges. double minmin = 0.0; double maxmax = 0.0; if(ui.GetString("TYPE").compare("AUTOMATIC") == 0) { minmin = -360.0; maxmax = 360.0; } else { minmin = ui.GetDouble("MIN"); maxmax = ui.GetDouble("MAX"); } processPds.SetOutputEndian(Isis::Msb); processPds.SetExportType(ProcessExportPds::Fixed); processPds.SetInputRange(minmin, maxmax); // Set the output pixel type and the special pixel values processPds.SetOutputType(Real); processPds.SetOutputRange(minmin, maxmax); processPds.SetOutputNull(NULL4); processPds.SetOutputLrs(LOW_REPR_SAT4); processPds.SetOutputLis(LOW_INSTR_SAT4); processPds.SetOutputHrs(HIGH_REPR_SAT4); processPds.SetOutputHis(HIGH_INSTR_SAT4); Progress p; p.SetText("Modifying Keywords"); p.SetMaximumSteps(6); p.CheckStatus(); // Get the PDS label from the process Pvl &pdsLabel = processPds.StandardPdsLabel(ProcessExportPds::Image); // Translate the keywords from the original EDR PDS label that go in // this DDR PDS label. Note that we have to open the original (FROM) // cube as the phocube output goes into the specification of the // output PDS file (required for 5 band IMAGE object). Cube from; from.open(input.expanded()); OriginalLabel origBlob; from.read(origBlob); Pvl origLabel; PvlObject origLabelObj = origBlob.ReturnLabels(); origLabelObj.setName("OriginalLabelObject"); origLabel.addObject(origLabelObj); p.CheckStatus(); // Translates the ISIS labels along with the original EDR labels origLabel.addObject(*from.label()); PvlTranslationManager labels(origLabel, "$messenger/translations/mdisDDRLabel.trn"); labels.Auto(pdsLabel); p.CheckStatus(); // Add any new keywords QString lnote = "2007-12-20, S. Murchie (JHU/APL); " "2008-01-02, S. Murchie (JHU/APL); " "2008-01-11, J. Ward (GEO)"; pdsLabel += PvlKeyword("LABEL_REVISION_NOTE", lnote); pdsLabel += PvlKeyword("SPACECRAFT_NAME", Quote("MESSENGER")); // Fixes bad keywords PvlKeyword &data_set_id = pdsLabel.findKeyword("DATA_SET_ID", Pvl::Traverse); data_set_id.setValue(dataSetID); QString prodid(input.baseName()); PvlKeyword &product_id = pdsLabel.findKeyword("PRODUCT_ID", Pvl::Traverse); if((product_id.size() == 0) || ((product_id.size() > 0) && (product_id[0] == "N/A"))) { product_id.setValue(prodid); } else { QString pid = product_id[0]; pid[0] = 'D'; pid.remove(QRegExp("_.*")); pid.append("_DE_0"); product_id.setValue(pid); prodid = pid; } // Now we have enough to establish output file name if(!toEntered) to = opath + "/" + prodid; FileName output(to); output = output.addExtension("IMG"); if(!toEntered) ui.PutFileName("TO", output.expanded()); PvlKeyword &product_creation_time = pdsLabel.findKeyword("PRODUCT_CREATION_TIME", Pvl::Traverse); product_creation_time.setValue(mdisddr_runtime); PvlKeyword &software_name = pdsLabel.findKeyword("SOFTWARE_NAME", Pvl::Traverse); software_name.setValue(mdisddr_program); PvlKeyword &software_version_id = pdsLabel.findKeyword("SOFTWARE_VERSION_ID", Pvl::Traverse); software_version_id.setValue(Quote(mdisddr_version)); PvlKeyword &filter_number = pdsLabel.findKeyword("FILTER_NUMBER", Pvl::Traverse); if((filter_number.size() > 0)) { filter_number.setValue(Quote(filter_number[0])); } // Add quotes PvlKeyword &data_quality_id = pdsLabel.findKeyword("DATA_QUALITY_ID", Pvl::Traverse); data_quality_id.setValue(Quote(data_quality_id)); PvlKeyword &sequence_name = pdsLabel.findKeyword("SEQUENCE_NAME", Pvl::Traverse); sequence_name.setValue(Quote(sequence_name)); PvlKeyword &start_count = pdsLabel.findKeyword("SPACECRAFT_CLOCK_START_COUNT", Pvl::Traverse); start_count.setValue(Quote(start_count)); PvlKeyword &stop_count = pdsLabel.findKeyword("SPACECRAFT_CLOCK_STOP_COUNT", Pvl::Traverse); stop_count.setValue(Quote(stop_count)); // For DDRs, the SOURCE_PRODUCT_ID is made up of SPICE kernels. I need to // go get em. Kernels kernels(from); QStringList kfiles = kernels.getKernelList(); PvlKeyword &source_product_id = pdsLabel.findKeyword("SOURCE_PRODUCT_ID", Pvl::Traverse); source_product_id.clear(); for(int i = 0; i < kfiles.size(); i++) { FileName kfile(kfiles[i]); source_product_id.addValue(Quote(kfile.name())); } // Enforce parentheses for scalars if(source_product_id.size() == 1) source_product_id.setValue('(' + source_product_id[0] + ')'); // Removes keywords PvlObject imageObject(pdsLabel.findObject("IMAGE")); if(imageObject.hasKeyword("CENTER_FILTER_WAVELENGTH")) imageObject.deleteKeyword("CENTER_FILTER_WAVELENGTH"); if(imageObject.hasKeyword("BANDWIDTH")) imageObject.deleteKeyword("BANDWIDTH"); if(imageObject.hasKeyword("UNIT")) imageObject.deleteKeyword("UNIT"); if(imageObject.hasKeyword("DARK_STRIP_MEAN")) imageObject.deleteKeyword("DARK_STRIP_MEAN"); if(imageObject.hasKeyword("OFFSET")) imageObject.deleteKeyword("OFFSET"); if(imageObject.hasKeyword("SCALING_FACTOR")) imageObject.deleteKeyword("SCALING_FACTOR"); if(imageObject.hasKeyword("SAMPLE_BIT_MASK")) imageObject.deleteKeyword("SAMPLE_BIT_MASK"); // Add band names to image object PvlKeyword &bandNames = imageObject.findKeyword("FILTER_NAME"); bandNames.setName("BAND_NAME"); bandNames.clear(); bandNames.addValue("Latitude, planetocentric, deg N"); bandNames.addValue("Longitude, planetocentric, deg E"); bandNames.addValue("Incidence angle at equipotential surface, deg"); bandNames.addValue("Emission angle at equipotential surface, deg"); bandNames.addValue("Phase angle at equipotential surface, deg"); pdsLabel.deleteObject("IMAGE"); pdsLabel.addObject(imageObject); p.CheckStatus(); // Fix all the hosed units upon ingest. They are illformed. FixUnit(pdsLabel, "RETICLE_POINT_RA", "DEG"); FixUnit(pdsLabel, "RETICLE_POINT_DECLINATION", "DEG"); FixUnit(pdsLabel, "RETICLE_POINT_LATITUDE", "DEG"); FixUnit(pdsLabel, "RETICLE_POINT_LONGITUDE", "DEG"); // Now address nested keywords in SUBFRAME groups for(int i = 1 ; i <= 5 ; i++) { QString n(toString(i)); QString group = "SUBFRAME" + n + "_PARAMETERS"; if(pdsLabel.hasGroup(group)) { PvlGroup &grp = pdsLabel.findGroup(group); ValidateUnit(grp.findKeyword("RETICLE_POINT_LATITUDE"), "DEG"); ValidateUnit(grp.findKeyword("RETICLE_POINT_LONGITUDE"), "DEG"); } } p.CheckStatus(); // Finally, fix keywords by Quoting missing N/A values FixLabels(pdsLabel); p.CheckStatus(); // All done...write result. pdsLabel.setFormatTemplate("$messenger/templates/labels/mdisPdsDDR.pft"); QString ofile(output.expanded()); ofstream outstream(ofile.toAscii().data()); processPds.OutputLabel(outstream); // Writing out the 5 bands is a bit tricky for this product. The bands // must be ordered in a specific order, but phocube orders them in a // different order. To make this approach work, determine the proper band // as ordered in the phocube output and select the desired bands one at a // time setting the input cube to the desired band and writing it out by // stream. // Write latitude, longitude, incidence, emission, phase bands WriteBand(processPds, outstream, pfile, bandmap.get("Latitude")); WriteBand(processPds, outstream, pfile, bandmap.get("Longitude")); WriteBand(processPds, outstream, pfile, bandmap.get("Incidence Angle")); WriteBand(processPds, outstream, pfile, bandmap.get("Emission Angle")); WriteBand(processPds, outstream, pfile, bandmap.get("Phase Angle")); outstream.close(); processPds.EndProcess(); remove(pfile.toAscii().data()); } catch(IException &) { remove(pfile.toAscii().data()); throw; } catch(...) { remove(pfile.toAscii().data()); throw IException(IException::Unknown, "Unexpected exception caught!", _FILEINFO_); } }
// Construct a BLOb to contain the Hirise main line suffix and prefix data void SaveHiriseAncillaryData (ProcessImportPds &process, Cube *ocube) { vector<int> ConvertCalibrationPixels (int samples, Isis::PixelType pixelType, unsigned char *data); // Setup a Table to hold the main image prefix/suffix data TableField gap("GapFlag", TableField::Integer); TableField line("LineNumber", TableField::Integer); TableField buffer("BufferPixels", TableField::Integer, 12); TableField dark("DarkPixels", TableField::Integer, 16); TableRecord rec; rec += gap; rec += line; rec += buffer; rec += dark; Table table("HiRISE Ancillary", rec); table.SetAssociation (Table::Lines); // Loop through all the prefix and suffix data and construct the table records // In the case of HiRISE there is only one band so the outside vector // only contains one entry. The inside vector contains nl entries. vector<vector<char *> > pre = process.DataPrefix(); vector<vector<char *> > suf = process.DataSuffix(); vector<char *> prefix = pre.at(0); vector<char *> suffix = suf.at(0); Progress progress; progress.SetText("Saving ancillary data"); progress.SetMaximumSteps(prefix.size()); progress.CheckStatus(); for (unsigned int l=0; l<prefix.size(); l++) { unsigned char *linePrefix = (unsigned char *)(prefix[l]); // Pull out the gap byte (in byte 0) rec[0] = (int)(linePrefix[0]); // Pull out the line number (bytes 3-5 3=MSB, 5=LSB) int lineCounter = 0; lineCounter += ((int)(linePrefix[3])) << 16; lineCounter += ((int)(linePrefix[4])) << 8; lineCounter += ((int)(linePrefix[5])); rec[1] = lineCounter; // Pull the 12 buffer pixels (same type as image data) // from the image prefix area linePrefix += 6; section = 3; rec[2] = ConvertCalibrationPixels (12, process.PixelType(),linePrefix); linePrefix += 12 * SizeOf(process.PixelType()); // Pull the 16 dark pixels (same type as image data) // from the image suffix area unsigned char *lineSuffix = (unsigned char *)(suffix[l]); section = 5; rec[3] = ConvertCalibrationPixels (16, process.PixelType(),lineSuffix); lineSuffix += 16 * SizeOf(process.PixelType()); // Add this record to the table table += rec; // Report the progress progress.CheckStatus(); } // Add the table to the output cube ocube->Write(table); }
void IsisMain() { UserInterface &ui = Application::GetUserInterface(); double time0,//start time time1,//end time alti, //altitude of the spacecraftmore fmc, //forward motion compensation rad/sec horV, //horizontal velocity km/sec radV, //radial velocity km/sec rollV,//roll speed in rad/sec led; //line exposure duration in seconds Cube panCube; iTime isisTime; QString iStrTEMP; int i,j,k,scFrameCode,insCode; QString mission; SpicePosition *spPos; SpiceRotation *spRot; //int nlines,nsamples,nbands; double deg2rad = acos(-1.0)/180.0; ProcessImport jp; FileName transFile("$apollo15/translations/apollopantranstable.trn"); PvlTranslationTable transTable(transFile); PvlGroup kernels_pvlG; //scFrameCode and insCode from user input mission = ui.GetString("MISSION"); if (mission == "APOLLO12") scFrameCode = -912000; if (mission == "APOLLO14") scFrameCode = -914000; if (mission == "APOLLO15") scFrameCode = -915000; if (mission == "APOLLO16") scFrameCode = -916000; if (mission == "APOLLO17") scFrameCode = -917000; insCode = scFrameCode - 230; try { panCube.open(ui.GetFileName("FROM"),"rw"); } catch (IException &e) { throw IException(IException::User, "Unable to open the file [" + ui.GetFileName("FROM") + "] as a cube.", _FILEINFO_); } ////////////////////////////////////////////build the cube header instrament group PvlGroup inst_pvlG("Instrument"); PvlKeyword keyword; //four that are the same for every panaramic mission keyword.setName("SpacecraftName"); keyword.setValue(mission); inst_pvlG.addKeyword(keyword); keyword.setName("InstrumentName"); keyword.setValue(transTable.Translate("InstrumentName","whatever")); inst_pvlG.addKeyword(keyword); keyword.setName("InstrumentId"); keyword.setValue(transTable.Translate("InstrumentId","whatever")); inst_pvlG.addKeyword(keyword); keyword.setName("TargetName"); keyword.setValue(transTable.Translate("TargetName","whatever")); inst_pvlG.addKeyword(keyword); //three that need to be calculated from input values horV = ui.GetDouble("VEL_HORIZ"); radV = ui.GetDouble("VEL_RADIAL"); alti = ui.GetDouble("CRAFT_ALTITUDE"); //caculate the LineExposureDuration (led) if( ui.WasEntered("V/H_OVERRIDE") ) fmc = ui.GetDouble("V/H_OVERRIDE")/1000.0; else //forward motion compensation is directly equivalent to V/H fmc = sqrt(horV*horV + radV*radV)/alti; rollV = fmc*ROLLC; //roll angular velcoity is equal to V/H * constant (units rad/sec) //led = rad/mm * sec/rad = radians(2.5)/FIDL / rollV (final units: sec/mm) led = (2.5*acos(-1.0)/180.0)/rollV/FIDL; //use led and the number of mm to determine the start and stop times isisTime = ui.GetString("GMT"); //calculate starting and stoping times time0 = isisTime.Et() - led*FIDL*21.5; time1 = time0 + led*FIDL*43; isisTime = time0; keyword.setName("StartTime"); keyword.setValue(iStrTEMP=isisTime.UTC()); inst_pvlG.addKeyword(keyword); isisTime = time1; keyword.setName("StopTime"); keyword.setValue(iStrTEMP=isisTime.UTC()); inst_pvlG.addKeyword(keyword); keyword.setName("LineExposureDuration"); //converted led to msec/mm--negative sign to account for the anti-parallel time and line axes keyword.setValue(iStrTEMP=toString(-led),"sec/mm"); inst_pvlG.addKeyword(keyword); panCube.putGroup(inst_pvlG); ///////////////////////////////////The kernals group kernels_pvlG.setName("Kernels"); kernels_pvlG.clear(); keyword.setName("NaifFrameCode"); keyword.setValue(toString(insCode)); kernels_pvlG.addKeyword(keyword); keyword.setName("LeapSecond"); keyword.setValue( transTable.Translate("LeapSecond","File1") ); kernels_pvlG.addKeyword(keyword); keyword.setName("TargetAttitudeShape"); keyword.setValue( transTable.Translate("TargetAttitudeShape", "File1") ); keyword.addValue( transTable.Translate("TargetAttitudeShape", "File2") ); keyword.addValue( transTable.Translate("TargetAttitudeShape", "File3") ); kernels_pvlG.addKeyword(keyword); keyword.setName("TargetPosition"); keyword.setValue("Table"); keyword.addValue( transTable.Translate("TargetPosition", "File1") ); keyword.addValue( transTable.Translate("TargetPosition", "File2") ); kernels_pvlG.addKeyword(keyword); keyword.setName("ShapeModel"); keyword.setValue( transTable.Translate("ShapeModel", "File1") ); kernels_pvlG.addKeyword(keyword); keyword.setName("InstrumentPointing"); keyword.setValue("Table"); kernels_pvlG.addKeyword(keyword); keyword.setName("InstrumentPosition"); keyword.setValue("Table"); kernels_pvlG.addKeyword(keyword); keyword.setName("InstrumentAddendum"); keyword.setValue( transTable.Translate("InstrumentAddendum",mission)); kernels_pvlG.addKeyword(keyword); panCube.putGroup(kernels_pvlG); //Load all the kernals Load_Kernel(kernels_pvlG["TargetPosition"]); Load_Kernel(kernels_pvlG["TargetAttitudeShape"]); Load_Kernel(kernels_pvlG["LeapSecond"]); //////////////////////////////////////////attach a target rotation table char frameName[32]; SpiceInt frameCode; SpiceBoolean found; //get the framecode from the body code (301=MOON) cidfrm_c(301, sizeof(frameName), &frameCode, frameName, &found); if(!found) { QString naifTarget = QString("IAU_MOOM"); namfrm_c(naifTarget.toAscii().data(), &frameCode); if(frameCode == 0) { QString msg = "Can not find NAIF code for [" + naifTarget + "]"; throw IException(IException::Io, msg, _FILEINFO_); } } spRot = new SpiceRotation(frameCode); //create a table from starttime to endtime (streched by 3%) with NODES entries spRot->LoadCache(time0-0.015*(time1-time0), time1+0.015*(time1-time0), NODES); Table tableTargetRot = spRot->Cache("BodyRotation"); tableTargetRot.Label() += PvlKeyword("Description", "Created by apollopaninit"); panCube.write(tableTargetRot); //////////////////////////////////////////////////attach a sun position table spPos = new SpicePosition(10,301); //Position of the sun (10) WRT to the MOON (301) //create a table from starttime to endtime (stretched by 3%) with NODES entries spPos->LoadCache(time0-0.015*(time1-time0), time1+0.015*(time1-time0), NODES); Table tableSunPos = spPos->Cache("SunPosition"); tableSunPos.Label() += PvlKeyword("SpkTableStartTime", toString(time0-0.015*(time1-time0))); tableSunPos.Label() += PvlKeyword("SpkTablleEndTime", toString(time1+0.015*(time1-time0))); tableSunPos.Label() += PvlKeyword("Description", "Created by apollopaninit"); panCube.write(tableSunPos); //attach the table to the cube /////////////Finding the principal scan line position and orientation //get the radii of the MOON SpiceInt tempRadii = 0; bodvcd_c(301,"RADII",3,&tempRadii,R_MOON); //units are km double omega,phi,kappa; std::vector<double> posSel; //Seleno centric position std::vector<double> sunPos; //sunPosition used to transform to J2000 std::vector<double> posJ20; //camera position in J2000 posSel.resize(3); sunPos.resize(3); posJ20.resize(3); double temp, vel[3] = { 0.0, 0.0, 0.0 }, //the total velocity vector (combined Horizonatal and normal components) // in km/sec M[3][3] = { { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } }, //rotation matrix zDir[] = { 0.0, 0.0, 1.0 }, //selenographic Z axis northPN[3] = { 0.0, 0.0, 0.0 }, //normal to the plane containing all the north/south directions, // that is plane containing // the origin, the z axis, and the primary point of intersection northL[3] = { 0.0, 0.0, 0.0 }, //north direction vector in local horizontal plane azm[3] = { 0.0, 0.0, 0.0 }, //azm direction of the veclocity vector in selenographic coordinates azmP[3] = { 0.0, 0.0, 0.0 }, //azm rotated (partially) and projected into the image plane norm[3] = { 0.0, 0.0, 0.0 }, //normal to the local horizontal plane look[3] = { 0.0, 0.0, 0.0 }; //unit direction vector in the pincipal cameral look direction, // parallel to the vector from the center of the moon through the spacecraft double pos0[3] = { 0.0, 0.0, 0.0 }, //coordinate of the camera position pInt[3] = { 0.0, 0.0, 0.0 }; //coordinate of the principle intersection point /////////////////calculating the camera position for the center (principal scan line) pos0[1] = ui.GetDouble("LON_NADIR")*deg2rad; pos0[0] = ui.GetDouble("LAT_NADIR")*deg2rad; pos0[2] = ui.GetDouble("CRAFT_ALTITUDE"); //units are km Geographic2GeocentricLunar(pos0,pos0); //function is written so the input can also be the // output /////////////////////calculating the camera orientation for the center (principal) scan line pInt[1] = ui.GetDouble("LON_INT")*deg2rad; pInt[0] = ui.GetDouble("LAT_INT")*deg2rad; pInt[2] = 0.0; Geographic2GeocentricLunar(pInt,pInt); //function is written so the input can also be the output //calculate the unit look direction vector in object space look[0] = -pos0[0] + pInt[0]; look[1] = -pos0[1] + pInt[1]; look[2] = -pos0[2] + pInt[2]; temp = sqrt(look[0]*look[0] + look[1]*look[1] + look[2]*look[2]); look[0] /= temp; look[1] /= temp; look[2] /= temp; //the local normal vector is equal to pInt0/|pInt0| temp = sqrt(pInt[0]*pInt[0] + pInt[1]*pInt[1] + pInt[2]*pInt[2]); norm[0] = pInt[0]/temp; norm[1] = pInt[1]/temp; norm[2] = pInt[2]/temp; //omega and phi are defined so that M(phi)M(omega)look = [0 0 -1] leaving only the roation // around z axis to be found omega = -atan2(look[1], look[2]); //omega rotation to zero look[1] phi = atan2(-look[0], sin(omega)*look[1] - cos(omega)*look[2]); //phi rotation to zero look[0] //use the horizontal velocity vector direction to solve for the last rotation; we will make the // image x axis parallel to the in-image-plane projection of the horizontal direction of flight. // The local normal cross the selenogrpahic z gives northPN (normal to the plane containing all // the north/south directions), that is, the plane containing the origin, the z axis, and the // primary point of intersection. crossp(northPN,norm,northL); //The normal to the plane containing all the north/south directions cross the local normal // direction gives the local north/south direction in the local normal plane crossp(norm, zDir, northPN); if (northL[2] < 0) { //if by chance we got the south direction change the signs northL[0] = -northL[0]; northL[1] = -northL[1]; northL[2] = -northL[2]; } //define the rotation matrix to convert northL to the azimuth of flight. // A left handed rotation of "VEL_AZM" around the positive normal direction will convert northL // to azm MfromVecLeftAngle(M,norm,ui.GetDouble("VEL_AZM")*deg2rad); azm[0] = M[0][0]*northL[0] + M[0][1]*northL[1] + M[0][2]*northL[2]; azm[1] = M[1][0]*northL[0] + M[1][1]*northL[1] + M[1][2]*northL[2]; azm[2] = M[2][0]*northL[0] + M[2][1]*northL[1] + M[2][2]*northL[2]; //apply the two rotations we already know MfromLeftEulers(M,omega,phi,0.0); azmP[0] = M[0][0]*azm[0] + M[0][1]*azm[1] + M[0][2]*azm[2]; azmP[1] = M[1][0]*azm[1] + M[1][1]*azm[1] + M[1][2]*azm[2]; azmP[2] = M[2][0]*azm[2] + M[2][1]*azm[1] + M[2][2]*azm[2]; //subtract that portion of the azm that is perpindicular to the image plane (also the portion // which is parallel to look) making azm a vector parrallel to the image plane // Further, since we're now rotated into some coordinate system that differs from // the image coordinate system by only a kappa rotation making the vector parrallel to the // image plan is as simple as zeroing the z component (and as pointless to further calculations // as a nat's fart in hurricane) nevertheless it completes the logical transition azmP[2] = 0.0; //finally the kappa rotation that will make azmP parallel (including sign) to the camera x axis kappa = -atan2(-azmP[1], azmP[0]); ////////////////////Add an instrument position table //Define the table records TableRecord recordPos; // reacord to be added to table // add x,y,z position labels and ephemeris time et to record TableField x("J2000X", TableField::Double); TableField y("J2000Y", TableField::Double); TableField z("J2000Z", TableField::Double); TableField t("ET", TableField::Double); recordPos += x; recordPos += y; recordPos += z; recordPos += t; Table tablePos("InstrumentPosition", recordPos); //now that the azm and norm vectors are defined // the total velocity vector can be calcualted (km/sec) vel[0] = horV*azm[0] + radV * norm[0]; vel[1] = horV*azm[1] + radV * norm[1]; vel[2] = horV*azm[2] + radV * norm[2]; //we'll provide a two ellement table (more is redundant because the motion is modeled as linear // at this point) we'll extend the nodes 3% beyond the edges of the images to be sure // rounding errors don't cause problems temp = 0.515*(time1-time0); //3% extension posSel[0] = pos0[0] - temp*vel[0]; //selenocentric coordinate calculation posSel[1] = pos0[1] - temp*vel[1]; posSel[2] = pos0[2] - temp*vel[2]; //converting to J2000 temp = time0 - 0.005*(time1-time0); //et just before the first scan line spPos->SetEphemerisTime(temp); spRot->SetEphemerisTime(temp); //Despite being labeled as J2000, the coordinates for the instrument position are in fact in // target centric coordinated rotated to a system centered at the target with aces parallel // to J2000, whatever that means posJ20 = spRot->J2000Vector(posSel); //J2000Vector calls rotates the position vector into J2000, // completing the transformation recordPos[0] = posJ20[0]; recordPos[1] = posJ20[1]; recordPos[2] = posJ20[2]; recordPos[3] = temp; //temp = et (right now anyway) tablePos += recordPos; tablePos.Label() += PvlKeyword("SpkTableStartTime",toString(temp)); //now the other node temp = 0.515*(time1-time0); //3% extension posSel[0] = pos0[0] + temp*vel[0]; //selenocentric coordinate calculation posSel[1] = pos0[1] + temp*vel[1]; posSel[2] = pos0[2] + temp*vel[2]; //converting to J2000 temp = time1 + 0.015*(time1-time0); //et just after the last scan line spPos->SetEphemerisTime(temp); spRot->SetEphemerisTime(temp); //Despite being labeled as J2000, the coordinates for the instrument position are in fact // in target centric coordinated rotated to a system centered at the target with aces // parallel to J2000, whatever that means posJ20 = spRot->J2000Vector(posSel); //J2000Vector calls rotates the position vector into J2000, // completing the transformation recordPos[0] = posJ20[0]; recordPos[1] = posJ20[1]; recordPos[2] = posJ20[2]; recordPos[3] = temp; //temp = et (right now anyway) tablePos += recordPos; tablePos.Label() += PvlKeyword("SpkTableEndTime",toString(temp)); tablePos.Label() += PvlKeyword("CacheType","Linear"); tablePos.Label() += PvlKeyword("Description","Created by apollopaninit"); panCube.write(tablePos); //now attach it to the table /////////////////////////////attach a camera pointing table double cacheSlope, //time between epoches in the table rollComb, //magnitude of roll relative to the center in the middle of the epoch relT, //relative time at the center of each epoch Q[NODES][5], //NODES four ellement unit quarternions and et (to be calculated). gimVec[3], //the direction of the gimbal rotation vector (to the cameras persepective // this is always changing because the camera is mounted to the roll frame // assembly which is mounted to the gimbal) M0[3][3], //rotation matrix of the previous epoch Mtemp1[3][3], //intermediate step in the multiplication of rotation matricies Mtemp2[3][3], //intermediate step in the multiplication of rotation matricies Mdg[3][3], //incremental rotation due the the gimbal motion in the camera frame Mdr[3][3]; //the contribution of the roll motion in the camera frame during time // cacheSlope std::vector <double> M_J2toT; //rotation matrix from J2000 to the target frame M_J2toT.resize(9); //Table Definition TableField q0("J2000Q0", TableField::Double); TableField q1("J2000Q1", TableField::Double); TableField q2("J2000Q2", TableField::Double); TableField q3("J2000Q3", TableField::Double); TableField et("ET", TableField::Double); TableRecord recordRot; recordRot += q0; recordRot += q1; recordRot += q2; recordRot += q3; recordRot += et; Table tableRot("InstrumentPointing",recordRot); //From the cameras perspective the gimbal motion is around a constantly changing axis, // this is handled by combining a series of incremental rotations MfromLeftEulers(M0, omega, phi, kappa); //rotation matrix in the center Q[(NOPDES-1)/2] spRot->SetEphemerisTime(isisTime.Et()); M_J2toT = spRot->Matrix(); //this actually gives the rotation from J2000 to target centric for(j=0; j<3; j++) //reformating M_J2toT to a 3x3 for(k=0; k<3; k++) Mtemp1[j][k] = M_J2toT[3*j+k]; mxm_c(M0, Mtemp1, Mtemp2); M2Q(Mtemp2, Q[(NODES-1)/2]); //save the middle scan line quarternion Q[(NODES-1)/2][4] = (time1 + time0)/2.0; //time in the center of the image //the total time is scaled up slightly so that nodes will extend just beyond the edge of the image cacheSlope = 1.03*(time1 - time0)/(NODES-1); //Mdr is constant for all the forward time computations MfromLeftEulers(Mdr,cacheSlope*rollV,0.0,0.0); for (i=(NODES-1)/2+1; i<NODES; i++) { //moving foward in time first Q[i][4] = Q[i-1][4] + cacheSlope; //new time epoch //epoch center time relative to the center line relT = double(i - (NODES-1)/2 - 0.5)*cacheSlope; rollComb = relT*rollV; gimVec[0] = 0.0; //gimbal rotation vector direction in the middle of the epoch gimVec[1] = cos(rollComb); gimVec[2] = -sin(rollComb); //incremental rotation due to the gimbal (forward motion compensation) MfromVecLeftAngle(Mdg, gimVec, fmc*cacheSlope); //the new rotation matrix is Transpose(Mdr)*Transpose(Mdg)*M0--NOTE the order swap and // transposes are needed because both Mdr and Mdg were caculated in image space and need to be // transposed to apply to object space mtxm_c(Mdg, M0, Mtemp1); //M0 is now what would typically be considered the rotation matrix of an image. It rotates a // vector from the target centric space into camera space. However, what is standard to // include in the cube labels is a rotation from camera space to J2000. M0 is therefore the // transpose of the first part of this rotation. Transpose(M0) is the rotation from camera // space to target centric space mtxm_c(Mdr, Mtemp1, M0); //now adding the rotation from the target frame to J2000 spRot->SetEphemerisTime(Q[i][4]); //this actually gives the rotation from J2000 to target centric--hence the mxmt_c function being // used later M_J2toT = spRot->Matrix(); for(j=0; j<3; j++) //reformating M_J2toT to a 3x3 for(k=0; k<3; k++) Mtemp1[j][k] = M_J2toT[3*j+k]; mxm_c(M0, Mtemp1, Mtemp2); M2Q(Mtemp2, Q[i]); //convert to a quarterion } MfromLeftEulers(M0, omega, phi, kappa); //rotation matrix in the center Q[(NOPDES-1)/2] //Mdr is constant for all the backward time computations MfromLeftEulers(Mdr, -cacheSlope*rollV, 0.0, 0.0); for (i=(NODES-1)/2-1; i>=0; i--) { //moving backward in time Q[i][4] = Q[i+1][4] - cacheSlope; //new time epoch //epoch center time relative to the center line relT = double(i - (NODES-1)/2 + 0.5)*cacheSlope; rollComb = relT*rollV; gimVec[0] = 0.0; //gimbal rotation vector direction in the middle of the epoch gimVec[1] = cos(rollComb); gimVec[2] = -sin(rollComb); //incremental rotation due to the gimbal (forward motion compensation) MfromVecLeftAngle(Mdg, gimVec, -fmc*cacheSlope); //the new rotation matrix is Transpose(Mdr)*Transpose(Mdg)*M0 NOTE the order swap and // transposes are needed because both Mdr and Mdg were caculated in image space and need to be // transposed to apply to object space mtxm_c(Mdg, M0, Mtemp1); //M0 is now what would typically be considered the rotation matrix of an image. It rotates a // vector from the target centric space into camera space. However, what is standard to // include in the cube labels is a rotation from camera space to J2000. M0 is therefore the // transpose of the first part of this rotation. Transpose(M0) is the rotation from camera // space to target centric space mtxm_c(Mdr, Mtemp1, M0); //now adding the rotation from the target frame to J2000 spRot->SetEphemerisTime(Q[i][4]); M_J2toT = spRot->Matrix(); for(j=0; j<3; j++) //reformating M_J2toT to a 3x3 for(k=0; k<3; k++) Mtemp1[j][k] = M_J2toT[3*j+k]; mxm_c(M0, Mtemp1, Mtemp2); M2Q(Mtemp2, Q[i]); //convert to a quarterion } //fill in the table for (i=0; i<NODES; i++) { recordRot[0] = Q[i][0]; recordRot[1] = Q[i][1]; recordRot[2] = Q[i][2]; recordRot[3] = Q[i][3]; recordRot[4] = Q[i][4]; tableRot += recordRot; } tableRot.Label() += PvlKeyword("CkTableStartTime", toString(Q[0][4])); tableRot.Label() += PvlKeyword("CkTableEndTime", toString(Q[NODES-1][4])); tableRot.Label() += PvlKeyword("Description", "Created by appollopan2isis"); keyword.setName("TimeDependentFrames"); keyword.setValue(toString(scFrameCode)); keyword.addValue("1"); tableRot.Label() += keyword; keyword.setName("ConstantFrames"); keyword.setValue(toString(insCode)); keyword.addValue(toString(scFrameCode)); tableRot.Label() += keyword; keyword.setName("ConstantRotation"); keyword.setValue("1"); for (i=1;i<9;i++) if (i%4 == 0) keyword.addValue("1"); else keyword.addValue("0"); tableRot.Label() += keyword; panCube.write(tableRot); /////////////////////////Attach a table with all the measurements of the fiducial mark locations. Chip patternS,searchS; //scaled pattern and search chips Cube fidC; //Fiducial image //line and sample coordinates for looping through the panCube double l=1,s=1,sample,line,sampleInitial=1,lineInitial=1,play; int regStatus, fidn, panS, refL, //number of lines in the patternS refS; //number of samples in the patternS Pvl pvl; bool foundFirst=false; QString fileName; panS = panCube.sampleCount(); //Table definition TableRecord recordFid; TableField indexFid("FID_INEX",TableField::Integer); TableField xFid("X_COORD",TableField::Double); TableField yFid("Y_COORD",TableField::Double); recordFid += indexFid; recordFid += xFid; recordFid += yFid; Table tableFid("Fiducial Measurement",recordFid); //read the image resolutions and scale the constants acordingly double resolution = ui.GetDouble("MICRONS"), //pixel size in microns scale = SCALE *5.0/resolution, //reduction scale for fast autoregistrations searchHeight = SEARCHh*5.0/resolution, //number of lines (in 5-micron-pixels) in // search space for the first fiducial searchCellSize = SEARCHc*5.0/resolution, //height/width of search chips block averageSamples = AVERs *5.0/resolution, //scaled smaples between fiducials averageLines = AVERl *5.0/resolution; //scaled average distance between the top and //bottom fiducials if( 15.0/resolution < 1.5) play=1.5; else play = 15.0/resolution; //copy the patternS chip (the entire ApolloPanFiducialMark.cub) FileName fiducialFileName("$apollo15/calibration/ApolloPanFiducialMark.cub"); fidC.open(fiducialFileName.expanded(),"r"); if( !fidC.isOpen() ) { QString msg = "Unable to open the fiducial patternS cube: ApolloPanFiducialMark.cub\n"; throw IException(IException::User, msg, _FILEINFO_); } refL = fidC.lineCount(); refS = fidC.sampleCount(); //scaled pattern chip for fast matching patternS.SetSize(int((refS-2)/SCALE), int((refL-2)/SCALE)); patternS.TackCube((refS-1)/2, (refL-1)/2); patternS.Load(fidC, 0, SCALE); //parameters for maximum correlation autoregestration // see: file:///usgs/pkgs/isis3nightly2011-09-21/isis/doc/documents/patternSMatch/patternSMatch.html#DistanceTolerance FileName fiducialPvl("$apollo15/templates/apolloPanFiducialFinder.pvl"); pvl.read(fiducialPvl.expanded()); //read in the autoreg parameters AutoReg *arS = AutoRegFactory::Create(pvl); *arS->PatternChip() = patternS; //patternS chip is constant //set up a centroid measurer CentroidApolloPan centroid(resolution); Chip inputChip,selectionChip; inputChip.SetSize(int(ceil(200*5.0/resolution)), int(ceil(200*5.0/resolution))); fileName = ui.GetFileName("FROM"); if( panCube.pixelType() == 1) //UnsignedByte centroid.setDNRange(12, 1e99); //8 bit bright target else centroid.setDNRange(3500, 1e99); //16 bit bright target Progress progress; progress.SetText("Locating Fiducials"); progress.SetMaximumSteps(91); //Search for the first fiducial, search sizes are constanst searchS.SetSize(int(searchCellSize/scale),int(searchCellSize/scale)); //now start searching along a horizontal line for the first fiducial mark for(l = searchCellSize/2; l<searchHeight+searchCellSize/2.0 && !foundFirst; l+=searchCellSize-125*5.0/resolution) { for (s = searchCellSize/2; s < averageSamples + searchCellSize/2.0 && !foundFirst; s += searchCellSize-125*5.0/resolution) { searchS.TackCube(s, l); searchS.Load(panCube, 0, scale); *arS->SearchChip() = searchS; regStatus = arS->Register(); if (regStatus == AutoReg::SuccessPixel) { inputChip.TackCube(arS->CubeSample(), arS->CubeLine()); inputChip.Load(panCube, 0, 1); inputChip.SetCubePosition(arS->CubeSample(), arS->CubeLine()); //continuous dynamic range selection centroid.selectAdaptive(&inputChip, &selectionChip); //elliptical trimming/smoothing if (centroid.elipticalReduction(&selectionChip, 95, play, 2000)) { //center of mass to reduce selection to a single measure centroid.centerOfMass(&selectionChip, &sample, &line); inputChip.SetChipPosition(sample, line); sampleInitial = inputChip.CubeSample(); lineInitial = inputChip.CubeLine(); foundFirst = true; //once the first fiducial is found stop } } } } if(s>=averageLines+searchCellSize/2.0) { QString msg = "Unable to locate a fiducial mark in the input cube [" + fileName + "]. Check FROM and MICRONS parameters."; throw IException(IException::Io, msg, _FILEINFO_); return; } progress.CheckStatus(); //record first fiducial measurement in the table recordFid[0] = 0; recordFid[1] = sampleInitial; recordFid[2] = lineInitial; tableFid += recordFid; for (s= sampleInitial, l=lineInitial, fidn=0; s<panS; s+=averageSamples, fidn++) { //corrections for half spacing of center fiducials if (fidn == 22) s -= averageSamples/2.0; if (fidn == 23) s -= averageSamples/2.0; //look for the bottom fiducial searchS.TackCube(s,l+averageLines); searchS.Load(panCube, 0, scale); *arS->SearchChip() = searchS; regStatus = arS->Register(); if (regStatus == AutoReg::SuccessPixel) { inputChip.TackCube(arS->CubeSample(), arS->CubeLine()); inputChip.Load(panCube,0,1); inputChip.SetCubePosition(arS->CubeSample(), arS->CubeLine()); } else { //if autoreg is unsuccessful, a larger window will be used inputChip.TackCube(s, l+averageLines); inputChip.Load(panCube, 0, 1); inputChip.SetCubePosition(s, l+averageLines); } centroid.selectAdaptive(&inputChip, &selectionChip); //continuous dynamic range selection //elliptical trimming/smoothing... if this fails move on if (centroid.elipticalReduction(&selectionChip, 95, play, 2000) != 0 ) { //center of mass to reduce selection to a single measure centroid.centerOfMass(&selectionChip, &sample, &line); inputChip.SetChipPosition(sample, line); sample = inputChip.CubeSample(); line = inputChip.CubeLine(); recordFid[0] = fidn*2+1; recordFid[1] = sample; recordFid[2] = line; tableFid += recordFid; } progress.CheckStatus(); //look for the top fiducial if (s == sampleInitial) //first time through the loop? continue; //then the top fiducial was already found searchS.TackCube(s, l); searchS.Load(panCube, 0, scale); *arS->SearchChip() = searchS; regStatus = arS->Register(); if (regStatus == AutoReg::SuccessPixel) { inputChip.TackCube(arS->CubeSample(), arS->CubeLine()); inputChip.Load(panCube, 0, 1); inputChip.SetCubePosition(arS->CubeSample(), arS->CubeLine()); } else { //if autoreg is unsuccessful, a larger window will be used inputChip.TackCube(s, l); inputChip.Load(panCube, 0, 1); inputChip.SetCubePosition(s, l); } centroid.selectAdaptive(&inputChip, &selectionChip);//continuous dynamic range selection //inputChip.Write("inputTemp.cub");//debug //selectionChip.Write("selectionTemp.cub");//debug //elliptical trimming/smoothing... if this fails move on if (centroid.elipticalReduction(&selectionChip, 95, play, 2000) !=0) { //center of mass to reduce selection to a single measure centroid.centerOfMass(&selectionChip, &sample, &line); inputChip.SetChipPosition(sample, line); //when finding the top fiducial both s and l are refined for a successful measurement, // this will help follow trends in the scaned image s = inputChip.CubeSample(); l = inputChip.CubeLine(); recordFid[0] = fidn*2; recordFid[1] = s; recordFid[2] = l; tableFid += recordFid; } progress.CheckStatus(); } panCube.write(tableFid); //close the new cube panCube.close(false); panCube.open(ui.GetFileName("FROM"),"rw"); delete spPos; delete spRot; //now instantiate a camera to make sure all of this is working ApolloPanoramicCamera* cam = (ApolloPanoramicCamera*)(panCube.camera()); //log the residual report from interior orientation PvlGroup residualStats("InteriorOrientationStats"); residualStats += PvlKeyword("FiducialsFound", toString(tableFid.Records())); residualStats += PvlKeyword("ResidualMax", toString(cam->intOriResidualMax()),"pixels"); residualStats += PvlKeyword("ResidualMean", toString(cam->intOriResidualMean()),"pixels"); residualStats += PvlKeyword("ResidualStdev", toString(cam->intOriResidualStdev()),"pixels"); Application::Log( residualStats ); return; }