Isis 3 Programmer Reference
AutoReg.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "AutoReg.h"
8#include "Buffer.h"
9#include "Centroid.h"
10#include "Chip.h"
11#include "FileName.h"
12#include "Histogram.h"
13#include "IException.h"
14#include "Interpolator.h"
15#include "LeastSquares.h"
16#include "Matrix.h"
17#include "PixelType.h"
18#include "Plugin.h"
19#include "PolynomialBivariate.h"
20#include "Pvl.h"
21
22using namespace std;
23namespace Isis {
67 p_template = pvl.findObject("AutoRegistration");
68
69 // Set default parameters
72 p_fitChip.SetSize(5, 5);
77
82
86
88
89 // Clear statistics
90 //TODO: Delete these after control net refactor.
101
102 p_sampMovement = 0.;
103 p_lineMovement = 0.;
104
105 Init();
106 Parse(pvl);
107 }
108
115 // Set computed parameters to NULL so we don't use values from a previous
116 // run
120
121 p_bestSamp = 0;
122 p_bestLine = 0;
124
125 // --------------------------------------------------
126 // Nulling out the fit chip
127 // --------------------------------------------------
128 for(int line = 1; line <= p_fitChip.Lines(); line++) {
129 for(int samp = 1; samp <= p_fitChip.Samples(); samp++) {
130 p_fitChip.SetValue(samp, line, Isis::Null);
131 }
132 }
133 // --------------------------------------------------
134 // Nulling out the reduced pattern chip
135 // --------------------------------------------------
136 for(int line = 1; line <= p_reducedPatternChip.Lines(); line++) {
137 for(int samp = 1; samp <= p_reducedPatternChip.Samples(); samp++) {
139 }
140 }
141 // --------------------------------------------------
142 // Nulling out the reduced search chip
143 // --------------------------------------------------
144 for(int line = 1; line <= p_reducedSearchChip.Lines(); line++) {
145 for(int samp = 1; samp <= p_reducedSearchChip.Samples(); samp++) {
147 }
148 }
149
150 }
151
154
155 }
156
194 void AutoReg::Parse(Pvl &pvl) {
195 try {
196 // Get info from Algorithm group
197 PvlGroup &algo = pvl.findGroup("Algorithm", Pvl::Traverse);
198 SetTolerance(algo["Tolerance"]);
199 if(algo.hasKeyword("ChipInterpolator")) {
200 SetChipInterpolator((QString)algo["ChipInterpolator"]);
201 }
202
203 if(algo.hasKeyword("SubpixelAccuracy")) {
204 SetSubPixelAccuracy((QString)algo["SubpixelAccuracy"] == "True");
205 }
206
207 if(algo.hasKeyword("ReductionFactor")) {
208 SetReductionFactor((int)algo["ReductionFactor"]);
209 }
210
211 if (algo.hasKeyword("Gradient")) {
212 SetGradientFilterType((QString)algo["Gradient"]);
213 }
214
215 // Setup the pattern chip
216 PvlGroup &pchip = pvl.findGroup("PatternChip", Pvl::Traverse);
217 PatternChip()->SetSize((int)pchip["Samples"], (int)pchip["Lines"]);
218
219 double minimum = Isis::ValidMinimum;
220 double maximum = Isis::ValidMaximum;
221 if(pchip.hasKeyword("ValidMinimum")) minimum = pchip["ValidMinimum"];
222 if(pchip.hasKeyword("ValidMaximum")) maximum = pchip["ValidMaximum"];
223 PatternChip()->SetValidRange(minimum, maximum);
224
225 if(pchip.hasKeyword("MinimumZScore")) {
226 SetPatternZScoreMinimum((double)pchip["MinimumZScore"]);
227 }
228 if(pchip.hasKeyword("ValidPercent")) {
229 SetPatternValidPercent((double)pchip["ValidPercent"]);
230 }
231
232 // Setup the search chip
233 PvlGroup &schip = pvl.findGroup("SearchChip", Pvl::Traverse);
234 SearchChip()->SetSize((int)schip["Samples"], (int)schip["Lines"]);
235
236 minimum = Isis::ValidMinimum;
237 maximum = Isis::ValidMaximum;
238 if(schip.hasKeyword("ValidMinimum")) minimum = schip["ValidMinimum"];
239 if(schip.hasKeyword("ValidMaximum")) maximum = schip["ValidMaximum"];
240 SearchChip()->SetValidRange(minimum, maximum);
241 if(schip.hasKeyword("SubchipValidPercent")) {
242 SetSubsearchValidPercent((double)schip["SubchipValidPercent"]);
243 }
244
245 // Setup surface model
246 PvlObject ar = pvl.findObject("AutoRegistration");
247 if(ar.hasGroup("SurfaceModel")) {
248 PvlGroup &smodel = ar.findGroup("SurfaceModel", Pvl::Traverse);
249 if(smodel.hasKeyword("DistanceTolerance")) {
250 SetSurfaceModelDistanceTolerance((double)smodel["DistanceTolerance"]);
251 }
252
253 if(smodel.hasKeyword("WindowSize")) {
254 SetSurfaceModelWindowSize((int)smodel["WindowSize"]);
255 }
256 }
257
258 }
259 catch(IException &e) {
260 QString msg = "Improper format for AutoReg PVL [" + pvl.fileName() + "]";
261 throw IException(e, IException::User, msg, _FILEINFO_);
262 }
263 return;
264 }
265
273 void AutoReg::SetGradientFilterType(const QString &gradientFilterType) {
274 if (gradientFilterType == "None") {
276 }
277 else if (gradientFilterType == "Sobel") {
279 }
280 else {
282 "Invalid Gradient type. Cannot use ["
283 + gradientFilterType + "] to filter chip",
284 _FILEINFO_);
285 }
286 }
287
288
289 QString AutoReg::GradientFilterString() const {
290 switch (p_gradientFilterType) {
291 case None: return "None";
292 case Sobel: return "Sobel";
293 default: throw IException(
295 "AutoReg only allows Sobel gradient filter or None",
296 _FILEINFO_);
297 }
298 }
299
300
314 }
315
339 void AutoReg::SetPatternValidPercent(const double percent) {
340 if((percent <= 0.0) || (percent > 100.0)) {
341 string msg = "Invalid value for PatternChip ValidPercent ["
342 + IString(percent)
343 + "]. Must be greater than 0.0 and less than or equal to 100.0 (Default is 50.0).";
344 throw IException(IException::User, msg, _FILEINFO_);
345 }
346 p_patternValidPercent = percent;
347 }
348
349
367 void AutoReg::SetSubsearchValidPercent(const double percent) {
368 if((percent <= 0.0) || (percent > 100.0)) {
369 string msg = "Invalid value for SearchChip SubchipValidPercent ["
370 + IString(percent) + "]"
371 + "]. Must be greater than 0.0 and less than or equal to 100.0 (Default is 50.0).";
372 throw IException(IException::User, msg, _FILEINFO_);
373 }
374 p_subsearchValidPercent = percent;
375 }
376
377
394 void AutoReg::SetPatternZScoreMinimum(double minimum) {
395 if(minimum <= 0.0) {
396 string msg = "Invalid value for PatternChip MinimumZScore ["
397 + IString(minimum)
398 + "]. Must be greater than 0.0. (Default is 1.0).";
399 throw IException(IException::User, msg, _FILEINFO_);
400 }
401 p_minimumPatternZScore = minimum;
402 }
403
404
416 void AutoReg::SetTolerance(const double tolerance) {
417 p_tolerance = tolerance;
418 }
419
440 void AutoReg::SetChipInterpolator(const QString &interpolator) {
441
443 if(interpolator == "NearestNeighborType") {
444 itype = Isis::Interpolator::NearestNeighborType;
445 }
446 else if(interpolator == "BiLinearType") {
447 itype = Isis::Interpolator::BiLinearType;
448 }
449 else if(interpolator == "CubicConvolutionType") {
450 itype = Isis::Interpolator::CubicConvolutionType;
451 }
452 else {
454 "Invalid Interpolator type. Cannot use ["
455 + interpolator + "] to load chip",
456 _FILEINFO_);
457 }
458
459 // Set pattern and search chips to use this interpolator type when reading data from cube
464
465 }
466
481 if(size % 2 != 1 || size < 3) {
482 string msg = "Invalid value for SurfaceModel WindowSize ["
483 + IString(size) + "]. Must be an odd number greater than or equal to 3";
484 throw IException(IException::User, msg, _FILEINFO_);
485 }
486 p_windowSize = size;
487 }
488
502 if(distance <= 0.0) {
503 string msg = "Invalid value for SurfaceModel DistanceTolerance ["
504 + IString(distance) + "]. Must greater than 0.0.";
505 throw IException(IException::User, msg, _FILEINFO_);
506 }
507 p_distanceTolerance = distance;
508 }
509
510
522 if(factor < 1) {
523 string msg = "Invalid value for Algorithm ReductionFactor ["
524 + IString(factor) + "]. Must greater than or equal to 1.";
525 throw IException(IException::User, msg, _FILEINFO_);
526 }
527 p_reduceFactor = factor;
528 }
529
539 Chip AutoReg::Reduce(Chip &chip, int reductionFactor) {
540 Chip rChip((int)chip.Samples() / reductionFactor,
541 (int)chip.Lines() / reductionFactor);
542 if((int)rChip.Samples() < 1 || (int)rChip.Lines() < 1) {
543 return chip;
544 }
545
546 // ----------------------------------
547 // Fill the reduced Chip with nulls.
548 // ----------------------------------
549 for(int line = 1; line <= rChip.Lines(); line++) {
550 for(int samp = 1; samp <= rChip.Samples(); samp++) {
551 rChip.SetValue(samp, line, Isis::Null);
552 }
553 }
554
555 Statistics stats;
556 for(int l = 1; l <= rChip.Lines(); l++) {
557 int istartLine = (l - 1) * reductionFactor + 1;
558 int iendLine = istartLine + reductionFactor - 1;
559 for(int s = 1; s <= rChip.Samples(); s++) {
560
561 int istartSamp = (s - 1) * reductionFactor + 1;
562 int iendSamp = istartSamp + reductionFactor - 1;
563
564 stats.Reset();
565 for(int line = istartLine; line < iendLine; line++) {
566 for(int sample = istartSamp; sample < iendSamp; sample++) {
567 stats.AddData(chip.GetValue(sample, line));
568 }
569 }
570 rChip.SetValue(s, l, stats.Average());
571 }
572 }
573 return rChip;
574 }
575
576
588 // The search chip must be bigger than the pattern chip by N pixels in
589 // both directions for a successful surface model
590 int N = p_windowSize / 2 + 1;
591
593 string msg = "Search chips samples [";
594 msg += IString(p_searchChip.Samples()) + "] must be at ";
595 msg += "least [" + IString(N) + "] pixels wider than the pattern chip samples [";
596 msg += IString(p_patternChip.Samples()) + "] for successful surface modeling";
597 throw IException(IException::User, msg, _FILEINFO_);
598 }
599
600 if(p_searchChip.Lines() < p_patternChip.Lines() + N) {
601 string msg = "Search chips lines [";
602 msg += IString(p_searchChip.Lines()) + "] must be at ";
603 msg += "least [" + IString(N) + "] pixels taller than the pattern chip lines [";
604 msg += IString(p_patternChip.Lines()) + "] for successful surface modeling";
605 throw IException(IException::User, msg, _FILEINFO_);
606 }
607
608 Init();
610
611 // Create copies of the search and pattern chips and run a gradient filter
612 // over them before attempting to perform a match. We do this so that
613 // multiple calls to this method won't result in having a gradient filter
614 // applied multiple times to the same chip.
615 Chip gradientPatternChip(p_patternChip);
616 Chip gradientSearchChip(p_searchChip);
617 ApplyGradientFilter(gradientPatternChip);
618 ApplyGradientFilter(gradientSearchChip);
619
620 // See if the pattern chip has enough good data
621 if(!gradientPatternChip.IsValid(p_patternValidPercent)) {
625 }
626
627 if(!ComputeChipZScore(gradientPatternChip)) {
630 return PatternZScoreNotMet;
631 }
632
652 int startSamp = (gradientPatternChip.Samples() - 1) / 2 + 1;
653 int startLine = (gradientPatternChip.Lines() - 1) / 2 + 1;
654 int endSamp = gradientSearchChip.Samples() - startSamp + 1;
655 int endLine = gradientSearchChip.Lines() - startLine + 1;
656
657 // ----------------------------------------------------------------------
658 // Before we attempt to apply the reduction factor, we need to make sure
659 // we won't produce a chip of a bad size.
660 // ----------------------------------------------------------------------
661 if (p_reduceFactor != 1) {
662 if(gradientPatternChip.Samples() / p_reduceFactor < 2 || gradientPatternChip.Lines() / p_reduceFactor < 2) {
663 string msg = "Reduction factor is too large";
664 throw IException(IException::User, msg, _FILEINFO_);
665 }
666 }
667
668 // Establish the center search tack point as best pixel to start for the
669 // adaptive algorithm prior to reduction.
670 int bestSearchSamp = gradientSearchChip.TackSample();
671 int bestSearchLine = gradientSearchChip.TackLine();
672
673 // ---------------------------------------------------------------------
674 // if the reduction factor is still not equal to one, then we go ahead
675 // with the reduction of the chips and call Match to get the first
676 // estimate of the best line/sample.
677 // ---------------------------------------------------------------------
678 if(p_reduceFactor != 1) {
679 p_reducedPatternChip.SetSize((int)gradientPatternChip.Samples() / p_reduceFactor,
680 (int)gradientPatternChip.Lines() / p_reduceFactor);
681
682 // ----------------------------------
683 // Fill the reduced Chip with nulls.
684 // ----------------------------------
685 for(int line = 1; line <= p_reducedPatternChip.Lines(); line++) {
686 for(int samp = 1; samp <= p_reducedPatternChip.Samples(); samp++) {
688 }
689 }
690
691 p_reducedPatternChip = Reduce(gradientPatternChip, p_reduceFactor);
695 return PatternZScoreNotMet;
696 }
697
698 p_reducedSearchChip = Reduce(gradientSearchChip, p_reduceFactor);
699 int reducedStartSamp = (p_reducedPatternChip.Samples() - 1) / 2 + 1;
700 int reducedEndSamp = p_reducedSearchChip.Samples() - reducedStartSamp + 1;
701 int reducedStartLine = (p_reducedPatternChip.Lines() - 1) / 2 + 1;
702 int reducedEndLine = p_reducedSearchChip.Lines() - reducedStartLine + 1;
703
705 reducedStartSamp, reducedEndSamp, reducedStartLine, reducedEndLine);
706
707 if(p_bestFit == Isis::Null) {
710 return FitChipNoData;
711 }
712
713 // ------------------------------------------------------
714 // p_bestSamp and p_bestLine are set in Match() which is
715 // called above.
716 // -----------------------------------------------------
717 int bs = (p_bestSamp - 1) * p_reduceFactor + ((p_reduceFactor - 1) / 2) + 1;
718 int bl = (p_bestLine - 1) * p_reduceFactor + ((p_reduceFactor - 1) / 2) + 1;
719
720 // ---------------------------------------------------------------
721 // Now we grow our window size according to the reduction factor.
722 // And we grow around where the first call Match() told us was the
723 // best line/sample.
724 // ---------------------------------------------------------------
725 int newstartSamp = bs - p_reduceFactor - p_windowSize - 1;
726 int newendSamp = bs + p_reduceFactor + p_windowSize + 1;
727 int newstartLine = bl - p_reduceFactor - p_windowSize - 1;
728 int newendLine = bl + p_reduceFactor + p_windowSize + 1;
729
730 if(newstartLine < startLine) newstartLine = startLine;
731 if(newendSamp > endSamp) newendSamp = endSamp;
732 if(newstartSamp < startSamp) newstartSamp = startSamp;
733 if(newendLine > endLine) newendLine = endLine;
734
735 startSamp = newstartSamp;
736 endSamp = newendSamp;
737 startLine = newstartLine;
738 endLine = newendLine;
739 // We have found a good pixel in the reduction chip, but we
740 // don't want to use its position, so reset in prep. for
741 // non-adaptive registration. Save it off for the adaptive algorithm.
742 bestSearchSamp = bs;
743 bestSearchLine = bl;
744 p_bestSamp = 0;
745 p_bestLine = 0;
747 }
748
749 p_registrationStatus = Registration(gradientSearchChip, gradientPatternChip,
750 p_fitChip, startSamp, startLine, endSamp, endLine,
751 bestSearchSamp, bestSearchLine);
752
753 gradientSearchChip.SetChipPosition(p_chipSample, p_chipLine);
755 p_cubeSample = gradientSearchChip.CubeSample();
756 p_cubeLine = gradientSearchChip.CubeLine();
757
758 // Save off the gradient search and pattern chips if we used a gradient
759 // filter.
760 if (p_gradientFilterType != None) {
761 p_gradientSearchChip = gradientSearchChip;
762 p_gradientPatternChip = gradientPatternChip;
763 }
764
766
767 if (Success()) {
770 else
772 }
773
775 }
776
777
812 Chip &fChip, int startSamp, int startLine, int endSamp, int endLine,
813 int bestSamp, int bestLine) {
814
815 // Not adaptive, continue with slower search traverse
816 Match(sChip, pChip, fChip, startSamp, endSamp, startLine, endLine);
817
818 // Check to see if we went through the fit chip and never got a fit at
819 // any location.
820 if (p_bestFit == Isis::Null) {
823 return FitChipNoData;
824 }
825
826 // Now see if we satisified the goodness of fit tolerance
831 }
832
833 // Try to fit a model for sub-pixel accuracy if necessary
836 fChip.Extract(p_bestSamp, p_bestLine, window);
837 window.SetChipPosition(p_windowSize / 2 + 1, p_windowSize / 2 + 1);
838
839 // Make sure more than 2/3 of the data in the window is valid. Otherwise,
840 // we are likely too close to the edge.
841 if (!window.IsValid(100.0 * 2.1 / 3.0)) {
847 }
848
849 // Now that we know we have enough data to model the surface we call
850 // SetSubpixelPosition() to get the sub-pixel accuracy we are looking for.
851 bool computedSubPixel = SetSubpixelPosition(window);
852 if (!computedSubPixel) {
857 }
858
859 // See if the surface model solution moved too far from our whole pixel
860 // solution
865
871 }
872
874 return SuccessSubPixel;
875 }
876 else {
880 return SuccessPixel;
881 }
882 }
883
884
896 Statistics patternStats;
897 for(int i = 0; i < chip.Samples(); i++) {
898 double pixels[chip.Lines()];
899 for(int j = 0; j < chip.Lines(); j++) {
900 pixels[j] = chip.GetValue(i + 1, j + 1);
901 }
902 patternStats.AddData(pixels, chip.Lines());
903 }
904
905 // If it does not pass, return
906 p_zScoreMin = patternStats.ZScore(patternStats.Minimum());
907 p_zScoreMax = patternStats.ZScore(patternStats.Maximum());
908
909 // p_zScoreMin is made negative here so as to make it the equivalent of
910 // taking the absolute value (because p_zScoreMin is guaranteed to be
911 // negative)
913 return false;
914 }
915 else {
916 return true;
917 }
918 }
919
928 if (p_gradientFilterType == None) {
929 return;
930 }
931
932 // Use a different subchip size depending on which gradient filter is
933 // being applied.
934 int subChipWidth;
936 subChipWidth = 3;
937 }
938 else {
939 // Perform extra sanity check.
940 string msg =
941 "No rule to set sub-chip width for selected Gradient Filter Type.";
942 throw IException(IException::Programmer, msg, _FILEINFO_);
943 }
944
945 // Create a new chip to hold output during processing.
946 Chip filteredChip(chip.Samples(), chip.Lines());
947
948 // Move the subchip through the chip, extracting the contents into a buffer
949 // of the same shape. This simulates the processing of a cube by boxcar,
950 // but since that can only operate on cubes, this functionality had to be
951 // replicated for use on chips.
952 for (int line = 1; line <= chip.Lines(); line++) {
953 for (int sample = 1; sample <= chip.Samples(); sample++) {
954 Chip subChip = chip.Extract(subChipWidth, subChipWidth,
955 sample, line);
956
957 // Fill a buffer with subchip's contents. Since we'll never be storing
958 // raw bytes in the buffer, we don't care about the pixel type.
959 Buffer buffer(subChipWidth, subChipWidth, 1, Isis::None);
960 double *doubleBuffer = buffer.DoubleBuffer();
961 int bufferIndex = 0;
962 for (int subChipLine = 1; subChipLine <= subChip.Lines();
963 subChipLine++) {
964 for (int subChipSample = 1; subChipSample <= subChip.Samples();
965 subChipSample++) {
966 doubleBuffer[bufferIndex] = subChip.GetValue(subChipSample,
967 subChipLine);
968 bufferIndex++;
969 }
970 }
971
972 // Calculate gradient based on contents in buffer and insert it into
973 // output chip.
974 double newPixelValue = 0;
976 SobelGradient(buffer, newPixelValue);
977 }
978 filteredChip.SetValue(sample, line, newPixelValue);
979 }
980 }
981
982 // Copy the data from the filtered chip back into the original chip.
983 for (int line = 1; line <= filteredChip.Lines(); line++) {
984 for (int sample = 1; sample <= filteredChip.Samples(); sample++) {
985 chip.SetValue(sample, line, filteredChip.GetValue(sample, line));
986 }
987 }
988 }
989
990
1000 void AutoReg::SobelGradient(Buffer &in, double &v) {
1001 bool specials = false;
1002 for(int i = 0; i < in.size(); ++i) {
1003 if(IsSpecial(in[i])) {
1004 specials = true;
1005 }
1006 }
1007 if(specials) {
1008 v = Isis::Null;
1009 return;
1010 }
1011 v = abs((in[0] + 2 * in[1] + in[2]) - (in[6] + 2 * in[7] + in[8])) +
1012 abs((in[2] + 2 * in[5] + in[8]) - (in[0] + 2 * in[3] + in[6]));
1013 }
1014
1031 void AutoReg::Match(Chip &sChip, Chip &pChip, Chip &fChip, int startSamp, int endSamp, int startLine, int endLine) {
1032 // Sanity check. Should have been caught by the two previous tests
1033 if(startSamp == endSamp && startLine == endLine) {
1034 string msg = "StartSample [" + IString(startSamp) + "] = EndSample ["
1035 + IString(endSamp) + "] and StartLine [" + IString(startLine) + " = EndLine ["
1036 + IString(endLine) + "].";
1037 throw IException(IException::Programmer, msg, _FILEINFO_);
1038 }
1039
1040 // Ok create a fit chip whose size is the same as the search chip
1041 // and then fill it with nulls
1042 fChip.SetSize(sChip.Samples(), sChip.Lines());
1043 for(int line = 1; line <= fChip.Lines(); line++) {
1044 for(int samp = 1; samp <= fChip.Samples(); samp++) {
1045 fChip.SetValue(samp, line, Isis::Null);
1046 }
1047 }
1048
1049 // Create a chip the same size as the pattern chip.
1050 Chip subsearch(pChip.Samples(), pChip.Lines());
1051
1052 for(int line = startLine; line <= endLine; line++) {
1053 for(int samp = startSamp; samp <= endSamp; samp++) {
1054 // Extract the subsearch chip and make sure it has enough valid data
1055 sChip.Extract(samp, line, subsearch);
1056
1057// if(!subsearch.IsValid(p_patternValidPercent)) continue;
1058 if(!subsearch.IsValid(p_subsearchValidPercent)) continue;
1059
1060 // Try to match the two subchips
1061 double fit = MatchAlgorithm(pChip, subsearch);
1062
1063 // If we had a fit save off information about that fit
1064 if(fit != Isis::Null) {
1065 fChip.SetValue(samp, line, fit);
1066 if((p_bestFit == Isis::Null) || CompareFits(fit, p_bestFit)) {
1067 p_bestFit = fit;
1068 p_bestSamp = samp;
1069 p_bestLine = line;
1070 }
1071 }
1072 }
1073 }
1074 }
1075
1076
1088 // The best correlation will be at the center of the window
1089 // if it's smaller than the edge DN's invert the chip DNs
1090 double samples = window.Samples();
1091 double lines= window.Lines();
1092 double bestDN = window.GetValue(window.ChipSample(), window.ChipLine());
1093 if (bestDN < window.GetValue(1, 1)) {
1094 for (int s=1; s <= samples; s++)
1095 for (int l=1; l <= lines; l++)
1096 window.SetValue(s, l, 1.0/window.GetValue(s, l)); //invert all the window DN's
1097 bestDN = 1 / bestDN;
1098 }
1099
1100 // Find the greatest edge DN
1101 double greatestEdgeDn = 0.0;
1102 for (int s = 1; s <= samples; s++) {
1103 greatestEdgeDn = max(window.GetValue(s, 1), greatestEdgeDn);
1104 greatestEdgeDn = max(window.GetValue(s, lines), greatestEdgeDn);
1105 }
1106 for (int l = 2; l <= lines - 1; l++) {
1107 greatestEdgeDn = max(window.GetValue(1, l), greatestEdgeDn);
1108 greatestEdgeDn = max(window.GetValue(samples, l), greatestEdgeDn);
1109 }
1110
1111 //This is a small shift so the the centroid doesn't reach the edge, add 20%
1112 // of the difference between the hightest edge DN and the max DN to the highest edge DN
1113 //The 20% shift added here is somewhat arbitrary, but was choosen because it worked well
1114 // for the maximum correlation tests we did. For new area based algorithms we may want
1115 // to revist this. Possible make it a function of the match type
1116 double temp = greatestEdgeDn + 0.2 * (bestDN - greatestEdgeDn);
1117
1118 Centroid floodFill;
1119 floodFill.setDNRange(temp, 1e100);
1120
1121 Chip selectionChip(window);
1122 floodFill.select(&window, &selectionChip);
1123
1124 double windowSample;
1125 double windowLine;
1126 floodFill.centerOfMassWeighted(
1127 &window, &selectionChip, &windowSample, &windowLine);
1128
1129 int offsetS = p_bestSamp - window.ChipSample();
1130 int offsetL = p_bestLine - window.ChipLine();
1131 p_chipSample = windowSample + offsetS;
1132 p_chipLine = windowLine + offsetL;
1133
1134 if (p_chipSample != p_chipSample) {
1136 return false; //this should never happen, but just in case...
1137 }
1138
1139 return true;
1140 }
1141
1142
1152 bool AutoReg::CompareFits(double fit1, double fit2) {
1153 return(std::fabs(fit1 - IdealFit()) <= std::fabs(fit2 - IdealFit()));
1154 }
1155
1162 bool AutoReg::IsIdeal(double fit) {
1163 return(std::fabs(IdealFit() - fit) < 0.00001);
1164 }
1165
1166
1178 Pvl pvl;
1179 PvlGroup stats("AutoRegStatistics");
1183 pvl.addGroup(stats);
1184
1185 PvlGroup successes("Successes");
1186 successes += PvlKeyword("SuccessPixel", toString(p_pixelSuccesses));
1187 successes += PvlKeyword("SuccessSubPixel", toString(p_subpixelSuccesses));
1188 pvl.addGroup(successes);
1189
1190 PvlGroup grp("PatternChipFailures");
1191 grp += PvlKeyword("PatternNotEnoughValidData", toString(p_patternChipNotEnoughValidDataCount));
1192 grp += PvlKeyword("PatternZScoreNotMet", toString(p_patternZScoreNotMetCount));
1193 pvl.addGroup(grp);
1194
1195 PvlGroup fit("FitChipFailures");
1196 fit += PvlKeyword("FitChipNoData", toString(p_fitChipNoDataCount));
1197 fit += PvlKeyword("FitChipToleranceNotMet", toString(p_fitChipToleranceNotMetCount));
1198 pvl.addGroup(fit);
1199
1200 PvlGroup model("SurfaceModelFailures");
1201 model += PvlKeyword("SurfaceModelNotEnoughValidData", toString(p_surfaceModelNotEnoughValidDataCount));
1202 model += PvlKeyword("SurfaceModelSolutionInvalid", toString(p_surfaceModelSolutionInvalidCount));
1203 model += PvlKeyword("SurfaceModelDistanceInvalid", toString(p_surfaceModelDistanceInvalidCount));
1204 pvl.addGroup(model);
1205
1206 return (AlgorithmStatistics(pvl));
1207 }
1208
1217 PvlGroup reg("AutoRegistration");
1218
1219 PvlGroup &algo = p_template.findGroup("Algorithm", Pvl::Traverse);
1220 reg += PvlKeyword("Algorithm", algo["Name"][0]);
1221 reg += PvlKeyword("Tolerance", algo["Tolerance"][0]);
1222 if(algo.hasKeyword("SubpixelAccuracy")) {
1223 reg += PvlKeyword("SubpixelAccuracy", algo["SubpixelAccuracy"][0]);
1224 }
1225 if(algo.hasKeyword("ReductionFactor")) {
1226 reg += PvlKeyword("ReductionFactor", algo["ReductionFactor"][0]);
1227 }
1228 if(algo.hasKeyword("Gradient")) {
1229 reg += PvlKeyword("Gradient", algo["Gradient"][0]);
1230 }
1231
1232 PvlGroup &pchip = p_template.findGroup("PatternChip", Pvl::Traverse);
1233 reg += PvlKeyword("PatternSamples", pchip["Samples"][0]);
1234 reg += PvlKeyword("PatternLines", pchip["Lines"][0]);
1235 if(pchip.hasKeyword("ValidMinimum")) {
1236 reg += PvlKeyword("PatternMinimum", pchip["ValidMinimum"][0]);
1237 }
1238 if(pchip.hasKeyword("ValidMaximum")) {
1239 reg += PvlKeyword("PatternMaximum", pchip["ValidMaximum"][0]);
1240 }
1241 if(pchip.hasKeyword("MinimumZScore")) {
1242 reg += PvlKeyword("MinimumZScore", pchip["MinimumZScore"][0]);
1243 }
1244 if(pchip.hasKeyword("ValidPercent")) {
1245 SetPatternValidPercent((double)pchip["ValidPercent"]);
1246 reg += PvlKeyword("ValidPercent", pchip["ValidPercent"][0]);
1247 }
1248
1249 PvlGroup &schip = p_template.findGroup("SearchChip", Pvl::Traverse);
1250 reg += PvlKeyword("SearchSamples", schip["Samples"][0]);
1251 reg += PvlKeyword("SearchLines", schip["Lines"][0]);
1252 if(schip.hasKeyword("ValidMinimum")) {
1253 reg += PvlKeyword("SearchMinimum", schip["ValidMinimum"][0]);
1254 }
1255 if(schip.hasKeyword("ValidMaximum")) {
1256 reg += PvlKeyword("SearchMaximum", schip["ValidMaximum"][0]);
1257 }
1258 if(schip.hasKeyword("SubchipValidPercent")) {
1259 SetSubsearchValidPercent((double)schip["SubchipValidPercent"]);
1260 reg += PvlKeyword("SubchipValidPercent", schip["SubchipValidPercent"][0]);
1261 }
1262
1263 if(p_template.hasGroup("SurfaceModel")) {
1264 PvlGroup &smodel = p_template.findGroup("SurfaceModel", Pvl::Traverse);
1265 if(smodel.hasKeyword("DistanceTolerance")) {
1266 reg += PvlKeyword("DistanceTolerance", smodel["DistanceTolerance"][0]);
1267 }
1268
1269 if(smodel.hasKeyword("WindowSize")) {
1270 reg += PvlKeyword("WindowSize", smodel["WindowSize"][0]);
1271 }
1272 }
1273
1274 return reg;
1275 }
1276
1277
1290 PvlGroup reg("AutoRegistration");
1291
1292 reg += PvlKeyword("Algorithm", AlgorithmName());
1293 reg += PvlKeyword("Tolerance", toString(Tolerance()));
1294 reg += PvlKeyword("SubpixelAccuracy",
1295 SubPixelAccuracy() ? "True" : "False");
1296 reg += PvlKeyword("ReductionFactor", toString(ReductionFactor()));
1297 reg += PvlKeyword("Gradient", GradientFilterString());
1298
1299 Chip *pattern = PatternChip();
1300 reg += PvlKeyword("PatternSamples", toString(pattern->Samples()));
1301 reg += PvlKeyword("PatternLines", toString(pattern->Lines()));
1302 reg += PvlKeyword("MinimumZScore", toString(MinimumZScore()));
1303 reg += PvlKeyword("ValidPercent", toString(PatternValidPercent()));
1304 // TODO Chip needs accessors to valid minimum and maximum
1305
1306 Chip *search = SearchChip();
1307 reg += PvlKeyword("SearchSamples", toString(search->Samples()));
1308 reg += PvlKeyword("SearchLines", toString(search->Lines()));
1309 reg += PvlKeyword("SubchipValidPercent", toString(SubsearchValidPercent()));
1310 // TODO Chip needs accessors to valid minimum and maximum
1311
1312 if (SubPixelAccuracy()) {
1313 reg += PvlKeyword("DistanceTolerance", toString(DistanceTolerance()));
1314 reg += PvlKeyword("WindowSize", toString(WindowSize()));
1315 }
1316
1317 return reg;
1318 }
1319}
1320
Isis::AutoReg::RegisterStatus p_registrationStatus
Registration status to be returned by Register().
Definition AutoReg.h:529
double p_bestFit
Goodness of fit for adaptive algorithms.
Definition AutoReg.h:523
RegisterStatus
Enumeration of the Register() method's return status.
Definition AutoReg.h:179
@ PatternChipNotEnoughValidData
Not enough valid data in pattern chip.
Definition AutoReg.h:182
@ SuccessPixel
Success registering to whole pixel.
Definition AutoReg.h:180
@ PatternZScoreNotMet
Pattern data max or min does not pass the z-score test.
Definition AutoReg.h:188
@ SurfaceModelSolutionInvalid
Could not model surface for sub-pixel accuracy.
Definition AutoReg.h:186
@ SuccessSubPixel
Success registering to sub-pixel accuracy.
Definition AutoReg.h:181
@ FitChipToleranceNotMet
Goodness of fit tolerance not satisfied.
Definition AutoReg.h:184
@ FitChipNoData
Fit chip did not have any valid data.
Definition AutoReg.h:183
@ SurfaceModelDistanceInvalid
Surface model moves registration more than one pixel.
Definition AutoReg.h:187
@ SurfaceModelNotEnoughValidData
Not enough points to fit a surface model for sub-pixel accuracy.
Definition AutoReg.h:185
double WindowSize() const
Return window size.
Definition AutoReg.h:295
@ Sobel
Sobel gradient filter.
Definition AutoReg.h:198
@ None
default, no gradient filter
Definition AutoReg.h:197
int p_totalRegistrations
Registration Statistics Total keyword.
Definition AutoReg.h:495
bool p_subpixelAccuracy
Indicates whether sub-pixel accuracy is enabled. Default is true.
Definition AutoReg.h:492
double p_zScoreMax
Second Z-Score of pattern chip.
Definition AutoReg.h:507
double p_lineMovement
The number of lines the point moved.
Definition AutoReg.h:527
PvlGroup UpdatedTemplate()
Returns a PvlGroup containing the PvlKeywords of the parameters this object was most recently run wit...
Definition AutoReg.cpp:1289
void Init()
Initialize AutoReg object private variables.
Definition AutoReg.cpp:114
void Match(Chip &sChip, Chip &pChip, Chip &fChip, int startSamp, int endSamp, int startLine, int endLine)
Empty copy constructor.
Definition AutoReg.cpp:1031
int p_fitChipNoDataCount
Registration statistics FitChipNoData keyword.
Definition AutoReg.h:500
PvlObject p_template
AutoRegistration object that created this projection.
Definition AutoReg.h:449
int p_patternChipNotEnoughValidDataCount
Registration statistics PatternNotEnoughValidData keyword.
Definition AutoReg.h:498
virtual bool CompareFits(double fit1, double fit2)
This virtual method must return if the 1st fit is equal to or better than the second fit.
Definition AutoReg.cpp:1152
Chip p_searchChip
Chip to be searched for best registration.
Definition AutoReg.h:484
AutoReg(Pvl &pvl)
Create AutoReg object.
Definition AutoReg.cpp:66
void Parse(Pvl &pvl)
Initialize parameters in the AutoReg class using a PVL specification.
Definition AutoReg.cpp:194
bool IsIdeal(double fit)
Returns true if the fit parameter is arbitrarily close to the ideal fit value.
Definition AutoReg.cpp:1162
void ApplyGradientFilter(Chip &chip)
Run a gradient filter over the chip.
Definition AutoReg.cpp:927
int p_pixelSuccesses
Registration statistics Success keyword.
Definition AutoReg.h:496
Chip p_reducedFitChip
Fit Chip with reduction factor.
Definition AutoReg.h:490
int ReductionFactor()
Return the reduction factor.
Definition AutoReg.h:275
void SetSubsearchValidPercent(const double percent)
Set the amount of data in the search chip's subchip that must be valid.
Definition AutoReg.cpp:367
PvlGroup RegTemplate()
This function returns the keywords that this object was created from.
Definition AutoReg.cpp:1216
void SetChipInterpolator(const QString &interpolator)
Sets the Chip class interpolator type to be used to load pattern and search chips.
Definition AutoReg.cpp:440
double DistanceTolerance() const
Return distance tolerance.
Definition AutoReg.h:300
int p_surfaceModelDistanceInvalidCount
Registration statistics SurfaceModelDistanceInvalid keyword.
Definition AutoReg.h:504
double p_cubeSample
Cube sample.
Definition AutoReg.h:515
AutoReg::GradientFilterType p_gradientFilterType
Type of gradient filter to use before matching.
Definition AutoReg.h:530
double p_cubeLine
Cube line.
Definition AutoReg.h:516
int p_subpixelSuccesses
Registration statistics Success keyword.
Definition AutoReg.h:497
bool Success() const
Return whether the match algorithm succeeded or not.
Definition AutoReg.h:318
virtual double IdealFit() const =0
Returns the ideal (perfect) fit that could be returned by the MatchAlgorithm.
double PatternValidPercent() const
Return pattern chip valid percent. The default value is.
Definition AutoReg.h:280
double p_chipLine
Chip line.
Definition AutoReg.h:514
double p_zScoreMin
First Z-Score of pattern chip.
Definition AutoReg.h:506
double p_chipSample
Chip sample.
Definition AutoReg.h:513
Pvl RegistrationStatistics()
This returns the cumulative registration statistics.
Definition AutoReg.cpp:1177
int p_reduceFactor
Reduction factor.
Definition AutoReg.h:528
int p_fitChipToleranceNotMetCount
Registration statistics FitChipToleranceNotMet keyword.
Definition AutoReg.h:501
double p_tolerance
Tolerance for acceptable goodness of fit in match algorithm.
Definition AutoReg.h:518
void SetPatternValidPercent(const double percent)
Set the amount of data in the pattern chip that must be valid.
Definition AutoReg.cpp:339
int p_surfaceModelSolutionInvalidCount
Registration statistics SurfaceModelSolutionInvalid keyword.
Definition AutoReg.h:503
double SubsearchValidPercent() const
Return subsearch chip valid percent.
Definition AutoReg.h:285
Chip * SearchChip()
Return pointer to search chip.
Definition AutoReg.h:207
virtual AutoReg::RegisterStatus Registration(Chip &sChip, Chip &pChip, Chip &fChip, int startSamp, int startLine, int endSamp, int endLine, int bestSamp, int bestLine)
Performs matching between the pattern and search at both whole-pixel and subpixel levels.
Definition AutoReg.cpp:811
void SobelGradient(Buffer &in, double &v)
Compute a Sobel gradient based on an input buffer.
Definition AutoReg.cpp:1000
void SetReductionFactor(int reductionFactor)
Set the reduction factor used to speed up the pattern matching algorithm.
Definition AutoReg.cpp:521
int p_bestLine
Line value of best fit.
Definition AutoReg.h:525
bool SubPixelAccuracy()
Return whether this object will attempt to register to whole or sub-pixel accuracy.
Definition AutoReg.h:270
int p_windowSize
Surface model window size.
Definition AutoReg.h:520
void SetSubPixelAccuracy(bool on)
If the sub-pixel accuracy is enabled, the Register() method will attempt to match the pattern chip to...
Definition AutoReg.cpp:312
double p_subsearchValidPercent
Percentage of data in subsearch chip that must be valid.
Definition AutoReg.h:511
Chip p_reducedPatternChip
Pattern Chip with reduction factor.
Definition AutoReg.h:488
bool ComputeChipZScore(Chip &chip)
This method computes the given Chip's Z-Score.
Definition AutoReg.cpp:895
Chip Reduce(Chip &chip, int reductionFactor)
This method reduces the given chip by the given reduction factor.
Definition AutoReg.cpp:539
int p_bestSamp
Sample value of best fit.
Definition AutoReg.h:524
virtual ~AutoReg()
Destroy AutoReg object.
Definition AutoReg.cpp:153
bool SetSubpixelPosition(Chip &window)
Set the search chip sample and line to subpixel values if possible.
Definition AutoReg.cpp:1087
double MinimumZScore() const
Return minimumPatternZScore.
Definition AutoReg.h:350
void SetPatternZScoreMinimum(double minimum)
Set the minimum pattern zscore.
Definition AutoReg.cpp:394
virtual Pvl AlgorithmStatistics(Pvl &pvl)
Provide (adaptive) algorithms a chance to report results.
Definition AutoReg.h:461
int p_surfaceModelNotEnoughValidDataCount
Registration statistics SurfaceModelNotEnoughValidData keyword.
Definition AutoReg.h:502
Chip p_gradientPatternChip
Chip to be matched with gradient applied.
Definition AutoReg.h:487
double p_minimumPatternZScore
Minimum pattern Z-Score.
Definition AutoReg.h:509
Chip p_gradientSearchChip
Chip to be searched for best registration with gradient applied.
Definition AutoReg.h:486
void SetSurfaceModelDistanceTolerance(double distance)
Set a distance the surface model solution is allowed to move away from the best whole pixel fit in th...
Definition AutoReg.cpp:501
Chip p_fitChip
Results from MatchAlgorithm() method.
Definition AutoReg.h:485
Chip p_patternChip
Chip to be matched.
Definition AutoReg.h:483
void SetTolerance(double tolerance)
Set the tolerance for an acceptable goodness of fit.
Definition AutoReg.cpp:416
Chip * PatternChip()
Return pointer to pattern chip.
Definition AutoReg.h:202
int p_patternZScoreNotMetCount
Registration statistics PatternZScoreNotMet keyword.
Definition AutoReg.h:499
virtual double MatchAlgorithm(Chip &pattern, Chip &subsearch)=0
Given two identically sized chips return a double that indicates how well they match.
Chip p_reducedSearchChip
Search Chip with reduction factor.
Definition AutoReg.h:489
virtual QString AlgorithmName() const =0
Returns the name of the algorithm.
void SetSurfaceModelWindowSize(int size)
Set the surface model window size.
Definition AutoReg.cpp:480
double p_distanceTolerance
Maximum distance the surface model solution may be from the best whole pixel fit in the fit chip.
Definition AutoReg.h:521
void SetGradientFilterType(const QString &gradientFilterType)
Set the gradient filter type to be applied to the search and pattern chips.
Definition AutoReg.cpp:273
double p_goodnessOfFit
Goodness of fit of the match algorithm.
Definition AutoReg.h:517
AutoReg::RegisterStatus Register()
Walk the pattern chip through the search chip to find the best registration.
Definition AutoReg.cpp:587
double Tolerance() const
Return match algorithm tolerance.
Definition AutoReg.h:290
double p_patternValidPercent
Percentage of data in pattern chip that must be valid.
Definition AutoReg.h:510
double p_sampMovement
The number of samples the point moved.
Definition AutoReg.h:526
Buffer for reading and writing cube data.
Definition Buffer.h:53
double * DoubleBuffer() const
Returns the value of the shape buffer.
Definition Buffer.h:138
Selection class derived from the Pure Virtual Parent Class for all Selection classes.
Definition Centroid.h:31
int setDNRange(double minimumDN, double maximumDN)
Set the range of the DNs.
Definition Centroid.cpp:126
A small chip of data used for pattern matching.
Definition Chip.h:86
void SetReadInterpolator(const Interpolator::interpType type)
Sets Interpolator Type for loading a chip.
Definition Chip.h:323
void SetSize(const int samples, const int lines)
Change the size of the Chip.
Definition Chip.cpp:134
double GetValue(int sample, int line)
Loads a Chip with a value.
Definition Chip.h:145
int Samples() const
Definition Chip.h:99
void SetValidRange(const double minimum=Isis::ValidMinimum, const double maximum=Isis::ValidMaximum)
Set the valid range of data in the chip.
Definition Chip.cpp:681
int Lines() const
Definition Chip.h:106
void SetChipPosition(const double sample, const double line)
Compute the position of the cube given a chip coordinate.
Definition Chip.cpp:643
Chip Extract(int samples, int lines, int samp, int line)
Extract a sub-chip from a chip.
Definition Chip.cpp:727
void SetValue(int sample, int line, const double &value)
Sets a value in the chip.
Definition Chip.h:126
Isis exception class.
Definition IException.h:91
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition IException.h:126
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
Adds specific functionality to C++ strings.
Definition IString.h:165
interpType
The interpolator type, including: None, Nearest Neighbor, BiLinear or Cubic Convultion.
Contains multiple PvlContainers.
Definition PvlGroup.h:41
Container for cube-like labels.
Definition Pvl.h:119
A single keyword-value pair.
Definition PvlKeyword.h:87
Contains Pvl Groups and Pvl Objects.
Definition PvlObject.h:61
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
Definition PvlObject.h:276
bool hasGroup(const QString &name) const
Returns a boolean value based on whether the object has the specified group or not.
Definition PvlObject.h:212
@ Traverse
Search child objects.
Definition PvlObject.h:158
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition PvlObject.h:129
This class is used to accumulate statistics on double arrays.
Definition Statistics.h:94
void Reset()
Reset all accumulators and counters to zero.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition IString.cpp:211
const double ValidMaximum
The maximum valid double value for Isis pixels.
const double Null
Value for an Isis Null pixel.
const double ValidMinimum
The minimum valid double value for Isis pixels.
bool IsSpecial(const double d)
Returns if the input pixel is special.
Namespace for the standard library.