13#include "tnt/tnt_array1d_utils.h" 
   93    m_filePattern = pattern;
 
 
  158                       double &resid, GMatrix &atai, 
AffineRadio &affrad) {
 
  163    int tackSamp = pattern.TackSample();
 
  164    int tackLine = pattern.TackLine();
 
  167    double rshift = radio.Shift();
 
  168    double rgain  = radio.Gain();
 
  170    int maxPnts((pattern.Samples()-2) * (pattern.Lines()-2));
 
  171    GMatrix a(maxPnts, 8);
 
  172    GVector lvec(maxPnts);
 
  177    for(
int line = 2 ; line < pattern.Lines() ; line++) {
 
  178      for(
int samp = 2; samp < pattern.Samples() ; samp++) {
 
  180        if(!pattern.IsValid(samp, line)) 
continue;
 
  181        if(!subsearch.IsValid(samp, line)) 
continue;
 
  182        if(!subsearch.IsValid(samp + 1, line)) 
continue;
 
  183        if(!subsearch.IsValid(samp - 1, line)) 
continue;
 
  184        if(!subsearch.IsValid(samp, line - 1)) 
continue;
 
  185        if(!subsearch.IsValid(samp, line + 1)) 
continue;
 
  188        double x0 = (double)(samp - tackSamp);
 
  189        double y0 = (double)(line - tackLine);
 
  192        double gxtemp = subsearch.GetValue(samp + 1, line) -
 
  193                        subsearch.GetValue(samp - 1, line);
 
  194        double gytemp = subsearch.GetValue(samp, line + 1) -
 
  195                        subsearch.GetValue(samp, line - 1);
 
  198        a[npts][1] = gxtemp * x0;
 
  199        a[npts][2] = gxtemp * y0;
 
  201        a[npts][4] = gytemp * x0;
 
  202        a[npts][5] = gytemp * y0;
 
  204        a[npts][7] = subsearch.GetValue(samp, line);
 
  206        double ell = pattern.GetValue(samp, line) -
 
  207                     (((1.0 + rgain) * subsearch.GetValue(samp, line)) +
 
  211        resid += (ell * ell);
 
  219      std::ostringstream mess;
 
  221           << 
") criteria not met (" << npts << 
")";
 
  222      return (
logError(NotEnoughPoints, mess.str().c_str()));
 
  227    for(
int i = 0 ; i < 8 ; i++) {
 
  228      for(
int j = 0 ; j < 8 ; j++) {
 
  230        for (
int k = 0 ; k < npts ; k++) {
 
  231          temp += (a[k][i] * a[k][j]);
 
  241      GMatrix b = Identity(8);
 
  243      atai = 
Cholsl(atai, p, b, x);
 
  246      QString mess = 
"Cholesky Failed:: " + ie.toString();
 
  247      return (
logError(CholeskyFailed, mess));
 
  252    for (
int i = 0 ; i < 8 ; i++) {
 
  254      for (
int k = 0 ; k < npts ; k++) {
 
  255        temp += a[k][i] * lvec[k];
 
  260    GVector alpha(8, 0.0);
 
  261    for (
int i = 0 ; i < 8 ; i++) {
 
  262      for (
int k = 0 ; k < 8 ; k++) {
 
  263        alpha[i] += atai[i][k] * atl[k];
 
  271      QString mess = 
"Affine failed: " + ie.toString();
 
  272      return (
logError(AffineNotInvertable, mess));
 
 
  290                                const GMatrix &atai) {
 
  293    results.m_npts = npts;
 
  298    for(
int r = 0 ; r < 8 ; r++) {
 
  299      for(
int c = 0 ; c < 8 ; c++) {
 
  300        kmat[r][c] = variance * atai[r][c];
 
  303    results.m_variance = variance;
 
  308    skmat[0][0] = kmat[0][0];
 
  309    skmat[0][1] = kmat[0][3];
 
  310    skmat[1][0] = kmat[3][0];
 
  311    skmat[1][1] = kmat[3][3];
 
  314      Jacobi(skmat, eigen, skmat);
 
  316      for (
int i = 0 ; i < 2 ; i++) {
 
  317        results.m_sevals[i] = eigen[i];
 
  318        results.m_kmat[i] = kmat[i*3][i*3];
 
  322      QString errmsg = 
"Eigen Solution Failed:: " + ie.toString();
 
  323      results.m_status = 
logError(EigenSolutionFailed, errmsg);
 
  327    results.m_status = 0;
 
 
  345    GMatrix aa = a.copy();
 
  348    for(
int i = 0 ; i < nrows ; i++) {
 
  349      for(
int j = i ; j < ncols ; j++) {
 
  350        double sum = aa[i][j];
 
  351        for(
int k = i-1 ; k >= 0 ; k--) {
 
  352          sum -= (aa[i][k] * aa[j][k]);
 
  358                             "Choldc failed - matrix not postive definite",
 
  364          aa[j][i] = sum / p[i];
 
 
  384                        const GMatrix &x)
 const {
 
  385    assert(b.dim1() == x.dim1());
 
  386    assert(b.dim2() == x.dim2());
 
  387    assert(p.dim1() == b.dim2());
 
  392    GMatrix xout = x.copy();
 
  393    for(
int j = 0 ; j < nrows ; j++) {
 
  395      for(
int i = 0 ; i < ncols ; i++) {
 
  396        double sum = b[j][i];
 
  397        for(
int k = i-1 ; k >= 0 ; k--) {
 
  398          sum -= (a[i][k] * xout[j][k]);
 
  400        xout[j][i] = sum / p[i];
 
  403      for (
int i = ncols-1 ; i >= 0 ; i--) {
 
  404        double sum = xout[j][i];
 
  405        for(
int k = i+1 ; k < ncols ; k++) {
 
  406          sum -= (a[k][i] * xout[j][k]);
 
  408        xout[j][i] = sum / p[i];
 
 
  428                    GMatrix &evecs, 
const int &MaxIters)
 const {
 
  432    GMatrix v = Identity(nrows);
 
  433    GVector d(nrows),b(nrows), z(nrows);
 
  435    for(
int ip = 0 ; ip < nrows ; ip++) {
 
  441    double n2(
double(nrows) * 
double(nrows));
 
  442    GMatrix aa = a.copy();
 
  444    for ( ; nrot < MaxIters ; nrot++) {
 
  446      for(
int ip = 0 ; ip < nrows-1 ; ip++) {
 
  447        for(
int iq = ip+1 ; iq < nrows ; iq++) {
 
  448          sm += fabs(aa[ip][iq]);
 
  459      double thresh = (nrot < 3) ? (0.2 * sm/n2 ): 0.0;
 
  460      for (
int ip = 0 ; ip < nrows-1 ; ip++) {
 
  461        for (
int iq = ip+1 ; iq < nrows ; iq++) {
 
  462          double g = 100.0 * fabs(aa[ip][iq]);
 
  464               ( (fabs(d[ip]+g) == fabs(d[ip])) ) &&
 
  465               ( (fabs(d[iq]+g) == fabs(d[iq])) ) ) {
 
  468          else if ( fabs(aa[ip][iq]) > thresh ) {
 
  469            double h = d[iq] - d[ip];
 
  471            if ( (fabs(h)+g) == fabs(h) ) {
 
  475              double theta = 0.5 * h / aa[ip][iq];
 
  476              t = 1.0 / (fabs(theta) + sqrt(1.0 + theta * theta));
 
  477              if (theta < 0.0)  t = -1.0 * t;
 
  479            double c = 1./sqrt(1.0 + t * t);
 
  481            double tau = s / (1.0 + c);
 
  491            for (
int j = 0 ; j < ip-1 ; j++) {
 
  494              aa[j][ip] = g - s * (h + g * tau);
 
  495              aa[j][iq] = h + s * (g - h * tau);
 
  498            for (
int j = ip+1 ; j < iq-1 ; j++) {
 
  501              aa[ip][j] = g - s * (h + g * tau);
 
  502              aa[j][iq] = h + s * (g - h * tau);
 
  505            for (
int j = iq+1 ; j < ncols ; j++) {
 
  508              aa[ip][j] = g - s * (h + g * tau);
 
  509              aa[j][iq] = h + s * (g - h * tau);
 
  512            for (
int j = 0 ; j < ncols ; j++) {
 
  515              v[j][ip] = g - s * (h + g * tau);
 
  516              v[j][iq] = h + s * (g - h * tau);
 
  523      for (
int ip = 0 ; ip < nrows ; ip++) {
 
  524        b[ip] = b[ip] + z[ip];
 
  534                     "Too many iterations in Jacobi",
 
 
  540  GMatrix Gruen::Identity(
const int &ndiag)
 const {
 
  541    GMatrix ident(ndiag, ndiag, 0.0);
 
  542    for (
int i = 0 ; i < ndiag ; i++) {
 
  557    assert(evals.dim1() == evecs.dim1());
 
  559    for (
int i = 0 ; i < n-1 ; i++ ) {
 
  562      for (
int j = i+1 ; j < n ; j++) {
 
  571        for (
int j = 0 ; j < n ; j++) {
 
  573          evecs[j][i] = evecs[j][k];
 
 
  616                           npts, resid, atai, affrad);
 
  620      if (analysis.isValid()) {
 
  621        return (analysis.getEigen());
 
 
  637    return (fit1 <= fit2);
 
 
  681      Chip &fChip, 
int startSamp,
 
  682      int startLine, 
int endSamp,
 
  683      int endLine, 
int bestSamp,
 
  689    QString chipOut = m_filePattern;
 
  694    pChip.SetChipPosition(pChip.TackSample(), pChip.TackLine());
 
  695    sChip.SetChipPosition(sChip.TackSample(), sChip.TackLine());
 
  707    fChip.SetSize(pChip.Samples(), pChip.Lines());
 
  716    Coordinate best(bestLine-sChip.TackLine(), bestSamp-sChip.TackSample());
 
  717    affine.Translate(best);
 
  727      Affine extractor(affine.m_affine);
 
  728      sChip.Extract(fChip, extractor);
 
  731      if (!chipOut.isEmpty()) {
 
  732        std::ostringstream ss;
 
  733        ss << 
"C" << std::setw(6) << std::setfill(
'0') << m_callCount << 
"I" 
  734           << std::setw(3) << std::setfill(
'0') << m_nIters;
 
  735        QString sfname = chipOut + ss.str().c_str() + 
".cub";
 
  744      int status = 
algorithm(pChip, fChip, affine.m_radio, npts, resid,
 
  748        return (
Status(matchpt.setStatus(status)));
 
  752      matchpt.m_nIters = ++m_nIters;
 
  753      if (m_nIters > m_maxIters) {
 
  754        QString errmsg = 
"Maximum Iterations exceeded";
 
  755        matchpt.setStatus(
logError(MaxIterationsExceeded, errmsg));
 
  761        if(thresh.hasConverged(alpha)) {
 
  763          matchpt.m_affine = affine;
 
  765          matchpt.setStatus(matchpt.m_analysis.m_status);
 
  766          if (matchpt.isValid()) {
 
  787        QString mess = 
"Affine invalid/not invertable";
 
  788        matchpt.setStatus(
logError(AffineNotInvertable, mess));
 
 
  805    regdef = 
Pvl(
"$ISISROOT/appdata/templates/autoreg/coreg.adaptgruen.p1515s3030.def");
 
 
  830    for (
int e = 0 ; e <  m_errors.
size() ; e++) {
 
  831      algo += m_errors.
getNth(e).LogIt();
 
  834    if (m_unclassified > 0) {
 
 
  894    parms += 
ValidateKey(
"AffineScaleTolerance", m_scaleTol);
 
  895    parms += 
ValidateKey(
"AffineShearTolerance", m_shearTol);
 
  896    parms += 
ValidateKey(
"AffineTranslationTolerance", m_transTol);
 
  901    parms += 
ParameterKey(
"RadioShiftTolerance", m_shiftTol);
 
  903    parms += 
ParameterKey(
"RadioGainMinTolerance", m_rgainMinTol);
 
  904    parms += 
ParameterKey(
"RadioGainMaxTolerance", m_rgainMaxTol);
 
  906    parms += 
ValidateKey(
"DefaultRadioGain",  m_defGain);
 
  907    parms += 
ValidateKey(
"DefaultRadioShift", m_defShift);
 
 
  949    if (!m_errors.
exists(gerrno)) {
 
  953      m_errors.
get(gerrno).BumpIt();
 
 
  969    if (pvl.hasObject(
"AutoRegistration")) {
 
  976    if (m_prof.
Name().isEmpty())  m_prof.
setName(
"Gruen");
 
 1000    m_totalIterations = 0;
 
 
 1019    m_eigenStat.
Reset();
 
 1021    m_shiftStat.
Reset();
 
 
 1093    if (point.isValid()) {
 
 1094      if (point.m_nIters > m_maxIters) {
 
 1095        QString errmsg = 
"Maximum Iterations exceeded";
 
 1096        return (
logError(MaxIterationsExceeded, errmsg));
 
 1098      m_iterStat.
AddData(point.m_nIters);
 
 1101        QString errmsg = 
"Maximum Eigenvalue exceeded";
 
 1102        return (
logError(MaxEigenExceeded, errmsg));
 
 1104      m_eigenStat.
AddData(point.getEigen());
 
 1106      double shift = point.m_affine.m_radio.Shift();
 
 1107      if ( shift > m_shiftTol) {
 
 1108        QString errmsg = 
"Radiometric shift exceeds tolerance";
 
 1109        return (
logError(RadShiftExceeded, errmsg));
 
 1113      double gain = point.m_affine.m_radio.Gain();
 
 1114      if (((1.0 + gain) > m_rgainMaxTol) ||
 
 1115          ((1.0 + gain) < m_rgainMinTol)) {
 
 1116        QString errmsg = 
"Radiometric gain exceeds tolerances";
 
 1117        return (
logError(RadGainExceeded, errmsg));
 
 1124        QString errmsg = 
"Affine distance exceeded";
 
 1125        return (
logError(AffineDistExceeded, errmsg));
 
 1128    return (point.getStatus());
 
 
Container for affine and radiometric parameters.
 
RegisterStatus
Enumeration of the Register() method's return status.
 
@ SuccessSubPixel
Success registering to sub-pixel accuracy.
 
@ AdaptiveAlgorithmFailed
Error occured in Adaptive algorithm.
 
void SetChipLine(double line)
Sets the search chip subpixel line that matches the pattern tack line.
 
double PatternValidPercent() const
Return pattern chip valid percent. The default value is.
 
void SetChipSample(double sample)
Sets the search chip subpixel sample that matches the pattern tack sample.
 
void SetGoodnessOfFit(double fit)
Sets the goodness of fit for adaptive algorithms.
 
double Tolerance() const
Return match algorithm tolerance.
 
A small chip of data used for pattern matching.
 
int TackSample() const
This method returns a chip's fixed tack sample; the middle of the chip.
 
void SetChipPosition(const double sample, const double line)
Compute the position of the cube given a chip coordinate.
 
double ChipSample() const
 
void TackCube(const double cubeSample, const double cubeLine)
This sets which cube position will be located at the chip tack position.
 
double CubeSample() const
 
int TackLine() const
This method returns a chip's fixed tack line; the middle of the chip.
 
int size() const
Returns the size of the collection.
 
T & get(const K &key)
Returns the value associated with the name provided.
 
bool exists(const K &key) const
Checks the existance of a particular key in the list.
 
void add(const K &key, const T &value)
Adds the element to the list.
 
T & getNth(int nth)
Returns the nth value in the collection.
 
Define a generic Y/X container.
 
double getDistance(const Coordinate &pntA=Coordinate(0.0, 0.0)) const
Computes the distance from this point and the point provided.
 
A DbProfile is a container for access parameters to a database.
 
void setName(const QString &name)
Set the name of this profile.
 
QString Name() const
Returns the name of this property.
 
Gruen pattern matching algorithm.
 
void EigenSort(GVector &evals, GMatrix &evecs) const
Sort eigenvectors from highest to lowest.
 
double getAffineConstraint() const
Returns the Affine tolerance constraint as read from config file.
 
void WriteSubsearchChips(const QString &pattern="SubChip")
Set up for writing subsearch for a a given registration call.
 
void resetStats()
Reset Gruen statistics as needed.
 
QString ConfKey(const DbProfile &conf, const QString &keyname, const QString &defval, int index=0) const
Helper method to initialize parameters.
 
Gruen()
Default constructor.
 
int Jacobi(const GMatrix &a, GVector &evals, GMatrix &evecs, const int &MaxIters=50) const
Compute the Jacobian of a covariance matrix.
 
const AffineRadio & getDefaultAffineRadio() const
Returns default settings for Affine/Radiometric parameters.
 
void init(Pvl &pvl)
Initialize the object.
 
Coordinate getChipUpdate(Chip &sChip, MatchPoint &point) const
Compute the chip coordinate of the registered pixel.
 
virtual double MatchAlgorithm(Chip &pattern, Chip &subsearch)
Minimization of data set using Gruen algorithm.
 
virtual QString AlgorithmName() const
Returns the default name of the algorithm as Gruen.
 
Analysis errorAnalysis(const BigInt &npts, const double &resid, const GMatrix &atai)
Compute the error analysis of convergent Gruen matrix.
 
static Pvl & getDefaultParameters()
Load default Gruen parameter file in $ISISROOT/appdata/templates.
 
int logError(int gerrno, const QString &gerrmsg)
Logs a Gruen error.
 
bool ValidPoints(BigInt totalPoints, BigInt nPoints) const
Determines if number of points is valid percentage of all points.
 
void setAffineRadio()
Set affine parameters to defaults.
 
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.
 
GMatrix Cholsl(const GMatrix &a, const GVector &p, const GMatrix &b, const GMatrix &x) const
Compute Cholesky solution matrix from correlation.
 
AutoReg::RegisterStatus Status(const MatchPoint &result)
Returns the proper status given a Gruen result container.
 
PvlGroup ParameterLog() const
Create a PvlGroup with the Gruen specific parameters.
 
PvlKeyword ValidateKey(const QString keyname, const double &value, const QString &unit="") const
Checks value of key, produces appropriate value.
 
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.
 
PvlGroup StatsLog() const
Create a PvlGroup with the Gruen specific statistics.
 
Radiometric getDefaultRadio() const
Returns the default radiometric gain value.
 
int algorithm(Chip &pattern, Chip &subsearch, const Radiometric &radio, BigInt &ptsUsed, double &resid, GMatrix &atai, AffineRadio &affrad)
Real workhorse of the computational Gruen algorithm.
 
int CheckConstraints(MatchPoint &point)
Test user limits/contraints after the algorithm has converged.
 
ErrorList initErrorList() const
Creates an error list from know Gruen errors.
 
GMatrix Choldc(const GMatrix &a, GVector &p) const
Compute Cholesky solution.
 
PvlKeyword ParameterKey(const QString &keyname, const T &value, const QString &unit="") const
Keyword formatter for Gruen parameters.
 
double DegreesOfFreedom(const int npts) const
Returns number of degrees of freedom of points.
 
virtual Pvl AlgorithmStatistics(Pvl &pvl)
Create Gruen error and processing statistics Pvl output.
 
BigInt MinValidPoints(BigInt totalPoints) const
Computes the number of minimum valid points.
 
const AffineRadio & getAffineRadio() const
Return current state of Affine/Radio state
 
AffineTolerance getAffineTolerance() const
Return set of tolerances for affine convergence.
 
@ Programmer
This error is for when a programmer made an API call that was illegal.
 
Structure containing comprehensive registration info/results.
 
Coordinate getAffinePoint(const Coordinate &coord=Coordinate(0.0, 0.0)) const
Return registration offset of a given chip coordinate from center
 
Define a point set of left, right and geometry at that location.
 
Contains multiple PvlContainers.
 
Container for cube-like labels.
 
A single keyword-value pair.
 
@ Traverse
Search child objects.
 
Store for radiometric gain and shift parameters.
 
double Average() const
Computes and returns the average.
 
double Minimum() const
Returns the absolute minimum double found in all data passed through the AddData method.
 
void AddData(const double *data, const unsigned int count)
Add an array of doubles to the accumulators and counters.
 
double Maximum() const
Returns the absolute maximum double found in all data passed through the AddData method.
 
double StandardDeviation() const
Computes and returns the standard deviation.
 
void Reset()
Reset all accumulators and counters to zero.
 
Compute/test the Affine convergence from given parameters/chip.
 
This is free and unencumbered software released into the public domain.
 
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
 
int toInt(const QString &string)
Global function to convert from a string to an integer.
 
const double Null
Value for an Isis Null pixel.
 
long long int BigInt
Big int.
 
double toDouble(const QString &string)
Global function to convert from a string to a double.
 
Namespace for the standard library.
 
Container for Affine limits parameters.
 
Error analysis of Gruen match point solution.
 
Struct that maintains error counts.