OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimFcsiModel.cpp
Go to the documentation of this file.
1 //*****************************************************************************
2 // FILE: ossimFcsiModel.cc
3 //
4 // Copyright (C) 2001 ImageLinks, Inc.
5 //
6 // LGPL
7 //
8 // AUTHOR: Oscar Kramer (okramer@imagelinks.com)
9 //
10 // DESCRIPTION: Contains sensor model implementation for "Frame Camera Scanned
11 // Image" (FCSI, pronounced "foxy").
12 //
13 // This model represents image data that was scanned from film exposed by a
14 // conventional aerial frame camera. The data members defined in this class
15 // represent the fundamental quantities needed for the transformation.
16 // Typically, a different set of parameters will be provided in the metadata.
17 // An interface (support data) class will need to be implemented to convert
18 // a particular system's format to the quantities needed by this model.
19 //
20 // Coordinate systems in use are described here:
21 //
22 // Pixel -- line/sample in the digital image. The origin of this system is
23 // the upper left corner of the image, and represents a LEFT-
24 // HANDED coordinate system with Y (line) positive down and X
25 // (sample) positive to the right.
26 //
27 // Film -- x, y related to pixel space by affine transform (which includes
28 // mirror reflection due to left-handed system above) represented
29 // by thePrincipalPoint and the theScanXformMatrix. The latter
30 // contains scale, skew, and rotation/reflection. The film
31 // coordinates are adjusted for radial and decentering distortion.
32 //
33 // Camera/ -- 3D system containing film plane and optical (Z) axis. Given the
34 // Platform focal length (Z) and the film point (X,Y), a 3D ray direction
35 // is established in this space. This space is also termed "LSR"
36 // in the code. If there is a rotation between the film/optical
37 // axes and the platform (interior orientation), then that
38 // transformation must be included as part of the LSR-to-ECF
39 // rotation by the metadata reader object.
40 //
41 // ECF -- Universal earth frame of reference. The imaging ray direction
42 // is transformed from Camera space to ECF by theAdjLsrToEcfRot.
43 //
44 // There are two rotations to go from Camera to ECF. First is the initial
45 // camera orientation as derived from the metadata, combining the interior
46 // orientation (relation between camera and platform) and the exterior
47 // orientation dependent on the platform attitude w.r.t. the ECF system.
48 // The second rotation is a differential rotation due to the attitude
49 // adjustable params. These are arbitrarily taken as rotations about the ECF
50 // XYZ axes, not the platform attitude axes of roll/pitch/yaw. The
51 // combined rotation is stored in theAdjLsrToEcfRot, which is precomputed
52 // in updateModel() once with each adjustment.
53 //
54 // When the time comes to incorporate least-squares parameter adjustment, care
55 // must be taken to propagate the a priori sigmas for position and attitude
56 // (including both internal and external orientation angles) into the ECF
57 // coordinates. This also applies to the affine transform parameters used in
58 // transforming pixels to film coordinates. The propagated uncertainties can
59 // then be used to assign the adjustable parameter sigmas array (and
60 // covariance when we get to that...)
61 //
62 // SOFTWARE HISTORY:
63 // 16JAN2003 Oscar Kramer, ImageLinks
64 // Initial coding
65 //
66 //*****************************************************************************
67 // $Id: ossimFcsiModel.cpp 13005 2008-06-08 20:26:36Z dburken $
68 
69 #include <cstdlib>
70 #include <fstream>
71 #include <sstream>
72 
78 
79 RTTI_DEF1(ossimFcsiModel, "ossimFcsiModel", ossimSensorModel);
80 
81 //***
82 // Define Trace flags for use within this file:
83 //***
84 #include <ossim/base/ossimTrace.h>
85 static ossimTrace traceExec ("ossimFcsiModel:exec");
86 static ossimTrace traceDebug ("ossimFcsiModel:debug");
87 
88 //***
89 // File-scope constants:
90 //***
91 static const int MODEL_VERSION_NUMBER = 1;
92 static const ossimString PARAM_NAMES[] ={"x_pos_offset",
93  "y_pos_offset",
94  "z_pos_offset",
95  "x_rot_corr",
96  "y_rot_corr",
97  "z_rot_corr",
98  "foc_len_offset",
99  "scan_skew_corr"};
100 static const ossimString PARAM_UNITS[] ={"meters",
101  "meters",
102  "meters",
103  "degrees",
104  "degress",
105  "degress",
106  "millimeters",
107  "degrees"};
108 
109 //***
110 // Public FCSI Keywords:
111 //***
112 const char* ossimFcsiModel::PRINCIPAL_POINT_X_KW = "principal_point_x";
113 const char* ossimFcsiModel::PRINCIPAL_POINT_Y_KW = "principal_point_y";
114 const char* ossimFcsiModel::SCAN_SCALE_MATRIX_00_KW = "scan_scale_matrix_00";
115 const char* ossimFcsiModel::SCAN_SCALE_MATRIX_01_KW = "scan_scale_matrix_01";
116 const char* ossimFcsiModel::SCAN_SCALE_MATRIX_10_KW = "scan_scale_matrix_10";
117 const char* ossimFcsiModel::SCAN_SCALE_MATRIX_11_KW = "scan_scale_matrix_11";
118 const char* ossimFcsiModel::SCAN_ROTATION_ANGLE_KW = "scan_rotation_angle";
119 const char* ossimFcsiModel::SCAN_SKEW_ANGLE_KW = "scan_skew_angle";
120 const char* ossimFcsiModel::FOCAL_LENGTH_KW = "focal_length";
121 const char* ossimFcsiModel::PLATFORM_POSITION_X_KW = "platform_position_x";
122 const char* ossimFcsiModel::PLATFORM_POSITION_Y_KW = "platform_position_y";
123 const char* ossimFcsiModel::PLATFORM_POSITION_Z_KW = "platform_position_z";
125  = "camera_orientation_matrix_elem_";
126 
127 //*****************************************************************************
128 // DEFAULT CONSTRUCTOR: ossimFcsiModel()
129 //
130 // Note: Using this constructor results in an uninitialized model. It is
131 // expected that either a loadState with valid keywordlist is called, or that
132 // the individual set-methods (including the base-class' set methods are
133 // called. When set-methods are used, a final call to completeInitialization()
134 // (declared in ossimSensorModel) is required to give the model a chance to
135 // "digest" the values previously set.
136 //
137 //*****************************************************************************
139  :
140  ossimSensorModel (),
141  thePrincipalPoint (0, 0),
142  theScanSkew (0.0),
143  theScanRotation (0.0),
144  theOpticalDistortion (0),
145  theLsrToEcfRot (3, 3),
146  theEcfOffset (0, 0, 0),
147  theXrotCorr (0.0),
148  theYrotCorr (0.0),
149  theZrotCorr (0.0),
150  theFocalOffset (0.0),
151  theScanSkewCorr (0.0),
152  theAdjLsrToEcfRot (3, 3),
153  theAdjEcfToLsrRot (3, 3)
154 {
155  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::ossimFcsiModel: entering..." << std::endl;
156  theScanScaleMatrix[0] = 1.0;
157  theScanScaleMatrix[1] = 0.0;
158  theScanScaleMatrix[2] = 0.0;
159  theScanScaleMatrix[3] = 1.0;
160  theScanXformMatrix[0] = 1.0;
161  theScanXformMatrix[1] = 0.0;
162  theScanXformMatrix[2] = 0.0;
163  theScanXformMatrix[3] = 1.0;
165  setErrorStatus(); // indicate uninitialized
166 
167  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::ossimFcsiModel: returning..." << std::endl;
168 }
169 
170 //*****************************************************************************
171 // CONSTRUCTOR: ossimFcsiModel(filename)
172 //
173 // Constructs model from a keywordlist filename
174 //
175 //*****************************************************************************
177  :
178  ossimSensorModel (),
179  thePrincipalPoint (0, 0),
180  theScanSkew (0.0),
181  theScanRotation (0.0),
182  theOpticalDistortion (0),
183  theLsrToEcfRot (3, 3),
184  theEcfOffset (0, 0, 0),
185  theXrotCorr (0.0),
186  theYrotCorr (0.0),
187  theZrotCorr (0.0),
188  theFocalOffset (0.0),
189  theScanSkewCorr (0.0),
190  theAdjLsrToEcfRot (3, 3),
191  theAdjEcfToLsrRot (3, 3)
192 {
193  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::ossimFcsiModel: entering..." << std::endl;
194 
196  ossimKeywordlist kwl (init_file);
197  loadState(kwl);
198 
199  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::ossimFcsiModel: Exited..." << std::endl;
200 }
201 
202 //*****************************************************************************
203 // CONSTRUCTOR: ossimFcsiModel(kwl)
204 //
205 // Constructs model from keywordlist geometry file
206 //
207 //*****************************************************************************
209  :
210  ossimSensorModel (),
211  thePrincipalPoint (0, 0),
212  theScanSkew (0.0),
213  theScanRotation (0.0),
214  theOpticalDistortion (0),
215  theLsrToEcfRot (3, 3),
216  theEcfOffset (0, 0, 0),
217  theXrotCorr (0.0),
218  theYrotCorr (0.0),
219  theZrotCorr (0.0),
220  theFocalOffset (0.0),
221  theScanSkewCorr (0.0),
222  theAdjLsrToEcfRot (3, 3),
223  theAdjEcfToLsrRot (3, 3)
224 {
225  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::ossimFcsiModel: entering..." << std::endl;
226 
228  loadState(geom_kwl);
229 
230  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::ossimFcsiModel: Exited..." << std::endl;
231 }
232 
233 //*****************************************************************************
234 // COPY CONSTRUCTOR:
235 //*****************************************************************************
237  :
238  ossimSensorModel (foxy),
239  thePrincipalPoint (foxy.thePrincipalPoint),
240  theScanSkew (foxy.theScanSkew),
241  theScanRotation (foxy.theScanRotation),
242  theFocalLen (foxy.theFocalLen),
243  thePlatformPos (foxy.thePlatformPos),
244  theLsrToEcfRot (foxy.theLsrToEcfRot),
245  theEcfOffset (foxy.theEcfOffset),
246  theXrotCorr (foxy.theXrotCorr),
247  theYrotCorr (foxy.theYrotCorr),
248  theZrotCorr (foxy.theZrotCorr),
249  theFocalOffset (foxy.theFocalOffset),
250  theScanSkewCorr (foxy.theScanSkewCorr)
251 {
252  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::ossimFcsiModel: entering..." << std::endl;
253 
254  if(foxy.theOpticalDistortion)
255  {
256  //
257  // Finish the copy:
258  //
261  }
262 
263  for (int i=0; i<4; i++)
265 
266  //***
267  // Compute quantities derived from adjustables:
268  //***
269  updateModel();
270 
271  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::ossimFcsiModel: returning..." << std::endl;
272 }
273 
274 //*****************************************************************************
275 // METHOD: ossimFcsiModel::lineSampleHeightToWorld()
276 //
277 // Performs the line/sample to groundpoint projection given an elevation.
278 //
279 // 1. Compute ECF Imaging ray (see imagingRay() method below)
280 // 5. Intersect imaging ray with elevation surface.
281 //
282 //*****************************************************************************
284  const double& height,
285  ossimGpt& gpt) const
286 {
287  bool debug = false; // setable via interactive debugger
288  if (traceExec() || debug) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::ossimFcsiModel: entering..." << std::endl;
289 
290  //***
291  // Extrapolate if point is outside image:
292  //***
293  if (!insideImage(image_point))
294  {
295  gpt = extrapolate(image_point, height);
296  }
297 
298  else
299  {
300  //***
301  // First establish imaging ray from image point:
302  //***
303  ossimEcefRay imaging_ray;
304  imagingRay(image_point, imaging_ray);
305  ossimEcefPoint Pecf (imaging_ray.intersectAboveEarthEllipsoid(height));
306  gpt = ossimGpt(Pecf);
307 
308  if (traceDebug() || debug)
309  {
310  ossimNotify(ossimNotifyLevel_DEBUG) << "Pecf = " << Pecf << std::endl;
311  ossimNotify(ossimNotifyLevel_DEBUG) << "gpt = " << gpt << std::endl;
312  }
313  }
314 
315  if (traceExec() || debug) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::ossimFcsiModel: returning..." << std::endl;
316 }
317 
318 
319 //*****************************************************************************
320 // METHOD: ossimFcsiModel::imagingRay()
321 //
322 // Establishes an origin (at the platform position) and direction of the
323 // imaging ray as follows:
324 //
325 // 1. Remove any pixel offset into the image (in the case where the digital
326 // image is a sub-image of a larger scan).
327 // 2. Transform pixel coordinates to film point (with inherent lens distortion)
328 // 3. Remove radial and decentering lens distortion to arrive at ideal film
329 // coordinates.
330 // 4. Establish an internal imaging ray direction vector given the focal length
331 // 5. Transform ray direction vector to ECF coordinates and assign origin.
332 //
333 //*****************************************************************************
334 void ossimFcsiModel::imagingRay(const ossimDpt& image_point,
335  ossimEcefRay& image_ray) const
336 {
337  bool debug = false; // setable via interactive debugger: "set debug = true"
338  if (traceExec() || debug) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::imagingRay: entering..." << std::endl;
339 
340  //***
341  // In case this is a sub-image of a full image scan, need to add the
342  // sub-image offset maintained in the base-class:
343  //***
344  ossimDpt p0 (image_point + theSubImageOffset);
345 
346  if (traceDebug() || debug)
347  {
348  ossimNotify(ossimNotifyLevel_DEBUG) << "image_point = " << image_point << std::endl;
349  ossimNotify(ossimNotifyLevel_DEBUG) << "theSubImageOffset = " << theSubImageOffset << std::endl;
350  ossimNotify(ossimNotifyLevel_DEBUG) << "p0 = " << p0 << std::endl;
351  }
352 
353  //***
354  // Apply pixel to film coordinates affine transform:
355  //***
356  ossimDpt p1 (p0 - theRefImgPt);
358  theScanXformMatrix[2]*p1.x + theScanXformMatrix[3]*p1.y);
359  ossimDpt film (f1 - thePrincipalPoint);
360  if (traceDebug() || debug)
361  {
362  ossimNotify(ossimNotifyLevel_DEBUG) << "theRefImgPt = " << theRefImgPt << std::endl;
363  ossimNotify(ossimNotifyLevel_DEBUG) << "p1 = " << p1 << std::endl;
364  for (int i=0; i<4; i++)
365  {
366  ossimNotify(ossimNotifyLevel_DEBUG) << "theScanXformMatrix["<<i<<"] = "<<theScanXformMatrix[i] << std::endl;
367  }
368  ossimNotify(ossimNotifyLevel_DEBUG) << "f1 = " << f1 << std::endl;
369  ossimNotify(ossimNotifyLevel_DEBUG) << "thePrincipalPoint = " << thePrincipalPoint << std::endl;
370  ossimNotify(ossimNotifyLevel_DEBUG) << "film (distorted) = " << film << std::endl;
371  }
372 
373  //***
374  // Correct film point for optical (radial, decentering) distortion:
375  //***
378  if (traceDebug() || debug)
379  {
380  ossimNotify(ossimNotifyLevel_DEBUG) << "film (undistorted) = " << film << std::endl;
382  {
384  }
385  }
386 
387  //***
388  // Establish image ray in camera-space (LSR) coordinates, then rotate to the
389  // ECF. This rotation contains interior orientation, exterior orientation,
390  // and attitude correction:
391  //***
392  ossimColumnVector3d cam_ray_dir (film.x, film.y, -theAdjFocalLen);
393  ossimEcefVector ecf_ray_dir (theAdjLsrToEcfRot*cam_ray_dir);
394  ecf_ray_dir = ecf_ray_dir*(1.0/ecf_ray_dir.magnitude());
395  if (traceDebug() || debug)
396  {
397  ossimNotify(ossimNotifyLevel_DEBUG) << "theAdjFocalLen = " << theAdjFocalLen << std::endl;
398  ossimNotify(ossimNotifyLevel_DEBUG) << "cam_ray_dir = " << cam_ray_dir << std::endl;
399  ossimNotify(ossimNotifyLevel_DEBUG) << "theAdjLsrToEcfRot = \n" << theAdjLsrToEcfRot << std::endl;
400  ossimNotify(ossimNotifyLevel_DEBUG) << "ecf_ray_dir = " << ecf_ray_dir << std::endl;
401  }
402 
403  //***
404  // Establish ECF Ray object to represent imaging ray:
405  //***
406  image_ray.setOrigin(theAdjPlatformPos);
407  image_ray.setDirection(ecf_ray_dir);
408  if (traceDebug() || debug)
409  {
410  ossimNotify(ossimNotifyLevel_DEBUG) << "theAdjPlatformPos = " << theAdjPlatformPos << std::endl;
411  ossimNotify(ossimNotifyLevel_DEBUG) << "theAdjPlatformPos (ossimGpt): " << ossimGpt(theAdjPlatformPos)
412  << std::endl;
413  ossimNotify(ossimNotifyLevel_DEBUG) << "image_ray = " << image_ray << std::endl;
414  }
415 
416  if (traceExec() || debug) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::imagingRay: returning..." << std::endl;
417 }
418 
419 //*****************************************************************************
420 // METHOD ossimFcsiModel::worldToLineSample()
421 //
422 // Rigorous inverse transform overrides base-class iterative solution. It
423 // implements the exact reverse transform as imagingRay() above.
424 //
425 //*****************************************************************************
427  ossimDpt& image_point) const
428 {
429  bool debug = false; // setable via interactive debugger: "set debug = true"
430  if (traceExec() || debug) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::imagingRay: entering..." << std::endl;
431 
432  //***
433  // Establish ECF ray from platform to ground point and rotate to platform LSR
434  //***
435  ossimEcefPoint g_ecf (world_point);
436  ossimEcefVector ecf_ray_dir (g_ecf - theAdjPlatformPos);
437  ossimColumnVector3d cam_ray_dir (theAdjEcfToLsrRot*ecf_ray_dir.data());
438 
439  if (traceDebug() || debug)
440  {
441  ossimNotify(ossimNotifyLevel_DEBUG)<<"world_point = " << world_point << endl;
442  ossimNotify(ossimNotifyLevel_DEBUG)<<"g_ecf = " << g_ecf << endl;
443  ossimNotify(ossimNotifyLevel_DEBUG)<<"theAdjPlatformPos = " << theAdjPlatformPos << endl;
444  ossimNotify(ossimNotifyLevel_DEBUG)<<"theAdjPlatformPos (ossimGpt): "<<ossimGpt(theAdjPlatformPos)<<endl;
445  ossimNotify(ossimNotifyLevel_DEBUG)<<"ecf_ray_dir = " << ecf_ray_dir.unitVector() << endl;
446  ossimNotify(ossimNotifyLevel_DEBUG)<<"theAdjEcfToLsrRot = \n" << theAdjEcfToLsrRot << endl;
447  ossimNotify(ossimNotifyLevel_DEBUG)<<"cam_ray_dir = " << cam_ray_dir << endl;
448  }
449 
450  //***
451  // Scale the direction vector by the focal length to arrive at film
452  // coordinates:
453  //***
454  double scale = -theAdjFocalLen/cam_ray_dir[2];
455  ossimDpt film (scale*cam_ray_dir[0], scale*cam_ray_dir[1]);
456 
457  if (traceDebug() || debug)
458  {
459  ossimNotify(ossimNotifyLevel_DEBUG) << "theAdjFocalLen = " << theAdjFocalLen << endl;
460  ossimNotify(ossimNotifyLevel_DEBUG) << "scale = " << scale << endl;
461  ossimNotify(ossimNotifyLevel_DEBUG) << "film (undistorted) = " << film << endl;
462  }
463 
464  //***
465  // Add distortion:
466  //***
469 
470  if (traceDebug() || debug)
471  {
472  ossimNotify(ossimNotifyLevel_DEBUG) << "film (distorted) = " << film << endl;
473  }
474 
475  //***
476  // Apply film to pixel coordinates affine transform:
477  //***
478  ossimDpt f1(film + thePrincipalPoint);
481  ossimDpt p0 (p1 + theRefImgPt);
482 
483  if (traceDebug() || debug)
484  {
485  ossimNotify(ossimNotifyLevel_DEBUG) << "thePrincipalPoint = " << thePrincipalPoint << endl;
486  ossimNotify(ossimNotifyLevel_DEBUG) << "f1 = " << f1 << endl;
487  for (int i=0; i<4; i++)
488  ossimNotify(ossimNotifyLevel_DEBUG)<<"theInvScanXformMatrix["<<i<<"] = "<<theInvScanXformMatrix[i]
489  <<endl;
490  ossimNotify(ossimNotifyLevel_DEBUG) << "p1 = " << p1 << endl;
491  ossimNotify(ossimNotifyLevel_DEBUG) << "theRefImgPt = " << theRefImgPt << endl;
492  ossimNotify(ossimNotifyLevel_DEBUG) << "p0 = " << p0 << endl;
493  }
494 
495  //***
496  // Finally, apply the sub-image offset to get to digital image coordinates:
497  //***
498  image_point = p0 - theSubImageOffset;
499 
500  if (traceDebug() || debug)
501  {
502  ossimNotify(ossimNotifyLevel_DEBUG) << "theImageOffset = " << theSubImageOffset << endl;
503  ossimNotify(ossimNotifyLevel_DEBUG) << "image_point = " << image_point << endl;
504  }
505 
506  if (traceExec() || debug) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::imagingRay: returning..." << std::endl;
507 }
508 
509 
510 //*****************************************************************************
511 // METHOD: ossimFcsiModel::print()
512 //
513 // Formatted dump of data members.
514 //
515 //*****************************************************************************
517 {
518  out << "\nDump of ossimFcsiModel object at " << hex << this << ":\n"
519  << "\nossimFcsiModel data members: "
520  << "\n thePrincipalPoint: " << thePrincipalPoint
521  << "\n theScanScaleMatrix: " << theScanScaleMatrix[0] << " "
522  << theScanScaleMatrix[1]
523  << "\n " << theScanScaleMatrix[2] << " "
524  << theScanScaleMatrix[3]
525  << "\n theScanSkew: " << theScanSkew
526  << "\n theScanRotation: " << theScanRotation;
527 
528  for (int i=0; i<4; ++i)
529  {
530  out << "\ntheScanXformMatrix["<<i<<"]: " << theScanXformMatrix[i];
531  }
532 
533  out << "\n theFocalLen: " << theFocalLen
534  << "\n thePlatformPos: " << thePlatformPos
535  << "\n theLsrToEcfRot: \n" << theLsrToEcfRot
536  << "\n theAdjLsrToEcfRot: \n" << theAdjLsrToEcfRot
537  << "\n theEcfOffset: " << theEcfOffset
538  << "\n theXrotCorr: " << theXrotCorr
539  << "\n theYrotCorr: " << theYrotCorr
540  << "\n theZrotCorr: " << theZrotCorr
541  << "\n theFocalOffset: " << theFocalOffset
542  << "\n theScanSkewCorr: " << theScanSkewCorr
543  << endl;
544 
546  {
547  out << *theOpticalDistortion << endl;
548  }
549 
550  return ossimSensorModel::print(out);
551 }
552 
553 //*****************************************************************************
554 // METHOD: ossimFcsiModel::saveState()
555 //
556 // Saves the model state to the KWL. This KWL also serves as a geometry file.
557 //
558 //*****************************************************************************
560  const char* prefix) const
561 {
562  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::saveState: entering..." << std::endl;
563 
564  kwl.add(prefix, ossimKeywordNames::TYPE_KW, "ossimFcsiModel");
565 
566  //***
567  // Hand off to base class for common stuff:
568  //***
569  ossimSensorModel::saveState(kwl, prefix);
570 
571  //***
572  // Save off data members:
573  //***
580  kwl.add(prefix, SCAN_SKEW_ANGLE_KW, theScanSkew);
582  kwl.add(prefix, FOCAL_LENGTH_KW, theFocalLen);
583  kwl.add(prefix, PLATFORM_POSITION_X_KW,
584  thePlatformPos.x());
585  kwl.add(prefix, PLATFORM_POSITION_Y_KW,
586  thePlatformPos.y());
587  kwl.add(prefix, PLATFORM_POSITION_Z_KW,
588  thePlatformPos.z());
589 
590  //***
591  // Camera orientation matrix:
592  // i is row and j is column
593  //***
594  for (int i=0; i<3; i++)
595  {
596  for (int j=0; j<3; j++)
597  {
598  ostringstream ostr;
600  << i << "_" << j << ends;
601  kwl.add(prefix, ostr.str().c_str(), theLsrToEcfRot[i][j]);
602  }
603  }
604 
605  //***
606  // Optical distortion coefficients:
607  //***
609  {
610  ostringstream ostr;
611  ostr << prefix << "distortion." << ends;
612  theOpticalDistortion->saveState(kwl, ostr.str().c_str());
613  }
614 
615  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::saveState: returning..." << std::endl;
616  return true;
617 }
618 
619 //*****************************************************************************
620 // METHOD: ossimFcsiModel::loadState()
621 //
622 // Restores the model's state from the KWL. This KWL also serves as a
623 // geometry file.
624 //
625 //*****************************************************************************
627  const char* prefix)
628 {
629  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::loadState: entering..." << std::endl;
630 
631  if (traceDebug())
632  {
634  << "\nInput kwl: " << kwl
635  << std::endl;
636  }
637 
638  const char* value;
639  const char* keyword;
640  bool success;
641 
642  //***
643  // Assure this keywordlist contains correct type info:
644  //***
645  keyword = ossimKeywordNames::TYPE_KW;
646  value = kwl.find(prefix, keyword);
647  if (!value)
648  {
651  "Type name not found");
652  return false;
653 
654  }
655  if (strcmp(value, TYPE_NAME(this)))
656  {
657  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::saveState: returning..." << std::endl;
658  return false;
659  }
660 
661  //***
662  // Clear out any existing adjustable params:
663  //***
664 
665  //***
666  // Pass on to the base-class for parsing first:
667  //***
668  success = ossimSensorModel::loadState(kwl, prefix);
669  if (!success)
670  {
671  return false;
672  }
674  {
676  }
677 
678  //***
679  // Now begin loading data members:
680  //***
681  keyword = PRINCIPAL_POINT_X_KW;
682  value = kwl.find(prefix, keyword);
683  if (!value)
684  {
687  "principle point x not given");
688  return false;
689  }
690  thePrincipalPoint.x = atof(value);
691 
692  keyword = PRINCIPAL_POINT_Y_KW;
693  value = kwl.find(prefix, keyword);
694  if (!value)
695  {
698  "principle point y not given");
699  return false;
700  }
701 
702  thePrincipalPoint.y = atof(value);
703 
704  keyword = SCAN_SCALE_MATRIX_00_KW;
705  value = kwl.find(prefix, keyword);
706  if (!value)
707  {
710  "scale matrix 0,0 not given");
711  return false;
712  }
713  theScanScaleMatrix[0] = atof(value);
714 
715  keyword = SCAN_SCALE_MATRIX_01_KW;
716  value = kwl.find(prefix, keyword);
717  if (!value)
718  {
721  "scale matrix 0,1 not given");
722  return false;
723  }
724  theScanScaleMatrix[1] = atof(value);
725 
726  keyword = SCAN_SCALE_MATRIX_10_KW;
727  value = kwl.find(prefix, keyword);
728  if (!value)
729  {
732  "scale matrix 1,0 not given");
733  return false;
734  }
735  theScanScaleMatrix[2] = atof(value);
736 
737  keyword = SCAN_SCALE_MATRIX_11_KW;
738  value = kwl.find(prefix, keyword);
739  if (!value)
740  {
743  "scale matrix 1,1 not given");
744  return false;
745  }
746  theScanScaleMatrix[3] = atof(value);
747 
748  keyword = SCAN_SKEW_ANGLE_KW;
749  value = kwl.find(prefix, keyword);
750  if (!value)
751  theScanSkew = 0.0;
752  else
753  theScanSkew = atof(value);
754 
755  keyword = SCAN_ROTATION_ANGLE_KW;
756  value = kwl.find(prefix, keyword);
757  if (!value)
758  theScanRotation = 0.0;
759  else
760  theScanRotation = atof(value);
761 
762  keyword = FOCAL_LENGTH_KW;
763  value = kwl.find(prefix, keyword);
764  if (!value)
765  {
768  "Focal length not given");
769  return false;
770  }
771  theFocalLen = atof(value);
772 
773  keyword = PLATFORM_POSITION_X_KW;
774  value = kwl.find(prefix, keyword);
775  if (!value)
776  {
779  "Platform position X not given");
780  return false;
781  }
782  thePlatformPos.x() = atof(value);
783 
784  keyword = PLATFORM_POSITION_Y_KW;
785  value = kwl.find(prefix, keyword);
786  if (!value)
787  {
790  "Platform position Y not given");
791  }
792  thePlatformPos.y() = atof(value);
793 
794  keyword = PLATFORM_POSITION_Z_KW;
795  value = kwl.find(prefix, keyword);
796  if (!value)
797  {
800  "Platform position Z not given");
801  }
802  thePlatformPos.z() = atof(value);
803 
804  //***
805  // Platform orientation matrix:
806  //***
807  for (int i=0; i<3; i++)
808  {
809  for (int j=0; j<3; j++)
810  {
811  ostringstream ostr;
813  << i << "_" << j << ends;
814  ossimString s = ostr.str();
815  keyword = s.c_str();
816  value = kwl.find(prefix, keyword);
817  if (!value)
818  {
821  "Camera orientation matrix not given");
822  }
823  theLsrToEcfRot[i][j] = ossimString(value).toDouble();
824  }
825  }
826 
827  //***
828  // Reading of optical distortion coefficients is left to the service object:
829  //***
831  delete theOpticalDistortion;
833 
834  //***
835  // Initialize given parameters read:
836  //***
838  updateModel();
839 
840  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::loadState: returning..." << std::endl;
841  return true;
842 }
843 
844 //*****************************************************************************
845 // PROTECTED METHOD: ossimFcsiModel::updateModel()
846 //
847 // Following a parameter adjustment, this method is called to recompute all
848 // dependent quantities that are used by the projection methods.
849 //
850 //*****************************************************************************
852 {
853  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::updateModel: entering..." << std::endl;
854 
855  //***
856  // Update the geometry...
857  // Adjusted = Initial + adj_parm[i]*adj_sigma[i]
858  // Some parameters have a zero initial value and that term is not included.
859  //***
876 
877  //***
878  // Compute adjusted quatities used in projection code:
879  //***
882 
883  //***
884  // Establish the Scanner to film transform matrix.
885  //
886  // NOTE FOR IMPLEMENTING PARAMETER ADJUSTMENT: while the scan skew
887  // angle is an adjustable parameter, the pixel scaling is not since this
888  // error can be absorbed by the focal length adjustment, though the sigma
889  // for the focal length must be inflated to account for the additional error
890  // source. A similar situation occurrs with the scan rotation which manifests
891  // as an attitude adjustment.
892  //***
893  double cos_rot = ossim::cosd(theScanRotation);
894  double sin_rot = ossim::sind(theScanRotation);
895  double tan_skew = ossim::tand(theScanSkew + theScanSkewCorr);
896 
897  double a = theScanScaleMatrix[0]*(sin_rot*tan_skew + cos_rot) +
898  theScanScaleMatrix[1]*(cos_rot*tan_skew - sin_rot);
899  double b = theScanScaleMatrix[0]*sin_rot + theScanScaleMatrix[1]*cos_rot;
900  double c = theScanScaleMatrix[2]*(sin_rot*tan_skew + cos_rot) +
901  theScanScaleMatrix[3]*(cos_rot*tan_skew - sin_rot);
902  double d = theScanScaleMatrix[2]*sin_rot + theScanScaleMatrix[3]*cos_rot;
903 
904  theScanXformMatrix[0] = a;
905  theScanXformMatrix[1] = b;
906  theScanXformMatrix[2] = c;
907  theScanXformMatrix[3] = d;
908 
909  //***
910  // The inverse of the scanner-to-film transform must be computed since it is
911  // not an orthogonal matrix (inverse != transpose):
912  //***
913  theInvScanXformMatrix[0] = d/(d*a - b*c);
914  theInvScanXformMatrix[1] = -b/(d*a - b*c);
915  theInvScanXformMatrix[2] = c/(b*c - a*d);
916  theInvScanXformMatrix[3] = -a/(b*c - a*d);
917 
918  //***
919  // Establish the differential rotation matrix due to attitude correction:
920  //***
921  double cw = ossim::cosd(theXrotCorr);
922  double sw = ossim::sind(theXrotCorr);
923  double cp = ossim::cosd(theYrotCorr);
924  double sp = ossim::sind(theYrotCorr);
925  double ck = ossim::cosd(theZrotCorr);
926  double sk = ossim::sind(theZrotCorr);
927 
928  NEWMAT::Matrix attitudeCorrection(3, 3);
929  attitudeCorrection(1,1) = ck*cw - sk*sp*sw;
930  attitudeCorrection(1,2) = sk*cp;
931  attitudeCorrection(1,3) = ck*sw + sk*sp*cw;
932  attitudeCorrection(2,1) = -sk*cw - ck*sp*sw;
933  attitudeCorrection(2,2) = cp*ck;
934  attitudeCorrection(2,3) = -sk*sw + ck*sp*cw;
935  attitudeCorrection(3,1) = -cp*sw;
936  attitudeCorrection(3,2) = -sp;
937  attitudeCorrection(3,3) = cp*cw;
938 
939  //***
940  // Now compute the final LSR to ECF rotation:
941  //***
942  theAdjLsrToEcfRot = attitudeCorrection * theLsrToEcfRot;
944 
945  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::updateModel: returning..." << std::endl;
946 }
947 
948 
949 //*****************************************************************************
950 // PRIVATE METHOD: ossimFcsiModel::initAdjustableParameters()
951 //
952 // This method initializes the base class adjustable parameter and associated
953 // sigmas arrays with quantities specific to this model. These are default
954 // values only. A functional implementation would assign the sigmas via a
955 // keywordlist or camera specific derived class.
956 //
957 //*****************************************************************************
959 {
960  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::initAdjustableParameters: entering..." << std::endl;
961 
962  int numParams = NUM_ADJUSTABLE_PARAMS;
964 
965 // if(!getNumberOfAdjustableParameters())
967  //***
968  // Allocate storage for adjustables and assign their names and units strings
969  //***
970 // newAdjustment(NUM_ADJUSTABLE_PARAMS);
971 // }
972  //***
973  // Initialize base-class adjustable parameter array:
974  //***
975  for (int i=0; i<numParams; i++)
976  {
977  setAdjustableParameter(i, 0.0);
978  setParameterDescription(i, PARAM_NAMES[i]);
979  setParameterUnit(i, PARAM_UNITS[i]);
980  }
981 
982  //***
983  // Initialize base-class parameter sigma array:
984  //***
985  setParameterSigma(X_POS, 50.0);
986  setParameterSigma(Y_POS, 50.0);
987  setParameterSigma(Z_POS, 50.0);
988  setParameterSigma(X_ROT, 0.01);
989  setParameterSigma(Y_ROT, 0.01);
990  setParameterSigma(Z_ROT, 0.01);
993 
994  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::initAdjustableParameters: returning..." << std::endl;
995 }
996 
997 //*****************************************************************************
998 // STATIC METHOD: ossimFcsiModel::writeGeomTemplate
999 //
1000 // Writes a sample kwl to output stream. Please update this method with any
1001 // format and/or keyword changes. It will make life a lot easier for everyone.
1002 //
1003 //*****************************************************************************
1005 {
1006  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::writeGeomTemplate: entering..." << std::endl;
1007 
1008  os <<
1009  "//*****************************************************************\n"
1010  "// Template for Frame Camera Scanned Image (FCSI) model keywordlist\n"
1011  "//*****************************************************************\n"
1012  << ossimKeywordNames::TYPE_KW << ": " << "ossimFcsiModel" << endl;
1013 
1015 
1016  os << "//***\n"
1017  << "// Derived-class FCSI Keywords:\n"
1018  << "//***\n"
1019  << PRINCIPAL_POINT_X_KW << ": <pixels>\n"
1020  << PRINCIPAL_POINT_Y_KW << ": <pixels>\n"
1021  << SCAN_SCALE_MATRIX_00_KW << ": <mm/pixel>\n"
1022  << SCAN_SCALE_MATRIX_01_KW << ": <mm/pixel>\n"
1023  << SCAN_SCALE_MATRIX_10_KW << ": <mm/pixel>\n"
1024  << SCAN_SCALE_MATRIX_11_KW << ": <mm/pixel>\n"
1025  << SCAN_SKEW_ANGLE_KW << ": <degrees> [OPTIONAL]\n"
1026  << SCAN_ROTATION_ANGLE_KW << ": <degrees> [OPTIONAL]\n"
1027  << FOCAL_LENGTH_KW << ": <millimeters>\n"
1028  << PLATFORM_POSITION_X_KW << ": <meters (ECF)>\n"
1029  << PLATFORM_POSITION_Y_KW << ": <meters (ECF)>\n"
1030  << PLATFORM_POSITION_Z_KW << ": <meters (ECF)>\n"
1031  << "\n"
1032  << "//***\n"
1033  << "// Camera (LSR) to ECF orientation matrix:\n"
1034  << "//***\n";
1035 
1036  for (int i=0; i<3; i++)
1037  {
1038  for (int j=0; j<3; j++)
1039  {
1040  ostringstream ostr;
1042  << i << "_" << j << ends;
1043  os << ostr.str() << ": <Euler rot matrix element>\n";
1044  }
1045  }
1046 
1047  os << "\n"
1048  << "//***\n"
1049  << "// Optical distortion coefficients [OPTIONAL]:\n"
1050  << "//***\n"
1051  << "distortion."
1053  << "N: <coeff N> (for N <= 5)\n"
1054  << "distortion."
1056  << "N: <coeff N> (for N <= 4)\n"
1057  << endl;
1058 
1059  if (traceExec()) ossimNotify(ossimNotifyLevel_DEBUG) << "DEBUG ossimFcsiModel::writeGeomTemplate: returning..." << std::endl;
1060 
1061  return;
1062 }
1063 
1064 
OSSIMDLLEXPORT void ossimSetError(const char *className, ossim_int32 error, const char *fmtString=0,...)
void setParameterDescription(ossim_uint32 idx, const ossimString &descrption)
ossimEcefVector unitVector() const
static const char * FOCAL_LENGTH_KW
#define TYPE_NAME(p)
Definition: ossimRtti.h:326
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
double z() const
static const char * PLATFORM_POSITION_Y_KW
virtual void lineSampleHeightToWorld(const ossimDpt &image_point, const double &heightEllipsoid, ossimGpt &worldPoint) const
double theScanSkewCorr
ossimEcefPoint intersectAboveEarthEllipsoid(const double &heightAboveEllipsoid, const ossimDatum *aDatum=ossimDatumFactory::instance() ->wgs84()) const
Represents serializable keyword/value map.
virtual void updateModel()
const char * find(const char *key) const
ossimEcefVector theEcfOffset
static const char * PRINCIPAL_POINT_X_KW
virtual void forward(const ossimDpt &undistorted_point_in, ossimDpt &distorted_point_out) const
NEWMAT::Matrix theAdjEcfToLsrRot
double y
Definition: ossimDpt.h:165
NEWMAT::Matrix theLsrToEcfRot
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
static const char * PRINCIPAL_POINT_Y_KW
double x() const
double magnitude() const
ossimRadialDecentLensDistortion * theOpticalDistortion
static const ossimErrorCode OSSIM_ERROR
virtual ossimString getClassName() const
Definition: ossimObject.cpp:64
virtual void imagingRay(const ossimDpt &image_point, ossimEcefRay &image_ray) const
double sind(double x)
Definition: ossimCommon.h:260
static const char * SCAN_ROTATION_ANGLE_KW
virtual std::ostream & print(std::ostream &out) const
void setOrigin(const ossimEcefPoint &orig)
Definition: ossimEcefRay.h:81
static const char * TYPE_KW
static const char * PLATFORM_POSITION_Z_KW
double tand(double x)
Definition: ossimCommon.h:261
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
ossimDpt theSubImageOffset
ossimEcefPoint theAdjPlatformPos
double theScanScaleMatrix[4]
virtual void inverse(const ossimDpt &input, ossimDpt &output) const
RTTI_DEF1(ossimFcsiModel, "ossimFcsiModel", ossimSensorModel)
static const char * CAMERA_ORIENTATION_MATRIX_ELEM_KW
static const char * SCAN_SCALE_MATRIX_11_KW
double theInvScanXformMatrix[4]
double toDouble() const
static const char * PLATFORM_POSITION_X_KW
void initAdjustableParameters()
virtual std::ostream & print(std::ostream &out) const
static void writeGeomTemplate(ostream &os)
void setParameterUnit(ossim_uint32 idx, ossimUnitType unit)
static const char * SCAN_SCALE_MATRIX_00_KW
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
virtual std::ostream & print(std::ostream &out) const
double cosd(double x)
Definition: ossimCommon.h:259
virtual ossimDpt extrapolate(const ossimGpt &gp) const
static void writeGeomTemplate(ostream &os)
double x() const
double y() const
NEWMAT::Matrix theAdjLsrToEcfRot
virtual void setAdjustableParameter(ossim_uint32 idx, double value, bool notify=false)
double y() const
double x
Definition: ossimDpt.h:164
void resizeAdjustableParameterArray(ossim_uint32 numberOfParameters)
ossimEcefPoint thePlatformPos
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
const ossimColumnVector3d & data() const
double theScanRotation
virtual bool insideImage(const ossimDpt &p) const
virtual void worldToLineSample(const ossimGpt &world_point, ossimDpt &image_point) const
ossimDpt thePrincipalPoint
void setDirection(const ossimEcefVector &d)
Definition: ossimEcefRay.h:82
double z() const
static const char * SCAN_SKEW_ANGLE_KW
void setParameterSigma(ossim_uint32 idx, double value, bool notify=false)
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23
static const char * SCAN_SCALE_MATRIX_01_KW
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
double theScanXformMatrix[4]
static const char * SCAN_SCALE_MATRIX_10_KW