Isis 3 Programmer Reference
AutoReg.cpp
1 
20 #include "AutoReg.h"
21 #include "Buffer.h"
22 #include "Centroid.h"
23 #include "Chip.h"
24 #include "FileName.h"
25 #include "Histogram.h"
26 #include "IException.h"
27 #include "Interpolator.h"
28 #include "LeastSquares.h"
29 #include "Matrix.h"
30 #include "PixelType.h"
31 #include "Plugin.h"
32 #include "PolynomialBivariate.h"
33 #include "Pvl.h"
34 
35 using namespace std;
36 namespace Isis {
79  AutoReg::AutoReg(Pvl &pvl) {
80  p_template = pvl.findObject("AutoRegistration");
81 
82  // Set default parameters
83  p_patternChip.SetSize(3, 3);
84  p_searchChip.SetSize(5, 5);
85  p_fitChip.SetSize(5, 5);
86  p_reducedPatternChip.SetSize(3, 3);
87  p_reducedSearchChip.SetSize(5, 5);
88  p_reducedFitChip.SetSize(5, 5);
89  p_gradientFilterType = None;
90 
91  SetPatternValidPercent(50.0);
92  SetSubsearchValidPercent(50.0);
93  SetPatternZScoreMinimum(1.0);
94  SetTolerance(Isis::Null);
95 
96  SetSubPixelAccuracy(true);
97  SetSurfaceModelDistanceTolerance(1.5);
98  SetSurfaceModelWindowSize(5);
99 
100  SetReductionFactor(1);
101 
102  // Clear statistics
103  //TODO: Delete these after control net refactor.
104  p_totalRegistrations = 0;
105  p_pixelSuccesses = 0;
106  p_subpixelSuccesses = 0;
107  p_patternChipNotEnoughValidDataCount = 0;
108  p_patternZScoreNotMetCount = 0;
109  p_fitChipNoDataCount = 0;
110  p_fitChipToleranceNotMetCount = 0;
111  p_surfaceModelNotEnoughValidDataCount = 0;
112  p_surfaceModelSolutionInvalidCount = 0;
113  p_surfaceModelDistanceInvalidCount = 0;
114 
115  p_sampMovement = 0.;
116  p_lineMovement = 0.;
117 
118  Init();
119  Parse(pvl);
120  }
121 
127  void AutoReg::Init() {
128  // Set computed parameters to NULL so we don't use values from a previous
129  // run
130  p_zScoreMin = Isis::Null;
131  p_zScoreMax = Isis::Null;
132  p_goodnessOfFit = Isis::Null;
133 
134  p_bestSamp = 0;
135  p_bestLine = 0;
136  p_bestFit = Isis::Null;
137 
138  // --------------------------------------------------
139  // Nulling out the fit chip
140  // --------------------------------------------------
141  for(int line = 1; line <= p_fitChip.Lines(); line++) {
142  for(int samp = 1; samp <= p_fitChip.Samples(); samp++) {
143  p_fitChip.SetValue(samp, line, Isis::Null);
144  }
145  }
146  // --------------------------------------------------
147  // Nulling out the reduced pattern chip
148  // --------------------------------------------------
149  for(int line = 1; line <= p_reducedPatternChip.Lines(); line++) {
150  for(int samp = 1; samp <= p_reducedPatternChip.Samples(); samp++) {
151  p_reducedPatternChip.SetValue(samp, line, Isis::Null);
152  }
153  }
154  // --------------------------------------------------
155  // Nulling out the reduced search chip
156  // --------------------------------------------------
157  for(int line = 1; line <= p_reducedSearchChip.Lines(); line++) {
158  for(int samp = 1; samp <= p_reducedSearchChip.Samples(); samp++) {
159  p_reducedSearchChip.SetValue(samp, line, Isis::Null);
160  }
161  }
162 
163  }
164 
166  AutoReg::~AutoReg() {
167 
168  }
169 
207  void AutoReg::Parse(Pvl &pvl) {
208  try {
209  // Get info from Algorithm group
210  PvlGroup &algo = pvl.findGroup("Algorithm", Pvl::Traverse);
211  SetTolerance(algo["Tolerance"]);
212  if(algo.hasKeyword("ChipInterpolator")) {
213  SetChipInterpolator((QString)algo["ChipInterpolator"]);
214  }
215 
216  if(algo.hasKeyword("SubpixelAccuracy")) {
217  SetSubPixelAccuracy((QString)algo["SubpixelAccuracy"] == "True");
218  }
219 
220  if(algo.hasKeyword("ReductionFactor")) {
221  SetReductionFactor((int)algo["ReductionFactor"]);
222  }
223 
224  if (algo.hasKeyword("Gradient")) {
225  SetGradientFilterType((QString)algo["Gradient"]);
226  }
227 
228  // Setup the pattern chip
229  PvlGroup &pchip = pvl.findGroup("PatternChip", Pvl::Traverse);
230  PatternChip()->SetSize((int)pchip["Samples"], (int)pchip["Lines"]);
231 
232  double minimum = Isis::ValidMinimum;
233  double maximum = Isis::ValidMaximum;
234  if(pchip.hasKeyword("ValidMinimum")) minimum = pchip["ValidMinimum"];
235  if(pchip.hasKeyword("ValidMaximum")) maximum = pchip["ValidMaximum"];
236  PatternChip()->SetValidRange(minimum, maximum);
237 
238  if(pchip.hasKeyword("MinimumZScore")) {
239  SetPatternZScoreMinimum((double)pchip["MinimumZScore"]);
240  }
241  if(pchip.hasKeyword("ValidPercent")) {
242  SetPatternValidPercent((double)pchip["ValidPercent"]);
243  }
244 
245  // Setup the search chip
246  PvlGroup &schip = pvl.findGroup("SearchChip", Pvl::Traverse);
247  SearchChip()->SetSize((int)schip["Samples"], (int)schip["Lines"]);
248 
249  minimum = Isis::ValidMinimum;
250  maximum = Isis::ValidMaximum;
251  if(schip.hasKeyword("ValidMinimum")) minimum = schip["ValidMinimum"];
252  if(schip.hasKeyword("ValidMaximum")) maximum = schip["ValidMaximum"];
253  SearchChip()->SetValidRange(minimum, maximum);
254  if(schip.hasKeyword("SubchipValidPercent")) {
255  SetSubsearchValidPercent((double)schip["SubchipValidPercent"]);
256  }
257 
258  // Setup surface model
259  PvlObject ar = pvl.findObject("AutoRegistration");
260  if(ar.hasGroup("SurfaceModel")) {
261  PvlGroup &smodel = ar.findGroup("SurfaceModel", Pvl::Traverse);
262  if(smodel.hasKeyword("DistanceTolerance")) {
263  SetSurfaceModelDistanceTolerance((double)smodel["DistanceTolerance"]);
264  }
265 
266  if(smodel.hasKeyword("WindowSize")) {
267  SetSurfaceModelWindowSize((int)smodel["WindowSize"]);
268  }
269  }
270 
271  }
272  catch(IException &e) {
273  QString msg = "Improper format for AutoReg PVL [" + pvl.fileName() + "]";
274  throw IException(e, IException::User, msg, _FILEINFO_);
275  }
276  return;
277  }
278 
286  void AutoReg::SetGradientFilterType(const QString &gradientFilterType) {
287  if (gradientFilterType == "None") {
288  p_gradientFilterType = None;
289  }
290  else if (gradientFilterType == "Sobel") {
291  p_gradientFilterType = Sobel;
292  }
293  else {
294  throw IException(IException::User,
295  "Invalid Gradient type. Cannot use ["
296  + gradientFilterType + "] to filter chip",
297  _FILEINFO_);
298  }
299  }
300 
301 
302  QString AutoReg::GradientFilterString() const {
303  switch (p_gradientFilterType) {
304  case None: return "None";
305  case Sobel: return "Sobel";
306  default: throw IException(
307  IException::Programmer,
308  "AutoReg only allows Sobel gradient filter or None",
309  _FILEINFO_);
310  }
311  }
312 
313 
325  void AutoReg::SetSubPixelAccuracy(bool on) {
326  p_subpixelAccuracy = on;
327  }
328 
352  void AutoReg::SetPatternValidPercent(const double percent) {
353  if((percent <= 0.0) || (percent > 100.0)) {
354  string msg = "Invalid value for PatternChip ValidPercent ["
355  + IString(percent)
356  + "]. Must be greater than 0.0 and less than or equal to 100.0 (Default is 50.0).";
357  throw IException(IException::User, msg, _FILEINFO_);
358  }
359  p_patternValidPercent = percent;
360  }
361 
362 
380  void AutoReg::SetSubsearchValidPercent(const double percent) {
381  if((percent <= 0.0) || (percent > 100.0)) {
382  string msg = "Invalid value for SearchChip SubchipValidPercent ["
383  + IString(percent) + "]"
384  + "]. Must be greater than 0.0 and less than or equal to 100.0 (Default is 50.0).";
385  throw IException(IException::User, msg, _FILEINFO_);
386  }
387  p_subsearchValidPercent = percent;
388  }
389 
390 
407  void AutoReg::SetPatternZScoreMinimum(double minimum) {
408  if(minimum <= 0.0) {
409  string msg = "Invalid value for PatternChip MinimumZScore ["
410  + IString(minimum)
411  + "]. Must be greater than 0.0. (Default is 1.0).";
412  throw IException(IException::User, msg, _FILEINFO_);
413  }
414  p_minimumPatternZScore = minimum;
415  }
416 
417 
429  void AutoReg::SetTolerance(const double tolerance) {
430  p_tolerance = tolerance;
431  }
432 
453  void AutoReg::SetChipInterpolator(const QString &interpolator) {
454 
456  if(interpolator == "NearestNeighborType") {
457  itype = Isis::Interpolator::NearestNeighborType;
458  }
459  else if(interpolator == "BiLinearType") {
460  itype = Isis::Interpolator::BiLinearType;
461  }
462  else if(interpolator == "CubicConvolutionType") {
463  itype = Isis::Interpolator::CubicConvolutionType;
464  }
465  else {
466  throw IException(IException::User,
467  "Invalid Interpolator type. Cannot use ["
468  + interpolator + "] to load chip",
469  _FILEINFO_);
470  }
471 
472  // Set pattern and search chips to use this interpolator type when reading data from cube
473  p_patternChip.SetReadInterpolator(itype);
474  p_searchChip.SetReadInterpolator(itype);
475  p_reducedPatternChip.SetReadInterpolator(itype);
476  p_reducedSearchChip.SetReadInterpolator(itype);
477 
478  }
479 
493  void AutoReg::SetSurfaceModelWindowSize(int size) {
494  if(size % 2 != 1 || size < 3) {
495  string msg = "Invalid value for SurfaceModel WindowSize ["
496  + IString(size) + "]. Must be an odd number greater than or equal to 3";
497  throw IException(IException::User, msg, _FILEINFO_);
498  }
499  p_windowSize = size;
500  }
501 
514  void AutoReg::SetSurfaceModelDistanceTolerance(double distance) {
515  if(distance <= 0.0) {
516  string msg = "Invalid value for SurfaceModel DistanceTolerance ["
517  + IString(distance) + "]. Must greater than 0.0.";
518  throw IException(IException::User, msg, _FILEINFO_);
519  }
520  p_distanceTolerance = distance;
521  }
522 
523 
534  void AutoReg::SetReductionFactor(int factor) {
535  if(factor < 1) {
536  string msg = "Invalid value for Algorithm ReductionFactor ["
537  + IString(factor) + "]. Must greater than or equal to 1.";
538  throw IException(IException::User, msg, _FILEINFO_);
539  }
540  p_reduceFactor = factor;
541  }
542 
552  Chip AutoReg::Reduce(Chip &chip, int reductionFactor) {
553  Chip rChip((int)chip.Samples() / reductionFactor,
554  (int)chip.Lines() / reductionFactor);
555  if((int)rChip.Samples() < 1 || (int)rChip.Lines() < 1) {
556  return chip;
557  }
558 
559  // ----------------------------------
560  // Fill the reduced Chip with nulls.
561  // ----------------------------------
562  for(int line = 1; line <= rChip.Lines(); line++) {
563  for(int samp = 1; samp <= rChip.Samples(); samp++) {
564  rChip.SetValue(samp, line, Isis::Null);
565  }
566  }
567 
568  Statistics stats;
569  for(int l = 1; l <= rChip.Lines(); l++) {
570  int istartLine = (l - 1) * reductionFactor + 1;
571  int iendLine = istartLine + reductionFactor - 1;
572  for(int s = 1; s <= rChip.Samples(); s++) {
573 
574  int istartSamp = (s - 1) * reductionFactor + 1;
575  int iendSamp = istartSamp + reductionFactor - 1;
576 
577  stats.Reset();
578  for(int line = istartLine; line < iendLine; line++) {
579  for(int sample = istartSamp; sample < iendSamp; sample++) {
580  stats.AddData(chip.GetValue(sample, line));
581  }
582  }
583  rChip.SetValue(s, l, stats.Average());
584  }
585  }
586  return rChip;
587  }
588 
589 
600  AutoReg::RegisterStatus AutoReg::Register() {
601  // The search chip must be bigger than the pattern chip by N pixels in
602  // both directions for a successful surface model
603  int N = p_windowSize / 2 + 1;
604 
605  if(p_searchChip.Samples() < p_patternChip.Samples() + N) {
606  string msg = "Search chips samples [";
607  msg += IString(p_searchChip.Samples()) + "] must be at ";
608  msg += "least [" + IString(N) + "] pixels wider than the pattern chip samples [";
609  msg += IString(p_patternChip.Samples()) + "] for successful surface modeling";
610  throw IException(IException::User, msg, _FILEINFO_);
611  }
612 
613  if(p_searchChip.Lines() < p_patternChip.Lines() + N) {
614  string msg = "Search chips lines [";
615  msg += IString(p_searchChip.Lines()) + "] must be at ";
616  msg += "least [" + IString(N) + "] pixels taller than the pattern chip lines [";
617  msg += IString(p_patternChip.Lines()) + "] for successful surface modeling";
618  throw IException(IException::User, msg, _FILEINFO_);
619  }
620 
621  Init();
622  p_totalRegistrations++;
623 
624  // Create copies of the search and pattern chips and run a gradient filter
625  // over them before attempting to perform a match. We do this so that
626  // multiple calls to this method won't result in having a gradient filter
627  // applied multiple times to the same chip.
628  Chip gradientPatternChip(p_patternChip);
629  Chip gradientSearchChip(p_searchChip);
630  ApplyGradientFilter(gradientPatternChip);
631  ApplyGradientFilter(gradientSearchChip);
632 
633  // See if the pattern chip has enough good data
634  if(!gradientPatternChip.IsValid(p_patternValidPercent)) {
635  p_patternChipNotEnoughValidDataCount++;
636  p_registrationStatus = PatternChipNotEnoughValidData;
637  return PatternChipNotEnoughValidData;
638  }
639 
640  if(!ComputeChipZScore(gradientPatternChip)) {
641  p_patternZScoreNotMetCount++;
642  p_registrationStatus = PatternZScoreNotMet;
643  return PatternZScoreNotMet;
644  }
645 
665  int startSamp = (gradientPatternChip.Samples() - 1) / 2 + 1;
666  int startLine = (gradientPatternChip.Lines() - 1) / 2 + 1;
667  int endSamp = gradientSearchChip.Samples() - startSamp + 1;
668  int endLine = gradientSearchChip.Lines() - startLine + 1;
669 
670  // ----------------------------------------------------------------------
671  // Before we attempt to apply the reduction factor, we need to make sure
672  // we won't produce a chip of a bad size.
673  // ----------------------------------------------------------------------
674  if (p_reduceFactor != 1) {
675  if(gradientPatternChip.Samples() / p_reduceFactor < 2 || gradientPatternChip.Lines() / p_reduceFactor < 2) {
676  string msg = "Reduction factor is too large";
677  throw IException(IException::User, msg, _FILEINFO_);
678  }
679  }
680 
681  // Establish the center search tack point as best pixel to start for the
682  // adaptive algorithm prior to reduction.
683  int bestSearchSamp = gradientSearchChip.TackSample();
684  int bestSearchLine = gradientSearchChip.TackLine();
685 
686  // ---------------------------------------------------------------------
687  // if the reduction factor is still not equal to one, then we go ahead
688  // with the reduction of the chips and call Match to get the first
689  // estimate of the best line/sample.
690  // ---------------------------------------------------------------------
691  if(p_reduceFactor != 1) {
692  p_reducedPatternChip.SetSize((int)gradientPatternChip.Samples() / p_reduceFactor,
693  (int)gradientPatternChip.Lines() / p_reduceFactor);
694 
695  // ----------------------------------
696  // Fill the reduced Chip with nulls.
697  // ----------------------------------
698  for(int line = 1; line <= p_reducedPatternChip.Lines(); line++) {
699  for(int samp = 1; samp <= p_reducedPatternChip.Samples(); samp++) {
700  p_reducedPatternChip.SetValue(samp, line, Isis::Null);
701  }
702  }
703 
704  p_reducedPatternChip = Reduce(gradientPatternChip, p_reduceFactor);
705  if(!ComputeChipZScore(p_reducedPatternChip)) {
706  p_patternZScoreNotMetCount++;
707  p_registrationStatus = PatternZScoreNotMet;
708  return PatternZScoreNotMet;
709  }
710 
711  p_reducedSearchChip = Reduce(gradientSearchChip, p_reduceFactor);
712  int reducedStartSamp = (p_reducedPatternChip.Samples() - 1) / 2 + 1;
713  int reducedEndSamp = p_reducedSearchChip.Samples() - reducedStartSamp + 1;
714  int reducedStartLine = (p_reducedPatternChip.Lines() - 1) / 2 + 1;
715  int reducedEndLine = p_reducedSearchChip.Lines() - reducedStartLine + 1;
716 
717  Match(p_reducedSearchChip, p_reducedPatternChip, p_reducedFitChip,
718  reducedStartSamp, reducedEndSamp, reducedStartLine, reducedEndLine);
719 
720  if(p_bestFit == Isis::Null) {
721  p_fitChipNoDataCount++;
722  p_registrationStatus = FitChipNoData;
723  return FitChipNoData;
724  }
725 
726  // ------------------------------------------------------
727  // p_bestSamp and p_bestLine are set in Match() which is
728  // called above.
729  // -----------------------------------------------------
730  int bs = (p_bestSamp - 1) * p_reduceFactor + ((p_reduceFactor - 1) / 2) + 1;
731  int bl = (p_bestLine - 1) * p_reduceFactor + ((p_reduceFactor - 1) / 2) + 1;
732 
733  // ---------------------------------------------------------------
734  // Now we grow our window size according to the reduction factor.
735  // And we grow around where the first call Match() told us was the
736  // best line/sample.
737  // ---------------------------------------------------------------
738  int newstartSamp = bs - p_reduceFactor - p_windowSize - 1;
739  int newendSamp = bs + p_reduceFactor + p_windowSize + 1;
740  int newstartLine = bl - p_reduceFactor - p_windowSize - 1;
741  int newendLine = bl + p_reduceFactor + p_windowSize + 1;
742 
743  if(newstartLine < startLine) newstartLine = startLine;
744  if(newendSamp > endSamp) newendSamp = endSamp;
745  if(newstartSamp < startSamp) newstartSamp = startSamp;
746  if(newendLine > endLine) newendLine = endLine;
747 
748  startSamp = newstartSamp;
749  endSamp = newendSamp;
750  startLine = newstartLine;
751  endLine = newendLine;
752  // We have found a good pixel in the reduction chip, but we
753  // don't want to use its position, so reset in prep. for
754  // non-adaptive registration. Save it off for the adaptive algorithm.
755  bestSearchSamp = bs;
756  bestSearchLine = bl;
757  p_bestSamp = 0;
758  p_bestLine = 0;
759  p_bestFit = Isis::Null;
760  }
761 
762  p_registrationStatus = Registration(gradientSearchChip, gradientPatternChip,
763  p_fitChip, startSamp, startLine, endSamp, endLine,
764  bestSearchSamp, bestSearchLine);
765 
766  gradientSearchChip.SetChipPosition(p_chipSample, p_chipLine);
767  p_searchChip.SetChipPosition(p_chipSample, p_chipLine);
768  p_cubeSample = gradientSearchChip.CubeSample();
769  p_cubeLine = gradientSearchChip.CubeLine();
770 
771  // Save off the gradient search and pattern chips if we used a gradient
772  // filter.
773  if (p_gradientFilterType != None) {
774  p_gradientSearchChip = gradientSearchChip;
775  p_gradientPatternChip = gradientPatternChip;
776  }
777 
778  p_goodnessOfFit = p_bestFit;
779 
780  if (Success()) {
781  if (p_registrationStatus == AutoReg::SuccessSubPixel)
782  p_subpixelSuccesses++;
783  else
784  p_pixelSuccesses++;
785  }
786 
787  return p_registrationStatus;
788  }
789 
790 
824  AutoReg::RegisterStatus AutoReg::Registration(Chip &sChip, Chip &pChip,
825  Chip &fChip, int startSamp, int startLine, int endSamp, int endLine,
826  int bestSamp, int bestLine) {
827 
828  // Not adaptive, continue with slower search traverse
829  Match(sChip, pChip, fChip, startSamp, endSamp, startLine, endLine);
830 
831  // Check to see if we went through the fit chip and never got a fit at
832  // any location.
833  if (p_bestFit == Isis::Null) {
834  p_fitChipNoDataCount++;
835  p_registrationStatus = FitChipNoData;
836  return FitChipNoData;
837  }
838 
839  // Now see if we satisified the goodness of fit tolerance
840  if (!CompareFits(p_bestFit, Tolerance())) {
841  p_fitChipToleranceNotMetCount++;
842  p_registrationStatus = FitChipToleranceNotMet;
843  return FitChipToleranceNotMet;
844  }
845 
846  // Try to fit a model for sub-pixel accuracy if necessary
847  if (p_subpixelAccuracy && !IsIdeal(p_bestFit)) {
848  Chip window(p_windowSize, p_windowSize);
849  fChip.Extract(p_bestSamp, p_bestLine, window);
850  window.SetChipPosition(p_windowSize / 2 + 1, p_windowSize / 2 + 1);
851 
852  // Make sure more than 2/3 of the data in the window is valid. Otherwise,
853  // we are likely too close to the edge.
854  if (!window.IsValid(100.0 * 2.1 / 3.0)) {
855  p_surfaceModelNotEnoughValidDataCount++;
856  p_registrationStatus = SurfaceModelNotEnoughValidData;
857  p_chipSample = p_bestSamp;
858  p_chipLine = p_bestLine;
859  return SurfaceModelNotEnoughValidData;
860  }
861 
862  // Now that we know we have enough data to model the surface we call
863  // SetSubpixelPosition() to get the sub-pixel accuracy we are looking for.
864  bool computedSubPixel = SetSubpixelPosition(window);
865  if (!computedSubPixel) {
866  p_chipSample = p_bestSamp;
867  p_chipLine = p_bestLine;
868  p_registrationStatus = SurfaceModelSolutionInvalid;
869  return SurfaceModelSolutionInvalid;
870  }
871 
872  // See if the surface model solution moved too far from our whole pixel
873  // solution
874  p_sampMovement = fabs(p_bestSamp - p_chipSample);
875  p_lineMovement = fabs(p_bestLine - p_chipLine);
876  if (p_sampMovement > p_distanceTolerance ||
877  p_lineMovement > p_distanceTolerance) {
878 
879  p_surfaceModelDistanceInvalidCount++;
880  p_registrationStatus = SurfaceModelDistanceInvalid;
881  p_chipSample = p_bestSamp;
882  p_chipLine = p_bestLine;
883  return SurfaceModelDistanceInvalid;
884  }
885 
886  p_registrationStatus = SuccessSubPixel;
887  return SuccessSubPixel;
888  }
889  else {
890  p_chipSample = p_bestSamp;
891  p_chipLine = p_bestLine;
892  p_registrationStatus = SuccessPixel;
893  return SuccessPixel;
894  }
895  }
896 
897 
908  bool AutoReg::ComputeChipZScore(Chip &chip) {
909  Statistics patternStats;
910  for(int i = 0; i < chip.Samples(); i++) {
911  double pixels[chip.Lines()];
912  for(int j = 0; j < chip.Lines(); j++) {
913  pixels[j] = chip.GetValue(i + 1, j + 1);
914  }
915  patternStats.AddData(pixels, chip.Lines());
916  }
917 
918  // If it does not pass, return
919  p_zScoreMin = patternStats.ZScore(patternStats.Minimum());
920  p_zScoreMax = patternStats.ZScore(patternStats.Maximum());
921 
922  // p_zScoreMin is made negative here so as to make it the equivalent of
923  // taking the absolute value (because p_zScoreMin is guaranteed to be
924  // negative)
925  if (p_zScoreMax < p_minimumPatternZScore && -p_zScoreMin < p_minimumPatternZScore) {
926  return false;
927  }
928  else {
929  return true;
930  }
931  }
932 
940  void AutoReg::ApplyGradientFilter(Chip &chip) {
941  if (p_gradientFilterType == None) {
942  return;
943  }
944 
945  // Use a different subchip size depending on which gradient filter is
946  // being applied.
947  int subChipWidth;
948  if (p_gradientFilterType == Sobel) {
949  subChipWidth = 3;
950  }
951  else {
952  // Perform extra sanity check.
953  string msg =
954  "No rule to set sub-chip width for selected Gradient Filter Type.";
955  throw IException(IException::Programmer, msg, _FILEINFO_);
956  }
957 
958  // Create a new chip to hold output during processing.
959  Chip filteredChip(chip.Samples(), chip.Lines());
960 
961  // Move the subchip through the chip, extracting the contents into a buffer
962  // of the same shape. This simulates the processing of a cube by boxcar,
963  // but since that can only operate on cubes, this functionality had to be
964  // replicated for use on chips.
965  for (int line = 1; line <= chip.Lines(); line++) {
966  for (int sample = 1; sample <= chip.Samples(); sample++) {
967  Chip subChip = chip.Extract(subChipWidth, subChipWidth,
968  sample, line);
969 
970  // Fill a buffer with subchip's contents. Since we'll never be storing
971  // raw bytes in the buffer, we don't care about the pixel type.
972  Buffer buffer(subChipWidth, subChipWidth, 1, Isis::None);
973  double *doubleBuffer = buffer.DoubleBuffer();
974  int bufferIndex = 0;
975  for (int subChipLine = 1; subChipLine <= subChip.Lines();
976  subChipLine++) {
977  for (int subChipSample = 1; subChipSample <= subChip.Samples();
978  subChipSample++) {
979  doubleBuffer[bufferIndex] = subChip.GetValue(subChipSample,
980  subChipLine);
981  bufferIndex++;
982  }
983  }
984 
985  // Calculate gradient based on contents in buffer and insert it into
986  // output chip.
987  double newPixelValue = 0;
988  if (p_gradientFilterType == Sobel) {
989  SobelGradient(buffer, newPixelValue);
990  }
991  filteredChip.SetValue(sample, line, newPixelValue);
992  }
993  }
994 
995  // Copy the data from the filtered chip back into the original chip.
996  for (int line = 1; line <= filteredChip.Lines(); line++) {
997  for (int sample = 1; sample <= filteredChip.Samples(); sample++) {
998  chip.SetValue(sample, line, filteredChip.GetValue(sample, line));
999  }
1000  }
1001  }
1002 
1003 
1013  void AutoReg::SobelGradient(Buffer &in, double &v) {
1014  bool specials = false;
1015  for(int i = 0; i < in.size(); ++i) {
1016  if(IsSpecial(in[i])) {
1017  specials = true;
1018  }
1019  }
1020  if(specials) {
1021  v = Isis::Null;
1022  return;
1023  }
1024  v = abs((in[0] + 2 * in[1] + in[2]) - (in[6] + 2 * in[7] + in[8])) +
1025  abs((in[2] + 2 * in[5] + in[8]) - (in[0] + 2 * in[3] + in[6]));
1026  }
1027 
1044  void AutoReg::Match(Chip &sChip, Chip &pChip, Chip &fChip, int startSamp, int endSamp, int startLine, int endLine) {
1045  // Sanity check. Should have been caught by the two previous tests
1046  if(startSamp == endSamp && startLine == endLine) {
1047  string msg = "StartSample [" + IString(startSamp) + "] = EndSample ["
1048  + IString(endSamp) + "] and StartLine [" + IString(startLine) + " = EndLine ["
1049  + IString(endLine) + "].";
1050  throw IException(IException::Programmer, msg, _FILEINFO_);
1051  }
1052 
1053  // Ok create a fit chip whose size is the same as the search chip
1054  // and then fill it with nulls
1055  fChip.SetSize(sChip.Samples(), sChip.Lines());
1056  for(int line = 1; line <= fChip.Lines(); line++) {
1057  for(int samp = 1; samp <= fChip.Samples(); samp++) {
1058  fChip.SetValue(samp, line, Isis::Null);
1059  }
1060  }
1061 
1062  // Create a chip the same size as the pattern chip.
1063  Chip subsearch(pChip.Samples(), pChip.Lines());
1064 
1065  for(int line = startLine; line <= endLine; line++) {
1066  for(int samp = startSamp; samp <= endSamp; samp++) {
1067  // Extract the subsearch chip and make sure it has enough valid data
1068  sChip.Extract(samp, line, subsearch);
1069 
1070 // if(!subsearch.IsValid(p_patternValidPercent)) continue;
1071  if(!subsearch.IsValid(p_subsearchValidPercent)) continue;
1072 
1073  // Try to match the two subchips
1074  double fit = MatchAlgorithm(pChip, subsearch);
1075 
1076  // If we had a fit save off information about that fit
1077  if(fit != Isis::Null) {
1078  fChip.SetValue(samp, line, fit);
1079  if((p_bestFit == Isis::Null) || CompareFits(fit, p_bestFit)) {
1080  p_bestFit = fit;
1081  p_bestSamp = samp;
1082  p_bestLine = line;
1083  }
1084  }
1085  }
1086  }
1087  }
1088 
1089 
1100  bool AutoReg::SetSubpixelPosition(Chip &window) {
1101  // The best correlation will be at the center of the window
1102  // if it's smaller than the edge DN's invert the chip DNs
1103  double samples = window.Samples();
1104  double lines= window.Lines();
1105  double bestDN = window.GetValue(window.ChipSample(), window.ChipLine());
1106  if (bestDN < window.GetValue(1, 1)) {
1107  for (int s=1; s <= samples; s++)
1108  for (int l=1; l <= lines; l++)
1109  window.SetValue(s, l, 1.0/window.GetValue(s, l)); //invert all the window DN's
1110  bestDN = 1 / bestDN;
1111  }
1112 
1113  // Find the greatest edge DN
1114  double greatestEdgeDn = 0.0;
1115  for (int s = 1; s <= samples; s++) {
1116  greatestEdgeDn = max(window.GetValue(s, 1), greatestEdgeDn);
1117  greatestEdgeDn = max(window.GetValue(s, lines), greatestEdgeDn);
1118  }
1119  for (int l = 2; l <= lines - 1; l++) {
1120  greatestEdgeDn = max(window.GetValue(1, l), greatestEdgeDn);
1121  greatestEdgeDn = max(window.GetValue(samples, l), greatestEdgeDn);
1122  }
1123 
1124  //This is a small shift so the the centroid doesn't reach the edge, add 20%
1125  // of the difference between the hightest edge DN and the max DN to the highest edge DN
1126  //The 20% shift added here is somewhat arbitrary, but was choosen because it worked well
1127  // for the maximum correlation tests we did. For new area based algorithms we may want
1128  // to revist this. Possible make it a function of the match type
1129  double temp = greatestEdgeDn + 0.2 * (bestDN - greatestEdgeDn);
1130 
1131  Centroid floodFill;
1132  floodFill.setDNRange(temp, 1e100);
1133 
1134  Chip selectionChip(window);
1135  floodFill.select(&window, &selectionChip);
1136 
1137  double windowSample;
1138  double windowLine;
1139  floodFill.centerOfMassWeighted(
1140  &window, &selectionChip, &windowSample, &windowLine);
1141 
1142  int offsetS = p_bestSamp - window.ChipSample();
1143  int offsetL = p_bestLine - window.ChipLine();
1144  p_chipSample = windowSample + offsetS;
1145  p_chipLine = windowLine + offsetL;
1146 
1147  if (p_chipSample != p_chipSample) {
1148  p_surfaceModelSolutionInvalidCount++;
1149  return false; //this should never happen, but just in case...
1150  }
1151 
1152  return true;
1153  }
1154 
1155 
1165  bool AutoReg::CompareFits(double fit1, double fit2) {
1166  return(std::fabs(fit1 - IdealFit()) <= std::fabs(fit2 - IdealFit()));
1167  }
1168 
1175  bool AutoReg::IsIdeal(double fit) {
1176  return(std::fabs(IdealFit() - fit) < 0.00001);
1177  }
1178 
1179 
1190  Pvl AutoReg::RegistrationStatistics() {
1191  Pvl pvl;
1192  PvlGroup stats("AutoRegStatistics");
1193  stats += Isis::PvlKeyword("Total", toString(p_totalRegistrations));
1194  stats += Isis::PvlKeyword("Successful", toString(p_pixelSuccesses + p_subpixelSuccesses));
1195  stats += Isis::PvlKeyword("Failure", toString(p_totalRegistrations - (p_pixelSuccesses + p_subpixelSuccesses)));
1196  pvl.addGroup(stats);
1197 
1198  PvlGroup successes("Successes");
1199  successes += PvlKeyword("SuccessPixel", toString(p_pixelSuccesses));
1200  successes += PvlKeyword("SuccessSubPixel", toString(p_subpixelSuccesses));
1201  pvl.addGroup(successes);
1202 
1203  PvlGroup grp("PatternChipFailures");
1204  grp += PvlKeyword("PatternNotEnoughValidData", toString(p_patternChipNotEnoughValidDataCount));
1205  grp += PvlKeyword("PatternZScoreNotMet", toString(p_patternZScoreNotMetCount));
1206  pvl.addGroup(grp);
1207 
1208  PvlGroup fit("FitChipFailures");
1209  fit += PvlKeyword("FitChipNoData", toString(p_fitChipNoDataCount));
1210  fit += PvlKeyword("FitChipToleranceNotMet", toString(p_fitChipToleranceNotMetCount));
1211  pvl.addGroup(fit);
1212 
1213  PvlGroup model("SurfaceModelFailures");
1214  model += PvlKeyword("SurfaceModelNotEnoughValidData", toString(p_surfaceModelNotEnoughValidDataCount));
1215  model += PvlKeyword("SurfaceModelSolutionInvalid", toString(p_surfaceModelSolutionInvalidCount));
1216  model += PvlKeyword("SurfaceModelDistanceInvalid", toString(p_surfaceModelDistanceInvalidCount));
1217  pvl.addGroup(model);
1218 
1219  return (AlgorithmStatistics(pvl));
1220  }
1221 
1229  PvlGroup AutoReg::RegTemplate() {
1230  PvlGroup reg("AutoRegistration");
1231 
1232  PvlGroup &algo = p_template.findGroup("Algorithm", Pvl::Traverse);
1233  reg += PvlKeyword("Algorithm", algo["Name"][0]);
1234  reg += PvlKeyword("Tolerance", algo["Tolerance"][0]);
1235  if(algo.hasKeyword("SubpixelAccuracy")) {
1236  reg += PvlKeyword("SubpixelAccuracy", algo["SubpixelAccuracy"][0]);
1237  }
1238  if(algo.hasKeyword("ReductionFactor")) {
1239  reg += PvlKeyword("ReductionFactor", algo["ReductionFactor"][0]);
1240  }
1241  if(algo.hasKeyword("Gradient")) {
1242  reg += PvlKeyword("Gradient", algo["Gradient"][0]);
1243  }
1244 
1245  PvlGroup &pchip = p_template.findGroup("PatternChip", Pvl::Traverse);
1246  reg += PvlKeyword("PatternSamples", pchip["Samples"][0]);
1247  reg += PvlKeyword("PatternLines", pchip["Lines"][0]);
1248  if(pchip.hasKeyword("ValidMinimum")) {
1249  reg += PvlKeyword("PatternMinimum", pchip["ValidMinimum"][0]);
1250  }
1251  if(pchip.hasKeyword("ValidMaximum")) {
1252  reg += PvlKeyword("PatternMaximum", pchip["ValidMaximum"][0]);
1253  }
1254  if(pchip.hasKeyword("MinimumZScore")) {
1255  reg += PvlKeyword("MinimumZScore", pchip["MinimumZScore"][0]);
1256  }
1257  if(pchip.hasKeyword("ValidPercent")) {
1258  SetPatternValidPercent((double)pchip["ValidPercent"]);
1259  reg += PvlKeyword("ValidPercent", pchip["ValidPercent"][0]);
1260  }
1261 
1262  PvlGroup &schip = p_template.findGroup("SearchChip", Pvl::Traverse);
1263  reg += PvlKeyword("SearchSamples", schip["Samples"][0]);
1264  reg += PvlKeyword("SearchLines", schip["Lines"][0]);
1265  if(schip.hasKeyword("ValidMinimum")) {
1266  reg += PvlKeyword("SearchMinimum", schip["ValidMinimum"][0]);
1267  }
1268  if(schip.hasKeyword("ValidMaximum")) {
1269  reg += PvlKeyword("SearchMaximum", schip["ValidMaximum"][0]);
1270  }
1271  if(schip.hasKeyword("SubchipValidPercent")) {
1272  SetSubsearchValidPercent((double)schip["SubchipValidPercent"]);
1273  reg += PvlKeyword("SubchipValidPercent", schip["SubchipValidPercent"][0]);
1274  }
1275 
1276  if(p_template.hasGroup("SurfaceModel")) {
1277  PvlGroup &smodel = p_template.findGroup("SurfaceModel", Pvl::Traverse);
1278  if(smodel.hasKeyword("DistanceTolerance")) {
1279  reg += PvlKeyword("DistanceTolerance", smodel["DistanceTolerance"][0]);
1280  }
1281 
1282  if(smodel.hasKeyword("WindowSize")) {
1283  reg += PvlKeyword("WindowSize", smodel["WindowSize"][0]);
1284  }
1285  }
1286 
1287  return reg;
1288  }
1289 
1290 
1302  PvlGroup AutoReg::UpdatedTemplate() {
1303  PvlGroup reg("AutoRegistration");
1304 
1305  reg += PvlKeyword("Algorithm", AlgorithmName());
1306  reg += PvlKeyword("Tolerance", toString(Tolerance()));
1307  reg += PvlKeyword("SubpixelAccuracy",
1308  SubPixelAccuracy() ? "True" : "False");
1309  reg += PvlKeyword("ReductionFactor", toString(ReductionFactor()));
1310  reg += PvlKeyword("Gradient", GradientFilterString());
1311 
1312  Chip *pattern = PatternChip();
1313  reg += PvlKeyword("PatternSamples", toString(pattern->Samples()));
1314  reg += PvlKeyword("PatternLines", toString(pattern->Lines()));
1315  reg += PvlKeyword("MinimumZScore", toString(MinimumZScore()));
1316  reg += PvlKeyword("ValidPercent", toString(PatternValidPercent()));
1317  // TODO Chip needs accessors to valid minimum and maximum
1318 
1319  Chip *search = SearchChip();
1320  reg += PvlKeyword("SearchSamples", toString(search->Samples()));
1321  reg += PvlKeyword("SearchLines", toString(search->Lines()));
1322  reg += PvlKeyword("SubchipValidPercent", toString(SubsearchValidPercent()));
1323  // TODO Chip needs accessors to valid minimum and maximum
1324 
1325  if (SubPixelAccuracy()) {
1326  reg += PvlKeyword("DistanceTolerance", toString(DistanceTolerance()));
1327  reg += PvlKeyword("WindowSize", toString(WindowSize()));
1328  }
1329 
1330  return reg;
1331  }
1332 }
1333 
Buffer for reading and writing cube data.
Definition: Buffer.h:69
void SetChipPosition(const double sample, const double line)
Compute the position of the cube given a chip coordinate.
Definition: Chip.cpp:665
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
double * DoubleBuffer() const
Returns the value of the shape buffer.
Definition: Buffer.h:154
const double Null
Value for an Isis Null pixel.
Definition: SpecialPixel.h:110
interpType
The interpolator type, including: None, Nearest Neighbor, BiLinear or Cubic Convultion.
Definition: Interpolator.h:57
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:141
const double ValidMinimum
The minimum valid double value for Isis pixels.
Definition: SpecialPixel.h:102
double Minimum() const
Returns the absolute minimum double found in all data passed through the AddData method.
Definition: Statistics.cpp:395
A small chip of data used for pattern matching.
Definition: Chip.h:102
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
Definition: PvlObject.h:286
int select(Chip *inputChip, Chip *selectionChip)
Given a range of DN this function creates a biniary chip for all continuous pixels that have the DN w...
Definition: Centroid.cpp:44
void addGroup(const Isis::PvlGroup &group)
Add a group to the object.
Definition: PvlObject.h:198
Namespace for the standard library.
bool hasGroup(const QString &name) const
Returns a boolean value based on whether the object has the specified group or not.
Definition: PvlObject.h:222
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:226
Chip Extract(int samples, int lines, int samp, int line)
Extract a sub-chip from a chip.
Definition: Chip.cpp:749
int size() const
Returns the total number of pixels in the shape buffer.
Definition: Buffer.h:113
double Maximum() const
Returns the absolute maximum double found in all data passed through the AddData method.
Definition: Statistics.cpp:416
This class is used to accumulate statistics on double arrays.
Definition: Statistics.h:107
int Lines() const
Definition: Chip.h:122
bool IsValid(int sample, int line)
Definition: Chip.h:256
Contains multiple PvlContainers.
Definition: PvlGroup.h:57
void Reset()
Reset all accumulators and counters to zero.
Definition: Statistics.cpp:126
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
double CubeLine() const
Definition: Chip.h:226
A single keyword-value pair.
Definition: PvlKeyword.h:98
double CubeSample() const
Definition: Chip.h:219
bool IsSpecial(const double d)
Returns if the input pixel is special.
Definition: SpecialPixel.h:212
int TackSample() const
This method returns a chip&#39;s fixed tack sample; the middle of the chip.
Definition: Chip.h:192
double ChipLine() const
Definition: Chip.h:242
void SetSize(const int samples, const int lines)
Change the size of the Chip.
Definition: Chip.cpp:156
Container for cube-like labels.
Definition: Pvl.h:135
void SetValue(int sample, int line, const double &value)
Sets a value in the chip.
Definition: Chip.h:142
const double ValidMaximum
The maximum valid double value for Isis pixels.
Definition: SpecialPixel.h:137
int Samples() const
Definition: Chip.h:115
RegisterStatus
Enumeration of the Register() method&#39;s return status.
Definition: AutoReg.h:195
Selection class derived from the Pure Virtual Parent Class for all Selection classes ...
Definition: Centroid.h:46
QString fileName() const
Returns the filename used to initialise the Pvl object.
Definition: PvlContainer.h:246
Isis exception class.
Definition: IException.h:107
Adds specific functionality to C++ strings.
Definition: IString.h:181
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
int setDNRange(double minimumDN, double maximumDN)
Set the range of the DNs.
Definition: Centroid.cpp:140
double ChipSample() const
Definition: Chip.h:235
double GetValue(int sample, int line)
Loads a Chip with a value.
Definition: Chip.h:161
double ZScore(const double value) const
This method returns the better of the z-score of the given value.
Definition: Statistics.cpp:654
void AddData(const double *data, const unsigned int count)
Add an array of doubles to the accumulators and counters.
Definition: Statistics.cpp:154
Contains Pvl Groups and Pvl Objects.
Definition: PvlObject.h:74
Reduce the pixel dimensions of an image.
Definition: Reduce.h:42
double Average() const
Computes and returns the average.
Definition: Statistics.cpp:313
int TackLine() const
This method returns a chip&#39;s fixed tack line; the middle of the chip.
Definition: Chip.h:203