|
Isis 3.0 Object Programmers' Reference |
Home |
00001 #include "Chip.h" 00002 #include "Pvl.h" 00003 #include "AutoReg.h" 00004 #include "Plugin.h" 00005 #include "iException.h" 00006 #include "PolynomialBivariate.h" 00007 #include "LeastSquares.h" 00008 #include "Filename.h" 00009 #include "Histogram.h" 00010 #include "Matrix.h" 00011 00012 namespace Isis { 00022 AutoReg::AutoReg (Pvl &pvl) { 00023 p_template = pvl.FindObject("AutoRegistration"); 00024 00025 // Set default parameters 00026 p_patternChip.SetSize(3,3); 00027 p_searchChip.SetSize(5,5); 00028 p_fitChip.SetSize(5,5); 00029 p_reducedPatternChip.SetSize(3,3); 00030 p_reducedSearchChip.SetSize(5,5); 00031 p_reducedFitChip.SetSize(5,5); 00032 SetPatternValidPercent(50.0); 00033 SetPatternZScoreMinimum(1.0); 00034 SetTolerance(Isis::Null); 00035 SetSubPixelAccuracy(true); 00036 SetSurfaceModelDistanceTolerance(1.5); 00037 SetSurfaceModelWindowSize(5); 00038 SetSurfaceModelEccentricityRatio(2); // 2:1 00039 SetReductionFactor(1); 00040 00041 // Clear statistics 00042 //TODO: Delete these after control net refactor. 00043 p_Total = 0; 00044 p_Success = 0; 00045 p_PatternChipNotEnoughValidData = 0; 00046 p_PatternZScoreNotMet = 0; 00047 p_FitChipNoData = 0; 00048 p_FitChipToleranceNotMet = 0; 00049 p_SurfaceModelNotEnoughValidData = 0; 00050 p_SurfaceModelSolutionInvalid = 0; 00051 p_SurfaceModelDistanceInvalid = 0; 00052 p_SurfaceModelEccentricityRatioNotMet = 0; 00053 00054 Init(); 00055 Parse(pvl); 00056 } 00057 00062 void AutoReg::Init(){ 00063 // Set computed parameters to NULL so we don't use values from a previous 00064 // run 00065 p_ZScore1 = Isis::Null; 00066 p_ZScore2 = Isis::Null; 00067 p_goodnessOfFit = Isis::Null; 00068 p_surfaceModelEccentricity = Isis::Null; 00069 00070 p_bestSamp = 0; 00071 p_bestLine = 0; 00072 p_bestFit = Isis::Null; 00073 00074 // -------------------------------------------------- 00075 // Nulling out the fit chip 00076 // -------------------------------------------------- 00077 for (int line=1; line<=p_fitChip.Lines(); line++) { 00078 for (int samp=1; samp<=p_fitChip.Samples(); samp++) { 00079 p_fitChip.SetValue(samp,line,Isis::Null); 00080 } 00081 } 00082 // -------------------------------------------------- 00083 // Nulling out the reduced pattern chip 00084 // -------------------------------------------------- 00085 for (int line=1; line<=p_reducedPatternChip.Lines(); line++) { 00086 for (int samp=1; samp<=p_reducedPatternChip.Samples(); samp++) { 00087 p_reducedPatternChip.SetValue(samp,line,Isis::Null); 00088 } 00089 } 00090 // -------------------------------------------------- 00091 // Nulling out the reduced search chip 00092 // -------------------------------------------------- 00093 for (int line=1; line<=p_reducedSearchChip.Lines(); line++) { 00094 for (int samp=1; samp<=p_reducedSearchChip.Samples(); samp++) { 00095 p_reducedSearchChip.SetValue(samp,line,Isis::Null); 00096 } 00097 } 00098 00099 } 00100 00102 AutoReg::~AutoReg() { 00103 00104 } 00105 00136 void AutoReg::Parse(Pvl &pvl) { 00137 try { 00138 // Get info from Algorithm group 00139 PvlGroup &algo = pvl.FindGroup("Algorithm", Pvl::Traverse); 00140 SetTolerance(algo["Tolerance"]); 00141 00142 if (algo.HasKeyword("SubpixelAccuracy")) { 00143 SetSubPixelAccuracy((std::string)algo["SubpixelAccuracy"] == "True"); 00144 } 00145 00146 if (algo.HasKeyword("ReductionFactor")) { 00147 SetReductionFactor((int)algo["ReductionFactor"]); 00148 } 00149 00150 // Setup the pattern chip 00151 PvlGroup &pchip = pvl.FindGroup("PatternChip",Pvl::Traverse); 00152 PatternChip()->SetSize((int)pchip["Samples"],(int)pchip["Lines"]); 00153 00154 double minimum = Isis::ValidMinimum; 00155 double maximum = Isis::ValidMaximum; 00156 if (pchip.HasKeyword("ValidMinimum")) minimum = pchip["ValidMinimum"]; 00157 if (pchip.HasKeyword("ValidMaximum")) maximum = pchip["ValidMaximum"]; 00158 PatternChip()->SetValidRange(minimum,maximum); 00159 00160 if (pchip.HasKeyword("MinimumZScore")) { 00161 SetPatternZScoreMinimum((double)pchip["MinimumZScore"]); 00162 } 00163 00164 // Setup the search chip 00165 PvlGroup &schip = pvl.FindGroup("SearchChip",Pvl::Traverse); 00166 SearchChip()->SetSize((int)schip["Samples"],(int)schip["Lines"]); 00167 00168 minimum = Isis::ValidMinimum; 00169 maximum = Isis::ValidMaximum; 00170 if (schip.HasKeyword("ValidMinimum")) minimum = schip["ValidMinimum"]; 00171 if (schip.HasKeyword("ValidMaximum")) maximum = schip["ValidMaximum"]; 00172 SearchChip()->SetValidRange(minimum,maximum); 00173 00174 // What percentage of the pattern chip should be valid 00175 if (pchip.HasKeyword("ValidPercent")) { 00176 SetPatternValidPercent((double)pchip["ValidPercent"]); 00177 } 00178 00179 PvlObject ar = pvl.FindObject("AutoRegistration"); 00180 if(ar.HasGroup("SurfaceModel")) { 00181 PvlGroup &smodel = ar.FindGroup("SurfaceModel", Pvl::Traverse); 00182 if(smodel.HasKeyword("DistanceTolerance")) { 00183 SetSurfaceModelDistanceTolerance((double)smodel["DistanceTolerance"]); 00184 } 00185 00186 if(smodel.HasKeyword("WindowSize")) { 00187 SetSurfaceModelWindowSize((int)smodel["WindowSize"]); 00188 } 00189 00190 //What kind of eccentricity ratio will we tolerate? 00191 if(smodel.HasKeyword("EccentricityRatio")) { 00192 SetSurfaceModelEccentricityRatio((double)smodel["EccentricityRatio"]); 00193 } 00194 } 00195 00196 } catch (iException &e) { 00197 std::string msg = "Improper format for AutoReg PVL ["+pvl.Filename()+"]"; 00198 throw iException::Message(iException::User,msg,_FILEINFO_); 00199 } 00200 return; 00201 } 00202 00212 void AutoReg::SetSubPixelAccuracy(bool on) { 00213 p_subpixelAccuracy = on; 00214 } 00215 00234 void AutoReg::SetPatternValidPercent(const double percent) { 00235 if ((percent <= 0.0) || (percent > 100.0)) { 00236 std::string msg = "Invalid value of PatternValidPercent [" + 00237 iString(percent) + "]"; 00238 throw iException::Message(iException::User,msg,_FILEINFO_); 00239 } 00240 p_patternValidPercent = percent; 00241 } 00242 00243 00255 void AutoReg::SetPatternZScoreMinimum (double minimum) { 00256 if(minimum <= 0.0) { 00257 std::string msg = "MinimumZScore must be greater than 0"; 00258 throw iException::Message(iException::User,msg,_FILEINFO_); 00259 } 00260 p_minimumPatternZScore = minimum; 00261 } 00262 00263 00271 void AutoReg::SetTolerance(const double tolerance) { 00272 p_tolerance = tolerance; 00273 } 00274 00284 void AutoReg::SetSurfaceModelWindowSize (int size) { 00285 if(size % 2 != 1 || size < 3) { 00286 std::string msg = "WindowSize must be an odd number greater than or equal to 3"; 00287 throw iException::Message(iException::User,msg,_FILEINFO_); 00288 } 00289 p_windowSize = size; 00290 } 00291 00292 00300 void AutoReg::SetSurfaceModelEccentricityRatio(double eccentricityRatio){ 00301 if(eccentricityRatio < 1){ 00302 std::string msg = "EccentricityRatio must be 1 or larger."; 00303 throw iException::Message(iException::User,msg,_FILEINFO_); 00304 } 00305 p_surfaceModelEccentricityTolerance = sqrt(eccentricityRatio*eccentricityRatio -1)/ eccentricityRatio; 00306 } 00307 00308 00316 void AutoReg::SetSurfaceModelDistanceTolerance (double distance) { 00317 if(distance <= 0.0) { 00318 std::string msg = "DistanceTolerance must be greater than 0"; 00319 throw iException::Message(iException::User,msg,_FILEINFO_); 00320 } 00321 p_distanceTolerance = distance; 00322 } 00323 00324 00331 void AutoReg::SetReductionFactor(int factor){ 00332 if(factor < 1) { 00333 std::string msg = "ReductionFactor must be 1 or greater."; 00334 throw iException::Message(iException::User,msg,_FILEINFO_); 00335 } 00336 p_reduceFactor = factor; 00337 } 00338 00339 00348 Chip AutoReg::Reduce(Chip &chip, int reductionFactor){ 00349 Chip rChip((int)chip.Samples()/reductionFactor, 00350 (int)chip.Lines()/reductionFactor); 00351 if((int)rChip.Samples() < 1 || (int)rChip.Lines() < 1 ) { 00352 return chip; 00353 } 00354 00355 // ---------------------------------- 00356 // Fill the reduced Chip with nulls. 00357 // ---------------------------------- 00358 for (int line=1; line<=rChip.Lines(); line++) { 00359 for (int samp=1; samp<=rChip.Samples(); samp++) { 00360 rChip.SetValue(samp,line,Isis::Null); 00361 } 00362 } 00363 00364 Statistics stats; 00365 for(int l = 1; l <= rChip.Lines(); l++) { 00366 int isl = (l -1) * reductionFactor + 1; 00367 int iel = isl + reductionFactor - 1; 00368 for(int s = 1; s <= rChip.Samples(); s++) { 00369 00370 int iss = (s -1) * reductionFactor + 1; 00371 int ies = iss + reductionFactor - 1; 00372 00373 stats.Reset(); 00374 for(int line = isl; line < iel; line++ ) { 00375 for(int sample = iss; sample < ies; sample++ ) { 00376 stats.AddData(chip.GetValue(sample, line)); 00377 } 00378 } 00379 rChip.SetValue(s,l,stats.Average()); 00380 } 00381 } 00382 return rChip; 00383 } 00384 00385 00392 AutoReg::RegisterStatus AutoReg::Register() { 00393 // The search chip must be bigger than the pattern chip by N pixels in 00394 // both directions for a successful surface model 00395 int N = p_windowSize / 2 + 1; 00396 00397 if (p_searchChip.Samples() < p_patternChip.Samples() + N) { 00398 std::string msg = "Search chips samples ["; 00399 msg += iString(p_searchChip.Samples()) + "] must be at "; 00400 msg += "least [" +iString(N) + "] pixels wider than the pattern chip samples ["; 00401 msg += iString(p_patternChip.Samples()) + "] for successful surface modeling"; 00402 throw iException::Message(iException::User,msg,_FILEINFO_); 00403 } 00404 00405 if (p_searchChip.Lines() < p_patternChip.Lines() + N) { 00406 std::string msg = "Search chips lines ["; 00407 msg += iString(p_searchChip.Lines()) + "] must be at "; 00408 msg += "least [" +iString(N) + "] pixels taller than the pattern chip lines ["; 00409 msg += iString(p_patternChip.Lines()) + "] for successful surface modeling"; 00410 throw iException::Message(iException::User,msg,_FILEINFO_); 00411 } 00412 00413 Init(); 00414 p_Total++; 00415 00416 // See if the pattern chip has enough good data 00417 if (!p_patternChip.IsValid(p_patternValidPercent)) { 00418 p_PatternChipNotEnoughValidData++; 00419 p_status = PatternChipNotEnoughValidData; 00420 return PatternChipNotEnoughValidData; 00421 } 00422 00423 if(!ComputeChipZScore(p_patternChip)) { 00424 p_PatternZScoreNotMet++; 00425 p_status = PatternZScoreNotMet; 00426 return PatternZScoreNotMet; 00427 } 00428 00429 // ------------------------------------------------------------------ 00430 // Prep for walking the search chip by computing the starting sample 00431 // and line for the search. Also compute the sample and linc 00432 // increment for sparse walking 00433 // ------------------------------------------------------------------ 00434 int ss = (p_patternChip.Samples() - 1) / 2 + 1; 00435 int sl = (p_patternChip.Lines() - 1) / 2 + 1; 00436 int es = p_searchChip.Samples()-ss+1; 00437 int el = p_searchChip.Lines()-sl+1; 00438 00439 // ---------------------------------------------------------------------- 00440 // Before we attempt to apply the reduction factor, we need to make sure 00441 // we won't produce a chip of a bad size. 00442 // ---------------------------------------------------------------------- 00443 if(p_patternChip.Samples()/p_reduceFactor < 2 || p_patternChip.Lines() / p_reduceFactor < 2) { 00444 std::string msg = "Reduction factor is too large"; 00445 throw iException::Message(iException::User,msg,_FILEINFO_); 00446 } 00447 00448 // Establish the center search tack point as best pixel to start for the 00449 // adaptive algorithm prior to reduction. 00450 int bestSearchSamp = p_searchChip.TackSample(); 00451 int bestSearchLine = p_searchChip.TackLine(); 00452 00453 00454 // --------------------------------------------------------------------- 00455 // if the reduction factor is still not equal to one, then we go ahead 00456 // with the reduction of the chips and call Match to get the first 00457 // estimate of the best line/sample. 00458 // --------------------------------------------------------------------- 00459 if(p_reduceFactor != 1) { 00460 { //Do not remove this brace. It keeps ss, sl, es, and el in the 00461 //proper scope. 00462 00463 p_reducedPatternChip.SetSize((int)p_patternChip.Samples()/p_reduceFactor, 00464 (int)p_patternChip.Lines()/p_reduceFactor); 00465 00466 // ---------------------------------- 00467 // Fill the reduced Chip with nulls. 00468 // ---------------------------------- 00469 for (int line=1; line<=p_reducedPatternChip.Lines(); line++) { 00470 for (int samp=1; samp<=p_reducedPatternChip.Samples(); samp++) { 00471 p_reducedPatternChip.SetValue(samp,line,Isis::Null); 00472 } 00473 } 00474 00475 p_reducedPatternChip = Reduce(p_patternChip, p_reduceFactor); 00476 if(!ComputeChipZScore(p_reducedPatternChip)){ 00477 p_PatternZScoreNotMet++; 00478 p_status = PatternZScoreNotMet; 00479 return PatternZScoreNotMet; 00480 } 00481 00482 p_reducedSearchChip = Reduce(p_searchChip, p_reduceFactor); 00483 int ss = (p_reducedPatternChip.Samples() - 1) / 2 + 1; 00484 int sl = (p_reducedPatternChip.Lines() - 1) / 2 + 1; 00485 int es = p_reducedSearchChip.Samples() - ss + 1; 00486 int el = p_reducedSearchChip.Lines() - sl + 1; 00487 00488 Match(p_reducedSearchChip, p_reducedPatternChip, p_reducedFitChip, ss, es, sl, el); 00489 if (p_bestFit == Isis::Null) { 00490 p_FitChipNoData++; 00491 p_status = FitChipNoData; 00492 return FitChipNoData; 00493 } 00494 } 00495 00496 // ------------------------------------------------------ 00497 // p_bestSamp and p_bestLine are set in Match() which is 00498 // called above. 00499 // ----------------------------------------------------- 00500 int bs = (p_bestSamp -1) * p_reduceFactor + ((p_reduceFactor -1)/2) + 1; 00501 int bl = (p_bestLine -1) * p_reduceFactor + ((p_reduceFactor -1)/2) + 1; 00502 00503 // --------------------------------------------------------------- 00504 // Now we grow our window size according to the reduction factor. 00505 // And we grow around were the first call Match() told us was the 00506 // best line/sample. 00507 // --------------------------------------------------------------- 00508 int newss = bs - p_reduceFactor - p_windowSize -1; 00509 int newes = bs + p_reduceFactor + p_windowSize +1; 00510 int newsl = bl - p_reduceFactor - p_windowSize -1; 00511 int newel = bl + p_reduceFactor + p_windowSize +1; 00512 00513 if(newsl < sl) newsl = sl; 00514 if(newes > es) newes = es; 00515 if(newss < ss) newss = ss; 00516 if(newel > el) newel = el; 00517 00518 ss = newss; 00519 es = newes; 00520 sl = newsl; 00521 el = newel; 00522 // We have found a good pixel in the reduction chip, but we 00523 // don't want to use it's position, so reset in prep. for 00524 // non-adaptive registration. Save it off for the adaptive algorithm. 00525 bestSearchSamp = bs; 00526 bestSearchLine = bl; 00527 p_bestSamp = 0; 00528 p_bestLine = 0; 00529 p_bestFit = Isis::Null; 00530 } 00531 00532 // If the algorithm is adaptive then it expects the pattern and search chip 00533 // to be closely registered. Within a few pixels. So let it take over 00534 // doing the sub-pixel accuracy computation 00535 if (IsAdaptive()) { 00536 p_status = AdaptiveRegistration(p_searchChip, p_patternChip, p_fitChip, 00537 ss, sl, es, el, bestSearchSamp, 00538 bestSearchLine); 00539 if(p_status == AutoReg::Success) { 00540 p_searchChip.SetChipPosition(p_chipSample,p_chipLine); 00541 p_cubeSample = p_searchChip.CubeSample(); 00542 p_cubeLine = p_searchChip.CubeLine(); 00543 p_goodnessOfFit = p_bestFit; 00544 p_Success++; 00545 } 00546 return p_status; 00547 } 00548 00549 // Not adaptive continue with slower search traverse 00550 Match(p_searchChip, p_patternChip, p_fitChip, ss, es, sl, el); 00551 00552 // Check to see if we went through the fit chip and never got a fit at 00553 // any location. 00554 if (p_bestFit == Isis::Null) { 00555 p_FitChipNoData++; 00556 p_status = FitChipNoData; 00557 return FitChipNoData; 00558 } 00559 00560 // ----------------------------------------------------------------- 00561 // We had a location in the fit chip. Save the values even if they 00562 // may not meet tolerances. This is also saves the value in the 00563 // event the user does not want a surface model fit 00564 // ---------------------------------------------------------------- 00565 p_goodnessOfFit = p_bestFit; 00566 p_searchChip.SetChipPosition(p_bestSamp, p_bestLine); 00567 p_cubeSample = p_searchChip.CubeSample(); 00568 p_cubeLine = p_searchChip.CubeLine(); 00569 00570 // Now see if we satisified the goodness of fit tolerance 00571 if (!CompareFits(p_bestFit,Tolerance())) { 00572 p_FitChipToleranceNotMet++; 00573 p_status = FitChipToleranceNotMet; 00574 return FitChipToleranceNotMet; 00575 } 00576 00577 // Try to fit a model for sub-pixel accuracy if necessary 00578 if (p_subpixelAccuracy && !IsIdeal(p_bestFit)) { 00579 std::vector<double> samps,lines,fits; 00580 for (int line= p_bestLine-p_windowSize/2; line <= p_bestLine+p_windowSize/2; line++) { 00581 if (line < 1) continue; 00582 if (line > p_fitChip.Lines()) continue; 00583 for (int samp = p_bestSamp-p_windowSize/2; samp <= p_bestSamp+p_windowSize/2; samp++) { 00584 if (samp < 1) continue; 00585 if (samp > p_fitChip.Samples()) continue; 00586 if (p_fitChip.GetValue(samp,line) == Isis::Null) continue; 00587 samps.push_back((double) samp); 00588 lines.push_back((double) line); 00589 fits.push_back(p_fitChip.GetValue(samp,line)); 00590 } 00591 } 00592 00593 // ----------------------------------------------------------- 00594 // Make sure we have enough data for a surface fit. That is, 00595 // we are not too close to the edge of the fit chip 00596 // ----------------------------------------------------------- 00597 if ((int)samps.size() < p_windowSize*p_windowSize * 2 / 3 + 1) { 00598 p_SurfaceModelNotEnoughValidData++; 00599 p_status = SurfaceModelNotEnoughValidData; 00600 return SurfaceModelNotEnoughValidData; 00601 } 00602 00603 // ------------------------------------------------------------------- 00604 // Now that we know we have enough data to model the surface we call 00605 // ModelSurface to get the sub-pixel accuracy we are looking for. 00606 // ------------------------------------------------------------------- 00607 if(!ModelSurface(samps, lines, fits)) { 00608 return p_status; 00609 } 00610 00611 // --------------------------------------------------------------------- 00612 // See if the surface model solution moved too far from our whole pixel 00613 // solution 00614 // --------------------------------------------------------------------- 00615 if (std::fabs(p_bestSamp - p_chipSample) > p_distanceTolerance || 00616 std::fabs(p_bestLine - p_chipLine) > p_distanceTolerance) { 00617 p_SurfaceModelDistanceInvalid++; 00618 p_status = SurfaceModelDistanceInvalid; 00619 return SurfaceModelDistanceInvalid; 00620 } 00621 00622 // Ok we have subpixel fits in chip space so convert to cube space 00623 p_searchChip.SetChipPosition(p_chipSample,p_chipLine); 00624 p_cubeSample = p_searchChip.CubeSample(); 00625 p_cubeLine = p_searchChip.CubeLine(); 00626 } 00627 00628 p_Success++; 00629 p_status = Success; 00630 return Success; 00631 } 00632 00633 00642 bool AutoReg::ComputeChipZScore(Chip &chip){ 00643 Statistics patternStats; 00644 for (int i=0; i<chip.Samples(); i++) { 00645 double pixels[chip.Lines()]; 00646 for (int j=0; j<chip.Lines(); j++) { 00647 pixels[j] = chip.GetValue(i+1,j+1); 00648 } 00649 patternStats.AddData(pixels, chip.Lines()); 00650 } 00651 00652 // If it does not pass, return 00653 p_ZScore1 = patternStats.ZScore(patternStats.Minimum()); 00654 p_ZScore2 = patternStats.ZScore(patternStats.Maximum()); 00655 00656 if (p_ZScore2 < p_minimumPatternZScore || 00657 p_ZScore1 > -1*p_minimumPatternZScore) { 00658 return false; 00659 } else { 00660 return true; 00661 } 00662 } 00663 00664 00680 void AutoReg::Match(Chip &sChip, Chip &pChip, Chip &fChip, int ss, int es, int sl, int el){ 00681 // Sanity check. Should have been caught by the two previous tests 00682 if (ss==es && sl==el) { 00683 std::string msg = "Sanity check, this shouldn't happen!"; 00684 throw iException::Message(iException::Programmer,msg,_FILEINFO_); 00685 } 00686 00687 // Ok create a fit chip whose size is the same as the search chip 00688 // and then fill it with nulls 00689 fChip.SetSize(sChip.Samples(),sChip.Lines()); 00690 for (int line=1; line<=fChip.Lines(); line++) { 00691 for (int samp=1; samp<=fChip.Samples(); samp++) { 00692 fChip.SetValue(samp,line,Isis::Null); 00693 } 00694 } 00695 00696 // Create a chip the same size as the pattern chip. 00697 Chip subsearch(pChip.Samples(), pChip.Lines()); 00698 00699 for (int line=sl; line<=el; line++) { 00700 for (int samp=ss; samp<=es; samp++) { 00701 // Extract the sub search chip and make sure it has enough valid data 00702 sChip.Extract(samp,line, subsearch); 00703 00704 if (!subsearch.IsValid(p_patternValidPercent)) continue; 00705 00706 // Try to match the two subchips 00707 double fit = MatchAlgorithm(pChip, subsearch); 00708 00709 // If we had a fit save off information about that fit 00710 if (fit != Isis::Null) { 00711 fChip.SetValue(samp,line,fit); 00712 if ((p_bestFit == Isis::Null) || CompareFits(fit,p_bestFit)) { 00713 p_bestFit = fit; 00714 p_bestSamp = samp; 00715 p_bestLine = line; 00716 } 00717 } 00718 } 00719 } 00720 } 00721 00722 00745 bool AutoReg::ModelSurface(std::vector<double> &x, 00746 std::vector<double> &y, 00747 std::vector<double> &z) { 00748 PolynomialBivariate p(2); 00749 LeastSquares lsq(p); 00750 for (int i=0; i<(int)x.size(); i++) { 00751 std::vector<double> xy; 00752 xy.push_back(x[i]); 00753 xy.push_back(y[i]); 00754 lsq.AddKnown(xy,z[i]); 00755 } 00756 try { 00757 lsq.Solve(); 00758 } catch (iException &e) { 00759 e.Clear(); 00760 p_status = SurfaceModelSolutionInvalid; 00761 p_SurfaceModelSolutionInvalid++; 00762 return false; 00763 } 00764 00765 double a = p.Coefficient(0); 00766 double b = p.Coefficient(1); 00767 double c = p.Coefficient(2); 00768 double d = p.Coefficient(3); 00769 double e = p.Coefficient(4); 00770 double f = p.Coefficient(5); 00771 00772 //---------------------------------------------------------- 00773 // Compute eccentricity 00774 // For more information see: 00775 // http://mathworld.wolfram.com/Ellipse.html 00776 // Make sure delta matrix determinant is not equal to zero. 00777 // The general quadratic curve 00778 // dx^2+2exy+fy^2+2bx+2cy+a=0 00779 // is an ellipse when, after defining 00780 // Delta = |d e/2 b| 00781 // |e/2 f/2 c/2| 00782 // |b c/2 a| 00783 // J = |d e/2| 00784 // |e/2 f/e| 00785 // I = d + (f/2) 00786 // Delta!=0, J>0, and Delta/I<0. Also assume the ellipse is 00787 // nondegenerate (i.e., it is not a circle, so a!=c, and we have already 00788 // established is not a point, since J=ac-b^2!=0) 00789 // --------------------------------------------------------- 00790 Matrix delta(3, 3); 00791 delta[0][0] = d; delta[0][1] = e/2; delta[0][2] = b/2; 00792 delta[1][0] = e/2; delta[1][1] = f; delta[1][2] = c/2; 00793 delta[2][0] = b/2; delta[2][1] = c/2; delta[2][2] = a; 00794 if(delta.Determinant() == 0) { 00795 p_status = SurfaceModelEccentricityRatioNotMet; 00796 p_SurfaceModelEccentricityRatioNotMet++; 00797 return false; 00798 } 00799 00800 //Make sure J matrix is greater than zero. 00801 Matrix J(2, 2); 00802 J[0][0] = d; J[0][1] = e/2; 00803 J[1][0] = e/2; J[1][1] = f; 00804 if(J.Determinant() <= 0) { 00805 p_status = SurfaceModelEccentricityRatioNotMet; 00806 p_SurfaceModelEccentricityRatioNotMet++; 00807 return false; 00808 } 00809 00810 double I = d + (f); 00811 if(delta.Determinant() / I >= 0) { 00812 p_status = SurfaceModelEccentricityRatioNotMet; 00813 p_SurfaceModelEccentricityRatioNotMet++; 00814 return false; 00815 } 00816 00817 // ------------------------------------------- 00818 // Now we can calculate a prime and b prime 00819 // ------------------------------------------- 00820 double eA = sqrt((2*(d*(c/2)*(c/2) + f*(b/2)*(b/2) + a*(e/2)*(e/2) - 2*(e/2)*(b/2)*(c/2) - d*f*a)) / 00821 (((e/2)*(e/2) - d*f) * (sqrt((d - f)*(d -f) + 4*(e/2)*(e/2)) - (d + f)))); 00822 00823 double eB = sqrt((2*(d*(c/2)*(c/2) + f*(b/2)*(b/2) + a*(e/2)*(e/2) - 2*(e/2)*(b/2)*(c/2) - d*f*a)) / 00824 (((e/2)*(e/2) - d*f) * (-sqrt((d - f)*(d -f) + 4*(e/2)*(e/2)) - (d + f)))); 00825 00826 if(eB > eA) { 00827 double tempVar = eB; 00828 eB = eA; 00829 eA = tempVar; 00830 } 00831 // Compute eccentricity 00832 p_surfaceModelEccentricity = sqrt(eA*eA - eB*eB)/eA; 00833 if(p_surfaceModelEccentricity > p_surfaceModelEccentricityTolerance) { 00834 p_status = SurfaceModelEccentricityRatioNotMet; 00835 p_SurfaceModelEccentricityRatioNotMet++; 00836 return false; 00837 } 00838 00839 // Compute the determinant 00840 double det = 4.0*d*f - e*e; 00841 if (det == 0.0){ 00842 p_status = SurfaceModelSolutionInvalid; 00843 p_SurfaceModelSolutionInvalid++; 00844 return false; 00845 } 00846 00847 // Compute our chip position to sub-pixel accuracy 00848 p_chipSample = (c*e - 2.0*b*f) / det; 00849 p_chipLine = (b*e - 2.0*c*d) / det; 00850 std::vector<double> temp; 00851 temp.push_back(p_chipSample); 00852 temp.push_back(p_chipLine); 00853 p_goodnessOfFit = lsq.Evaluate(temp); 00854 return true; 00855 } 00856 00857 00865 bool AutoReg::CompareFits (double fit1, double fit2) { 00866 return(std::fabs(fit1-IdealFit()) <= std::fabs(fit2-IdealFit())); 00867 } 00868 00869 // See if the fit is arbitrarily close 00870 // to the ideal value 00871 bool AutoReg::IsIdeal(double fit) { 00872 return( std::fabs(IdealFit() - fit) < 0.00001 ); 00873 } 00874 00875 00876 #if 0 00877 00881 AutoRegItem AutoReg::RegisterInformation(){ 00882 AutoRegItem item; 00883 item.setSearchFile(p_searchChip.Filename()); 00884 item.setPatternFile(p_patternChip.Filename()); 00885 //item.setStatus(p_status); 00886 item.setGoodnessOfFit(p_goodnessOfFit); 00887 item.setEccentricity(p_surfaceModelEccentricity); 00888 item.setZScoreOne(p_ZScore1); 00889 item.setZScoreTwo(p_ZScore2); 00890 00891 /*if(p_goodnessOfFit != Isis::Null)item.setGoodnessOfFit(p_goodnessOfFit); 00892 if(p_surfaceModelEccentricity != Isis::Null) item.setEccentricity(p_surfaceModelEccentricity); 00893 if(p_ZScore1 != Isis::Null)item.setZScoreOne(p_ZScore1); 00894 if(p_ZScore2 != Isis::Null)item.setZScoreTwo(p_ZScore2);*/ 00895 00896 // Set the autoRegItem's change in line/sample numbers. 00897 if(p_status == Success) { 00898 item.setDeltaSample(p_searchChip.TackSample() - p_searchChip.CubeSample()); 00899 item.setDeltaLine(p_searchChip.TackLine() - p_searchChip.CubeLine()); 00900 } else { 00901 item.setDeltaSample(Isis::Null); 00902 item.setDeltaLine(Isis::Null); 00903 } 00904 00905 return item; 00906 } 00907 #endif 00908 00909 00920 Pvl AutoReg::RegistrationStatistics() { 00921 Pvl pvl; 00922 PvlGroup stats("AutoRegStatistics"); 00923 stats += Isis::PvlKeyword("Total", p_Total); 00924 stats += Isis::PvlKeyword("Successful", p_Success); 00925 stats += Isis::PvlKeyword("Failure", p_Total - p_Success); 00926 pvl.AddGroup(stats); 00927 00928 PvlGroup grp("PatternChipFailures"); 00929 grp += PvlKeyword("PatternNotEnoughValidData", p_PatternChipNotEnoughValidData); 00930 grp += PvlKeyword("PatternZScoreNotMet", p_PatternZScoreNotMet); 00931 pvl.AddGroup(grp); 00932 00933 PvlGroup fit("FitChipFailures"); 00934 fit += PvlKeyword("FitChipNoData", p_FitChipNoData); 00935 fit += PvlKeyword("FitChipToleranceNotMet", p_FitChipToleranceNotMet); 00936 pvl.AddGroup(fit); 00937 00938 PvlGroup model("SurfaceModelFailures"); 00939 model += PvlKeyword("SurfaceModelNotEnoughValidData", p_SurfaceModelNotEnoughValidData); 00940 model += PvlKeyword("SurfaceModelSolutionInvalid", p_SurfaceModelSolutionInvalid); 00941 model += PvlKeyword("SurfaceModelEccentricityRatioNotMet", p_SurfaceModelEccentricityRatioNotMet); 00942 model += PvlKeyword("SurfaceModelDistanceInvalid", p_SurfaceModelDistanceInvalid); 00943 pvl.AddGroup(model); 00944 00945 return (AlgorithmStatistics(pvl)); 00946 } 00947 00981 AutoReg::RegisterStatus AutoReg::AdaptiveRegistration(Chip &sChip, 00982 Chip &pChip, 00983 Chip &fChip, 00984 int startSamp, 00985 int startLine, 00986 int endSamp, 00987 int endLine, 00988 int bestSamp, 00989 int bestLine) { 00990 std::string msg = "Programmer needs to write their own virtual AdaptiveRegistration method"; 00991 throw iException::Message(iException::Programmer,msg,_FILEINFO_); 00992 return Success; 00993 } 00994 01002 PvlGroup AutoReg::RegTemplate() { 01003 PvlGroup reg("AutoRegistration"); 01004 01005 PvlGroup &algo = p_template.FindGroup("Algorithm", Pvl::Traverse); 01006 reg += PvlKeyword("Algorithm", algo["Name"][0]); 01007 reg += PvlKeyword("Tolerance", algo["Tolerance"][0]); 01008 if (algo.HasKeyword("SubpixelAccuracy")) { 01009 reg += PvlKeyword("SubpixelAccuracy", algo["SubpixelAccuracy"][0]); 01010 } 01011 if (algo.HasKeyword("ReductionFactor")) { 01012 reg += PvlKeyword("ReductionFactor", algo["ReductionFactor"][0]); 01013 } 01014 01015 PvlGroup &pchip = p_template.FindGroup("PatternChip",Pvl::Traverse); 01016 reg += PvlKeyword("PatternSamples", pchip["Samples"][0]); 01017 reg += PvlKeyword("PatternLines", pchip["Lines"][0]); 01018 if (pchip.HasKeyword("ValidMinimum")) { 01019 reg += PvlKeyword("PatternMinimum", pchip["ValidMinimum"][0]); 01020 } 01021 if (pchip.HasKeyword("ValidMaximum")) { 01022 reg += PvlKeyword("PatternMaximum", pchip["ValidMaximum"][0]); 01023 } 01024 if (pchip.HasKeyword("MinimumZScore")) { 01025 reg += PvlKeyword("MinimumZScore", pchip["MinimumZScore"][0]); 01026 } 01027 if (pchip.HasKeyword("ValidPercent")) { 01028 SetPatternValidPercent((double)pchip["ValidPercent"]); 01029 reg += PvlKeyword("ValidPercent", pchip["ValidPercent"][0]); 01030 } 01031 01032 PvlGroup &schip = p_template.FindGroup("SearchChip",Pvl::Traverse); 01033 reg += PvlKeyword("SearchSamples", schip["Samples"][0]); 01034 reg += PvlKeyword("SearchLines", schip["Lines"][0]); 01035 if (schip.HasKeyword("ValidMinimum")) { 01036 reg += PvlKeyword("SearchMinimum", schip["ValidMinimum"][0]); 01037 } 01038 if (schip.HasKeyword("ValidMaximum")) { 01039 reg += PvlKeyword("SearchMaximum", schip["ValidMaximum"][0]); 01040 } 01041 01042 if(p_template.HasGroup("SurfaceModel")) { 01043 PvlGroup &smodel = p_template.FindGroup("SurfaceModel", Pvl::Traverse); 01044 if(smodel.HasKeyword("DistanceTolerance")) { 01045 reg += PvlKeyword("DistanceTolerance", smodel["DistanceTolerance"][0]); 01046 } 01047 01048 if(smodel.HasKeyword("WindowSize")) { 01049 reg += PvlKeyword("WindowSize", smodel["WindowSize"][0]); 01050 } 01051 01052 if(smodel.HasKeyword("EccentricityRatio")) { 01053 reg += PvlKeyword("EccentricityRatio", smodel["EccentricityRatio"][0]); 01054 } 01055 } 01056 01057 return reg; 01058 } 01059 }