USGS

Isis 3.0 Application Source Code Reference

Home

autoseed.cpp

Go to the documentation of this file.
00001 #include "Isis.h"
00002 
00003 #include <map>
00004 #include <sstream>
00005 
00006 #include <QString>
00007 
00008 #include "geos/util/GEOSException.h"
00009 
00010 #include "Brick.h"
00011 #include "CameraFactory.h"
00012 #include "ControlMeasure.h"
00013 #include "ControlNet.h"
00014 #include "ControlPoint.h"
00015 #include "Cube.h"
00016 #include "ID.h"
00017 #include "ImageOverlap.h"
00018 #include "ImageOverlapSet.h"
00019 #include "ImagePolygon.h"
00020 #include "PolygonSeeder.h"
00021 #include "PolygonSeederFactory.h"
00022 #include "PolygonTools.h"
00023 #include "Process.h"
00024 #include "Pvl.h"
00025 #include "PvlGroup.h"
00026 #include "PvlKeyword.h"
00027 #include "SerialNumberList.h"
00028 #include "SpecialPixel.h"
00029 #include "UniversalGroundMap.h"
00030 #include "iException.h"
00031 #include "iString.h"
00032 
00033 enum SeedDomain {
00034   XY,
00035   SampleLine
00036 };
00037 
00038 
00039 using namespace std;
00040 using namespace Isis;
00041 
00042 void IsisMain() {
00043 
00044   UserInterface &ui = Application::GetUserInterface();
00045   SerialNumberList serialNumbers(ui.GetFilename("FROMLIST"));
00046 
00047   // Get the AutoSeed PVL internalized
00048   Pvl seedDef(ui.GetFilename("DEFFILE"));
00049 
00050   PolygonSeeder *seeder = PolygonSeederFactory::Create(seedDef);
00051   Pvl invalidInput = seeder->InvalidInput();
00052   PvlGroup &unusedDefKeywords = invalidInput.FindGroup(
00053                                   "PolygonSeederAlgorithm", Pvl::Traverse);
00054 
00055   // Get the distance from the edge of an image a measure must be
00056   double pixelsFromEdge = -1.0;
00057   if(seedDef.HasKeyword("PixelsFromEdge", Pvl::Traverse)) {
00058     pixelsFromEdge = seedDef.FindKeyword("PixelsFromEdge", Pvl::Traverse);
00059     if(unusedDefKeywords.HasKeyword("PixelsFromEdge"))
00060       unusedDefKeywords.DeleteKeyword("PixelsFromEdge");
00061   }
00062 
00063   // Get the Emission range
00064   double minEmission = 0.0;
00065   double maxEmission = 180.0;
00066   if(seedDef.HasKeyword("MinEmission", Pvl::Traverse)) {
00067     minEmission = seedDef.FindKeyword("MinEmission", Pvl::Traverse);
00068     if(unusedDefKeywords.HasKeyword("MinEmission"))
00069       unusedDefKeywords.DeleteKeyword("MinEmission");
00070   }
00071   if(seedDef.HasKeyword("MaxEmission", Pvl::Traverse)) {
00072     maxEmission = seedDef.FindKeyword("MaxEmission", Pvl::Traverse);
00073     if(unusedDefKeywords.HasKeyword("MaxEmission"))
00074       unusedDefKeywords.DeleteKeyword("MaxEmission");
00075   }
00076 
00077   // Get the Incidence range
00078   double minIncidence = 0.0;
00079   double maxIncidence = 180.0;
00080   if(seedDef.HasKeyword("MinIncidence", Pvl::Traverse)) {
00081     minIncidence = seedDef.FindKeyword("MinIncidence", Pvl::Traverse);
00082     if(unusedDefKeywords.HasKeyword("MinIncidence"))
00083       unusedDefKeywords.DeleteKeyword("MinIncidence");
00084   }
00085   if(seedDef.HasKeyword("MaxIncidence", Pvl::Traverse)) {
00086     maxIncidence = seedDef.FindKeyword("MaxIncidence", Pvl::Traverse);
00087     if(unusedDefKeywords.HasKeyword("MaxIncidence"))
00088       unusedDefKeywords.DeleteKeyword("MaxIncidence");
00089   }
00090 
00091   // Get the DN range
00092   bool hasDNRestriction = false;
00093   double minDN = -DBL_MAX;
00094   double maxDN = DBL_MAX;
00095   if(seedDef.HasKeyword("MinDN", Pvl::Traverse)) {
00096     minDN = seedDef.FindKeyword("MinDN", Pvl::Traverse);
00097     hasDNRestriction = true;
00098     if(unusedDefKeywords.HasKeyword("MinDN"))
00099       unusedDefKeywords.DeleteKeyword("MinDN");
00100   }
00101   if(seedDef.HasKeyword("MaxDN", Pvl::Traverse)) {
00102     maxDN = seedDef.FindKeyword("MaxDN", Pvl::Traverse);
00103     hasDNRestriction = true;
00104     if(unusedDefKeywords.HasKeyword("MaxDN"))
00105       unusedDefKeywords.DeleteKeyword("MaxDN");
00106   }
00107 
00108   // Get the resolution
00109   double minResolution = 0.0;
00110   double maxResolution = 0.0;
00111   if(seedDef.HasKeyword("MinResolution", Pvl::Traverse)) {
00112     minResolution  = seedDef.FindKeyword("MinResolution", Pvl::Traverse);
00113     if(unusedDefKeywords.HasKeyword("MinResolution"))
00114       unusedDefKeywords.DeleteKeyword("MinResolution");
00115   }
00116   if(seedDef.HasKeyword("MaxResolution", Pvl::Traverse)) {
00117     maxResolution  = seedDef.FindKeyword("MaxResolution", Pvl::Traverse);
00118     if(unusedDefKeywords.HasKeyword("MaxResolution"))
00119       unusedDefKeywords.DeleteKeyword("MaxResolution");
00120   }
00121 
00122   // Get seed domain for unit conversion, no keyword == XY
00123   SeedDomain seedDomain = XY;
00124   if(seedDef.HasKeyword("SeedDomain", Pvl::Traverse)) {
00125     iString domain = (std::string) seedDef.FindKeyword("SeedDomain", Pvl::Traverse);
00126     if(unusedDefKeywords.HasKeyword("SeedDomain"))
00127       unusedDefKeywords.DeleteKeyword("SeedDomain");
00128 
00129     if(domain.UpCase() == "SAMPLELINE") {
00130       seedDomain = SampleLine;
00131     }
00132     else if(domain.UpCase() != "XY") {
00133       iString msg = "Invalid value provided for keywork [SeedDomain]";
00134       msg += " Possible values include [XY, SampleLine]";
00135       throw iException::Message(iException::User, msg, _FILEINFO_);
00136     }
00137   }
00138 
00139   // Grab the labels from the first filename in the SerialNumberList to get
00140   // some info
00141   Pvl cubeLab(serialNumbers.Filename(0));
00142 
00143   // Construct a Projection for converting between Lon/Lat and X/Y
00144   // This is used inside the seeding algorithms.
00145   // Note: Should this be an option to include this in the program?
00146   PvlGroup inst = cubeLab.FindGroup("Instrument", Pvl::Traverse);
00147   string target = inst["TargetName"];
00148   PvlGroup radii = Projection::TargetRadii(target);
00149   Isis::Pvl maplab;
00150   maplab.AddGroup(Isis::PvlGroup("Mapping"));
00151   Isis::PvlGroup &mapGroup = maplab.FindGroup("Mapping");
00152   mapGroup += Isis::PvlKeyword("EquatorialRadius", (string)radii["EquatorialRadius"]);
00153   mapGroup += Isis::PvlKeyword("PolarRadius", (string)radii["PolarRadius"]);
00154   mapGroup += Isis::PvlKeyword("LatitudeType", "Planetocentric");
00155   mapGroup += Isis::PvlKeyword("LongitudeDirection", "PositiveEast");
00156   mapGroup += Isis::PvlKeyword("LongitudeDomain", 360);
00157   mapGroup += Isis::PvlKeyword("CenterLatitude", 0);
00158   mapGroup += Isis::PvlKeyword("CenterLongitude", 0);
00159   mapGroup += Isis::PvlKeyword("ProjectionName", "Sinusoidal");
00160 
00161   //PolygonSeeder *seeder = PolygonSeederFactory::Create(seedDef);
00162 
00163   Projection *proj = NULL;
00164   UniversalGroundMap *ugmap = NULL;
00165   if(seedDomain == XY) {
00166     proj = Isis::ProjectionFactory::Create(maplab);
00167   }
00168   else if(seedDomain == SampleLine) {
00169     Cube cube;
00170     cube.open(serialNumbers.Filename(0));
00171     ugmap = new UniversalGroundMap(*cube.getLabel());
00172   }
00173 
00174   // Create the control net to store the points in.
00175   ControlNet cnet;
00176   cnet.SetTarget(target);
00177   cnet.SetNetworkId(ui.GetString("NETWORKID"));
00178   cnet.SetUserName(Isis::Application::UserName());
00179   cnet.SetDescription(ui.GetString("DESCRIPTION"));
00180 
00181   // Set up an automatic id generator for the point ids
00182   ID pointId = ID(ui.GetString("POINTID"));
00183 
00184   // Find all the overlaps between the images in the FROMLIST
00185   // The overlap polygon coordinates are in Lon/Lat order
00186   ImageOverlapSet overlaps;
00187   overlaps.ReadImageOverlaps(ui.GetFilename("OVERLAPLIST"));
00188 
00189   // Create a Universal Ground Map (UGM) for each image in the list
00190   int stats_noOverlap = 0;
00191   int stats_tolerance = 0;
00192 
00193   map<std::string, UniversalGroundMap *> gMaps;
00194   for(int sn = 0; sn < serialNumbers.Size(); ++sn) {
00195     // Create the UGM for the cube associated with this SN
00196     Pvl lab = Pvl(serialNumbers.Filename(sn));
00197     gMaps.insert(std::pair<std::string, UniversalGroundMap *>
00198                  (serialNumbers.SerialNumber(sn), new UniversalGroundMap(lab)));
00199   }
00200 
00201   stringstream errors(stringstream::in | stringstream::out);
00202   int errorNum = 0;
00203 
00204   // Process each overlap area
00205   //   Seed measurments into it
00206   //   Store the measurments in the control network
00207 
00208   bool previousControlNet = ui.WasEntered("CNET");
00209 
00210   vector< geos::geom::Point *> points;
00211   if(previousControlNet) {
00212 
00213     ControlNet precnet(ui.GetFilename("CNET"));
00214 
00215     Progress progress;
00216     progress.SetText("Calculating Provided Control Net");
00217     progress.SetMaximumSteps(precnet.GetNumPoints());
00218     progress.CheckStatus();
00219 
00220     for(int i = 0 ; i < precnet.GetNumPoints(); i ++) {
00221       ControlPoint *cp = precnet.GetPoint(i);
00222       ControlMeasure *cm = cp->GetRefMeasure();
00223       iString c = serialNumbers.Filename(cm->GetCubeSerialNumber());
00224       Pvl cubepvl(c);
00225       Camera *cam = CameraFactory::Create(cubepvl);
00226       cam->SetImage(cm->GetSample(), cm->GetLine());
00227 
00228 
00229       points.push_back(Isis::globalFactory.createPoint(geos::geom::Coordinate(
00230                          cam->UniversalLongitude(), cam->UniversalLatitude())));
00231 
00232       delete cam;
00233       cam = NULL;
00234 
00235       progress.CheckStatus();
00236     }
00237 
00238   }
00239 
00240   Progress progress;
00241   progress.SetText("Seeding Points");
00242   progress.SetMaximumSteps(overlaps.Size());
00243   progress.CheckStatus();
00244 
00245   int cpIgnoredCount = 0;
00246   int cmIgnoredCount = 0;
00247 
00248   for(int ov = 0; ov < overlaps.Size(); ++ov) {
00249     progress.CheckStatus();
00250 
00251     if(overlaps[ov]->Size() == 1) {
00252       stats_noOverlap++;
00253       continue;
00254     }
00255 
00256     // Checks if this overlap was already seeded
00257     if(previousControlNet) {
00258 
00259       // Grabs the Multipolygon's Envelope for Lat/Lon comparison
00260       const geos::geom::MultiPolygon *lonLatPoly = overlaps[ov]->Polygon();
00261 
00262       bool overlapSeeded = false;
00263       for(unsigned int j = 0; j < lonLatPoly->getNumGeometries()  &&  !overlapSeeded; j ++) {
00264         const geos::geom::Geometry *lonLatGeom = lonLatPoly->getGeometryN(j);
00265 
00266         // Checks if Control Point is in the MultiPolygon using Lon/Lat
00267         for(unsigned int i = 0 ; i < points.size()  &&  !overlapSeeded; i ++) {
00268           if(lonLatGeom->contains(points[i])) overlapSeeded = true;
00269         }
00270       }
00271 
00272       if(overlapSeeded) continue;
00273     }
00274 
00275     // Seed this overlap with points
00276     const geos::geom::MultiPolygon *polygonOverlaps = overlaps[ov]->Polygon();
00277     std::vector<geos::geom::Point *> points;
00278 
00279     try {
00280       geos::geom::MultiPolygon *mp = NULL;
00281       if(seedDomain == XY) {
00282         mp = PolygonTools::LatLonToXY(*polygonOverlaps, proj);
00283       }
00284       else if(seedDomain == SampleLine) {
00285         mp = PolygonTools::LatLonToSampleLine(*polygonOverlaps, ugmap);
00286       }
00287       points = seeder->Seed(mp);
00288     }
00289     catch(iException &e) {
00290 
00291       if(ui.WasEntered("ERRORS")) {
00292 
00293         if(errorNum > 0) {
00294           errors << endl;
00295         }
00296         errorNum ++;
00297 
00298         errors << e.PvlErrors().Group(0).FindKeyword("Message")[0];
00299         for(int serNum = 0; serNum < overlaps[ov]->Size(); serNum++) {
00300           if(serNum == 0) {
00301             errors << ": ";
00302           }
00303           else {
00304             errors << ", ";
00305           }
00306           errors << (*overlaps[ov])[serNum];
00307         }
00308       }
00309 
00310       e.Clear();
00311       continue;
00312     }
00313 
00314     // No points were seeded in this polygon, so collect some stats and move on
00315     if(points.size() == 0) {
00316       stats_tolerance++;
00317       continue;
00318     }
00319 
00320     vector<geos::geom::Point *> seed;
00321     if(seedDomain == XY) {
00322       // Convert the X/Y points back to Lat/Lon points
00323       for(unsigned int pt = 0; pt < points.size(); pt ++) {
00324         if(proj->SetCoordinate(points[pt]->getX(), points[pt]->getY())) {
00325           seed.push_back(Isis::globalFactory.createPoint(
00326                            geos::geom::Coordinate(proj->UniversalLongitude(),
00327                                                   proj->UniversalLatitude())));
00328         }
00329         else {
00330           iString msg = "Unable to convert from X/Y to a (lon,lat)";
00331           throw iException::Message(iException::Programmer, msg, _FILEINFO_);
00332         }
00333       }
00334     }
00335     else if(seedDomain == SampleLine) {
00336       // Convert the Sample/Line points back to Lat/Lon points
00337       for(unsigned int pt = 0; pt < points.size(); pt ++) {
00338         if(ugmap->SetImage(points[pt]->getX(), points[pt]->getY())) {
00339           seed.push_back(Isis::globalFactory.createPoint(
00340                            geos::geom::Coordinate(ugmap->UniversalLongitude(),
00341                                                   ugmap->UniversalLatitude())));
00342         }
00343         else {
00344           iString msg = "Unable to convert from Sample/Line to a (lon,lat)";
00345           throw iException::Message(iException::Programmer, msg, _FILEINFO_);
00346         }
00347       }
00348     }
00349 
00350     //   Create a control point for each seeded point in this overlap
00351     for(unsigned int point = 0; point < seed.size(); ++point) {
00352 
00353       ControlPoint *controlpt = new ControlPoint();
00354       controlpt->SetId(QString::fromStdString(pointId.Next()));
00355       controlpt->SetType(ControlPoint::Free);
00356 
00357       // Create a measurment at this point for each image in the overlap area
00358       for(int sn = 0; sn < overlaps[ov]->Size(); ++sn) {
00359         bool ignore = false;
00360 
00361         // Get the line/sample of the lat/lon for this cube
00362         UniversalGroundMap *gmap = gMaps[(*overlaps[ov])[sn]];
00363 
00364         if(!gmap) {
00365           std::string msg = "Unable to create a Universal Ground for Serial Number [";
00366           msg += (*overlaps[ov])[sn] + "] The associated image is more than ";
00367           msg += "likely missing from your FROMLIST.";
00368           throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_);
00369         }
00370 
00371         if(!gmap->SetUniversalGround(seed[point]->getY(), seed[point]->getX())) {
00372           // This error is more than likely due to floating point roundoff
00373           continue;
00374         }
00375 
00376         // Check the line/sample with the gmap for image edge
00377         if(pixelsFromEdge > gmap->Sample() || pixelsFromEdge > gmap->Line()
00378             || gmap->Sample() > gmap->Camera()->Samples() - pixelsFromEdge
00379             || gmap->Line() > gmap->Camera()->Lines() - pixelsFromEdge) {
00380           ignore = true;
00381         }
00382 
00383         // Check the Emission/Incidence Angle with the camera from the gmap
00384         if(gmap->Camera()->EmissionAngle() < minEmission ||
00385             gmap->Camera()->EmissionAngle() > maxEmission) {
00386           ignore = true;
00387         }
00388         if(gmap->Camera()->IncidenceAngle() < minIncidence ||
00389             gmap->Camera()->IncidenceAngle() > maxIncidence) {
00390           ignore = true;
00391         }
00392 
00393         // Check the DNs with the cube, Note: this is costly to do
00394         if(hasDNRestriction) {
00395           Cube cube;
00396           string c = serialNumbers.Filename((*overlaps[ov])[sn]);
00397           cube.open(c);
00398           Isis::Brick brick(1, 1, 1, cube.getPixelType());
00399           brick.SetBasePosition((int)gmap->Camera()->Sample(), (int)gmap->Camera()->Line(), (int)gmap->Camera()->Band());
00400           cube.read(brick);
00401           if(Isis::IsSpecial(brick[0]) || brick[0] > maxDN || brick[0] < minDN) {
00402             ignore = true;
00403           }
00404         }
00405 
00406         // Check the Resolution with the camera from the gmap
00407         if(gmap->Resolution() < minResolution ||
00408             (maxResolution > 0.0 && gmap->Resolution() > maxResolution)) {
00409           ignore = true;
00410         }
00411 
00412         // Put the line/samp into a measurment
00413         ControlMeasure *measurement = new ControlMeasure();
00414         measurement->SetAprioriSample(gmap->Sample());
00415         measurement->SetAprioriLine(gmap->Line());
00416         measurement->SetCoordinate(gmap->Sample(), gmap->Line(),
00417                                   ControlMeasure::Candidate);
00418 
00419         measurement->SetType(ControlMeasure::Candidate);
00420         measurement->SetCubeSerialNumber((*(overlaps[ov]))[sn]);
00421         measurement->SetIgnored(ignore);
00422 
00423         if(ignore) {
00424           cmIgnoredCount ++;
00425         }
00426 
00427         controlpt->Add(measurement); //controlpt takes ownership
00428         measurement = NULL;
00429       }
00430 
00431       if(controlpt->GetNumValidMeasures() < 2) {
00432         controlpt->SetIgnored(true);
00433         cpIgnoredCount ++;
00434       }
00435 
00436       if(controlpt->GetNumMeasures() > 0) {
00437         cnet.AddPoint(controlpt); //cnet takes ownership
00438       }
00439       delete seed[point];
00440 
00441     } // End of create control points loop
00442 
00443   } // End of seeding loop
00444 
00445   // All done with the UGMs so delete them
00446   for(unsigned int sn = 0; sn < gMaps.size(); ++sn) {
00447     UniversalGroundMap *gmap = gMaps[serialNumbers.SerialNumber(sn)];
00448     delete gmap;
00449   }
00450   gMaps.clear();
00451 
00452   for(unsigned int i = 0 ; i < points.size(); i ++) {
00453     delete points[i];
00454     points[i] = NULL;
00455   }
00456 
00457   //Log the ERRORS file
00458   if(ui.WasEntered("ERRORS") && errorNum > 0) {
00459     string errorname = ui.GetFilename("ERRORS");
00460     std::ofstream errorsfile;
00461     errorsfile.open(errorname.c_str());
00462     errorsfile << errors.str();
00463     errorsfile.close();
00464   }
00465 
00466   // Make sure the control network is not empty
00467   if(cnet.GetNumPoints() == 0) {
00468     string msg = "The ouput control network is empty. This is likely due";
00469     msg += " to the input cubes failing to overlap.";
00470     throw iException::Message(iException::User, msg, _FILEINFO_);
00471   }
00472 
00473   // Write the control network out
00474   cnet.Write(ui.GetFilename("ONET"));
00475 
00476   // create SeedDef group and add to print.prt
00477   PvlGroup pluginInfo = seeder->PluginParameters("SeedDefinition");
00478   pluginInfo.AddKeyword(PvlKeyword("MaxIncidence", maxIncidence));
00479   pluginInfo.AddKeyword(PvlKeyword("MaxEmission", maxEmission));
00480   Application::Log(pluginInfo);
00481 
00482   // inform user of any unused (invalid) keywords found in the def file
00483   if(unusedDefKeywords.Keywords() != 0) {
00484     PvlGroup unusedKeywords(unusedDefKeywords);
00485     unusedKeywords.SetName("InvalidKeyordsFoundInDefFile");
00486     Application::Log(unusedKeywords);
00487   }
00488 
00489   // calc # of points and measures for results group in print.prt
00490   int cpCount = cnet.GetNumPoints();
00491   int msCount = 0;
00492   for(int i = 0; i < cpCount; i++) {
00493     msCount += cnet.GetPoint(i)->GetNumMeasures();
00494   }
00495 
00496   // create Results group and add to print.prt
00497   PvlKeyword cpCountKeyword("ControlPointCount", iString(cpCount));
00498   PvlKeyword msCountKeyword("ControlMeasureCount", iString(msCount));
00499   PvlKeyword cpIgnoredCountKeyword("ControlPointsIgnored", iString(cpIgnoredCount));
00500   PvlKeyword cmIgnoredCountKeyword("ControlMeasuresIgnored", iString(cmIgnoredCount));
00501 
00502   PvlGroup resultsGrp("Results");
00503   resultsGrp.AddKeyword(cpCountKeyword);
00504   resultsGrp.AddKeyword(msCountKeyword);
00505   resultsGrp.AddKeyword(cpIgnoredCountKeyword);
00506   resultsGrp.AddKeyword(cmIgnoredCountKeyword);
00507 
00508   Application::Log(resultsGrp);
00509 
00510   if(seedDomain == XY) {
00511     delete proj;
00512     proj = NULL;
00513   }
00514   else if(seedDomain == SampleLine) {
00515     delete ugmap;
00516     ugmap = NULL;
00517   }
00518 
00519   delete seeder;
00520   seeder = NULL;
00521 
00522 }