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.