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(); }
/** 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(); }