OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimBilinearProjection.cpp
Go to the documentation of this file.
1 //*******************************************************************
2 //
3 // License: See top level LICENSE.txt file.
4 //
5 // Author: Garrett Potts
6 //
7 //********************************************************************
8 // $Id: ossimBilinearProjection.cpp 19682 2011-05-31 14:21:20Z dburken $
9 
10 #include <sstream>
11 using namespace std;
12 
15 #include <ossim/base/ossimGpt.h>
16 #include <ossim/base/ossimDpt.h>
19 #include <ossim/base/ossimDrect.h>
20 #include <ossim/base/ossimDatum.h>
22 #include <ossim/base/ossimTrace.h>
26 
27 #ifdef OSSIM_ID_ENABLED
28 static const char OSSIM_ID[] = "$Id: ossimBilinearProjection.cpp 19682 2011-05-31 14:21:20Z dburken $";
29 #endif
30 
31 // static const ossim_uint32 MINIMUM_NMBER_OF_POINTS = 4;
32 
33 static ossimTrace traceDebug("ossimBilinearProjection:debug");
34 
36 
38  :
40  theLineSamplePt(0),
41  theGeographicPt(0),
42  theLatFit(),
43  theLonFit()
44 {
45 #ifdef OSSIM_ID_ENABLED
46  if (traceDebug()) ossimNotify(ossimNotifyLevel_DEBUG) << OSSIM_ID << endl;
47 #endif
48 }
49 
51  :
53  theLineSamplePt(rhs.theLineSamplePt),
54  theGeographicPt(rhs.theGeographicPt),
55  theLonFit(rhs.theLonFit)
56 {
57 }
58 
60  const ossimDpt& ur,
61  const ossimDpt& lr,
62  const ossimDpt& ll,
63  const ossimGpt& ulg,
64  const ossimGpt& urg,
65  const ossimGpt& lrg,
66  const ossimGpt& llg)
67  :
69  theLineSamplePt(4),
70  theGeographicPt(4),
71  theLatFit(),
72  theLonFit()
73 {
74  theLineSamplePt[0] = ul;
75  theLineSamplePt[1] = ur;
76  theLineSamplePt[2] = lr;
77  theLineSamplePt[3] = ll;
78 
79  theGeographicPt[0] = ulg;
80  theGeographicPt[1] = urg;
81  theGeographicPt[2] = lrg;
82  theGeographicPt[3] = llg;
83 
85 }
86 
88 {
89 }
90 
92 {
93  return new ossimBilinearProjection(*this);
94 }
95 
97 {
98  ossimGpt result;
99  result.makeNan();
100  if ( (theGeographicPt.size() == 0) || gPtsHaveNan() )
101  {
102  return result;
103  }
104 
105  double lat = 0.0;
106  double lon = 0.0;
107  const double SIZE = theGeographicPt.size();
108 
109  vector<ossimGpt>::const_iterator i = theGeographicPt.begin();
110  while (i != theGeographicPt.end())
111  {
112  lat += (*i).latd();
113  lon += (*i).lond();
114  ++i;
115  }
116 
117  result.latd(lat/SIZE);
118  result.lond(lon/SIZE);
119  result.height(0.0);
120  result.datum(theGeographicPt[0].datum());
121 
122  return result;
123 }
124 
126  ossimDpt& lineSampPt) const
127 {
129  {
130  ossimProjection::worldToLineSample(worldPoint, lineSampPt);
131  }
132  else
133  {
134  lineSampPt.makeNan();
135 
137  {
138  lineSampPt.x = theXFit.lsFitValue(worldPoint.lond(),
139  worldPoint.latd());
140  lineSampPt.y = theYFit.lsFitValue(worldPoint.lond(),
141  worldPoint.latd());
142  }
143  }
144 }
145 
147  ossimGpt& worldPt) const
148 {
149  lineSampleHeightToWorld(lineSampPt,
150  ossim::nan(),
151  worldPt);
152 
153 }
154 
156  const ossimDpt& lineSampPt,
157  const double& heightAboveEllipsoid,
158  ossimGpt& worldPt) const
159 {
160  worldPt.makeNan();
161 
163  {
164  return;
165  }
166 
167 
168  worldPt.lat = theLatFit.lsFitValue(lineSampPt.x, lineSampPt.y);
169  worldPt.lon = theLonFit.lsFitValue(lineSampPt.x, lineSampPt.y);
170  if (ossim::isnan(heightAboveEllipsoid) == false)
171  {
172  worldPt.hgt = heightAboveEllipsoid;
173  }
174  if (theGeographicPt.size())
175  {
176  worldPt.datum(theGeographicPt[0].datum());
177  }
178 }
179 
181  const char* prefix)const
182 {
183  if (theLineSamplePt.size() != theGeographicPt.size())
184  {
185  // Should never happen.
186  return false;
187  }
188 
189  ossimProjection::saveState(kwl, prefix);
190 
191  ossimString imagePoints;
192  ossimString groundPoints;
193  ossim::toStringList(imagePoints, theLineSamplePt);
194  ossim::toStringList(groundPoints, theGeographicPt);
195  kwl.add(prefix,
196  "image_points",
197  imagePoints,
198  true);
199  kwl.add(prefix,
200  "ground_points",
201  groundPoints,
202  true);
203 #if 0
204  const ossim_uint32 SIZE = (ossim_uint32)theLineSamplePt.size();
205 
206  for (ossim_uint32 i = 0; i < SIZE; ++i)
207  {
208  ossimString index_string = ossimString::toString(i);
209 
210  // Add the geographic point.
211  ossimString kw = "gpt";
212  kw += index_string;
213  ostringstream os1;
214  os1 << theGeographicPt[i];
215  kwl.add(prefix, kw, os1.str().c_str());
216 
217  // Add the sample line..
218  kw = "dpt";
219  kw += index_string;
221  os2 << theLineSamplePt[i];
222  kwl.add(prefix, kw, os2.str().c_str());
223  }
224 #endif
225  return true;
226 }
227 
229  const char* prefix)
230 {
231  // Load the base class.
232  ossimProjection::loadState(kwl, prefix);
233 
234  // Start with clear lists.
235  theLineSamplePt.clear();
236  theGeographicPt.clear();
237 
238  ossimString imagePoints = kwl.find(prefix, "image_points");
239  ossimString groundPoints = kwl.find(prefix, "ground_points");
240 
241  if(!imagePoints.empty()&&!groundPoints.empty())
242  {
243  ossim::toVector(theLineSamplePt, imagePoints);
244  ossim::toVector(theGeographicPt, groundPoints);
245  }
246  else
247  {
248  //---
249  // Get the number of points.
250  // If 0 or gpt size not equal to dpt size get out.
251  //---
252  const ossim_uint32 SIZE = kwl.numberOf(prefix, "gpt");
253  if ( (SIZE == 0) || (SIZE != kwl.numberOf(prefix, "dpt")) )
254  {
255  return false;
256  }
257 
258  for (ossim_uint32 i = 0; i < SIZE; ++i)
259  {
260  const char* lookup;
261  ossimString index_string = ossimString::toString(i);
262 
263  // Get the geographic point.
264  ossimString kw = "gpt";
265  kw += index_string;
266  lookup = kwl.find(prefix, kw);
267  if (lookup)
268  {
269  ossimGpt gp;
270  gp.toPoint(std::string(lookup));
271 
272  //---
273  // Allow for "nan" height values by substituting with 0.0 so the
274  // hasNans() will work. "nan"s will get placed in the point if the
275  // user doesn't have the elevation manager preferences set up
276  // correctly.
277  //---
278  if (gp.isHgtNan())
279  {
280  gp.height(0.0);
281  }
282  theGeographicPt.push_back(gp);
283  }
284 
285  // Get the line sample point.
286  kw = "dpt";
287  kw += index_string;
288  lookup = kwl.find(prefix, kw);
289  if (lookup)
290  {
291  ossimDpt dp;
292  dp.toPoint(std::string(lookup));
293  theLineSamplePt.push_back(dp);
294  }
295  }
296  }
297 
298  if (traceDebug())
299  {
301  }
302 
304 
305  return true;
306 }
307 
308 bool ossimBilinearProjection::operator==(const ossimProjection& /* projection */) const
309 {
310  return false;
311 }
312 
314 {
315  ossimGpt centerG;
316  ossimGpt rightG;
317  ossimGpt topG;
318 
319  ossimDpt midPoint = midLineSamplePt();
320 
321  lineSampleToWorld(midPoint, centerG);
322  lineSampleToWorld(midPoint+ossimDpt(1,0), rightG);
323  lineSampleToWorld(midPoint+ossimDpt(0,-1), topG);
324 
325  ossimEcefPoint centerP = centerG;
326  ossimEcefPoint rightP = rightG;
327  ossimEcefPoint topP = topG;
328 
329  ossimEcefVector horizontal = rightP-centerP;
330  ossimEcefVector vertical = topP-centerP;
331 
332  ossimDpt result(horizontal.magnitude(),
333  vertical.magnitude());
334 
335  result.x = (result.x + result.y)/2.0;
336  result.y = result.x;
337 
338  return result;
339 }
340 
342 {
346  {
347  theLatFit.clear();
348  theLonFit.clear();
349  theXFit.clear();
350  theYFit.clear();
351 
352  const ossim_uint32 SIZE = (ossim_uint32)theLineSamplePt.size();
353  if (SIZE != theGeographicPt.size())
354  {
355  return;
356  }
357 
358  for (ossim_uint32 i = 0; i < SIZE; ++i)
359  {
361  theLineSamplePt[i].y,
362  theGeographicPt[i].latd());
363 
365  theLineSamplePt[i].y,
366  theGeographicPt[i].lond());
367 
369  theGeographicPt[i].latd(),
370  theLineSamplePt[i].x);
372  theGeographicPt[i].latd(),
373  theLineSamplePt[i].y);
374 
375  }
376 
377  theLatFit.solveLS();
378  theLonFit.solveLS();
379  theXFit.solveLS();
380  theYFit.solveLS();
381  ossimDpt errorResult;
383  errorResult);
384  if(errorResult.length() > 1)
385  {
386  theInverseSupportedFlag = false;
387  }
388  }
389 }
390 
392 {
393  if (theLineSamplePt.size() == 0)
394  {
395  return false;
396  }
397 
398  vector<ossimDpt>::const_iterator i = theLineSamplePt.begin();
399  while (i != theLineSamplePt.end())
400  {
401  if ( (*i).hasNans() )
402  {
403  return true;
404  }
405  ++i;
406  }
407  return false;
408 }
409 
411 {
412  //---
413  // NOTE: This method ignores nans in the height field.
414  //---
415 
416  if (theGeographicPt.size() == 0)
417  {
418  return false;
419  }
420 
421  vector<ossimGpt>::const_iterator i = theGeographicPt.begin();
422  while (i != theGeographicPt.end())
423  {
424  if ( (*i).isLatNan() || (*i).isLonNan() )
425  {
426  return true;
427  }
428  ++i;
429  }
430  return false;
431 }
432 
434 {
435  ossimDpt result;
436 
437  if ( (theLineSamplePt.size() == 0) || dPtsHaveNan())
438  {
439  result.makeNan();
440  return result;
441  }
442 
443  double x = 0.0;
444  double y = 0.0;
445  vector<ossimDpt>::const_iterator i = theLineSamplePt.begin();
446  while (i != theLineSamplePt.end())
447  {
448  x += (*i).x;
449  y += (*i).y;
450  ++i;
451  }
452  const double SIZE = theLineSamplePt.size();
453  result.x = x / SIZE;
454  result.y = y / SIZE;
455 
456  return result;
457 }
458 
460 {
462  << "ossimBilinearProjection::print\n";
463 
464  ossim_uint32 index = 0;
465  vector<ossimDpt>::const_iterator di = theLineSamplePt.begin();
466  while (di != theLineSamplePt.end())
467  {
469  << "theLineSamplePt[" << index << "]: "
470  << (*di) << endl;
471  ++di;
472  ++index;
473  }
474 
475  index = 0;
476  vector<ossimGpt>::const_iterator gi = theGeographicPt.begin();
477  while (gi != theGeographicPt.end())
478  {
480  << "theGeographicPt[" << index << "]: "
481  << (*gi) << endl;
482  ++gi;
483  ++index;
484  }
485 
486  return ossimProjection::print(out);
487 }
488 
489 ossim_float64 ossimBilinearProjection::setTiePoints(const std::vector<ossimDpt>& lsPt,
490  const std::vector<ossimGpt>& geoPt)
491 {
492  if (lsPt.size() != geoPt.size())
493  {
495  << "mismatch in image and ground point number" << endl;
496  return -1.0;
497  }
498  if (lsPt.size() < 4)
499  {
501  << "not enough tie points - need at least 4" << endl;
502  return -1.0;
503  }
504 
505  theLineSamplePt = lsPt;
506  theGeographicPt = geoPt;
507 
508  //compute fit
510 
511  //compute variance
512  ossim_float64 sumerr2=0.0;
513  vector<ossimDpt>::const_iterator i;
514  vector<ossimGpt>::const_iterator j;
515  ossimGpt gres;
516  for(i=theLineSamplePt.begin() , j=theGeographicPt.begin() ; i != theLineSamplePt.end() ; ++i, ++j )
517  {
518  gres.lat = theLatFit.lsFitValue(i->x, i->y);
519  gres.lon = theLonFit.lsFitValue(i->x, i->y);
520  gres.hgt = j->hgt; //same height as ground point
521 
522  sumerr2 += ( ossimEcefPoint(gres) - ossimEcefPoint(*j) ).norm2(); //add squared error in meters
523  }
524 
525  return sumerr2 / theLineSamplePt.size(); //variance in meter^2
526 }
527 
529 {
530  return false;
531 }
532 
535 {
536  return 2*4; //height not used
537 }
538 
539 double
540 ossimBilinearProjection::optimizeFit(const ossimTieGptSet& tieSet, double* /* targetVariance */)
541 {
542  //NOTE : IGNORE targetVariance
543  std::vector<ossimDpt> imagePoints;
544  std::vector<ossimGpt> groundPoints;
545  tieSet.getSlaveMasterPoints(imagePoints, groundPoints);
546  return setTiePoints(imagePoints, groundPoints); //variance in meters
547 }
548 
549 //**************************************************************************************************
551 //**************************************************************************************************
552 void ossimBilinearProjection::getTiePoints(std::vector<ossimDpt>& lsPt,
553  std::vector<ossimGpt>& geoPt) const
554 {
555  lsPt = theLineSamplePt;
556  geoPt = theGeographicPt;
557 }
558 
std::ostringstream os2
ossim_uint32 x
virtual void worldToLineSample(const ossimGpt &worldPoint, ossimDpt &lineSampPt) const
virtual void clear()
Will clear everything and set it up to for another solve.
virtual ossimGpt origin() const
void getSlaveMasterPoints(std::vector< ossimDpt > &imv, std::vector< ossimGpt > &gdv) const
ossim_uint32 numberOf(const char *str) const
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
virtual void lineSampleHeightToWorld(const ossimDpt &lineSampPt, const double &heightAboveEllipsoid, ossimGpt &worldPt) const
virtual void addSample(double x, double yy, double zmea)
add a single data sample.
ossimLeastSquaresBilin theXFit
virtual void lineSampleToWorld(const ossimDpt &lineSampPt, ossimGpt &worldPt) const
virtual std::ostream & print(std::ostream &out) const
Outputs theErrorStatus as an ossimErrorCode and an ossimString.
double lond() const
Will convert the radian measure to degrees.
Definition: ossimGpt.h:97
Represents serializable keyword/value map.
ossim_uint32 y
OSSIM_DLL void toStringList(ossimString &resultStringOfPoints, const std::vector< ossimDpt > &pointList, char separator=' ')
Will take a vector of ossimDpt and convert to a string list separated by spaces For example: (45...
const char * find(const char *key) const
virtual std::ostream & print(std::ostream &out) const
Outputs theErrorStatus as an ossimErrorCode and an ossimString.
virtual ossimObject * dup() const
double nan()
Method to return ieee floating point double precision NAN.
Definition: ossimCommon.h:135
double y
Definition: ossimDpt.h:165
void makeNan()
Definition: ossimGpt.h:130
static ossimString toString(bool aValue)
Numeric to string methods.
double magnitude() const
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
ossim_float64 hgt
Height in meters above the ellipsiod.
Definition: ossimGpt.h:274
virtual ossim_uint32 degreesOfFreedom() const
better go from image to ground, also means that errors variance are in squared meters ...
double latd() const
Will convert the radian measure to degrees.
Definition: ossimGpt.h:87
double length() const
Definition: ossimDpt.h:81
virtual double optimizeFit(const ossimTieGptSet &tieSet, double *targetVariance=0)
bool isHgtNan() const
Definition: ossimGpt.h:143
const ossimDatum * datum() const
datum().
Definition: ossimGpt.h:196
std::vector< ossimGpt > theGeographicPt
double ossim_float64
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
ossimLeastSquaresBilin theLatFit
virtual class enabling projection optimization (can be used for outlier rejection - RANSAC) ...
OSSIM_DLL void toVector(std::vector< ossimDpt > &result, const ossimString &stringOfPoints)
Will take a string list separated by spaces and convert to a vector of ossimDpts. ...
ossimLeastSquaresBilin theYFit
ossim_float64 lon
Definition: ossimGpt.h:266
void toPoint(const std::string &s)
Initializes this point from string.
Definition: ossimGpt.cpp:116
unsigned int ossim_uint32
void toPoint(const std::string &s)
Initializes this point from string.
Definition: ossimDpt.cpp:192
double height() const
Definition: ossimGpt.h:107
bool gPtsHaveNan() const
Checks theGeographicPt for nans.
bool solveLS()
compute least squares parameter solution - true if succesfull.
virtual ossim_float64 setTiePoints(const std::vector< ossimDpt > &lsPt, const std::vector< ossimGpt > &geoPt)
RTTI_DEF2(ossimBilinearProjection, "ossimBilinearProjection", ossimProjection, ossimOptimizableProjection)
std::vector< ossimDpt > theLineSamplePt
void getTiePoints(std::vector< ossimDpt > &lsPt, std::vector< ossimGpt > &geoPt) const
Access method for tie point information.
storage class for a set of geographic tie points, between master and slave images ...
virtual bool operator==(const ossimProjection &projection) const
ossimLeastSquaresBilin theLonFit
double x
Definition: ossimDpt.h:164
const char * c_str() const
Returns a pointer to a null-terminated array of characters representing the string&#39;s contents...
Definition: ossimString.h:396
bool empty() const
Definition: ossimString.h:411
virtual double lsFitValue(double xx, double yy) const
interpolate LS-fit value at location (xx,yy) - returns z(xx,yy).
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
ossim_float64 lat
Definition: ossimGpt.h:265
virtual void getRoundTripError(const ossimDpt &imagePoint, ossimDpt &errorResult) const
bool dPtsHaveNan() const
Checks theLineSamplePt for nans.
virtual void worldToLineSample(const ossimGpt &worldPoint, ossimDpt &lineSampPt) const =0
virtual ossimDpt getMetersPerPixel() const
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
void makeNan()
Definition: ossimDpt.h:65
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23
virtual bool setupOptimizer(const ossimString &setup)
setupFromString() Derived classes should implement as needed. Initialize parameters needed for optimi...
bool isnan(const float &v)
isnan Test for floating point Not A Number (NAN) value.
Definition: ossimCommon.h:91