OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
Public Member Functions | Protected Member Functions | Protected Attributes | List of all members
ossimRpcSolver Class Reference

This currently only support Rational poilynomial B format. More...

#include <ossimRpcSolver.h>

Inheritance diagram for ossimRpcSolver:
ossimReferenced

Public Member Functions

 ossimRpcSolver (bool useElevation=false, bool useHeightAboveMSLFlag=false)
 The use elvation flag will deterimne if we force the height t be 0. More...
 
virtual ~ossimRpcSolver ()
 
void solveCoefficients (const ossimDrect &imageBounds, ossimProjection *imageProj, ossim_uint32 xSamples=8, ossim_uint32 ySamples=8)
 This will convert any projector to an RPC model. More...
 
void solveCoefficients (const ossimDrect &imageBounds, ossimImageGeometry *geom, ossim_uint32 xSamples=8, ossim_uint32 ySamples=8)
 
bool solve (const ossimDrect &aoiBounds, ossimImageGeometry *geom, const double &pixel_tolerance=0.5)
 Similar to the other solve methods except that the final grid size is established iteratively so that the error at the midpoints between grid nodes falls below tolerance. More...
 
bool solve (const ossimFilename &imageFilename, const double &pixel_tolerance=0.5)
 Performs iterative solve using the other solve method, but uses an image filename to initialize, and computes RPC over entire image rect. More...
 
void solveCoefficients (const std::vector< ossimDpt > &imagePoints, const std::vector< ossimGpt > &groundControlPoints)
 takes associated image points and ground points and solves the coefficents for the rational polynomial for line and sample calculations from world points. More...
 
const ossimRefPtr< ossimRpcModelgetRpcModel () const
 Fetches the solved-for RPC model. More...
 
double getRmsError () const
 
double getMaxError () const
 
ossimRefPtr< ossimNitfRegisteredTaggetNitfRpcBTag () const
 
void setValidImageRect (const ossimIrect &imageRect)
 Sets the image rect over which to compute the RPCs. More...
 
- Public Member Functions inherited from ossimReferenced
 ossimReferenced ()
 
 ossimReferenced (const ossimReferenced &)
 
ossimReferencedoperator= (const ossimReferenced &)
 
void ref () const
 increment the reference count by one, indicating that this object has another pointer which is referencing it. More...
 
void unref () const
 decrement the reference count by one, indicating that a pointer to this object is referencing it. More...
 
void unref_nodelete () const
 decrement the reference count by one, indicating that a pointer to this object is referencing it. More...
 
int referenceCount () const
 

Protected Member Functions

virtual void solveInitialCoefficients (NEWMAT::ColumnVector &coeff, const std::vector< double > &f, const std::vector< double > &x, const std::vector< double > &y, const std::vector< double > &z) const
 
virtual void solveCoefficients (NEWMAT::ColumnVector &coeff, const std::vector< double > &f, const std::vector< double > &x, const std::vector< double > &y, const std::vector< double > &z) const
 
double eval (const std::vector< double > &coeff, const double &x, const double &y, const double &z) const
 
void evalPoint (const ossimGpt &gpt, ossimDpt &ipt) const
 
NEWMAT::Matrix invert (const NEWMAT::Matrix &m) const
 Inverts using the SVD method. More...
 
void setupSystemOfEquations (NEWMAT::Matrix &equations, const NEWMAT::ColumnVector &f, const std::vector< double > &x, const std::vector< double > &y, const std::vector< double > &z) const
 
void setupWeightMatrix (NEWMAT::DiagonalMatrix &result, const NEWMAT::ColumnVector &coefficients, const NEWMAT::ColumnVector &f, const std::vector< double > &x, const std::vector< double > &y, const std::vector< double > &z) const
 
- Protected Member Functions inherited from ossimReferenced
virtual ~ossimReferenced ()
 

Protected Attributes

bool theUseElevationFlag
 
bool theHeightAboveMSLFlag
 
ossim_float64 theMeanResidual
 
ossim_float64 theMaxResidual
 
ossimRefPtr< ossimImageGeometrytheRefGeom
 
ossimRefPtr< ossimRpcModeltheRpcModel
 

Detailed Description

This currently only support Rational poilynomial B format.

This can be found in the NITF registered commercial tag document.

Note
x=longitude, y=latitude, z=height
Format is:
 coeff[ 0]       + coeff[ 1]*x     + coeff[ 2]*y     + coeff[ 3]*z     +
 coeff[ 4]*x*y   + coeff[ 5]*x*z   + coeff[ 6]*y*z   + coeff[ 7]*x*x   +
 coeff[ 8]*y*y   + coeff[ 9]*z*z   + coeff[10]*x*y*z + coeff[11]*x*x*x +
 coeff[12]*x*y*y + coeff[13]*x*z*z + coeff[14]*x*x*y + coeff[15]*y*y*y +
 coeff[16]*y*z*z + coeff[17]*x*x*z + coeff[18]*y*y*z + coeff[19]*z*z*z;
 where coeff is one of XNum, XDen, YNum, and YDen.  So there are 80
 coefficients all together.
Currently we use a linear least squares fit to solve the coefficients.
This is the simplest to implement.  We probably relly need a nonlinear
minimizer to fit the coefficients but I don't have time to experiment.
Levenberg Marquardt might be a solution to look into.
HOW TO USE:
   ossimRpcSolver solver;
   solver.solveCoefficients(rect,
                            *proj.get());
We can also call solve coefficients with a list of ground control points.
First is the list of image points followed by the ground points.
NOTE: Thes must be equal in size.
   solver.solveCoefficients(imagePoints,
                            groundPoints);
Once you call solveCoefficients you can create the projector:
   ossimRefPtr<ossimRpcProjection> rpc = solver.createRpcProjection();
Note that a sub-image bounding rect can be passed into the solve methods. This
constrains the solution fit to cover only that rectangle in the original image space,
but the image coordinates used are still based on the full image. If the intent is to
generate an RPC that will work for an image chip in that chip's local image coordinate
system (i.e., the UL corner of the chip is 0, 0), then you'll need to call
rpcModel->setImageOffset(chip_offset) on the output RPC model.
 

Definition at line 72 of file ossimRpcSolver.h.

Constructor & Destructor Documentation

◆ ossimRpcSolver()

ossimRpcSolver::ossimRpcSolver ( bool  useElevation = false,
bool  useHeightAboveMSLFlag = false 
)

The use elvation flag will deterimne if we force the height t be 0.

If the elevation is enabled then we use the height field of the control points to determine the coefficients of the RPC00 polynomial. If its false then we will ignore the height by setting the height field to 0.0.

Note: even if the elevation is enabled all NAN heights are set to 0.0.

Definition at line 21 of file ossimRpcSolver.cpp.

22 : theUseElevationFlag(useElevation),
23  theHeightAboveMSLFlag(useHeightAboveMSLFlag),
24  theMeanResidual(0),
26 {
27 }
ossim_float64 theMaxResidual
ossim_float64 theMeanResidual
bool theHeightAboveMSLFlag

◆ ~ossimRpcSolver()

virtual ossimRpcSolver::~ossimRpcSolver ( )
inlinevirtual

Definition at line 86 of file ossimRpcSolver.h.

86 {}

Member Function Documentation

◆ eval()

double ossimRpcSolver::eval ( const std::vector< double > &  coeff,
const double &  x,
const double &  y,
const double &  z 
) const
protected

◆ evalPoint()

void ossimRpcSolver::evalPoint ( const ossimGpt gpt,
ossimDpt ipt 
) const
protected

Definition at line 677 of file ossimRpcSolver.cpp.

References ossimDpt::makeNan(), theRpcModel, and ossimRpcModel::worldToLineSample().

Referenced by solveCoefficients().

678 {
679  if (!theRpcModel)
680  {
681  ipt.makeNan();
682  return;
683  }
684 
685  theRpcModel->worldToLineSample(gpt, ipt);
686 }
virtual void worldToLineSample(const ossimGpt &world_point, ossimDpt &image_point) const
worldToLineSample() Overrides base class implementation.
ossimRefPtr< ossimRpcModel > theRpcModel
void makeNan()
Definition: ossimDpt.h:65

◆ getMaxError()

double ossimRpcSolver::getMaxError ( ) const

Definition at line 426 of file ossimRpcSolver.cpp.

References theMaxResidual.

427 {
428  return theMaxResidual;
429 }
ossim_float64 theMaxResidual

◆ getNitfRpcBTag()

ossimRefPtr< ossimNitfRegisteredTag > ossimRpcSolver::getNitfRpcBTag ( ) const
Returns
ossimRefPtr<ossimNitfRegisteredTag>
Note
one of the solve methods should have been called prior to this.

Definition at line 689 of file ossimRpcSolver.cpp.

References ossimNitfRpcBase::setRpcModelParams(), and theRpcModel.

Referenced by ossimNitfWriterBase::addRpcbTag().

690 {
691  ossimNitfRpcBTag* rpcbTag = new ossimNitfRpcBTag();
692  rpcbTag->setRpcModelParams(theRpcModel);
693 
694  // Return it as an ossimRefPtr<ossimNitfRegisteredTag>...
696 
697  return tag;
698 }
virtual void setRpcModelParams(ossimRefPtr< ossimRpcModel > rpc)
For generating the RPC tag from existing RPC Model.
The layout of RPC00B is the same as RPC00A.
ossimRefPtr< ossimRpcModel > theRpcModel

◆ getRmsError()

double ossimRpcSolver::getRmsError ( ) const

Definition at line 421 of file ossimRpcSolver.cpp.

References theMeanResidual.

Referenced by ossimRpcProjection::optimizeFit().

422 {
423  return theMeanResidual;
424 }
ossim_float64 theMeanResidual

◆ getRpcModel()

const ossimRefPtr<ossimRpcModel> ossimRpcSolver::getRpcModel ( ) const
inline

Fetches the solved-for RPC model.

See note in header above on setting the image offset if this model will be applied to a sub-image chip.

Definition at line 138 of file ossimRpcSolver.h.

Referenced by ossimDemTool::doASP(), ossimSubImageTool::execute(), and ossimRpcProjection::optimizeFit().

138 { return theRpcModel; }
ossimRefPtr< ossimRpcModel > theRpcModel

◆ invert()

NEWMAT::Matrix ossimRpcSolver::invert ( const NEWMAT::Matrix &  m) const
protected

Inverts using the SVD method.

Definition at line 544 of file ossimRpcSolver.cpp.

References FLT_EPSILON, and SVD().

Referenced by solveCoefficients(), and solveInitialCoefficients().

545 {
546  ossim_uint32 idx = 0;
547  NEWMAT::DiagonalMatrix d;
548  NEWMAT::Matrix u;
549  NEWMAT::Matrix v;
550 
551  // decompose m.t*m which is stored in Temp into the singular values and vectors.
552  //
553  NEWMAT::SVD(m, d, u, v, true, true);
554 
555  // invert the diagonal
556  // this is just doing the reciprical fo all diagonal components and store back int
557  // d. ths compute d inverse.
558  //
559  for(idx=0; idx < (ossim_uint32)d.Ncols(); ++idx)
560  {
561  if(d[idx] > FLT_EPSILON)
562  {
563  d[idx] = 1.0/d[idx];
564  }
565  else
566  {
567  d[idx] = 0.0;
568  }
569  }
570 
571  //compute inverse of decomposed m;
572  return v*d*u.t();
573 }
#define FLT_EPSILON
unsigned int ossim_uint32
void SVD(const Matrix &, DiagonalMatrix &, Matrix &, Matrix &, bool=true, bool=true)
Definition: svd.cpp:26

◆ setupSystemOfEquations()

void ossimRpcSolver::setupSystemOfEquations ( NEWMAT::Matrix &  equations,
const NEWMAT::ColumnVector &  f,
const std::vector< double > &  x,
const std::vector< double > &  y,
const std::vector< double > &  z 
) const
protected

Definition at line 576 of file ossimRpcSolver.cpp.

References x, and y.

Referenced by solveCoefficients(), and solveInitialCoefficients().

581 {
582  ossim_uint32 idx;
583  equations.ReSize(f.Nrows(), 39);
584 
585  for(idx = 0; idx < (ossim_uint32)f.Nrows();++idx)
586  {
587  equations[idx][0] = 1;
588  equations[idx][1] = x[idx];
589  equations[idx][2] = y[idx];
590  equations[idx][3] = z[idx];
591  equations[idx][4] = x[idx]*y[idx];
592  equations[idx][5] = x[idx]*z[idx];
593  equations[idx][6] = y[idx]*z[idx];
594  equations[idx][7] = x[idx]*x[idx];
595  equations[idx][8] = y[idx]*y[idx];
596  equations[idx][9] = z[idx]*z[idx];
597  equations[idx][10] = x[idx]*y[idx]*z[idx];
598  equations[idx][11] = x[idx]*x[idx]*x[idx];
599  equations[idx][12] = x[idx]*y[idx]*y[idx];
600  equations[idx][13] = x[idx]*z[idx]*z[idx];
601  equations[idx][14] = x[idx]*x[idx]*y[idx];
602  equations[idx][15] = y[idx]*y[idx]*y[idx];
603  equations[idx][16] = y[idx]*z[idx]*z[idx];
604  equations[idx][17] = x[idx]*x[idx]*z[idx];
605  equations[idx][18] = y[idx]*y[idx]*z[idx];
606  equations[idx][19] = z[idx]*z[idx]*z[idx];
607  equations[idx][20] = -f[idx]*x[idx];
608  equations[idx][21] = -f[idx]*y[idx];
609  equations[idx][22] = -f[idx]*z[idx];
610  equations[idx][23] = -f[idx]*x[idx]*y[idx];
611  equations[idx][24] = -f[idx]*x[idx]*z[idx];
612  equations[idx][25] = -f[idx]*y[idx]*z[idx];
613  equations[idx][26] = -f[idx]*x[idx]*x[idx];
614  equations[idx][27] = -f[idx]*y[idx]*y[idx];
615  equations[idx][28] = -f[idx]*z[idx]*z[idx];
616  equations[idx][29] = -f[idx]*x[idx]*y[idx]*z[idx];
617  equations[idx][30] = -f[idx]*x[idx]*x[idx]*x[idx];
618  equations[idx][31] = -f[idx]*x[idx]*y[idx]*y[idx];
619  equations[idx][32] = -f[idx]*x[idx]*z[idx]*z[idx];
620  equations[idx][33] = -f[idx]*x[idx]*x[idx]*y[idx];
621  equations[idx][34] = -f[idx]*y[idx]*y[idx]*y[idx];
622  equations[idx][35] = -f[idx]*y[idx]*z[idx]*z[idx];
623  equations[idx][36] = -f[idx]*x[idx]*x[idx]*z[idx];
624  equations[idx][37] = -f[idx]*y[idx]*y[idx]*z[idx];
625  equations[idx][38] = -f[idx]*z[idx]*z[idx]*z[idx];
626  }
627 }
ossim_uint32 x
ossim_uint32 y
unsigned int ossim_uint32

◆ setupWeightMatrix()

void ossimRpcSolver::setupWeightMatrix ( NEWMAT::DiagonalMatrix &  result,
const NEWMAT::ColumnVector &  coefficients,
const NEWMAT::ColumnVector &  f,
const std::vector< double > &  x,
const std::vector< double > &  y,
const std::vector< double > &  z 
) const
protected

Definition at line 629 of file ossimRpcSolver.cpp.

References FLT_EPSILON, x, and y.

Referenced by solveCoefficients().

635 {
636  result.ReSize(f.Nrows());
637  ossim_uint32 idx = 0;
638  ossim_uint32 idx2 = 0;
639  NEWMAT::RowVector row(coefficients.Nrows());
640 
641  for(idx = 0; idx < (ossim_uint32)f.Nrows(); ++idx)
642  {
643  row[0] = 1;
644  row[1] = x[idx];
645  row[2] = y[idx];
646  row[3] = z[idx];
647  row[4] = x[idx]*y[idx];
648  row[5] = x[idx]*z[idx];
649  row[6] = y[idx]*z[idx];
650  row[7] = x[idx]*x[idx];
651  row[8] = y[idx]*y[idx];
652  row[9] = z[idx]*z[idx];
653  row[10] = x[idx]*y[idx]*z[idx];
654  row[11] = x[idx]*x[idx]*x[idx];
655  row[12] = x[idx]*y[idx]*y[idx];
656  row[13] = x[idx]*z[idx]*z[idx];
657  row[14] = x[idx]*x[idx]*y[idx];
658  row[15] = y[idx]*y[idx]*y[idx];
659  row[16] = y[idx]*z[idx]*z[idx];
660  row[17] = x[idx]*x[idx]*z[idx];
661  row[18] = y[idx]*y[idx]*z[idx];
662  row[19] = z[idx]*z[idx]*z[idx];
663 
664  result[idx] = 0.0;
665  for(idx2 = 0; idx2 < (ossim_uint32)row.Ncols(); ++idx2)
666  {
667  result[idx] += row[idx2]*coefficients[idx2];
668  }
669 
670  if(result[idx] > FLT_EPSILON)
671  {
672  result[idx] = 1.0/result[idx];
673  }
674  }
675 }
ossim_uint32 x
ossim_uint32 y
#define FLT_EPSILON
unsigned int ossim_uint32

◆ setValidImageRect()

void ossimRpcSolver::setValidImageRect ( const ossimIrect imageRect)

Sets the image rect over which to compute the RPCs.

The Resulting RPC will only be valid over that range of image space.

◆ solve() [1/2]

bool ossimRpcSolver::solve ( const ossimDrect aoiBounds,
ossimImageGeometry geom,
const double &  pixel_tolerance = 0.5 
)

Similar to the other solve methods except that the final grid size is established iteratively so that the error at the midpoints between grid nodes falls below tolerance.

The RPC is computed for the specified image bounds range only, not the full image. The expectation here (when the imageBounds is less than the full valid image rect) is to generate an RPC to accompany a subimage that will be written to disk.

Parameters
imageBoundsThe AOI in image space for the RPC computation.
geomRepresents the geometry of the input image
pixel_toleranceMaximum error in pixels (typically fraction of a pixel) to achieve.
Returns
true if solution converged below pixel tolerance.

Definition at line 290 of file ossimRpcSolver.cpp.

References ossimDrect::height(), theRefGeom, ossimDrect::ul(), and ossimDrect::width().

Referenced by ossimDemTool::doASP(), ossimSubImageTool::execute(), and solve().

293 {
294  static const char* MODULE = "ossimRpcSolver::solve() ";
295 
296  if (!geom)
297  return false;
298 
299  theRefGeom = geom;
300  ossimDpt ul = imageBounds.ul();
301  ossim_float64 w = imageBounds.width();
302  ossim_float64 h = imageBounds.height();
303  ossimDpt ipt, irpc;
304  ossimGpt gpt;
305 
306  // Start at the minimum grid size:
307  ossim_uint32 xSamples = STARTING_GRID_SIZE;
308  ossim_uint32 ySamples = STARTING_GRID_SIZE;
309 
310  // Loop until error is below threshold:
311  bool converged = false;
312  while (!converged)
313  {
314  double residual = 0;
315  double sumResiduals = 0;
316  int numResiduals = 0;
317  theMaxResidual = 0;
318 
319  converged = true; // hope for the best and get proved otherwise below
320  solveCoefficients(imageBounds, geom, xSamples, ySamples);
321 
322  // Sample along x and y directions to accumulate errors:
323  double deltaX = w/(xSamples-1);
324  double deltaY = h/(ySamples-1);
325 
326  // Sample the midpoints between image grid used to compute RPC:
327  for (ossim_uint32 y=0; y<ySamples-1; ++y)
328  {
329  ipt.y = deltaY*((double)y + 0.5) + ul.y;
330  for (ossim_uint32 x=0; x<xSamples-1; ++x)
331  {
332  // Forward projection using input model:
333  ipt.x = deltaX*((double)x + 0.5) + ul.x;
335  geom->localToWorld(ipt, gpt);
336  else
337  geom->localToWorld(ipt, 0, gpt);
339  {
341  if(ossim::isnan(h) == false)
342  gpt.height(h);
343  }
344 
345  // Reverse projection using RPC:
346  evalPoint(gpt, irpc);
347 
348  // Compute residual and accumulate:
349  residual = (ipt-irpc).length();
350  if (residual > theMaxResidual)
351  theMaxResidual = residual;
352  sumResiduals += residual;
353  ++numResiduals;
354  }
355  }
356 
357  theMeanResidual = sumResiduals/numResiduals;
358  if (theMaxResidual > tolerance)
359  converged = false;
360 
361 #if 1
362  { //### DEBUG BLOCK ###
364  <<"\n sampling grid size: ("<<xSamples<<", "<<ySamples<<")"
365  <<"\n mean residual: "<<theMeanResidual
366  <<"\n max residual: "<<theMaxResidual
367  <<"\n converged: "<<ossimString::toString(converged)<<endl;
368  }
369 #endif
370 
371  if ((xSamples >= ENDING_GRID_SIZE) && (ySamples >= ENDING_GRID_SIZE))
372  break;
373 
374  if (!converged)
375  {
376  xSamples *= 2;
377  if (xSamples > ENDING_GRID_SIZE)
378  xSamples = ENDING_GRID_SIZE;
379  ySamples *= 2;
380  if (ySamples > ENDING_GRID_SIZE)
381  ySamples = ENDING_GRID_SIZE;
382  }
383  }
384 
385  // Was testing the max residual. But use the mean for final test:
386  if (theMeanResidual <= tolerance)
387  converged = true;
388 
389  if (!converged)
390  {
392  << "WARNING: Unable to converge on desired error tolerance ("<<tolerance<<" p).\n"
393  <<" RMS residual error: " << theMeanResidual << "\n"
394  <<" Max residual error: " << theMaxResidual<<std::endl;
395  }
396  else if (theMaxResidual > tolerance)
397  {
399  << "WARNING: While the RPC solution did converge, at least one residual ("
400  <<theMaxResidual<<") is larger than the desired error tolerance ("<<tolerance<<" p)."
401  << std::endl;
402  }
403  return converged;
404 }
ossim_uint32 x
ossim_uint32 y
double y
Definition: ossimDpt.h:165
static ossimString toString(bool aValue)
Numeric to string methods.
static ossimElevManager * instance()
METHOD: instance() Implements singelton pattern.
void solveCoefficients(const ossimDrect &imageBounds, ossimProjection *imageProj, ossim_uint32 xSamples=8, ossim_uint32 ySamples=8)
This will convert any projector to an RPC model.
void evalPoint(const ossimGpt &gpt, ossimDpt &ipt) const
double ossim_float64
ossim_float64 theMaxResidual
bool localToWorld(const ossimDpt &local_pt, ossimGpt &world_pt) const
Exposes the 3D projection from image to world coordinates.
unsigned int ossim_uint32
double height() const
Definition: ossimGpt.h:107
ossim_float64 theMeanResidual
bool theHeightAboveMSLFlag
virtual double getHeightAboveMSL(const ossimGpt &gpt)
Height access methods:
double x
Definition: ossimDpt.h:164
ossimRefPtr< ossimImageGeometry > theRefGeom
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
bool isnan(const float &v)
isnan Test for floating point Not A Number (NAN) value.
Definition: ossimCommon.h:91

◆ solve() [2/2]

bool ossimRpcSolver::solve ( const ossimFilename imageFilename,
const double &  pixel_tolerance = 0.5 
)

Performs iterative solve using the other solve method, but uses an image filename to initialize, and computes RPC over entire image rect.

Definition at line 406 of file ossimRpcSolver.cpp.

References ossimRefPtr< T >::get(), ossimImageHandler::getBoundingRect(), ossimImageHandler::getImageGeometry(), ossimImageHandlerRegistry::instance(), ossimImageHandlerRegistry::open(), solve(), and ossimRefPtr< T >::valid().

408 {
409  // Establish input geometry:
411  if(!h.valid())
412  return false;
413 
415  ossimDrect imageRect (h->getBoundingRect());
416 
417  return solve(imageRect, geom.get(), pixel_tolerance);
418 }
virtual ossimImageHandler * open(const ossimFilename &fileName, bool trySuffixFirst=true, bool openOverview=true) const
open that takes a filename.
bool valid() const
Definition: ossimRefPtr.h:75
bool solve(const ossimDrect &aoiBounds, ossimImageGeometry *geom, const double &pixel_tolerance=0.5)
Similar to the other solve methods except that the final grid size is established iteratively so that...
virtual ossimRefPtr< ossimImageGeometry > getImageGeometry()
Returns the image geometry object associated with this tile source or NULL if non defined...
static ossimImageHandlerRegistry * instance()
virtual ossimIrect getBoundingRect(ossim_uint32 resLevel=0) const
Returns zero-based bounding rectangle of the image.

◆ solveCoefficients() [1/4]

void ossimRpcSolver::solveCoefficients ( const ossimDrect imageBounds,
ossimProjection imageProj,
ossim_uint32  xSamples = 8,
ossim_uint32  ySamples = 8 
)

This will convert any projector to an RPC model.

Definition at line 29 of file ossimRpcSolver.cpp.

References ossimRefPtr< T >::get(), and ossimImageGeometry::setProjection().

Referenced by ossimNitfWriterBase::addRpcbTag(), ossimRpcProjection::optimizeFit(), and solveCoefficients().

33 {
35  geom->setProjection(proj);
36  solveCoefficients(imageBounds, geom.get(), xSamples, ySamples);
37 }
void setProjection(ossimProjection *projection)
Sets the projection to be used for local-to-world coordinate transformation.
void solveCoefficients(const ossimDrect &imageBounds, ossimProjection *imageProj, ossim_uint32 xSamples=8, ossim_uint32 ySamples=8)
This will convert any projector to an RPC model.
Container class that holds both 2D transform and 3D projection information for an image Only one inst...

◆ solveCoefficients() [2/4]

void ossimRpcSolver::solveCoefficients ( const ossimDrect imageBounds,
ossimImageGeometry geom,
ossim_uint32  xSamples = 8,
ossim_uint32  ySamples = 8 
)

Definition at line 39 of file ossimRpcSolver.cpp.

References ossimImageGeometry::getProjection(), theRefGeom, x, and y.

43 {
44  if (!geom || !(geom->getProjection()))
45  return;
46  theRefGeom = geom;
47 
48  std::vector<ossimGpt> groundPoints;
49  std::vector<ossimDpt> imagePoints;
51  ossimGpt gpt;
52  ossimGpt defaultGround;
53  if (ySamples <= 1)
54  ySamples = STARTING_GRID_SIZE;
55  if (xSamples <= 1)
56  xSamples = STARTING_GRID_SIZE;
57  srand(time(0));
58  double Dx = imageBounds.width()/(xSamples-1);
59  double Dy = imageBounds.height()/(ySamples-1);
60  ossimDpt dpt;
61  for(y = 0; y < ySamples; ++y)
62  {
63  dpt.y = y*Dy + imageBounds.ul().y;
64  for(x = 0; x < xSamples; ++x)
65  {
66  dpt.x = x*Dx + imageBounds.ul().x;
68  geom->localToWorld(dpt, gpt);
69  else
70  geom->localToWorld(dpt, 0, gpt);
71 
72  if (gpt.isLatLonNan())
73  continue;
74 
75  if(gpt.isHgtNan())
76  gpt.height(0.0);
77 
78  gpt.changeDatum(defaultGround.datum());
80  {
82  if(ossim::isnan(h) == false)
83  gpt.height(h);
84  }
85 
86  imagePoints.push_back(dpt);
87  groundPoints.push_back(gpt);
88  }
89  }
90  solveCoefficients(imagePoints, groundPoints);
91 }
ossim_uint32 x
ossim_float64 width() const
Definition: ossimDrect.h:522
ossim_uint32 y
const ossimDpt & ul() const
Definition: ossimDrect.h:339
double y
Definition: ossimDpt.h:165
static ossimElevManager * instance()
METHOD: instance() Implements singelton pattern.
void solveCoefficients(const ossimDrect &imageBounds, ossimProjection *imageProj, ossim_uint32 xSamples=8, ossim_uint32 ySamples=8)
This will convert any projector to an RPC model.
void changeDatum(const ossimDatum *datum)
This will actually perform a shift.
Definition: ossimGpt.cpp:316
bool isHgtNan() const
Definition: ossimGpt.h:143
const ossimDatum * datum() const
datum().
Definition: ossimGpt.h:196
bool localToWorld(const ossimDpt &local_pt, ossimGpt &world_pt) const
Exposes the 3D projection from image to world coordinates.
unsigned int ossim_uint32
double height() const
Definition: ossimGpt.h:107
ossim_float64 height() const
Definition: ossimDrect.h:517
const ossimProjection * getProjection() const
Access methods for projection (may be NULL pointer).
bool theHeightAboveMSLFlag
virtual double getHeightAboveMSL(const ossimGpt &gpt)
Height access methods:
double x
Definition: ossimDpt.h:164
ossimRefPtr< ossimImageGeometry > theRefGeom
bool isLatLonNan() const
Definition: ossimGpt.h:142
bool isnan(const float &v)
isnan Test for floating point Not A Number (NAN) value.
Definition: ossimCommon.h:91

◆ solveCoefficients() [3/4]

void ossimRpcSolver::solveCoefficients ( const std::vector< ossimDpt > &  imagePoints,
const std::vector< ossimGpt > &  groundControlPoints 
)

takes associated image points and ground points and solves the coefficents for the rational polynomial for line and sample calculations from world points.

Note: All data will be normalized between -1 and 1 for numerical robustness.

Definition at line 93 of file ossimRpcSolver.cpp.

References ossimRpcModel::B, DBL_EPSILON, evalPoint(), FLT_EPSILON, ossimGpt::height(), ossimDrect::height(), ossim::isnan(), ossimDrect::midPoint(), solveCoefficients(), ossimRpcModel::theHgtOffset, ossimRpcModel::theHgtScale, ossimRpcModel::theLatOffset, ossimRpcModel::theLatScale, ossimRpcModel::theLineDenCoef, ossimRpcModel::theLineNumCoef, ossimRpcModel::theLineOffset, ossimRpcModel::theLineScale, ossimRpcModel::theLonOffset, ossimRpcModel::theLonScale, theMaxResidual, theMeanResidual, ossimRpcModel::thePolyType, theRpcModel, ossimRpcModel::theSampDenCoef, ossimRpcModel::theSampNumCoef, ossimRpcModel::theSampOffset, ossimRpcModel::theSampScale, theUseElevationFlag, ossimDrect::width(), ossimDpt::x, x, ossimDpt::y, and y.

95 {
96  if((imagePoints.size() != groundControlPoints.size()))
97  return;
98 
99  // we will first create f which holds the result of f(x,y,z).
100  // This basically holds the cooresponding image point for each
101  // ground control point. One for x and a second array for y
102  int numPoints = imagePoints.size();
103  std::vector<double> fx, fy;
104 
105  // Holds the x, y, z vectors
106  //
107  std::vector<double> x;
108  std::vector<double> y;
109  std::vector<double> z;
110  ossim_uint32 c = 0;
111  fx.resize(imagePoints.size());
112  fy.resize(imagePoints.size());
113  x.resize(imagePoints.size());
114  y.resize(imagePoints.size());
115  z.resize(imagePoints.size());
116 
117  // compute the image bounds for the given image points
118  ossimDrect rect(imagePoints);
119  ossimDpt centerImagePoint = rect.midPoint();
120 
121  // get the width and height that will be used in data normalization
122  ossim_float64 w = rect.width();
123  ossim_float64 h = rect.height();
124 
125  double latSum=0.0;
126  double lonSum=0.0;
127  double heightSum=0.0;
128 
129  // find the center ground Use elevation only if its enabled
130  for(c = 0; c < groundControlPoints.size();++c)
131  {
132  if(ossim::isnan(groundControlPoints[c].latd()) == false)
133  {
134  latSum += groundControlPoints[c].latd();
135  }
136  if(ossim::isnan(groundControlPoints[c].lond()) == false)
137  {
138  lonSum += groundControlPoints[c].lond();
139  }
140  if(!groundControlPoints[c].isHgtNan())
141  {
143  {
144  heightSum += groundControlPoints[c].height();
145  }
146  }
147  }
148 
149  // set the center ground for the offset
150  //
151  ossimGpt centerGround(latSum/groundControlPoints.size(),
152  lonSum/groundControlPoints.size(),
153  heightSum/groundControlPoints.size());
154 
155  // set up ground scales and deltas for normalization
156  ossim_float64 deltaLat = 0.0;
157  ossim_float64 deltaLon = 0.0;
158  ossim_float64 deltaHeight = 0.0;
159  ossim_float64 maxDeltaLat = 0.0;
160  ossim_float64 maxDeltaLon = 0.0;
161  ossim_float64 maxDeltaHeight = 0.0;
162  ossim_float64 heightTest = 0.0;
163  for(c = 0; c < groundControlPoints.size(); ++c)
164  {
165  deltaLat = (groundControlPoints[c].latd()-centerGround.latd());
166  deltaLon = (groundControlPoints[c].lond()-centerGround.lond());
167  if(!groundControlPoints[c].isHgtNan())
168  {
170  {
171  deltaHeight = groundControlPoints[c].height() - centerGround.height();
172  heightTest = groundControlPoints[c].height();
173  }
174  else
175  {
176  deltaHeight = 0.0;
177  heightTest = 0.0;
178  }
179  }
180  else
181  {
182  deltaHeight = 0.0;
183  }
184  fx[c] = (imagePoints[c].x - centerImagePoint.x)/(w/2.0);
185  fy[c] = (imagePoints[c].y - centerImagePoint.y)/(h/2.0);
186 
187  x[c] = deltaLon;
188  y[c] = deltaLat;
189  z[c] = deltaHeight;
190 
191  if(fabs(deltaLat) > maxDeltaLat)
192  maxDeltaLat = fabs(deltaLat);
193  if(fabs(deltaLon) > maxDeltaLon)
194  maxDeltaLon = fabs(deltaLon);
195  if(fabs(heightTest) > maxDeltaHeight)
196  maxDeltaHeight = fabs(heightTest);
197  }
198 
199  bool elevationEnabled = theUseElevationFlag;
200 
201  // if max delta is less than a degree set it to 1 degree.
202 // if(maxDeltaLat < 1.0)
203 // maxDeltaLat = 1.0;
204 // if(maxDeltaLon < 1.0)
205 // maxDeltaLon = 1.0;
206 
207  if(maxDeltaHeight < FLT_EPSILON)
208  elevationEnabled = false;
209  if(maxDeltaHeight < 1.0)
210  maxDeltaHeight = 1.0;
211 
212  // set the height scale to something pretty large
213  if(!elevationEnabled)
214  {
215  maxDeltaHeight = 1.0/DBL_EPSILON;
216  maxDeltaHeight = 10000;
217  centerGround.height(0.0);
218  }
219  // normalize the ground points
220  for(c = 0; c < groundControlPoints.size(); ++c)
221  {
222  x[c] /= maxDeltaLon;
223  y[c] /= maxDeltaLat;
224  z[c] /= maxDeltaHeight;
225  }
226 
229  theRpcModel->theLineOffset = centerImagePoint.y;
230  theRpcModel->theSampOffset = centerImagePoint.x;
231  theRpcModel->theLineScale = h/2.0;
232  theRpcModel->theSampScale = w/2.0;
233 
234  theRpcModel->theLatScale = maxDeltaLat;
235  theRpcModel->theLonScale = maxDeltaLon;
236  theRpcModel->theHgtScale = maxDeltaHeight;
237 
238  theRpcModel->theLatOffset = centerGround.lat;
239  theRpcModel->theLonOffset = centerGround.lon;
240  theRpcModel->theHgtOffset = centerGround.hgt;
241 
243  theRpcModel->theHgtOffset = 0.0;
244 
245  NEWMAT::ColumnVector coeffxVec;
246  NEWMAT::ColumnVector coeffyVec;
247 
248  // perform a least squares fit for sample values found in f
249  // given the world values with variables x, y, z
250  solveCoefficients(coeffxVec, fx, x, y, z);
251 
252  // perform a least squares fit for line values found in f
253  // given the world values with variables x, y, z
254  solveCoefficients(coeffyVec, fy, x, y, z);
255 
256  // there are 20 numerator coefficients and 19 denominator coefficients.
257  // I believe that the very first one for the denominator coefficients is fixed at 1.
258  theRpcModel->theLineNumCoef[0] = coeffyVec[0];
259  theRpcModel->theLineDenCoef[0] = 1.0;
260  theRpcModel->theSampNumCoef[0] = coeffxVec[0];
261  theRpcModel->theSampDenCoef[0] = 1.0;
262  for (int i=1; i<20; i++)
263  {
264  theRpcModel->theLineNumCoef[i] = coeffyVec[i];
265  theRpcModel->theLineDenCoef[i] = coeffyVec[i+19];
266  theRpcModel->theSampNumCoef[i] = coeffxVec[i];
267  theRpcModel->theSampDenCoef[i] = coeffxVec[i+19];
268  }
269 
270  // now lets compute the RMSE for the given control points by feeding it
271  // back through the modeled RPC
272  ossim_float64 sumSquareError = 0.0;
273  ossim_uint32 idx = 0;
274 
275  theMaxResidual = 0;
276  for (idx = 0; idx<imagePoints.size(); idx++)
277  {
278  ossimDpt evalPt;
279  evalPoint(groundControlPoints[idx], evalPt);
280  ossim_float64 len = (evalPt - imagePoints[idx]).length();
281  if (len > theMaxResidual)
282  theMaxResidual = len;
283  sumSquareError += (len*len);
284  }
285 
286  // set the error
287  theMeanResidual = sqrt(sumSquareError/imagePoints.size());
288 }
double theSampOffset
PolynomialType thePolyType
double theSampNumCoef[20]
ossim_uint32 x
ossim_uint32 y
double y
Definition: ossimDpt.h:165
double theLonScale
void solveCoefficients(const ossimDrect &imageBounds, ossimProjection *imageProj, ossim_uint32 xSamples=8, ossim_uint32 ySamples=8)
This will convert any projector to an RPC model.
double theLineScale
double theSampDenCoef[20]
void evalPoint(const ossimGpt &gpt, ossimDpt &ipt) const
double theLineNumCoef[20]
double theLatOffset
double ossim_float64
ossim_float64 theMaxResidual
double theHgtOffset
double theLonOffset
double theLatScale
#define FLT_EPSILON
unsigned int ossim_uint32
double height() const
Definition: ossimGpt.h:107
ossimRefPtr< ossimRpcModel > theRpcModel
#define DBL_EPSILON
ossim_float64 theMeanResidual
double x
Definition: ossimDpt.h:164
double theSampScale
double theLineDenCoef[20]
double theLineOffset
double theHgtScale
bool isnan(const float &v)
isnan Test for floating point Not A Number (NAN) value.
Definition: ossimCommon.h:91

◆ solveCoefficients() [4/4]

void ossimRpcSolver::solveCoefficients ( NEWMAT::ColumnVector &  coeff,
const std::vector< double > &  f,
const std::vector< double > &  x,
const std::vector< double > &  y,
const std::vector< double > &  z 
) const
protectedvirtual

Definition at line 449 of file ossimRpcSolver.cpp.

References FLT_EPSILON, invert(), setupSystemOfEquations(), setupWeightMatrix(), x, and y.

454 {
455  // this is an iterative linear least square fit. We really pobably need
456  // a nonlinear fit instead
457  //
458  ossim_uint32 idx = 0;
459  NEWMAT::Matrix m;
460 
461  NEWMAT::ColumnVector r((int)f.size());
462 
463  for(idx = 0; idx < f.size(); ++idx)
464  {
465  r[idx] = f[idx];
466  }
467 
468  NEWMAT::ColumnVector tempCoeff;
469  NEWMAT::DiagonalMatrix weights((int)f.size());
470  NEWMAT::ColumnVector denominator(20);
471 
472  // initialize the weight matrix to the identity
473  //
474  for(idx = 0; idx < f.size(); ++idx)
475  {
476  weights[idx] = 1.0;
477  }
478 
479  double residualValue = 1.0/FLT_EPSILON;
480  ossim_uint32 iterations = 0;
481  NEWMAT::Matrix w2;
482  do
483  {
484  w2 = weights*weights;
485 
486 #if 0
487  { //### DEBUG ###
488  cout<<"\nw2 = \n"<<w2<<endl;
489  cout<<"\nr = "<<r<<endl;
490  }
491 #endif
492 
493  // sets up the matrix to hold the system of equations
494  setupSystemOfEquations(m, r, x, y, z);
495 
496  // solve the least squares solution. Note: the invert is used
497  // to do a Singular Value Decomposition for the inverse since the
498  // matrix is more than likely singular. Slower but more robust
499 #if 0
500  { //### DEBUG ###
501  NEWMAT::Matrix mt = m.t();
502  cout<<"\nm = "<<m<<endl;
503  cout<<"\nmt = "<<mt<<endl;
504 
505  NEWMAT::Matrix mtw2 = m.t()*w2;
506  cout<<"\nmtw2 = "<<mtw2<<endl;
507  NEWMAT::Matrix mtw2m = mtw2*m;
508  cout<<"\nmtw2m = "<<mtw2m<<endl;
509  NEWMAT::Matrix mtw2r = mtw2*r;
510  cout<<"\nmtw2r = "<<mtw2r<<endl;
511 
512  NEWMAT::Matrix mtw2m_inv = invert(mtw2m);
513  cout<<"\nmtw2m_inv = "<<mtw2m_inv<<endl;
514  tempCoeff = mtw2m_inv * mtw2r;
515  cout<<"\ntempCoeff = "<<tempCoeff<<endl;
516  }
517 #else
518  tempCoeff = invert(m.t()*w2*m)*m.t()*w2*r;
519 #endif
520 
521  // set up the weight matrix by using the denominator
522  for(idx = 0; idx < 19; ++idx)
523  {
524  denominator[idx+1] = tempCoeff[20+idx];
525  }
526  denominator[0] = 1.0;
527 
528  setupWeightMatrix(weights, denominator, r, x, y, z);
529 
530  // compute the residual
531  NEWMAT::ColumnVector residual = m.t()*w2*(m*tempCoeff-r);
532 
533  // now get the innerproduct
534  NEWMAT::Matrix tempRes = (residual.t()*residual);
535  residualValue = sqrt(tempRes[0][0]);
536 
537  ++iterations;
538 
539  } while ((residualValue > FLT_EPSILON) && (iterations < 10));
540  coeff = tempCoeff;
541 
542 }
ossim_uint32 x
ossim_uint32 y
void setupSystemOfEquations(NEWMAT::Matrix &equations, const NEWMAT::ColumnVector &f, const std::vector< double > &x, const std::vector< double > &y, const std::vector< double > &z) const
void setupWeightMatrix(NEWMAT::DiagonalMatrix &result, const NEWMAT::ColumnVector &coefficients, const NEWMAT::ColumnVector &f, const std::vector< double > &x, const std::vector< double > &y, const std::vector< double > &z) const
#define FLT_EPSILON
unsigned int ossim_uint32
NEWMAT::Matrix invert(const NEWMAT::Matrix &m) const
Inverts using the SVD method.

◆ solveInitialCoefficients()

void ossimRpcSolver::solveInitialCoefficients ( NEWMAT::ColumnVector &  coeff,
const std::vector< double > &  f,
const std::vector< double > &  x,
const std::vector< double > &  y,
const std::vector< double > &  z 
) const
protectedvirtual

Definition at line 431 of file ossimRpcSolver.cpp.

References invert(), setupSystemOfEquations(), x, and y.

436 {
437  ossim_uint32 idx = 0;
438  NEWMAT::Matrix m;
439  NEWMAT::ColumnVector r((int)f.size());
440  for(idx = 0; idx < f.size(); ++idx)
441  {
442  r[idx] = f[idx];
443  }
444  setupSystemOfEquations(m, r, x, y, z);
445 
446  coeff = invert(m.t()*m)*m.t()*r;
447 }
ossim_uint32 x
ossim_uint32 y
void setupSystemOfEquations(NEWMAT::Matrix &equations, const NEWMAT::ColumnVector &f, const std::vector< double > &x, const std::vector< double > &y, const std::vector< double > &z) const
unsigned int ossim_uint32
NEWMAT::Matrix invert(const NEWMAT::Matrix &m) const
Inverts using the SVD method.

Member Data Documentation

◆ theHeightAboveMSLFlag

bool ossimRpcSolver::theHeightAboveMSLFlag
protected

Definition at line 192 of file ossimRpcSolver.h.

◆ theMaxResidual

ossim_float64 ossimRpcSolver::theMaxResidual
protected

Definition at line 194 of file ossimRpcSolver.h.

Referenced by getMaxError(), and solveCoefficients().

◆ theMeanResidual

ossim_float64 ossimRpcSolver::theMeanResidual
protected

Definition at line 193 of file ossimRpcSolver.h.

Referenced by getRmsError(), and solveCoefficients().

◆ theRefGeom

ossimRefPtr<ossimImageGeometry> ossimRpcSolver::theRefGeom
protected

Definition at line 195 of file ossimRpcSolver.h.

Referenced by solve(), and solveCoefficients().

◆ theRpcModel

ossimRefPtr<ossimRpcModel> ossimRpcSolver::theRpcModel
protected

Definition at line 196 of file ossimRpcSolver.h.

Referenced by evalPoint(), getNitfRpcBTag(), and solveCoefficients().

◆ theUseElevationFlag

bool ossimRpcSolver::theUseElevationFlag
protected

Definition at line 191 of file ossimRpcSolver.h.

Referenced by solveCoefficients().


The documentation for this class was generated from the following files: