USGS

Isis 3.0 Object Programmers' Reference

Home

AutoReg.cpp

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 }