Isis 3 Programmer Reference
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 
697  Chip &fChip, int startSamp,
698  int startLine, int endSamp,
699  int endLine, int bestSamp,
700  int bestLine) {
701  // Set conditions for writing subsearch chip states per call. This code
702  // implementation ensures caller must request it per call to this routine.
703  // See the WriteSubsearchChips() method.
704  m_callCount++;
705  QString chipOut = m_filePattern;
706  m_filePattern = "";
707 
708  // Initialize match point. Ensure points are centered to get real cube
709  // line/sample positions
710  pChip.SetChipPosition(pChip.TackSample(), pChip.TackLine());
711  sChip.SetChipPosition(sChip.TackSample(), sChip.TackLine());
712  MatchPoint matchpt = MatchPoint(PointPair(Coordinate(pChip),
713  Coordinate(sChip)));
714 
715  // Create the fit chip whose size is the same as the pattern chip.
716  // This chip will contain the final image at the last iteration. This
717  // usage differs from the non-adaptive purpose.
718  // It is critical to use the original search chip to create the subsearch.
719  // Copying the original search chip and then resizing preserves established
720  // minimum/maximum value ranges. Then, establish chip convergence
721  // condition for Gruen's affine.
722  fChip = sChip;
723  fChip.SetSize(pChip.Samples(), pChip.Lines());
724  Threshold thresh(fChip, getAffineTolerance());
725 
726  // Set up Affine transform by establishing search tack point
727  AffineRadio affine = m_affine;
728  m_affine = AffineRadio(); // Reset initial condition for next call
729 
730  // Set up bestLine/bestSample position. Do this using the local affine
731  // and not the search chip.
732  Coordinate best(bestLine-sChip.TackLine(), bestSamp-sChip.TackSample());
733  affine.Translate(best);
734 
735 
736  // Algorithm parameters
737  bool done = false;
738  m_nIters = 0;
739  do {
740 
741  // Extract the sub search chip. The algorithm method handles the
742  // determination of good data volumes
743  Affine extractor(affine.m_affine);
744  sChip.Extract(fChip, extractor);
745 
746  // If requested for this run, write the current subsearch chip state
747  if (!chipOut.isEmpty()) {
748  std::ostringstream ss;
749  ss << "C" << std::setw(6) << std::setfill('0') << m_callCount << "I"
750  << std::setw(3) << std::setfill('0') << m_nIters;
751  QString sfname = chipOut + ss.str().c_str() + ".cub";
752  fChip.Write(sfname);
753  }
754 
755  // Try to match the two subchips
756  AffineRadio alpha;
757  BigInt npts(0);
758  GMatrix atai;
759  double resid;
760  int status = algorithm(pChip, fChip, affine.m_radio, npts, resid,
761  atai, alpha);
762  if (status != 0) {
763  // Set failed return condition and give up!
764  return (Status(matchpt.setStatus(status)));
765  }
766 
767  // Test for termination conditions - errors or convergence
768  matchpt.m_nIters = ++m_nIters;
769  if (m_nIters > m_maxIters) {
770  QString errmsg = "Maximum Iterations exceeded";
771  matchpt.setStatus(logError(MaxIterationsExceeded, errmsg));
772  return (Status(matchpt)); // Error condition
773  }
774 
775  // Check for convergence after the first pass
776  if (m_nIters > 1) {
777  if(thresh.hasConverged(alpha)) {
778  // Compute error analysis
779  matchpt.m_affine = affine;
780  matchpt.m_analysis = errorAnalysis(npts, resid, atai);
781  matchpt.setStatus(matchpt.m_analysis.m_status);
782  if (matchpt.isValid()) {
783  // Update the point even if constraints don't pass
784  Coordinate uCoord = getChipUpdate(sChip, matchpt);
785  SetChipSample(uCoord.getSample());
786  SetChipLine(uCoord.getLine());
787  SetGoodnessOfFit(matchpt.getEigen());
788 
789  // Check constraints
790  matchpt.setStatus(CheckConstraints(matchpt));
791  }
792 
793  // Set output point
794  m_point = matchpt;
795  return (Status(matchpt)); // with AutoReg status
796  }
797  }
798  // Not done yet - update the affine transform for next loop
799  try {
800  affine += alpha;
801  }
802  catch (IException &ie) {
803  QString mess = "Affine invalid/not invertable";
804  matchpt.setStatus(logError(AffineNotInvertable, mess));
805  return (Status(matchpt)); // Another error condition to return
806  }
807  } while (!done);
808 
809  return (Status(matchpt));
810  }
811 
820  static Pvl regdef;
821  regdef = Pvl("$base/templates/autoreg/coreg.adaptgruen.p1515s3030.def");
822  return (regdef);
823  }
824 
841  PvlGroup algo("GruenFailures");
842  algo += PvlKeyword("Name", AlgorithmName());
843  algo += PvlKeyword("Mode", "Adaptive");
844 
845  // Log errors
846  for (int e = 0 ; e < m_errors.size() ; e++) {
847  algo += m_errors.getNth(e).LogIt();
848  }
849 
850  if (m_unclassified > 0) {
851  algo += PvlKeyword("UnclassifiedErrors", toString(m_unclassified));
852  }
853  pvl.addGroup(algo);
854  pvl.addGroup(StatsLog());
855  pvl.addGroup(ParameterLog());
856  return (pvl);
857  }
858 
870  PvlGroup stats("GruenStatistics");
871 
872  stats += PvlKeyword("TotalIterations", toString(m_totalIterations));
873  stats += ValidateKey("IterationMinimum", m_iterStat.Minimum());
874  stats += ValidateKey("IterationAverage", m_iterStat.Average());
875  stats += ValidateKey("IterationMaximum", m_iterStat.Maximum());
876  stats += ValidateKey("IterationStandardDeviation", m_iterStat.StandardDeviation());
877 
878  stats += ValidateKey("EigenMinimum", m_eigenStat.Minimum());
879  stats += ValidateKey("EigenAverage", m_eigenStat.Average());
880  stats += ValidateKey("EigenMaximum", m_eigenStat.Maximum());
881  stats += ValidateKey("EigenStandardDeviation", m_eigenStat.StandardDeviation());
882 
883  stats += ValidateKey("RadioShiftMinimum", m_shiftStat.Minimum());
884  stats += ValidateKey("RadioShiftAverage", m_shiftStat.Average());
885  stats += ValidateKey("RadioShiftMaximum", m_shiftStat.Maximum());
886  stats += ValidateKey("RadioShiftStandardDeviation", m_shiftStat.StandardDeviation());
887 
888  stats += ValidateKey("RadioGainMinimum", m_gainStat.Minimum());
889  stats += ValidateKey("RadioGainAverage", m_gainStat.Average());
890  stats += ValidateKey("RadioGainMaximum", m_gainStat.Maximum());
891  stats += ValidateKey("RadioGainStandardDeviation", m_gainStat.StandardDeviation());
892 
893  return (stats);
894 
895  }
896 
907  PvlGroup parms("GruenParameters");
908 
909  parms += PvlKeyword("MaximumIterations", toString(m_maxIters));
910  parms += ValidateKey("AffineScaleTolerance", m_scaleTol);
911  parms += ValidateKey("AffineShearTolerance", m_shearTol);
912  parms += ValidateKey("AffineTranslationTolerance", m_transTol);
913 
914  parms += ParameterKey("AffineTolerance", m_affineTol);
915  parms += ParameterKey("SpiceTolerance", m_spiceTol);
916 
917  parms += ParameterKey("RadioShiftTolerance", m_shiftTol);
918 
919  parms += ParameterKey("RadioGainMinTolerance", m_rgainMinTol);
920  parms += ParameterKey("RadioGainMaxTolerance", m_rgainMaxTol);
921 
922  parms += ValidateKey("DefaultRadioGain", m_defGain);
923  parms += ValidateKey("DefaultRadioShift", m_defShift);
924 
925  return (parms);
926  }
927 
928 
939  ErrorList elist;
940  elist.add(1, ErrorCounter(1, "NotEnoughPoints"));
941  elist.add(2, ErrorCounter(2, "CholeskyFailed"));
942  elist.add(3, ErrorCounter(3, "EigenSolutionFailed"));
943  elist.add(4, ErrorCounter(4, "AffineNotInvertable"));
944  elist.add(5, ErrorCounter(5, "MaxIterationsExceeded"));
945  elist.add(6, ErrorCounter(6, "RadShiftExceeded"));
946  elist.add(7, ErrorCounter(7, "RadGainExceeded"));
947  elist.add(8, ErrorCounter(8, "MaxEigenExceeded"));
948  elist.add(9, ErrorCounter(9, "AffineDistExceeded"));
949  return (elist);
950  }
951 
952 
964  int Gruen::logError(int gerrno, const QString &gerrmsg) {
965  if (!m_errors.exists(gerrno)) {
966  m_unclassified++;
967  }
968  else {
969  m_errors.get(gerrno).BumpIt();
970  }
971  return (gerrno);
972  }
973 
983  void Gruen::init(Pvl &pvl) {
984  // Establish the parameters
985  if (pvl.hasObject("AutoRegistration")) {
986  m_prof = DbProfile(pvl.findGroup("Algorithm", Pvl::Traverse));
987  }
988  else {
989  m_prof = DbProfile(pvl);
990  }
991 
992  if (m_prof.Name().isEmpty()) m_prof.setName("Gruen");
993 
994  // Define internal parameters
995  m_maxIters = toInt(ConfKey(m_prof, "MaximumIterations", toString(30)));
996 
997  m_transTol = toDouble(ConfKey(m_prof, "AffineTranslationTolerance", toString(0.1)));
998  m_scaleTol = toDouble(ConfKey(m_prof, "AffineScaleTolerance", toString(0.3)));
999  m_shearTol = toDouble(ConfKey(m_prof, "AffineShearTolerance", toString(m_scaleTol)));
1000  m_affineTol = toDouble(ConfKey(m_prof, "AffineTolerance", toString(DBL_MAX)));
1001 
1002  m_spiceTol = toDouble(ConfKey(m_prof, "SpiceTolerance", toString(DBL_MAX)));
1003 
1004  m_shiftTol = toDouble(ConfKey(m_prof, "RadioShiftTolerance", toString(DBL_MAX)));
1005  m_rgainMinTol = toDouble(ConfKey(m_prof, "RadioGainMinTolerance", toString(-DBL_MAX)));
1006  m_rgainMaxTol = toDouble(ConfKey(m_prof, "RadioGainMaxTolerance", toString(DBL_MAX)));
1007 
1008  // Set radiometric defaults
1009  m_defGain = toDouble(ConfKey(m_prof, "DefaultRadioGain", toString(0.0)));
1010  m_defShift = toDouble(ConfKey(m_prof, "DefaultRadioShift", toString(0.0)));
1011 
1012  m_callCount = 0;
1013  m_filePattern = "";
1014 
1015  m_nIters = 0;
1016  m_totalIterations = 0;
1017 
1018  m_errors = initErrorList();
1019  m_unclassified = 0;
1020 
1021  m_defAffine = AffineRadio(getDefaultRadio());
1022  m_affine = getAffineRadio();
1023  m_point = MatchPoint(m_affine);
1024 
1025  //reset();
1026  return;
1027  }
1028 
1029 
1035  m_eigenStat.Reset();
1036  m_iterStat.Reset();
1037  m_shiftStat.Reset();
1038  m_gainStat.Reset();
1039  return;
1040  }
1041 
1054  BigInt Gruen::MinValidPoints(BigInt totalPoints) const {
1055  double pts = (double) totalPoints * (PatternValidPercent() / 100.0);
1056  return ((BigInt) pts);
1057  }
1058 
1071  bool Gruen::ValidPoints(BigInt totalPoints, BigInt nPoints) const {
1072  return (nPoints > MinValidPoints(totalPoints));
1073  }
1074 
1083  return (AffineTolerance(m_transTol, m_scaleTol, m_shearTol));
1084  }
1085 
1107 
1108  // Point must be good for check to occur
1109  if (point.isValid()) {
1110  if (point.m_nIters > m_maxIters) {
1111  QString errmsg = "Maximum Iterations exceeded";
1112  return (logError(MaxIterationsExceeded, errmsg));
1113  }
1114  m_iterStat.AddData(point.m_nIters);
1115 
1116  if (point.getEigen() > Tolerance()) {
1117  QString errmsg = "Maximum Eigenvalue exceeded";
1118  return (logError(MaxEigenExceeded, errmsg));
1119  }
1120  m_eigenStat.AddData(point.getEigen());
1121 
1122  double shift = point.m_affine.m_radio.Shift();
1123  if ( shift > m_shiftTol) {
1124  QString errmsg = "Radiometric shift exceeds tolerance";
1125  return (logError(RadShiftExceeded, errmsg));
1126  }
1127  m_shiftStat.AddData(shift);
1128 
1129  double gain = point.m_affine.m_radio.Gain();
1130  if (((1.0 + gain) > m_rgainMaxTol) ||
1131  ((1.0 + gain) < m_rgainMinTol)) {
1132  QString errmsg = "Radiometric gain exceeds tolerances";
1133  return (logError(RadGainExceeded, errmsg));
1134  }
1135  m_gainStat.AddData(gain);
1136 
1137 
1138  double dist = point.getAffinePoint(Coordinate(0.0, 0.0)).getDistance();
1139  if (dist > getAffineConstraint()) {
1140  QString errmsg = "Affine distance exceeded";
1141  return (logError(AffineDistExceeded, errmsg));
1142  }
1143  }
1144  return (point.getStatus());
1145  }
1146 
1158  Coordinate chippt = point.getAffinePoint(Coordinate(0.0, 0.0));
1159  chip.SetChipPosition(chip.TackSample(), chip.TackLine());
1160  chip.TackCube(chip.CubeSample()+chippt.getSample(),
1161  chip.CubeLine()+chippt.getLine());
1162  return (Coordinate(chip.ChipLine(), chip.ChipSample()));
1163  }
1164 
1165 
1178  if ( mpt.isValid() ) { return (AutoReg::SuccessSubPixel); }
1180  }
1181 
1182 } // namespace Isis
bool ValidPoints(BigInt totalPoints, BigInt nPoints) const
Determines if number of points is valid percentage of all points.
Definition: Gruen.cpp:1071
long long int BigInt
Big int.
Definition: Constants.h:65
void SetChipPosition(const double sample, const double line)
Compute the position of the cube given a chip coordinate.
Definition: Chip.cpp:665
int Jacobi(const GMatrix &a, GVector &evals, GMatrix &evecs, const int &MaxIters=50) const
Compute the Jacobian of a covariance matrix.
Definition: Gruen.cpp:443
void setAffineRadio()
Set affine parameters to defaults.
Definition: Gruen.cpp:143
Error occured in Adaptive algorithm.
Definition: AutoReg.h:205
Success registering to sub-pixel accuracy.
Definition: AutoReg.h:197
double getEigen() const
Returns the square of the of sum of the squares of eigenvalues.
Definition: GruenTypes.h:412
const double Null
Value for an Isis Null pixel.
Definition: SpecialPixel.h:110
AutoReg::RegisterStatus Status(const MatchPoint &result)
Returns the proper status given a Gruen result container.
Definition: Gruen.cpp:1177
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:141
T & get(const K &key)
Returns the value associated with the name provided.
Definition: CollectorMap.h:583
virtual AutoReg::RegisterStatus Registration(Chip &sChip, Chip &pChip, Chip &fChip, int startSamp, int startLine, int endSamp, int endLine, int bestSamp, int bestLine)
Applies the adaptive Gruen algorithm to pattern and search chips.
Definition: Gruen.cpp:696
Define a generic Y/X container.
Definition: GruenTypes.h:69
void SetChipSample(double sample)
Sets the search chip subpixel sample that matches the pattern tack sample.
Definition: AutoReg.h:409
double StandardDeviation() const
Computes and returns the standard deviation.
Definition: Statistics.cpp:325
double Minimum() const
Returns the absolute minimum double found in all data passed through the AddData method.
Definition: Statistics.cpp:395
Store for radiometric gain and shift parameters.
Definition: GruenTypes.h:222
double getDistance(const Coordinate &pntA=Coordinate(0.0, 0.0)) const
Computes the distance from this point and the point provided.
Definition: GruenTypes.h:116
A small chip of data used for pattern matching.
Definition: Chip.h:102
void Translate(const Coordinate &offset)
Apply a translation to the given offset.
Definition: GruenTypes.h:279
T & getNth(int nth)
Returns the nth value in the collection.
Definition: CollectorMap.h:640
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: Gruen.cpp:652
Define a point set of left, right and geometry at that location.
Definition: GruenTypes.h:187
void addGroup(const Isis::PvlGroup &group)
Add a group to the object.
Definition: PvlObject.h:198
GMatrix Cholsl(const GMatrix &a, const GVector &p, const GMatrix &b, const GMatrix &x) const
Compute Cholesky solution matrix from correlation.
Definition: Gruen.cpp:399
int toInt(const QString &string)
Global function to convert from a string to an integer.
Definition: IString.cpp:108
Namespace for the standard library.
PvlGroup StatsLog() const
Create a PvlGroup with the Gruen specific statistics.
Definition: Gruen.cpp:869
void TackCube(const double cubeSample, const double cubeLine)
This sets which cube position will be located at the chip tack position.
Definition: Chip.cpp:204
virtual QString AlgorithmName() const
Returns the default name of the algorithm as Gruen.
Definition: Gruen.h:140
Search child objects.
Definition: PvlObject.h:170
Analysis errorAnalysis(const BigInt &npts, const double &resid, const GMatrix &atai)
Compute the error analysis of convergent Gruen matrix.
Definition: Gruen.cpp:305
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:226
int size() const
Returns the size of the collection.
Definition: CollectorMap.h:528
int logError(int gerrno, const QString &gerrmsg)
Logs a Gruen error.
Definition: Gruen.cpp:964
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition: IString.cpp:164
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:162
int algorithm(Chip &pattern, Chip &subsearch, const Radiometric &radio, BigInt &ptsUsed, double &resid, GMatrix &atai, AffineRadio &affrad)
Real workhorse of the computational Gruen algorithm.
Definition: Gruen.cpp:172
Chip Extract(int samples, int lines, int samp, int line)
Extract a sub-chip from a chip.
Definition: Chip.cpp:749
A DbProfile is a container for access parameters to a database.
Definition: DbProfile.h:65
virtual Pvl AlgorithmStatistics(Pvl &pvl)
Create Gruen error and processing statistics Pvl output.
Definition: Gruen.cpp:840
bool hasObject(const QString &name) const
Returns a boolean value based on whether the object exists in the current PvlObject or not...
Definition: PvlObject.h:335
Coordinate getChipUpdate(Chip &sChip, MatchPoint &point) const
Compute the chip coordinate of the registered pixel.
Definition: Gruen.cpp:1157
const AffineRadio & getAffineRadio() const
Return current state of Affine/Radio state.
Definition: Gruen.h:120
double Maximum() const
Returns the absolute maximum double found in all data passed through the AddData method.
Definition: Statistics.cpp:416
double DegreesOfFreedom(const int npts) const
Returns number of degrees of freedom of points.
Definition: Gruen.h:363
BigInt MinValidPoints(BigInt totalPoints) const
Computes the number of minimum valid points.
Definition: Gruen.cpp:1054
int Lines() const
Definition: Chip.h:122
Gruen()
Default constructor.
Definition: Gruen.cpp:48
void SetGoodnessOfFit(double fit)
Sets the goodness of fit for adaptive algorithms.
Definition: AutoReg.h:429
Affine basis function.
Definition: Affine.h:80
ErrorList initErrorList() const
Creates an error list from know Gruen errors.
Definition: Gruen.cpp:938
double Tolerance() const
Return match algorithm tolerance.
Definition: AutoReg.h:306
bool IsValid(int sample, int line)
Definition: Chip.h:256
QString ConfKey(const DbProfile &conf, const QString &keyname, const QString &defval, int index=0) const
Helper method to initialize parameters.
Definition: Gruen.h:257
void EigenSort(GVector &evals, GMatrix &evecs) const
Sort eigenvectors from highest to lowest.
Definition: Gruen.cpp:572
PvlKeyword ParameterKey(const QString &keyname, const T &value, const QString &unit="") const
Keyword formatter for Gruen parameters.
Definition: Gruen.h:317
Contains multiple PvlContainers.
Definition: PvlGroup.h:57
bool exists(const K &key) const
Checks the existance of a particular key in the list.
Definition: CollectorMap.h:567
void Write(const QString &filename)
Writes the contents of the Chip to a cube.
Definition: Chip.cpp:1007
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
void add(const K &key, const T &value)
Adds the element to the list.
Definition: CollectorMap.h:556
A single keyword-value pair.
Definition: PvlKeyword.h:98
double CubeSample() const
Definition: Chip.h:219
double PatternValidPercent() const
Return pattern chip valid percent. The default value is.
Definition: AutoReg.h:296
void WriteSubsearchChips(const QString &pattern="SubChip")
Set up for writing subsearch for a a given registration call.
Definition: Gruen.cpp:108
AffineTolerance getAffineTolerance() const
Return set of tolerances for affine convergence.
Definition: Gruen.cpp:1082
int TackSample() const
This method returns a chip&#39;s fixed tack sample; the middle of the chip.
Definition: Chip.h:192
void SetChipLine(double line)
Sets the search chip subpixel line that matches the pattern tack line.
Definition: AutoReg.h:420
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
virtual double MatchAlgorithm(Chip &pattern, Chip &subsearch)
Minimization of data set using Gruen algorithm.
Definition: Gruen.cpp:624
PvlGroup ParameterLog() const
Create a PvlGroup with the Gruen specific parameters.
Definition: Gruen.cpp:906
Container for cube-like labels.
Definition: Pvl.h:135
void setName(const QString &name)
Set the name of this profile.
Definition: DbProfile.h:109
Container for Affine limits parameters.
Definition: GruenTypes.h:335
Radiometric getDefaultRadio() const
Returns the default radiometric gain value.
Definition: Gruen.h:358
Container for affine and radiometric parameters.
Definition: GruenTypes.h:258
Auto Registration class.
Definition: AutoReg.h:183
int CheckConstraints(MatchPoint &point)
Test user limits/contraints after the algorithm has converged.
Definition: Gruen.cpp:1106
void init(Pvl &pvl)
Initialize the object.
Definition: Gruen.cpp:983
Structure containing comprehensive registration info/results.
Definition: GruenTypes.h:449
Gruen pattern matching algorithm.
Definition: Gruen.h:90
QString toString() const
Returns a string representation of this exception.
Definition: IException.cpp:553
PvlKeyword ValidateKey(const QString keyname, const double &value, const QString &unit="") const
Checks value of key, produces appropriate value.
Definition: Gruen.h:339
void resetStats()
Reset Gruen statistics as needed.
Definition: Gruen.cpp:1034
bool hasConverged(const AffineRadio &affine) const
Determines convergence from an affine/radiometric fit.
Definition: GruenTypes.h:379
int Samples() const
Definition: Chip.h:115
RegisterStatus
Enumeration of the Register() method&#39;s return status.
Definition: AutoReg.h:195
Isis exception class.
Definition: IException.h:107
const AffineRadio & getDefaultAffineRadio() const
Returns default settings for Affine/Radiometric parameters.
Definition: Gruen.h:117
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
double ChipSample() const
Definition: Chip.h:235
double GetValue(int sample, int line)
Loads a Chip with a value.
Definition: Chip.h:161
QString Name() const
Returns the name of this property.
Definition: DbProfile.h:118
Compute/test the Affine convergence from given parameters/chip.
Definition: GruenTypes.h:364
Coordinate getAffinePoint(const Coordinate &coord=Coordinate(0.0, 0.0)) const
Return registration offset of a given chip coordinate from center.
Definition: GruenTypes.h:468
Error analysis of Gruen match point solution.
Definition: GruenTypes.h:399
void AddData(const double *data, const unsigned int count)
Add an array of doubles to the accumulators and counters.
Definition: Statistics.cpp:154
static Pvl & getDefaultParameters()
Load default Gruen parameter file in $ISIS3DATA/base/templates.
Definition: Gruen.cpp:819
double Average() const
Computes and returns the average.
Definition: Statistics.cpp:313
GMatrix Choldc(const GMatrix &a, GVector &p) const
Compute Cholesky solution.
Definition: Gruen.cpp:357
double getAffineConstraint() const
Returns the Affine tolerance constraint as read from config file.
Definition: Gruen.h:111
Struct that maintains error counts.
Definition: Gruen.h:182
int TackLine() const
This method returns a chip&#39;s fixed tack line; the middle of the chip.
Definition: Chip.h:203