Isis 3.0 Application Source Code Reference |
Home |
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 }