12 #include "Histogram.h"
13 #include "IException.h"
14 #include "Interpolator.h"
15 #include "LeastSquares.h"
17 #include "PixelType.h"
19 #include "PolynomialBivariate.h"
66 AutoReg::AutoReg(
Pvl &pvl) {
67 p_template = pvl.
findObject(
"AutoRegistration");
70 p_patternChip.SetSize(3, 3);
71 p_searchChip.SetSize(5, 5);
72 p_fitChip.SetSize(5, 5);
73 p_reducedPatternChip.SetSize(3, 3);
74 p_reducedSearchChip.SetSize(5, 5);
75 p_reducedFitChip.SetSize(5, 5);
76 p_gradientFilterType = None;
78 SetPatternValidPercent(50.0);
79 SetSubsearchValidPercent(50.0);
80 SetPatternZScoreMinimum(1.0);
83 SetSubPixelAccuracy(
true);
84 SetSurfaceModelDistanceTolerance(1.5);
85 SetSurfaceModelWindowSize(5);
87 SetReductionFactor(1);
91 p_totalRegistrations = 0;
93 p_subpixelSuccesses = 0;
94 p_patternChipNotEnoughValidDataCount = 0;
95 p_patternZScoreNotMetCount = 0;
96 p_fitChipNoDataCount = 0;
97 p_fitChipToleranceNotMetCount = 0;
98 p_surfaceModelNotEnoughValidDataCount = 0;
99 p_surfaceModelSolutionInvalidCount = 0;
100 p_surfaceModelDistanceInvalidCount = 0;
114 void AutoReg::Init() {
128 for(
int line = 1; line <= p_fitChip.Lines(); line++) {
129 for(
int samp = 1; samp <= p_fitChip.Samples(); samp++) {
136 for(
int line = 1; line <= p_reducedPatternChip.Lines(); line++) {
137 for(
int samp = 1; samp <= p_reducedPatternChip.Samples(); samp++) {
138 p_reducedPatternChip.SetValue(samp, line,
Isis::Null);
144 for(
int line = 1; line <= p_reducedSearchChip.Lines(); line++) {
145 for(
int samp = 1; samp <= p_reducedSearchChip.Samples(); samp++) {
146 p_reducedSearchChip.SetValue(samp, line,
Isis::Null);
153 AutoReg::~AutoReg() {
194 void AutoReg::Parse(
Pvl &pvl) {
198 SetTolerance(algo[
"Tolerance"]);
200 SetChipInterpolator((QString)algo[
"ChipInterpolator"]);
204 SetSubPixelAccuracy((QString)algo[
"SubpixelAccuracy"] ==
"True");
208 SetReductionFactor((
int)algo[
"ReductionFactor"]);
212 SetGradientFilterType((QString)algo[
"Gradient"]);
217 PatternChip()->SetSize((
int)pchip[
"Samples"], (
int)pchip[
"Lines"]);
221 if(pchip.hasKeyword(
"ValidMinimum")) minimum = pchip[
"ValidMinimum"];
222 if(pchip.hasKeyword(
"ValidMaximum")) maximum = pchip[
"ValidMaximum"];
223 PatternChip()->SetValidRange(minimum, maximum);
225 if(pchip.hasKeyword(
"MinimumZScore")) {
226 SetPatternZScoreMinimum((
double)pchip[
"MinimumZScore"]);
228 if(pchip.hasKeyword(
"ValidPercent")) {
229 SetPatternValidPercent((
double)pchip[
"ValidPercent"]);
234 SearchChip()->SetSize((
int)schip[
"Samples"], (
int)schip[
"Lines"]);
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"]);
250 SetSurfaceModelDistanceTolerance((
double)smodel[
"DistanceTolerance"]);
254 SetSurfaceModelWindowSize((
int)smodel[
"WindowSize"]);
260 QString msg =
"Improper format for AutoReg PVL [" + pvl.
fileName() +
"]";
261 throw IException(e, IException::User, msg, _FILEINFO_);
273 void AutoReg::SetGradientFilterType(
const QString &gradientFilterType) {
274 if (gradientFilterType ==
"None") {
275 p_gradientFilterType = None;
277 else if (gradientFilterType ==
"Sobel") {
278 p_gradientFilterType = Sobel;
282 "Invalid Gradient type. Cannot use ["
283 + gradientFilterType +
"] to filter chip",
289 QString AutoReg::GradientFilterString()
const {
290 switch (p_gradientFilterType) {
291 case None:
return "None";
292 case Sobel:
return "Sobel";
294 IException::Programmer,
295 "AutoReg only allows Sobel gradient filter or None",
312 void AutoReg::SetSubPixelAccuracy(
bool on) {
313 p_subpixelAccuracy = on;
339 void AutoReg::SetPatternValidPercent(
const double percent) {
340 if((percent <= 0.0) || (percent > 100.0)) {
341 string msg =
"Invalid value for PatternChip ValidPercent ["
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_);
346 p_patternValidPercent = percent;
367 void AutoReg::SetSubsearchValidPercent(
const double percent) {
368 if((percent <= 0.0) || (percent > 100.0)) {
369 string msg =
"Invalid value for SearchChip SubchipValidPercent ["
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_);
374 p_subsearchValidPercent = percent;
394 void AutoReg::SetPatternZScoreMinimum(
double minimum) {
396 string msg =
"Invalid value for PatternChip MinimumZScore ["
398 +
"]. Must be greater than 0.0. (Default is 1.0).";
399 throw IException(IException::User, msg, _FILEINFO_);
401 p_minimumPatternZScore = minimum;
416 void AutoReg::SetTolerance(
const double tolerance) {
417 p_tolerance = tolerance;
440 void AutoReg::SetChipInterpolator(
const QString &interpolator) {
443 if(interpolator ==
"NearestNeighborType") {
444 itype = Isis::Interpolator::NearestNeighborType;
446 else if(interpolator ==
"BiLinearType") {
447 itype = Isis::Interpolator::BiLinearType;
449 else if(interpolator ==
"CubicConvolutionType") {
450 itype = Isis::Interpolator::CubicConvolutionType;
454 "Invalid Interpolator type. Cannot use ["
455 + interpolator +
"] to load chip",
460 p_patternChip.SetReadInterpolator(itype);
461 p_searchChip.SetReadInterpolator(itype);
462 p_reducedPatternChip.SetReadInterpolator(itype);
463 p_reducedSearchChip.SetReadInterpolator(itype);
480 void AutoReg::SetSurfaceModelWindowSize(
int size) {
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_);
501 void AutoReg::SetSurfaceModelDistanceTolerance(
double distance) {
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_);
507 p_distanceTolerance = distance;
521 void AutoReg::SetReductionFactor(
int factor) {
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_);
527 p_reduceFactor = factor;
539 Chip AutoReg::Reduce(
Chip &chip,
int reductionFactor) {
541 (
int)chip.
Lines() / reductionFactor);
542 if((
int)rChip.
Samples() < 1 || (
int)rChip.
Lines() < 1) {
549 for(
int line = 1; line <= rChip.
Lines(); line++) {
550 for(
int samp = 1; samp <= rChip.
Samples(); samp++) {
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++) {
561 int istartSamp = (s - 1) * reductionFactor + 1;
562 int iendSamp = istartSamp + reductionFactor - 1;
565 for(
int line = istartLine; line < iendLine; line++) {
566 for(
int sample = istartSamp; sample < iendSamp; sample++) {
590 int N = p_windowSize / 2 + 1;
592 if(p_searchChip.Samples() < p_patternChip.Samples() + N) {
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_);
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_);
609 p_totalRegistrations++;
615 Chip gradientPatternChip(p_patternChip);
616 Chip gradientSearchChip(p_searchChip);
617 ApplyGradientFilter(gradientPatternChip);
618 ApplyGradientFilter(gradientSearchChip);
621 if(!gradientPatternChip.
IsValid(p_patternValidPercent)) {
622 p_patternChipNotEnoughValidDataCount++;
623 p_registrationStatus = PatternChipNotEnoughValidData;
624 return PatternChipNotEnoughValidData;
627 if(!ComputeChipZScore(gradientPatternChip)) {
628 p_patternZScoreNotMetCount++;
629 p_registrationStatus = PatternZScoreNotMet;
630 return PatternZScoreNotMet;
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;
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_);
670 int bestSearchSamp = gradientSearchChip.
TackSample();
671 int bestSearchLine = gradientSearchChip.
TackLine();
678 if(p_reduceFactor != 1) {
679 p_reducedPatternChip.SetSize((
int)gradientPatternChip.
Samples() / p_reduceFactor,
680 (
int)gradientPatternChip.
Lines() / p_reduceFactor);
685 for(
int line = 1; line <= p_reducedPatternChip.Lines(); line++) {
686 for(
int samp = 1; samp <= p_reducedPatternChip.Samples(); samp++) {
687 p_reducedPatternChip.SetValue(samp, line,
Isis::Null);
691 p_reducedPatternChip =
Reduce(gradientPatternChip, p_reduceFactor);
692 if(!ComputeChipZScore(p_reducedPatternChip)) {
693 p_patternZScoreNotMetCount++;
694 p_registrationStatus = PatternZScoreNotMet;
695 return PatternZScoreNotMet;
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;
704 Match(p_reducedSearchChip, p_reducedPatternChip, p_reducedFitChip,
705 reducedStartSamp, reducedEndSamp, reducedStartLine, reducedEndLine);
708 p_fitChipNoDataCount++;
709 p_registrationStatus = FitChipNoData;
710 return FitChipNoData;
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;
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;
730 if(newstartLine < startLine) newstartLine = startLine;
731 if(newendSamp > endSamp) newendSamp = endSamp;
732 if(newstartSamp < startSamp) newstartSamp = startSamp;
733 if(newendLine > endLine) newendLine = endLine;
735 startSamp = newstartSamp;
736 endSamp = newendSamp;
737 startLine = newstartLine;
738 endLine = newendLine;
749 p_registrationStatus = Registration(gradientSearchChip, gradientPatternChip,
750 p_fitChip, startSamp, startLine, endSamp, endLine,
751 bestSearchSamp, bestSearchLine);
754 p_searchChip.SetChipPosition(p_chipSample, p_chipLine);
755 p_cubeSample = gradientSearchChip.
CubeSample();
756 p_cubeLine = gradientSearchChip.
CubeLine();
760 if (p_gradientFilterType != None) {
761 p_gradientSearchChip = gradientSearchChip;
762 p_gradientPatternChip = gradientPatternChip;
765 p_goodnessOfFit = p_bestFit;
768 if (p_registrationStatus == AutoReg::SuccessSubPixel)
769 p_subpixelSuccesses++;
774 return p_registrationStatus;
812 Chip &fChip,
int startSamp,
int startLine,
int endSamp,
int endLine,
813 int bestSamp,
int bestLine) {
816 Match(sChip, pChip, fChip, startSamp, endSamp, startLine, endLine);
821 p_fitChipNoDataCount++;
822 p_registrationStatus = FitChipNoData;
823 return FitChipNoData;
827 if (!CompareFits(p_bestFit, Tolerance())) {
828 p_fitChipToleranceNotMetCount++;
829 p_registrationStatus = FitChipToleranceNotMet;
830 return FitChipToleranceNotMet;
834 if (p_subpixelAccuracy && !IsIdeal(p_bestFit)) {
835 Chip window(p_windowSize, p_windowSize);
836 fChip.
Extract(p_bestSamp, p_bestLine, window);
841 if (!window.
IsValid(100.0 * 2.1 / 3.0)) {
842 p_surfaceModelNotEnoughValidDataCount++;
843 p_registrationStatus = SurfaceModelNotEnoughValidData;
844 p_chipSample = p_bestSamp;
845 p_chipLine = p_bestLine;
846 return SurfaceModelNotEnoughValidData;
851 bool computedSubPixel = SetSubpixelPosition(window);
852 if (!computedSubPixel) {
853 p_chipSample = p_bestSamp;
854 p_chipLine = p_bestLine;
855 p_registrationStatus = SurfaceModelSolutionInvalid;
856 return SurfaceModelSolutionInvalid;
861 p_sampMovement = fabs(p_bestSamp - p_chipSample);
862 p_lineMovement = fabs(p_bestLine - p_chipLine);
863 if (p_sampMovement > p_distanceTolerance ||
864 p_lineMovement > p_distanceTolerance) {
866 p_surfaceModelDistanceInvalidCount++;
867 p_registrationStatus = SurfaceModelDistanceInvalid;
868 p_chipSample = p_bestSamp;
869 p_chipLine = p_bestLine;
870 return SurfaceModelDistanceInvalid;
873 p_registrationStatus = SuccessSubPixel;
874 return SuccessSubPixel;
877 p_chipSample = p_bestSamp;
878 p_chipLine = p_bestLine;
879 p_registrationStatus = SuccessPixel;
895 bool AutoReg::ComputeChipZScore(
Chip &chip) {
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);
912 if (p_zScoreMax < p_minimumPatternZScore && -p_zScoreMin < p_minimumPatternZScore) {
927 void AutoReg::ApplyGradientFilter(
Chip &chip) {
928 if (p_gradientFilterType == None) {
935 if (p_gradientFilterType == Sobel) {
941 "No rule to set sub-chip width for selected Gradient Filter Type.";
942 throw IException(IException::Programmer, msg, _FILEINFO_);
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,
959 Buffer buffer(subChipWidth, subChipWidth, 1, Isis::None);
962 for (
int subChipLine = 1; subChipLine <= subChip.
Lines();
964 for (
int subChipSample = 1; subChipSample <= subChip.
Samples();
966 doubleBuffer[bufferIndex] = subChip.
GetValue(subChipSample,
974 double newPixelValue = 0;
975 if (p_gradientFilterType == Sobel) {
976 SobelGradient(buffer, newPixelValue);
978 filteredChip.
SetValue(sample, line, newPixelValue);
983 for (
int line = 1; line <= filteredChip.
Lines(); line++) {
984 for (
int sample = 1; sample <= filteredChip.
Samples(); sample++) {
1000 void AutoReg::SobelGradient(
Buffer &in,
double &v) {
1001 bool specials =
false;
1002 for(
int i = 0; i < in.
size(); ++i) {
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]));
1031 void AutoReg::Match(
Chip &sChip,
Chip &pChip,
Chip &fChip,
int startSamp,
int endSamp,
int startLine,
int endLine) {
1033 if(startSamp == endSamp && startLine == endLine) {
1034 string msg =
"StartSample [" +
IString(startSamp) +
"] = EndSample ["
1035 +
IString(endSamp) +
"] and StartLine [" +
IString(startLine) +
" = EndLine ["
1037 throw IException(IException::Programmer, msg, _FILEINFO_);
1043 for(
int line = 1; line <= fChip.
Lines(); line++) {
1044 for(
int samp = 1; samp <= fChip.
Samples(); samp++) {
1052 for(
int line = startLine; line <= endLine; line++) {
1053 for(
int samp = startSamp; samp <= endSamp; samp++) {
1055 sChip.
Extract(samp, line, subsearch);
1058 if(!subsearch.
IsValid(p_subsearchValidPercent))
continue;
1061 double fit = MatchAlgorithm(pChip, subsearch);
1066 if((p_bestFit ==
Isis::Null) || CompareFits(fit, p_bestFit)) {
1087 bool AutoReg::SetSubpixelPosition(
Chip &window) {
1090 double samples = window.
Samples();
1091 double lines= window.
Lines();
1093 if (bestDN < window.
GetValue(1, 1)) {
1094 for (
int s=1; s <= samples; s++)
1095 for (
int l=1; l <= lines; l++)
1097 bestDN = 1 / bestDN;
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);
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);
1116 double temp = greatestEdgeDn + 0.2 * (bestDN - greatestEdgeDn);
1121 Chip selectionChip(window);
1122 floodFill.
select(&window, &selectionChip);
1124 double windowSample;
1126 floodFill.centerOfMassWeighted(
1127 &window, &selectionChip, &windowSample, &windowLine);
1129 int offsetS = p_bestSamp - window.
ChipSample();
1130 int offsetL = p_bestLine - window.
ChipLine();
1131 p_chipSample = windowSample + offsetS;
1132 p_chipLine = windowLine + offsetL;
1134 if (p_chipSample != p_chipSample) {
1135 p_surfaceModelSolutionInvalidCount++;
1152 bool AutoReg::CompareFits(
double fit1,
double fit2) {
1153 return(std::fabs(fit1 - IdealFit()) <= std::fabs(fit2 - IdealFit()));
1162 bool AutoReg::IsIdeal(
double fit) {
1163 return(std::fabs(IdealFit() - fit) < 0.00001);
1177 Pvl AutoReg::RegistrationStatistics() {
1179 PvlGroup stats(
"AutoRegStatistics");
1190 PvlGroup grp(
"PatternChipFailures");
1191 grp +=
PvlKeyword(
"PatternNotEnoughValidData",
toString(p_patternChipNotEnoughValidDataCount));
1197 fit +=
PvlKeyword(
"FitChipToleranceNotMet",
toString(p_fitChipToleranceNotMetCount));
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));
1206 return (AlgorithmStatistics(pvl));
1219 PvlGroup &algo = p_template.findGroup(
"Algorithm", Pvl::Traverse);
1220 reg +=
PvlKeyword(
"Algorithm", algo[
"Name"][0]);
1221 reg +=
PvlKeyword(
"Tolerance", algo[
"Tolerance"][0]);
1223 reg +=
PvlKeyword(
"SubpixelAccuracy", algo[
"SubpixelAccuracy"][0]);
1226 reg +=
PvlKeyword(
"ReductionFactor", algo[
"ReductionFactor"][0]);
1229 reg +=
PvlKeyword(
"Gradient", algo[
"Gradient"][0]);
1232 PvlGroup &pchip = p_template.findGroup(
"PatternChip", Pvl::Traverse);
1233 reg +=
PvlKeyword(
"PatternSamples", pchip[
"Samples"][0]);
1234 reg +=
PvlKeyword(
"PatternLines", pchip[
"Lines"][0]);
1236 reg +=
PvlKeyword(
"PatternMinimum", pchip[
"ValidMinimum"][0]);
1239 reg +=
PvlKeyword(
"PatternMaximum", pchip[
"ValidMaximum"][0]);
1242 reg +=
PvlKeyword(
"MinimumZScore", pchip[
"MinimumZScore"][0]);
1245 SetPatternValidPercent((
double)pchip[
"ValidPercent"]);
1246 reg +=
PvlKeyword(
"ValidPercent", pchip[
"ValidPercent"][0]);
1249 PvlGroup &schip = p_template.findGroup(
"SearchChip", Pvl::Traverse);
1250 reg +=
PvlKeyword(
"SearchSamples", schip[
"Samples"][0]);
1251 reg +=
PvlKeyword(
"SearchLines", schip[
"Lines"][0]);
1253 reg +=
PvlKeyword(
"SearchMinimum", schip[
"ValidMinimum"][0]);
1256 reg +=
PvlKeyword(
"SearchMaximum", schip[
"ValidMaximum"][0]);
1258 if(schip.
hasKeyword(
"SubchipValidPercent")) {
1259 SetSubsearchValidPercent((
double)schip[
"SubchipValidPercent"]);
1260 reg +=
PvlKeyword(
"SubchipValidPercent", schip[
"SubchipValidPercent"][0]);
1263 if(p_template.hasGroup(
"SurfaceModel")) {
1264 PvlGroup &smodel = p_template.findGroup(
"SurfaceModel", Pvl::Traverse);
1266 reg +=
PvlKeyword(
"DistanceTolerance", smodel[
"DistanceTolerance"][0]);
1270 reg +=
PvlKeyword(
"WindowSize", smodel[
"WindowSize"][0]);
1292 reg +=
PvlKeyword(
"Algorithm", AlgorithmName());
1295 SubPixelAccuracy() ?
"True" :
"False");
1297 reg +=
PvlKeyword(
"Gradient", GradientFilterString());
1299 Chip *pattern = PatternChip();
1306 Chip *search = SearchChip();
1312 if (SubPixelAccuracy()) {