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
22namespace 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
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
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
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}
Container for affine and radiometric parameters.
Definition GruenTypes.h:242
@ SuccessSubPixel
Success registering to sub-pixel accuracy.
Definition AutoReg.h:181
virtual double Line() const
Returns the current line number.
Definition Camera.cpp:2740
int Lines() const
Returns the number of lines in the image.
Definition Camera.cpp:2816
virtual double Sample() const
Returns the current sample number.
Definition Camera.cpp:2720
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:156
bool InCube()
This returns true if the current Sample() or Line() value is outside of the cube (meaning the point m...
Definition Camera.cpp:2649
virtual bool SetUniversalGround(const double latitude, const double longitude)
Sets the lat/lon values to get the sample/line values.
Definition Camera.cpp:382
int Samples() const
Returns the number of samples in the image.
Definition Camera.cpp:2806
Define a generic Y/X container.
Definition GruenTypes.h:53
bool isValid() const
Check for goodness.
Definition GruenTypes.h:107
void setLatLon(const double &latitude, const double &longitude)
Use Latitude/Longitude interface.
Definition GruenTypes.h:62
void setLineSamp(const double &line, const double &sample)
Use the Line/Sample interface.
Definition GruenTypes.h:69
IO Handler for Isis Cubes.
Definition Cube.h:168
static GSLUtility * getInstance()
Return a reference to the GSL (singleton) object.
Gruen pattern matching algorithm.
Definition Gruen.h:74
Isis exception class.
Definition IException.h:91
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
Structure containing comprehensive registration info/results.
Definition GruenTypes.h:433
Container for a point and its geometry.
Definition SmtkPoint.h:24
Define a point set of left, right and geometry at that location.
Definition GruenTypes.h:171
Container for cube-like labels.
Definition Pvl.h:119
virtual double UniversalLatitude() const
Returns the planetocentric latitude, in degrees, at the surface intersection point in the body fixed ...
Definition Sensor.cpp:212
virtual double UniversalLongitude() const
Returns the positive east, 0-360 domain longitude, in degrees, at the surface intersection point in t...
Definition Sensor.cpp:235
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...
SmtkPoint Clone(const SmtkPoint &point, const Coordinate &left)
Clone a point set from a nearby (left image) point and Gruen affine.
SmtkQStackIter FindExpDistEV(SmtkQStack &stack, const double &seedsample, const double &minEV, const double &maxEV)
Find the best eigen value using exponential distribution formula.
void setImages(Cube *lhImage, Cube *rhImage)
Assign cubes for matching.
SmtkPoint makeRegisteredPoint(const PointGeometry &left, const PointGeometry &right, Gruen *gruen)
Create an SmtkPoint from Gruen match result.
bool isValid(const Coordinate &pnt)
Determine if a point is valid in both left/right images.
void setGruenDef(const QString &regdef)
Initialize Gruen algorithm with definitions in Pvl file provided.
bool validate(const bool &throwError=true) const
Validates the state of the Camera and Gruen algoritm.
~SmtkMatcher()
Free random number generator in destructor.
void randomNumberSetup()
Initialize the random number generator.
bool inCube(const Camera &camera, const Coordinate &point) const
Determines if the line/sample is within physical cube boundaries.
SmtkQStackIter FindSmallestEV(SmtkQStack &stack)
Find the smallest eigen value on the given stack.
void setWriteSubsearchChipPattern(const QString &fileptrn="SmtkMatcher")
Set file pattern for output subsearch chips.
SmtkMatcher()
Construct default matcher.
Coordinate getLineSample(Camera &camera, const Coordinate &geom)
Compute line,sample from latitude, longitude.
SmtkPoint Create(const Coordinate &left, const Coordinate &right)
Create a valid, unregistered SmtkPoint.
Coordinate getLatLon(Camera &camera, const Coordinate &pnt)
Compute latitude, longitude from line,sample.
Container for SMTK match points.
Definition SmtkPoint.h:54
const AffineRadio & getAffine() const
Returns the affine transform and radiometic results.
Definition SmtkPoint.h:117
const Coordinate & getLeft() const
Returns the left point.
Definition SmtkPoint.h:98
const Coordinate & getRight() const
Returns the registered right coordinate.
Definition SmtkPoint.h:112
This is free and unencumbered software released into the public domain.
Definition ControlNet.h:32
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16