USGS

Isis 3.0 Object Programmers' Reference

Home

Gruen.cpp
Go to the documentation of this file.
1 
23 #include "Chip.h"
24 #include "GruenTypes.h"
25 #include "Gruen.h"
26 #include "DbProfile.h"
27 #include "Pvl.h"
28 
29 #include "tnt/tnt_array1d_utils.h"
30 
31 #include <cmath>
32 #include <iostream>
33 #include <sstream>
34 #include <iomanip>
35 
36 #include <QTime>
37 
38 
39 using namespace std;
40 
41 namespace Isis {
42 
48  Gruen::Gruen() : AutoReg(Gruen::getDefaultParameters()) {
50  }
51 
63  Gruen::Gruen(Pvl &pvl) : AutoReg(pvl) {
64  init(pvl);
65  }
66 
108  void Gruen::WriteSubsearchChips(const QString &pattern) {
109  m_filePattern = pattern;
110  return;
111  }
112 
127  void Gruen::setAffineRadio(const AffineRadio &affrad) {
128  m_affine = affrad;
129  return;
130  }
131 
144  m_affine = getDefaultAffineRadio();
145  }
146 
172  int Gruen::algorithm(Chip &pattern, Chip &subsearch,
173  const Radiometric &radio, BigInt &ptsUsed,
174  double &resid, GMatrix &atai, AffineRadio &affrad) {
175 
176  m_totalIterations++; // Bump iteration counter
177 
178  // Initialize loop variables
179  int tackSamp = pattern.TackSample();
180  int tackLine = pattern.TackLine();
181 
182  // Internal variables
183  double rshift = radio.Shift();
184  double rgain = radio.Gain();
185 
186  int maxPnts((pattern.Samples()-2) * (pattern.Lines()-2));
187  GMatrix a(maxPnts, 8);
188  GVector lvec(maxPnts);
189 
190  // pattern chip is rh image , subsearch chip is lh image
191  resid = 0.0;
192  int npts = 0;
193  for(int line = 2 ; line < pattern.Lines() ; line++) {
194  for(int samp = 2; samp < pattern.Samples() ; samp++) {
195 
196  if(!pattern.IsValid(samp, line)) continue;
197  if(!subsearch.IsValid(samp, line)) continue;
198  if(!subsearch.IsValid(samp + 1, line)) continue;
199  if(!subsearch.IsValid(samp - 1, line)) continue;
200  if(!subsearch.IsValid(samp, line - 1)) continue;
201  if(!subsearch.IsValid(samp, line + 1)) continue;
202 
203  // Sample/Line numbers
204  double x0 = (double)(samp - tackSamp);
205  double y0 = (double)(line - tackLine);
206 
207  // Discrete derivatives (delta sample #)
208  double gxtemp = subsearch.GetValue(samp + 1, line) -
209  subsearch.GetValue(samp - 1, line);
210  double gytemp = subsearch.GetValue(samp, line + 1) -
211  subsearch.GetValue(samp, line - 1);
212 
213  a[npts][0] = gxtemp;
214  a[npts][1] = gxtemp * x0;
215  a[npts][2] = gxtemp * y0;
216  a[npts][3] = gytemp;
217  a[npts][4] = gytemp * x0;
218  a[npts][5] = gytemp * y0;
219  a[npts][6] = 1.0;
220  a[npts][7] = subsearch.GetValue(samp, line);
221 
222  double ell = pattern.GetValue(samp, line) -
223  (((1.0 + rgain) * subsearch.GetValue(samp, line)) +
224  rshift);
225 
226  lvec[npts] = ell;
227  resid += (ell * ell);
228  npts++;
229  }
230  }
231 
232  // Check for enough points
233  ptsUsed = npts;
234  if(!ValidPoints(maxPnts, npts)) {
235  std::ostringstream mess;
236  mess << "Minimum points (" << MinValidPoints(maxPnts)
237  << ") criteria not met (" << npts << ")";
238  return (logError(NotEnoughPoints, mess.str().c_str()));
239  }
240 
241  // Create the ATA array
242  GMatrix ata(8,8);
243  for(int i = 0 ; i < 8 ; i++) {
244  for(int j = 0 ; j < 8 ; j++) {
245  double temp(0.0);
246  for (int k = 0 ; k < npts ; k++) {
247  temp += (a[k][i] * a[k][j]);
248  }
249  ata[i][j] = temp;
250  }
251  }
252 
253  // Solve the ATAI with Cholesky
254  try {
255  GVector p(8);
256  atai = Choldc(ata, p);
257  GMatrix b = Identity(8);
258  GMatrix x = b;
259  atai = Cholsl(atai, p, b, x);
260  }
261  catch(IException &ie) {
262  QString mess = "Cholesky Failed:: " + ie.toString();
263  return (logError(CholeskyFailed, mess));
264  }
265 
266  // Compute the affine update if result are requested by caller.
267  GVector atl(8);
268  for (int i = 0 ; i < 8 ; i++) {
269  double temp(0.0);
270  for (int k = 0 ; k < npts ; k++) {
271  temp += a[k][i] * lvec[k];
272  }
273  atl[i] = temp;
274  }
275 
276  GVector alpha(8, 0.0);
277  for (int i = 0 ; i < 8 ; i++) {
278  for (int k = 0 ; k < 8 ; k++) {
279  alpha[i] += atai[i][k] * atl[k];
280  }
281  }
282 
283  try {
284  affrad = AffineRadio(alpha);
285  }
286  catch(IException &ie) {
287  QString mess = "Affine failed: " + ie.toString();
288  return (logError(AffineNotInvertable, mess));
289  }
290 
291  return (0);
292  }
293 
305  Analysis Gruen::errorAnalysis(const BigInt &npts, const double &resid,
306  const GMatrix &atai) {
307 
308  Analysis results;
309  results.m_npts = npts;
310 
311  // Converged, compute error anaylsis
312  double variance = resid / DegreesOfFreedom(npts);
313  GMatrix kmat(8,8);
314  for(int r = 0 ; r < 8 ; r++) {
315  for(int c = 0 ; c < 8 ; c++) {
316  kmat[r][c] = variance * atai[r][c];
317  }
318  }
319  results.m_variance = variance;
320 
321 
322  // Set up submatrix
323  GMatrix skmat(2,2);
324  skmat[0][0] = kmat[0][0];
325  skmat[0][1] = kmat[0][3];
326  skmat[1][0] = kmat[3][0];
327  skmat[1][1] = kmat[3][3];
328  try {
329  GVector eigen(2);
330  Jacobi(skmat, eigen, skmat);
331  EigenSort(eigen, skmat);
332  for (int i = 0 ; i < 2 ; i++) {
333  results.m_sevals[i] = eigen[i];
334  results.m_kmat[i] = kmat[i*3][i*3];
335  }
336  }
337  catch(IException &ie) {
338  QString errmsg = "Eigen Solution Failed:: " + ie.toString();
339  results.m_status = logError(EigenSolutionFailed, errmsg);
340  return (results);
341  }
342 
343  results.m_status = 0;
344  return (results);
345  }
346 
357  GMatrix Gruen::Choldc(const GMatrix &a, GVector &p) const {
358  int nrows(a.dim1());
359  int ncols(a.dim2());
360 
361  GMatrix aa = a.copy();
362  p = GVector(ncols);
363 
364  for(int i = 0 ; i < nrows ; i++) {
365  for(int j = i ; j < ncols ; j++) {
366  double sum = aa[i][j];
367  for(int k = i-1 ; k >= 0 ; k--) {
368  sum -= (aa[i][k] * aa[j][k]);
369  }
370  // Handle diagonal special
371  if (i == j) {
372  if (sum <= 0.0) {
374  "Choldc failed - matrix not postive definite",
375  _FILEINFO_);
376  }
377  p[i] = sqrt(sum);
378  }
379  else {
380  aa[j][i] = sum / p[i];
381  }
382  }
383  }
384  return (aa);
385  }
386 
399  GMatrix Gruen::Cholsl(const GMatrix &a,const GVector &p, const GMatrix &b,
400  const GMatrix &x) const {
401  assert(b.dim1() == x.dim1());
402  assert(b.dim2() == x.dim2());
403  assert(p.dim1() == b.dim2());
404 
405  int nrows(a.dim1());
406  int ncols(a.dim2());
407 
408  GMatrix xout = x.copy();
409  for(int j = 0 ; j < nrows ; j++) {
410 
411  for(int i = 0 ; i < ncols ; i++) {
412  double sum = b[j][i];
413  for(int k = i-1 ; k >= 0 ; k--) {
414  sum -= (a[i][k] * xout[j][k]);
415  }
416  xout[j][i] = sum / p[i];
417  }
418 
419  for (int i = ncols-1 ; i >= 0 ; i--) {
420  double sum = xout[j][i];
421  for(int k = i+1 ; k < ncols ; k++) {
422  sum -= (a[k][i] * xout[j][k]);
423  }
424  xout[j][i] = sum / p[i];
425  }
426 
427  }
428  return (xout);
429  }
430 
443  int Gruen::Jacobi(const GMatrix &a, GVector &evals,
444  GMatrix &evecs, const int &MaxIters) const {
445 
446  int nrows(a.dim1());
447  int ncols(a.dim2());
448  GMatrix v = Identity(nrows);
449  GVector d(nrows),b(nrows), z(nrows);
450 
451  for(int ip = 0 ; ip < nrows ; ip++) {
452  b[ip] = a[ip][ip];
453  d[ip] = b[ip];
454  z[ip] = 0.0;
455  }
456 
457  double n2(double(nrows) * double(nrows));
458  GMatrix aa = a.copy();
459  int nrot(0);
460  for ( ; nrot < MaxIters ; nrot++) {
461  double sm(0.0);
462  for(int ip = 0 ; ip < nrows-1 ; ip++) {
463  for(int iq = ip+1 ; iq < nrows ; iq++) {
464  sm += fabs(aa[ip][iq]);
465  }
466  }
467 
468  // Test for termination condition
469  if (sm == 0.0) {
470  evals = d;
471  evecs = v;
472  return (nrot);
473  }
474 
475  double thresh = (nrot < 3) ? (0.2 * sm/n2 ): 0.0;
476  for (int ip = 0 ; ip < nrows-1 ; ip++) {
477  for (int iq = ip+1 ; iq < nrows ; iq++) {
478  double g = 100.0 * fabs(aa[ip][iq]);
479  if ( (nrot > 3) &&
480  ( (fabs(d[ip]+g) == fabs(d[ip])) ) &&
481  ( (fabs(d[iq]+g) == fabs(d[iq])) ) ) {
482  aa[ip][iq] = 0.0;
483  }
484  else if ( fabs(aa[ip][iq]) > thresh ) {
485  double h = d[iq] - d[ip];
486  double t;
487  if ( (fabs(h)+g) == fabs(h) ) {
488  t = aa[ip][iq]/h;
489  }
490  else {
491  double theta = 0.5 * h / aa[ip][iq];
492  t = 1.0 / (fabs(theta) + sqrt(1.0 + theta * theta));
493  if (theta < 0.0) t = -1.0 * t;
494  }
495  double c = 1./sqrt(1.0 + t * t);
496  double s = t * c;
497  double tau = s / (1.0 + c);
498 
499  h = t * aa[ip][iq];
500  z[ip] = z[ip] - h;
501  z[iq] = z[iq] + h;
502  d[ip] = d[ip] - h;
503  d[iq] = d[iq] + h;
504  aa[ip][iq] = 0.0;
505 
506  double g;
507  for (int j = 0 ; j < ip-1 ; j++) {
508  g = aa[j][ip];
509  h = aa[j][iq];
510  aa[j][ip] = g - s * (h + g * tau);
511  aa[j][iq] = h + s * (g - h * tau);
512  }
513 
514  for (int j = ip+1 ; j < iq-1 ; j++) {
515  g = aa[ip][j];
516  h = aa[j][iq];
517  aa[ip][j] = g - s * (h + g * tau);
518  aa[j][iq] = h + s * (g - h * tau);
519  }
520 
521  for (int j = iq+1 ; j < ncols ; j++) {
522  g = aa[ip][j];
523  h = aa[j][iq];
524  aa[ip][j] = g - s * (h + g * tau);
525  aa[j][iq] = h + s * (g - h * tau);
526  }
527 
528  for (int j = 0 ; j < ncols ; j++) {
529  g = v[j][ip];
530  h = v[j][iq];
531  v[j][ip] = g - s * (h + g * tau);
532  v[j][iq] = h + s * (g - h * tau);
533  }
534  nrot++;
535  }
536  }
537  }
538 
539  for (int ip = 0 ; ip < nrows ; ip++) {
540  b[ip] = b[ip] + z[ip];
541  d[ip] = b[ip];
542  z[ip] = 0.0;
543  }
544  }
545 
546  // Reach here and we have too many iterations
547  evals = d;
548  evecs = v;
550  "Too many iterations in Jacobi",
551  _FILEINFO_);
552  return (nrot);
553  }
554 
555 
556  GMatrix Gruen::Identity(const int &ndiag) const {
557  GMatrix ident(ndiag, ndiag, 0.0);
558  for (int i = 0 ; i < ndiag ; i++) {
559  ident[i][i] = 1.0;
560  }
561  return (ident);
562  }
563 
572  void Gruen::EigenSort(GVector &evals, GMatrix &evecs) const {
573  assert(evals.dim1() == evecs.dim1());
574  int n(evals.dim1());
575  for (int i = 0 ; i < n-1 ; i++ ) {
576  int k = i;
577  double p = evals[i];
578  for (int j = i+1 ; j < n ; j++) {
579  if (evals[j] >= p) {
580  k = j;
581  p = evals[j];
582  }
583  }
584  if (k != i) {
585  evals[k] = evals[i];
586  evals[i] = p;
587  for (int j = 0 ; j < n ; j++) {
588  p = evecs[j][i];
589  evecs[j][i] = evecs[j][k];
590  evecs[j][k] = p;
591  }
592  }
593  }
594  return;
595  }
596 
597 
624  double Gruen::MatchAlgorithm(Chip &pattern, Chip &subsearch) {
625  // reset();
626 
627  BigInt npts;
628  double resid;
629  GMatrix atai;
630  AffineRadio affrad;
631  int status = algorithm(pattern, subsearch, getDefaultRadio(),
632  npts, resid, atai, affrad);
633  if (status == 0) {
634  // Compute fit quality
635  Analysis analysis = errorAnalysis(npts, resid, atai);
636  if (analysis.isValid()) {
637  return (analysis.getEigen());
638  }
639  }
640 
641  // Error conditions return failure
642  return (Null);
643  }
644 
652  bool Gruen::CompareFits(double fit1, double fit2) {
653  return (fit1 <= fit2);
654  }
655 
656 
698  Chip &fChip, int startSamp,
699  int startLine, int endSamp,
700  int endLine, int bestSamp,
701  int bestLine) {
702  // Set conditions for writing subsearch chip states per call. This code
703  // implementation ensures caller must request it per call to this routine.
704  // See the WriteSubsearchChips() method.
705  m_callCount++;
706  QString chipOut = m_filePattern;
707  m_filePattern = "";
708 
709  // Initialize match point. Ensure points are centered to get real cube
710  // line/sample positions
711  pChip.SetChipPosition(pChip.TackSample(), pChip.TackLine());
712  sChip.SetChipPosition(sChip.TackSample(), sChip.TackLine());
713  MatchPoint matchpt = MatchPoint(PointPair(Coordinate(pChip),
714  Coordinate(sChip)));
715 
716  // Create the fit chip whose size is the same as the pattern chip.
717  // This chip will contain the final image at the last iteration. This
718  // usage differs from the non-adaptive purpose.
719  // It is critical to use the original search chip to create the subsearch.
720  // Copying the original search chip and then resizing preserves established
721  // minimum/maximum value ranges. Then, establish chip convergence
722  // condition for Gruen's affine.
723  fChip = sChip;
724  fChip.SetSize(pChip.Samples(), pChip.Lines());
725  Threshold thresh(fChip, getAffineTolerance());
726 
727  // Set up Affine transform by establishing search tack point
728  AffineRadio affine = m_affine;
729  m_affine = AffineRadio(); // Reset initial condition for next call
730 
731  // Set up bestLine/bestSample position. Do this using the local affine
732  // and not the search chip.
733  Coordinate best(bestLine-sChip.TackLine(), bestSamp-sChip.TackSample());
734  affine.Translate(best);
735 
736 
737  // Algorithm parameters
738  bool done = false;
739  m_nIters = 0;
740  do {
741 
742  // Extract the sub search chip. The algorithm method handles the
743  // determination of good data volumes
744  Affine extractor(affine.m_affine);
745  sChip.Extract(fChip, extractor);
746 
747  // If requested for this run, write the current subsearch chip state
748  if (!chipOut.isEmpty()) {
749  std::ostringstream ss;
750  ss << "C" << std::setw(6) << std::setfill('0') << m_callCount << "I"
751  << std::setw(3) << std::setfill('0') << m_nIters;
752  QString sfname = chipOut + ss.str().c_str() + ".cub";
753  fChip.Write(sfname);
754  }
755 
756  // Try to match the two subchips
757  AffineRadio alpha;
758  BigInt npts(0);
759  GMatrix atai;
760  double resid;
761  int status = algorithm(pChip, fChip, affine.m_radio, npts, resid,
762  atai, alpha);
763  if (status != 0) {
764  // Set failed return condition and give up!
765  return (Status(matchpt.setStatus(status)));
766  }
767 
768  // Test for termination conditions - errors or convergence
769  matchpt.m_nIters = ++m_nIters;
770  if (m_nIters > m_maxIters) {
771  QString errmsg = "Maximum Iterations exceeded";
772  matchpt.setStatus(logError(MaxIterationsExceeded, errmsg));
773  return (Status(matchpt)); // Error condition
774  }
775 
776  // Check for convergence after the first pass
777  if (m_nIters > 1) {
778  if(thresh.hasConverged(alpha)) {
779  // Compute error analysis
780  matchpt.m_affine = affine;
781  matchpt.m_analysis = errorAnalysis(npts, resid, atai);
782  matchpt.setStatus(matchpt.m_analysis.m_status);
783  if (matchpt.isValid()) {
784  // Update the point even if constraints don't pass
785  Coordinate uCoord = getChipUpdate(sChip, matchpt);
786  SetChipSample(uCoord.getSample());
787  SetChipLine(uCoord.getLine());
788  SetGoodnessOfFit(matchpt.getEigen());
789 
790  // Check constraints
791  matchpt.setStatus(CheckConstraints(matchpt));
792  }
793 
794  // Set output point
795  m_point = matchpt;
796  return (Status(matchpt)); // with AutoReg status
797  }
798  }
799  // Not done yet - update the affine transform for next loop
800  try {
801  affine += alpha;
802  }
803  catch (IException &ie) {
804  QString mess = "Affine invalid/not invertable";
805  matchpt.setStatus(logError(AffineNotInvertable, mess));
806  return (Status(matchpt)); // Another error condition to return
807  }
808  } while (!done);
809 
810  return (Status(matchpt));
811  }
812 
821  static Pvl regdef;
822  regdef = Pvl("$base/templates/autoreg/coreg.adaptgruen.p1515s3030.def");
823  return (regdef);
824  }
825 
842  PvlGroup algo("GruenFailures");
843  algo += PvlKeyword("Name", AlgorithmName());
844  algo += PvlKeyword("Mode", "Adaptive");
845 
846  // Log errors
847  for (int e = 0 ; e < m_errors.size() ; e++) {
848  algo += m_errors.getNth(e).LogIt();
849  }
850 
851  if (m_unclassified > 0) {
852  algo += PvlKeyword("UnclassifiedErrors", toString(m_unclassified));
853  }
854  pvl.addGroup(algo);
855  pvl.addGroup(StatsLog());
856  pvl.addGroup(ParameterLog());
857  return (pvl);
858  }
859 
871  PvlGroup stats("GruenStatistics");
872 
873  stats += PvlKeyword("TotalIterations", toString(m_totalIterations));
874  stats += ValidateKey("IterationMinimum", m_iterStat.Minimum());
875  stats += ValidateKey("IterationAverage", m_iterStat.Average());
876  stats += ValidateKey("IterationMaximum", m_iterStat.Maximum());
877  stats += ValidateKey("IterationStandardDeviation", m_iterStat.StandardDeviation());
878 
879  stats += ValidateKey("EigenMinimum", m_eigenStat.Minimum());
880  stats += ValidateKey("EigenAverage", m_eigenStat.Average());
881  stats += ValidateKey("EigenMaximum", m_eigenStat.Maximum());
882  stats += ValidateKey("EigenStandardDeviation", m_eigenStat.StandardDeviation());
883 
884  stats += ValidateKey("RadioShiftMinimum", m_shiftStat.Minimum());
885  stats += ValidateKey("RadioShiftAverage", m_shiftStat.Average());
886  stats += ValidateKey("RadioShiftMaximum", m_shiftStat.Maximum());
887  stats += ValidateKey("RadioShiftStandardDeviation", m_shiftStat.StandardDeviation());
888 
889  stats += ValidateKey("RadioGainMinimum", m_gainStat.Minimum());
890  stats += ValidateKey("RadioGainAverage", m_gainStat.Average());
891  stats += ValidateKey("RadioGainMaximum", m_gainStat.Maximum());
892  stats += ValidateKey("RadioGainStandardDeviation", m_gainStat.StandardDeviation());
893 
894  return (stats);
895 
896  }
897 
908  PvlGroup parms("GruenParameters");
909 
910  parms += PvlKeyword("MaximumIterations", toString(m_maxIters));
911  parms += ValidateKey("AffineScaleTolerance", m_scaleTol);
912  parms += ValidateKey("AffineShearTolerance", m_shearTol);
913  parms += ValidateKey("AffineTranslationTolerance", m_transTol);
914 
915  parms += ParameterKey("AffineTolerance", m_affineTol);
916  parms += ParameterKey("SpiceTolerance", m_spiceTol);
917 
918  parms += ParameterKey("RadioShiftTolerance", m_shiftTol);
919 
920  parms += ParameterKey("RadioGainMinTolerance", m_rgainMinTol);
921  parms += ParameterKey("RadioGainMaxTolerance", m_rgainMaxTol);
922 
923  parms += ValidateKey("DefaultRadioGain", m_defGain);
924  parms += ValidateKey("DefaultRadioShift", m_defShift);
925 
926  return (parms);
927  }
928 
929 
940  ErrorList elist;
941  elist.add(1, ErrorCounter(1, "NotEnoughPoints"));
942  elist.add(2, ErrorCounter(2, "CholeskyFailed"));
943  elist.add(3, ErrorCounter(3, "EigenSolutionFailed"));
944  elist.add(4, ErrorCounter(4, "AffineNotInvertable"));
945  elist.add(5, ErrorCounter(5, "MaxIterationsExceeded"));
946  elist.add(6, ErrorCounter(6, "RadShiftExceeded"));
947  elist.add(7, ErrorCounter(7, "RadGainExceeded"));
948  elist.add(8, ErrorCounter(8, "MaxEigenExceeded"));
949  elist.add(9, ErrorCounter(9, "AffineDistExceeded"));
950  return (elist);
951  }
952 
953 
965  int Gruen::logError(int gerrno, const QString &gerrmsg) {
966  if (!m_errors.exists(gerrno)) {
967  m_unclassified++;
968  }
969  else {
970  m_errors.get(gerrno).BumpIt();
971  }
972  return (gerrno);
973  }
974 
984  void Gruen::init(Pvl &pvl) {
985  // Establish the parameters
986  if (pvl.hasObject("AutoRegistration")) {
987  m_prof = DbProfile(pvl.findGroup("Algorithm", Pvl::Traverse));
988  }
989  else {
990  m_prof = DbProfile(pvl);
991  }
992 
993  if (m_prof.Name().isEmpty()) m_prof.setName("Gruen");
994 
995  // Define internal parameters
996  m_maxIters = toInt(ConfKey(m_prof, "MaximumIterations", toString(30)));
997 
998  m_transTol = toDouble(ConfKey(m_prof, "AffineTranslationTolerance", toString(0.1)));
999  m_scaleTol = toDouble(ConfKey(m_prof, "AffineScaleTolerance", toString(0.3)));
1000  m_shearTol = toDouble(ConfKey(m_prof, "AffineShearTolerance", toString(m_scaleTol)));
1001  m_affineTol = toDouble(ConfKey(m_prof, "AffineTolerance", toString(DBL_MAX)));
1002 
1003  m_spiceTol = toDouble(ConfKey(m_prof, "SpiceTolerance", toString(DBL_MAX)));
1004 
1005  m_shiftTol = toDouble(ConfKey(m_prof, "RadioShiftTolerance", toString(DBL_MAX)));
1006  m_rgainMinTol = toDouble(ConfKey(m_prof, "RadioGainMinTolerance", toString(-DBL_MAX)));
1007  m_rgainMaxTol = toDouble(ConfKey(m_prof, "RadioGainMaxTolerance", toString(DBL_MAX)));
1008 
1009  // Set radiometric defaults
1010  m_defGain = toDouble(ConfKey(m_prof, "DefaultRadioGain", toString(0.0)));
1011  m_defShift = toDouble(ConfKey(m_prof, "DefaultRadioShift", toString(0.0)));
1012 
1013  m_callCount = 0;
1014  m_filePattern = "";
1015 
1016  m_nIters = 0;
1017  m_totalIterations = 0;
1018 
1019  m_errors = initErrorList();
1020  m_unclassified = 0;
1021 
1022  m_defAffine = AffineRadio(getDefaultRadio());
1023  m_affine = getAffineRadio();
1024  m_point = MatchPoint(m_affine);
1025 
1026  //reset();
1027  return;
1028  }
1029 
1030 
1036  m_eigenStat.Reset();
1037  m_iterStat.Reset();
1038  m_shiftStat.Reset();
1039  m_gainStat.Reset();
1040  return;
1041  }
1042 
1055  BigInt Gruen::MinValidPoints(BigInt totalPoints) const {
1056  double pts = (double) totalPoints * (PatternValidPercent() / 100.0);
1057  return ((BigInt) pts);
1058  }
1059 
1072  bool Gruen::ValidPoints(BigInt totalPoints, BigInt nPoints) const {
1073  return (nPoints > MinValidPoints(totalPoints));
1074  }
1075 
1084  return (AffineTolerance(m_transTol, m_scaleTol, m_shearTol));
1085  }
1086 
1108 
1109  // Point must be good for check to occur
1110  if (point.isValid()) {
1111  if (point.m_nIters > m_maxIters) {
1112  QString errmsg = "Maximum Iterations exceeded";
1113  return (logError(MaxIterationsExceeded, errmsg));
1114  }
1115  m_iterStat.AddData(point.m_nIters);
1116 
1117  if (point.getEigen() > Tolerance()) {
1118  QString errmsg = "Maximum Eigenvalue exceeded";
1119  return (logError(MaxEigenExceeded, errmsg));
1120  }
1121  m_eigenStat.AddData(point.getEigen());
1122 
1123  double shift = point.m_affine.m_radio.Shift();
1124  if ( shift > m_shiftTol) {
1125  QString errmsg = "Radiometric shift exceeds tolerance";
1126  return (logError(RadShiftExceeded, errmsg));
1127  }
1128  m_shiftStat.AddData(shift);
1129 
1130  double gain = point.m_affine.m_radio.Gain();
1131  if (((1.0 + gain) > m_rgainMaxTol) ||
1132  ((1.0 + gain) < m_rgainMinTol)) {
1133  QString errmsg = "Radiometric gain exceeds tolerances";
1134  return (logError(RadGainExceeded, errmsg));
1135  }
1136  m_gainStat.AddData(gain);
1137 
1138 
1139  double dist = point.getAffinePoint(Coordinate(0.0, 0.0)).getDistance();
1140  if (dist > getAffineConstraint()) {
1141  QString errmsg = "Affine distance exceeded";
1142  return (logError(AffineDistExceeded, errmsg));
1143  }
1144  }
1145  return (point.getStatus());
1146  }
1147 
1159  Coordinate chippt = point.getAffinePoint(Coordinate(0.0, 0.0));
1160  chip.SetChipPosition(chip.TackSample(), chip.TackLine());
1161  chip.TackCube(chip.CubeSample()+chippt.getSample(),
1162  chip.CubeLine()+chippt.getLine());
1163  return (Coordinate(chip.ChipLine(), chip.ChipSample()));
1164  }
1165 
1166 
1179  if ( mpt.isValid() ) { return (AutoReg::SuccessSubPixel); }
1181  }
1182 
1183 } // namespace Isis