Loading [MathJax]/jax/output/NativeMML/config.js
Isis 3 Programmer Reference
SmtkMatcher.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include <cmath>
8 #include <cstdlib>
9 #include <ctime>
10 #include <sstream>
11 #include <iostream>
12 #include <iomanip>
13 
14 #include <QSharedPointer>
15 
16 #include "Camera.h"
17 #include "Projection.h"
18 #include "SpecialPixel.h"
19 #include "SmtkMatcher.h"
20 
21 
22 namespace Isis {
23 
25  SmtkMatcher::SmtkMatcher() : m_lhCube(0), m_rhCube(0), m_gruen(),
26  m_offImage(0), m_spiceErr(0),
27  m_useAutoReg(true) {
29  }
30 
32  SmtkMatcher::SmtkMatcher(const QString &regdef) : m_lhCube(0),
33  m_rhCube(0),
34  m_gruen(0),
35  m_offImage(0),
36  m_spiceErr(0),
37  m_useAutoReg(true) {
38  setGruenDef(regdef);
40  }
41 
43  SmtkMatcher::SmtkMatcher(const QString &regdef, Cube *lhCube,
44  Cube *rhCube) : m_lhCube(lhCube),
45  m_rhCube(rhCube),
46  m_gruen(0), m_offImage(0),
47  m_spiceErr(0),
48  m_useAutoReg(true) {
49  setGruenDef(regdef);
51  }
52 
55  gsl_rng_free(r);
56  }
57 
58 
60  void SmtkMatcher::setImages(Cube *lhCube, Cube *rhCube) {
61  m_lhCube = lhCube;
62  m_rhCube = rhCube;
63  return;
64  }
65 
78  void SmtkMatcher::setGruenDef(const QString &regdef) {
79  Pvl reg(regdef);
80  m_gruen = QSharedPointer<Gruen> (new Gruen(reg)); // Deallocation automatic
81  return;
82  }
83 
101  bool SmtkMatcher::isValid(const Coordinate &pnt) {
102  validate(); // cubs and cameras
103  Coordinate pnt2 = getLatLon(lhCamera(), pnt);
104  if (pnt2.isValid()) {
105  pnt2 = getLineSample(rhCamera(), pnt2);
106  }
107  return (pnt2.isValid());
108  }
109 
132  void SmtkMatcher::setWriteSubsearchChipPattern(const QString &fileptrn) {
133  validate();
134  m_gruen->WriteSubsearchChips(fileptrn);
135  }
136 
149  SmtkQStackIter SmtkMatcher::FindSmallestEV(SmtkQStack &stack) {
150  SmtkQStackIter best(stack.begin()), current(stack.begin());
151  while ( current != stack.end() ) {
152  if (current.value().GoodnessOfFit() < best.value().GoodnessOfFit() ) {
153  best = current;
154  }
155  ++current;
156  }
157  return (best);
158  }
159 
160 
182  SmtkQStackIter SmtkMatcher::FindExpDistEV(SmtkQStack &stack,
183  const double &seedsample,
184  const double &minEV,
185  const double &maxEV) {
186 
187  if (stack.isEmpty()) return (stack.end());
188  SmtkQStackIter best(stack.begin()), current(stack.begin());
189 
190  // Random number generator must scale between 0 and 1
191  double randNum = gsl_rng_uniform (r);
192  double t1 = -std::log(1.0 - randNum *
193  (1.0 - std::exp(-seedsample)))/seedsample;
194  double pt = minEV + t1*(maxEV-minEV);
195  double best_ev(DBL_MAX);
196  while ( current != stack.end() ) {
197  double test_ev(std::fabs(current.value().GoodnessOfFit()-pt));
198  if ( test_ev < best_ev) {
199  best = current;
200  best_ev = test_ev; // differs from ISIS2 which saved current eigenvalue
201  }
202  ++current;
203  }
204  return (best);
205  }
206 
220  bool SmtkMatcher::isValid(const SmtkPoint &spnt) {
221  bool valid(true);
222 
223  if (!spnt.isValid()) {
224  std::cout << "Point status is invalid!\n";
225  valid = false;
226  }
227 
228  // Is valid in left image?
229  if (!inCube(lhCamera(), spnt.getLeft())) {
230  std::cout << "Left point (" << spnt.getLeft().getLine() << ","
231  << spnt.getLeft().getSample() << ") is invalid!\n";
232  valid = false;
233  }
234 
235  // Is valud in right image?
236  if (!inCube(rhCamera(), spnt.getRight())) {
237  std::cout << "Right point (" << spnt.getRight().getLine() << ","
238  << spnt.getRight().getSample() << ") is invalid!\n";
239  valid = false;
240  }
241 
242  return (valid);
243  }
244 
251  const AffineRadio &affrad) {
252  return (Register(PointGeometry(lpnt), PointGeometry(), affrad));
253  }
254 
266  const AffineRadio &affrad) {
267  return (Register(PointGeometry(pnts.getLeft()),
268  PointGeometry(pnts.getRight()), affrad));
269  }
270 
271 
272 
295  const AffineRadio &affrad) {
296 
297  // If point is already registered don't do it again.
298  if (spnt.isRegistered()) { return (spnt); }
299 
300  PointGeometry left = PointGeometry(spnt.getLeft());
301  PointGeometry right = PointGeometry(spnt.getRight());
302 
303  return (Register(left, right, affrad));
304  }
305 
306 
334  const PointGeometry &rpg,
335  const AffineRadio &affrad) {
336 
337  // Validate object state
338  validate();
339 
340  // Test if the left point is defined. This will throw an error if this
341  // situation occurs
342  if (!lpg.getPoint().isValid()) {
343  QString mess = "Left point is not defined which is required";
344  throw IException(IException::Programmer, mess, _FILEINFO_);
345  }
346 
347  // First we need a lat,lon from the left image to find the same place in
348  // the right image.
349  Coordinate lpnt = lpg.getPoint();
350  Coordinate lgeom = lpg.getGeometry();
351  if (!lgeom.isValid()) {
352  lgeom = getLatLon(lhCamera(), lpnt);
353  }
354 
355  // Construct geometry and check validity
356  PointGeometry left = PointGeometry(lpnt, lgeom);
357  if (!left.isValid()) {
358  m_offImage++;
359  return ( SmtkPoint(PointPair(lpnt), PointPair(lgeom)) );
360  }
361 
362  // Validate the right point
363  Coordinate rpnt = rpg.getPoint();
364  Coordinate rgeom = rpg.getGeometry();
365  if ( !rpnt.isValid() ) {
366  if (rgeom.isValid()) {
367  rpnt = getLineSample(rhCamera(), rgeom);
368  }
369  else {
370  rpnt = getLineSample(rhCamera(), lgeom);
371  rgeom = lgeom;
372  }
373  }
374  else if (!rgeom.isValid() ){
375  rgeom = getLatLon(rhCamera(), rpnt);
376  }
377 
378  // Construct and for good right geometry
379  PointGeometry right = PointGeometry(rpnt, rgeom);
380  if (!right.isValid()) {
381  m_spiceErr++;
382  return (SmtkPoint(PointPair(lpnt, rpnt), PointPair(lgeom, rgeom)));
383  }
384 
385  try {
386  // These calls are computationally expensive... can we fix it?
387  m_gruen->PatternChip()->TackCube(lpnt.getSample(), lpnt.getLine());
388  m_gruen->PatternChip()->Load(*m_lhCube);
389  m_gruen->SearchChip()->TackCube(rpnt.getSample(), rpnt.getLine());
390  m_gruen->SearchChip()->Load(*m_rhCube, *m_gruen->PatternChip(),
391  *m_lhCube);
392  }
393  catch (IException &) {
394  m_offImage++; // Failure to load is assumed an offimage error
395  return (SmtkPoint(PointPair(lpnt,rpnt), PointPair(lgeom,rgeom)));
396  }
397 
398  // Register the points with incoming affine/radiometric parameters
399  m_gruen->setAffineRadio(affrad);
400  return (makeRegisteredPoint(left, right, m_gruen.data()));
401  }
402 
428  const Coordinate &right) {
429 
430  // Check out left image point
431  Coordinate lgeom = getLatLon(lhCamera(), left);
432  if (!lgeom.isValid() ) {
433  m_offImage ++;
434  return (SmtkPoint(PointPair(left,right), PointPair(lgeom)));
435  }
436 
437  // Check out right image point
438  Coordinate rgeom = getLatLon(rhCamera(), right);
439  if (!rgeom.isValid() ) {
440  m_offImage ++;
441  return (SmtkPoint(PointPair(left,right), PointPair(lgeom,rgeom)));
442  }
443 
444  // Make the point
445  SmtkPoint spnt = SmtkPoint(PointPair(left,right), PointPair(lgeom,rgeom));
446  spnt.m_matchpt.m_analysis.setZeroState();
447  spnt.m_isValid = true;
448  return (spnt);
449  }
450 
451 
468  const Coordinate &left) {
469 
470  // Computes local chip location (chipLoc) with Affine. This gives offset
471  // in right pixel space. Simply add result to right point to get the
472  // new cloned right point.
473  Coordinate offset = left - point.getLeft();
474  Coordinate right = point.getRight() + point.getAffine().getPoint(offset);
475  PointPair cpoint = PointPair(left, right);
476 
477  MatchPoint mpt = point.m_matchpt;
478  mpt.m_point = cpoint;
479 
480  // Currently will not have any valid geometry
481  SmtkPoint spnt = SmtkPoint(mpt, PointGeometry(right), PointPair());
482  spnt.m_registered = false;
483  spnt.m_isValid = inCube(lhCamera(), left) && inCube(rhCamera(), right);
484  return (spnt);
485  }
486 
498  gsl_rng_env_setup();
499  T = gsl_rng_default;
500  r = gsl_rng_alloc (T);
501  return;
502  }
517  bool SmtkMatcher::validate(const bool &throwError) const {
518  bool isGood(true);
519  if (!m_lhCube) isGood = false;
520  if (!m_rhCube) isGood = false;
521  if (!m_gruen.data()) isGood = false;
522  if ((!isGood) && throwError) {
523  QString mess = "Images/match algorithm not initialized!";
524  throw IException(IException::Programmer, mess, _FILEINFO_);
525  }
526  return (isGood);
527  }
528 
540  bool SmtkMatcher::inCube(const Camera &camera, const Coordinate &pnt) const {
541  if (!pnt.isValid()) return (false);
542  if ( (pnt.getSample() < 0.5) || (pnt.getLine() < 0.5) ) return false;
543  if ( (pnt.getSample() > (camera.Samples() + 0.5)) ||
544  (pnt.getLine() > (camera.Lines() + 0.5)) ) {
545  return false;
546  }
547 
548  return true;
549  }
550 
551 
563  // Check if pixel coordinate is in the left image
564  Coordinate geom;
565  if (pnt.isValid()) {
566  if (inCube(camera, pnt)) {
567  if ( camera.SetImage(pnt.getSample(), pnt.getLine()) ) {
568  double latitude = camera.UniversalLatitude();
569  double longitude = camera.UniversalLongitude();
570  geom.setLatLon(latitude, longitude);
571  }
572  }
573  }
574  return (geom);
575  }
576 
588  const Coordinate &geom) {
589  // Check if pixel coordinate is in the left image
590  Coordinate pnt;
591  if (geom.isValid()) {
592  if ( camera.SetUniversalGround(geom.getLatitude(), geom.getLongitude()) ) {
593  if ( camera.InCube() ) {
594  pnt.setLineSamp(camera.Line(), camera.Sample());
595  }
596  }
597  }
598  return (pnt);
599  }
600 
621  const PointGeometry &right,
622  Gruen *gruen) {
623 
624  if (gruen->Register() != AutoReg::SuccessSubPixel) {
625  return (SmtkPoint(PointPair(left.getPoint(),right.getPoint()),
626  PointPair(left.getGeometry(), right.getGeometry())));
627  }
628 
629  // Registration point data
630  MatchPoint match = gruen->getLastMatch();
631 
632  // Compute new right coordinate data
633  Coordinate rcorr = Coordinate(gruen->CubeLine(), gruen->CubeSample());
634  Coordinate rgeom = getLatLon(rhCamera(), rcorr);
635  PointGeometry rpoint = PointGeometry(rcorr, rgeom);
636 
637  // Get left and original right geometry
638  PointPair pgeom = PointPair(left.getGeometry(), right.getGeometry());
639 
640  // Create SMTK point and determine status/validity
641  SmtkPoint spnt = SmtkPoint(match, rpoint, pgeom);
642 
643  // Check for valid mapping
644  if ( !rpoint.isValid() ) {
645  m_offImage++;
646  spnt.m_isValid = false;
647  }
648  else {
649  // Check for distance error
650  double dist = (rcorr - right.getPoint()).getDistance();
651  if (dist > gruen->getSpiceConstraint()) {
652  m_spiceErr++;
653  spnt.m_isValid = false;
654  }
655  else {
656  spnt.m_isValid = match.isValid();
657  }
658  }
659 
660  return (spnt);
661  }
662 
663 }
Isis::SmtkPoint::isRegistered
bool isRegistered() const
Returns registration status.
Definition: SmtkPoint.h:133
Isis::AffineRadio::getPoint
Coordinate getPoint(const Coordinate &location) const
Applies the affine transfrom to a point and returns result.
Definition: GruenTypes.h:272
Isis::SmtkMatcher::FindSmallestEV
SmtkQStackIter FindSmallestEV(SmtkQStack &stack)
Find the smallest eigen value on the given stack.
Definition: SmtkMatcher.cpp:149
Isis::SmtkMatcher::setGruenDef
void setGruenDef(const QString &regdef)
Initialize Gruen algorithm with definitions in Pvl file provided.
Definition: SmtkMatcher.cpp:78
Isis::SmtkMatcher::makeRegisteredPoint
SmtkPoint makeRegisteredPoint(const PointGeometry &left, const PointGeometry &right, Gruen *gruen)
Create an SmtkPoint from Gruen match result.
Definition: SmtkMatcher.cpp:620
Isis::SmtkPoint
Container for SMTK match points.
Definition: SmtkPoint.h:54
Isis::Camera::SetImage
virtual bool SetImage(const double sample, const double line)
Sets the sample/line values of the image to get the lat/lon values.
Definition: Camera.cpp:154
Isis::Coordinate::setLatLon
void setLatLon(const double &latitude, const double &longitude)
Use Latitude/Longitude interface.
Definition: GruenTypes.h:62
Isis::Camera::Sample
virtual double Sample() const
Returns the current sample number.
Definition: Camera.cpp:2690
Isis::SmtkMatcher::getLatLon
Coordinate getLatLon(Camera &camera, const Coordinate &pnt)
Compute latitude, longitude from line,sample.
Definition: SmtkMatcher.cpp:562
Isis::AffineRadio
Container for affine and radiometric parameters.
Definition: GruenTypes.h:242
Isis::AutoReg::Register
AutoReg::RegisterStatus Register()
Walk the pattern chip through the search chip to find the best registration.
Definition: AutoReg.cpp:587
Isis::Pvl
Container for cube-like labels.
Definition: Pvl.h:119
Isis::SmtkMatcher::randomNumberSetup
void randomNumberSetup()
Initialize the random number generator.
Definition: SmtkMatcher.cpp:496
QSharedPointer
Definition: JigsawWorkOrder.h:28
Isis::Camera
Definition: Camera.h:236
Isis::Coordinate
Define a generic Y/X container.
Definition: GruenTypes.h:53
Isis::SmtkPoint::getRight
const Coordinate & getRight() const
Returns the registered right coordinate.
Definition: SmtkPoint.h:112
Isis::GSL::GSLUtility::getInstance
static GSLUtility * getInstance()
Return a reference to the GSL (singleton) object.
Definition: GSLUtility.cpp:49
Isis::Gruen::getLastMatch
MatchPoint getLastMatch() const
Returns the register state of the last successful Gruen match.
Definition: Gruen.h:120
Isis::SmtkMatcher::Clone
SmtkPoint Clone(const SmtkPoint &point, const Coordinate &left)
Clone a point set from a nearby (left image) point and Gruen affine.
Definition: SmtkMatcher.cpp:467
Isis::SmtkMatcher::FindExpDistEV
SmtkQStackIter FindExpDistEV(SmtkQStack &stack, const double &seedsample, const double &minEV, const double &maxEV)
Find the best eigen value using exponential distribution formula.
Definition: SmtkMatcher.cpp:182
Isis::SmtkMatcher::validate
bool validate(const bool &throwError=true) const
Validates the state of the Camera and Gruen algoritm.
Definition: SmtkMatcher.cpp:517
Isis::SmtkMatcher::setImages
void setImages(Cube *lhImage, Cube *rhImage)
Assign cubes for matching.
Definition: SmtkMatcher.cpp:60
Isis::SmtkMatcher::SmtkMatcher
SmtkMatcher()
Construct default matcher.
Definition: SmtkMatcher.cpp:25
Isis::Gruen::getSpiceConstraint
double getSpiceConstraint() const
Returns the SPICE tolerance constraint as read from config file.
Definition: Gruen.h:92
Isis::AutoReg::SuccessSubPixel
@ SuccessSubPixel
Success registering to sub-pixel accuracy.
Definition: AutoReg.h:181
Isis::Camera::InCube
bool InCube()
This returns true if the current Sample() or Line() value is outside of the cube (meaning the point m...
Definition: Camera.cpp:2619
QHash
This is free and unencumbered software released into the public domain.
Definition: ControlNet.h:32
Isis::SmtkMatcher::setWriteSubsearchChipPattern
void setWriteSubsearchChipPattern(const QString &fileptrn="SmtkMatcher")
Set file pattern for output subsearch chips.
Definition: SmtkMatcher.cpp:132
Isis::Sensor::UniversalLongitude
virtual double UniversalLongitude() const
Returns the positive east, 0-360 domain longitude, in degrees, at the surface intersection point in t...
Definition: Sensor.cpp:233
Isis::SmtkPoint::getAffine
const AffineRadio & getAffine() const
Returns the affine transform and radiometic results.
Definition: SmtkPoint.h:117
Isis::AutoReg::CubeSample
double CubeSample() const
Return the search chip cube sample that best matched.
Definition: AutoReg.h:340
Isis::PointPair
Define a point set of left, right and geometry at that location.
Definition: GruenTypes.h:171
Isis::Camera::SetUniversalGround
virtual bool SetUniversalGround(const double latitude, const double longitude)
Sets the lat/lon values to get the sample/line values.
Definition: Camera.cpp:380
Isis::SmtkMatcher::~SmtkMatcher
~SmtkMatcher()
Free random number generator in destructor.
Definition: SmtkMatcher.cpp:54
Isis::SmtkMatcher::getLineSample
Coordinate getLineSample(Camera &camera, const Coordinate &geom)
Compute line,sample from latitude, longitude.
Definition: SmtkMatcher.cpp:587
Isis::Cube
IO Handler for Isis Cubes.
Definition: Cube.h:167
Isis::SmtkMatcher::isValid
bool isValid(const Coordinate &pnt)
Determine if a point is valid in both left/right images.
Definition: SmtkMatcher.cpp:101
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::Coordinate::isValid
bool isValid() const
Check for goodness.
Definition: GruenTypes.h:107
Isis::MatchPoint
Structure containing comprehensive registration info/results.
Definition: GruenTypes.h:433
Isis::Camera::Samples
int Samples() const
Returns the number of samples in the image.
Definition: Camera.cpp:2776
Isis::SmtkMatcher::inCube
bool inCube(const Camera &camera, const Coordinate &point) const
Determines if the line/sample is within physical cube boundaries.
Definition: SmtkMatcher.cpp:540
Isis::IException::Programmer
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:146
Isis::PointGeometry
Container for a point and its geometry.
Definition: SmtkPoint.h:24
Isis::Analysis::setZeroState
void setZeroState()
Resets eigenvalues to 0.
Definition: GruenTypes.h:403
Isis::AutoReg::CubeLine
double CubeLine() const
Return the search chip cube line that best matched.
Definition: AutoReg.h:345
Isis::Camera::Lines
int Lines() const
Returns the number of lines in the image.
Definition: Camera.cpp:2786
Isis::SmtkMatcher::Create
SmtkPoint Create(const Coordinate &left, const Coordinate &right)
Create a valid, unregistered SmtkPoint.
Definition: SmtkMatcher.cpp:427
Isis::Gruen
Gruen pattern matching algorithm.
Definition: Gruen.h:74
Isis::Camera::Line
virtual double Line() const
Returns the current line number.
Definition: Camera.cpp:2710
Isis::SmtkPoint::getLeft
const Coordinate & getLeft() const
Returns the left point.
Definition: SmtkPoint.h:98
Isis::Coordinate::setLineSamp
void setLineSamp(const double &line, const double &sample)
Use the Line/Sample interface.
Definition: GruenTypes.h:69
Isis::SmtkMatcher::Register
SmtkPoint Register(const Coordinate &lpnt, const AffineRadio &affrad=AffineRadio())
This method takes a sample, line from the left-hand image and tries to find the matching point in the...
Definition: SmtkMatcher.cpp:250
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::Sensor::UniversalLatitude
virtual double UniversalLatitude() const
Returns the planetocentric latitude, in degrees, at the surface intersection point in the body fixed ...
Definition: Sensor.cpp:210
Isis::SmtkPoint::isValid
bool isValid() const
Indicates the smtk portion of the point is valid.
Definition: SmtkPoint.h:70

U.S. Department of the Interior | U.S. Geological Survey
ISIS | Privacy & Disclaimers | Astrogeology Research Program
To contact us, please post comments and questions on the USGS Astrogeology Discussion Board
To report a bug, or suggest a feature go to: ISIS Github
File Modified: 07/13/2023 15:17:17