Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ProjectionParametersPerspective.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 
26 #include "Geometry/ProjectionParametersPerspective.hh"
27 
28 #include "SphericalCoordinates.hh"
29 
30 using namespace BIAS;
31 using namespace std;
32 
34 GetCutOutParameters(const Vector2<int>& centerPoint,
35  const unsigned int halfWidth,
36  const unsigned int halfHeight,
37  ProjectionParametersPerspective& cutOutParams) const
38 {
39  cutOutParams = (*this);
40  Vector2<int> UL(centerPoint[0]-halfWidth, centerPoint[1]-halfHeight);
41  Vector2<int> LR(centerPoint[0]+halfWidth, centerPoint[1]+halfHeight);
42  cutOutParams.width_ = 2 * halfWidth + 1;
43  cutOutParams.height_ = 2 * halfHeight + 1;
44 
45  cutOutParams.SetPrincipal(principalX_ - UL[0], principalY_ - UL[1]);
46 
47  return ((UL[0]>=0) && (UL[0]<(int)width_) &&
48  (UL[1]>=0) && (UL[1]<(int)height_) &&
49  (LR[0]>=0) && (LR[0]<(int)width_) &&
50  (LR[1]>=0) && (LR[1]<(int)height_));
51 }
52 
54 GetMinimalAngleInCorner_(const HomgPoint2D& corner, double& minAngle)
55 {
56  HomgPoint2D neighbour[3]; //looking for the 3 neighbours of a corner at distance 1 or sqrt(2)
57  Vector3<double> ray, p;
58  UnProjectLocal(corner, p, ray);
59  if(ray.NormL2()<1e-12) return -1;
60  ray.Normalize();
61 
62  Vector3<double> neighbourRay[3];
63 
64  const int x = 0;
65  const int y = 1;
66  const int diag = 2;
67 
68  neighbour[x] = corner; //neighbour in x direction
69  neighbour[y] = corner; //neighbour in y direction
70  neighbour[diag] = corner; //diagonal neighbour
71  if(neighbour[x][0] == 0) {
72  neighbour[x][0]+=1;
73  neighbour[diag][0]+=1;
74  } else {
75  neighbour[x][0]-=1;
76  neighbour[diag][0]-=1;
77  }
78 
79  if(neighbour[y][1] == 0) {
80  neighbour[y][1]+=1;
81  neighbour[diag][1]+=1;
82  } else {
83  neighbour[y][1]-=1;
84  neighbour[diag][1]-=1;
85  }
86 
87  double angleDiff[3];
88  for(unsigned int i=0; i<3; i++) {
90  UnProjectLocal(neighbour[i], p, neighbourRay[i]);
91  if(neighbourRay[i].NormL2() < 1e-12) {
92  return -1;
93  }
94  neighbourRay[i].Normalize();
95  angleDiff[i] = acos(ray.ScalarProduct(neighbourRay[i]));
96  }
97 
98  minAngle = (angleDiff[x] < angleDiff[y]) ? angleDiff[x] : angleDiff[y];
99  if(minAngle > angleDiff[diag]) {
100  minAngle = angleDiff[diag];
101  }
102 
103  return 0;
104 
105 }
106 
107 // looks into the corners and calculates angle differences to extremal
108 // optical rays
110 GetMinimalAngularSamplingStep(double& minAngleStep)
111 {
112  HomgPoint2D corner[4];
113 
114  corner[0][0] = 0;
115  corner[0][1] = 0;
116  corner[0][2] = 1;
117 
118  corner[1][0] = 0;
119  corner[1][1] = height_-1;
120  corner[1][2] = 1;
121 
122  corner[2][0] = width_-1;
123  corner[2][1] = height_-1;
124  corner[2][2] = 1;
125 
126  corner[3][0] = width_-1;
127  corner[3][1] = 0;
128  corner[3][2] = 1.0;
129 
130  double minAngle[4];
131  for(unsigned int i=0; i<4; i++) {
132  if(GetMinimalAngleInCorner_(corner[i], minAngle[i])!=0) {
133  return -1;
134  }
135  }
136  double minAngleStepTemp[2];
137  minAngleStepTemp[0] = (minAngle[0]<minAngle[1]) ? minAngle[0] : minAngle[1];
138  minAngleStepTemp[1] = (minAngle[2]<minAngle[3]) ? minAngle[2] : minAngle[3];
139 
140  minAngleStep =
141  (minAngleStepTemp[0]<minAngleStepTemp[1]) ?
142  minAngleStepTemp[0] : minAngleStepTemp[1];
143 
144  return 0;
145 }
146 
149 {
151  return true;
152 
154  dynamic_cast<const ProjectionParametersPerspective*>(p);
155  if(ppp == NULL)
156  return true;
157 
158  if(focallength_ != ppp->focallength_)
159  return true;
160 
161  if(kc1_ != ppp->kc1_ || kc2_ != ppp->kc2_ ||
162  kc3_ != ppp->kc3_ || kc4_ != ppp->kc4_)
163  return true;
164 
165  return false;
166 }
167 
170  HomgPoint2D& x,
171  bool IgnoreDistortion) const
172 {
173  // check if in front of camera (max. allowed FoV 168 degree)
174  // The FoV check is needed because near zero radial distortion
175  // produces really huge numbers
176  if(localX[2]/localX.NormL2() > minZlocal_) {
177  // now compute coordinates
178  x = ProjectLocal(localX, IgnoreDistortion);
179 
180  // check if ProjectLocal worked
181  if(x[0] == 0.0 && x[1]==0.0 && x[2]==0.0){
182  return false;
183  }
184 
185  // check if in image
186  return (x[0]>=-0.5 && x[1]>=-0.5 &&
187  x[0]<=(double)(width_)-0.5 && x[1]<=(double)(height_)-0.5 );
188  }
189  return false;
190 }
191 
192 
194 ProjectLocal(const Vector3<double>& point, bool IgnoreDistortion) const
195 {
196  // make sure we dont project points behind the camera. Also prevent radial
197  // distortion from double overflow !
198  if (point[2] <= minZlocal_) return HomgPoint2D(0,0,0);
199 
200  HomgPoint2D pos2(point), pos;
201  if (!IgnoreDistortion) {
202  int res = DistortNormalized(pos2);
203  if(distType_ == DISTYPE_INVERSE_RAD){
204  if(res!=0){
205  return HomgPoint2D(0,0,0);
206  }
207  }
208  }
209  // in-plane affine coordinate transformation with KMatrix
210  K_.Mult(pos2, pos);
211 
212  return pos.Homogenize();
213 }
214 
215 
218  bool IgnoreDistortion) const
219 {
220  if (point.NormL2()<1e-6) { // point coincides with camera center
221  p2d.Set(0., 0., 0.);
222  return -1;
223  }
224  HomgPoint2D pos2(point);
225  if (!IgnoreDistortion) {
226  int res = DistortNormalized(pos2);
227  if (res!=0) { return -2; }
228  }
229  // in-plane affine coordinate transformation with KMatrix
230  K_.Mult(pos2, p2d);
231  p2d.Homogenize();
232  return 0;
233 }
234 
235 
238  const double& zDistance,
239  bool ignoreDistortion) const
240 {
241  Vector3<double> d, p;
242  UnProjectLocal(pos, p,d, ignoreDistortion);
243 
244  d *= (zDistance/d[2]);
245 
246  HomgPoint3D local(d);
247  return Pose_.LocalToGlobal(local);
248 }
249 
250 
252 UnProjectToImagePlane(const HomgPoint2D& pos, const double& depth,
253  bool IgnoreDistortion) const
254 {
255  Vector3<double> d, p;
256  UnProjectLocal(pos, p, d, IgnoreDistortion);
257  if(Equal(d[2], 0.0))
258  return HomgPoint3D(0,0,0,0);
259  d*= depth / d[2];
260  if(Equal(d.NormL2(), 0.0))
261  return HomgPoint3D(0,0,0,0);
262  HomgPoint3D local(d);
263  return Pose_.LocalToGlobal(local);
264 }
265 
267 UnProjectLocal(const HomgPoint2D& cPos, Vector3<double>& pointOnRay,
268  Vector3<double>& direction, bool IgnoreDistortion) const {
269  HomgPoint2D mpos(cPos); // de-const pos
270  pointOnRay = Vector3<double>(0.);
271  // radial undistortion here
272  if (!IgnoreDistortion) {
273  if (!Undistort(mpos)){
274  BIASWARNONCE("ProjectionParametersPerspective::UnProjectLocal(): "
275  << "Error undistorting point: " << cPos)
276  direction = Vector3<double>(0., 0., 0.);
277  //mpos = HomgPoint2D(cPos);
278  }
279  }
280  //cout << "distorted: "<<cPos<<"\nundistorted: "<<mpos<<endl;
281  // in-plane affine coordinate transformation with KMatrix
282  invK_.Mult(mpos, direction);
283  const double n = direction.NormL2();
284  if (!Equal(n,0.0, 1e-15)){
285  direction /= n;
286  } else {
287  BIASWARNONCE("cannot normalize local ray - division by zero otherwise")
288  }
289 }
290 
291 
294 {
295  // do nothing in case of ideal lense
296  if (kc1_==0 && kc2_==0 && kc3_==0 && kc4_==0) return 0;
297  if (point2d.IsAtInfinity()) { return -1; }
298  point2d.Homogenize();
299  double dx = -1;
300  double dy = -1;
301  Distort_(point2d[0], point2d[1], dx, dy);
302  if(distType_==DISTYPE_INVERSE_RAD && dx == -1 && dy == -1){
303  BIASWARNONCE("Error distorting point with inverse rad distortion" << point2d)
304  return -1;
305  }
306  point2d[0] = dx;
307  point2d[1] = dy;
308  return 0;
309 }
310 
311 
313 Distort(HomgPoint2D& point2d) const
314 {
315  // do nothing in case of ideal lens
316  if (kc1_==0 && kc2_==0 && kc3_==0 && kc4_==0 && r0_==0) return true;
317 
318  // copy of distorted point
319  /*double distx,disty;
320  double x,y;*/
321  // this is effectively: (x,y,1) = K^-1 * point2D
322  // Points must be Bougouet-normalized
323  // (subtract principal point, then divide by focal length)
324  /*x = (point2d[0]-principalX_)/focallength_;
325  y = (point2d[1]-principalY_)/(GetAspectratio()*focallength_);*/
326  point2d = invK_*point2d;
327 
328  //Distort_(x, y, distx, disty);
329  Distort_(point2d[0],point2d[1], point2d[0],point2d[1]);
330  if(distType_ == DISTYPE_INVERSE_RAD && point2d[0]==-1 && point2d[1]==-1){
331  BIASWARN("Error distorting point with inverse rad distortion " << point2d)
332  point2d.Set(0,0,0);
333  return false;
334  }
335 
336  // invert Bougouet-normalization
337  /*point2d[0] = distx*focallength_ + principalX_;
338  point2d[1] = disty*GetAspectratio()*focallength_ + principalY_;*/
339  point2d = K_*point2d;
340  return true;
341 }
342 
343 
345 Undistort(HomgPoint2D& point2d) const
346 {
347  BIASASSERT(!point2d.IsAtInfinity());
348  // do nothing in case of ideal lens
349  if (kc1_==0 && kc2_==0 && kc3_==0 && kc4_==0 && r0_==0){
350  return true;
351  }
352 
353  point2d.Homogenize();
354 
355  /*double distx,disty;
356  double x,y;*/
357  // Points must be Bouguet-normalized
358  // (subtract principal point, then divide by focal length)
359  point2d = invK_*point2d;
360  /*x = point2d[0] = (point2d[0]-principalX_)/focallength_;
361  y = point2d[1] = (point2d[1]-principalY_)/(GetAspectratio()*focallength_);*/
362 
363  if (!Undistort_(point2d[0], point2d[1], point2d[0], point2d[1])){
364  point2d.Set(0., 0., 0.);
365  return false;
366  }
367  // invert Bouguet-normalization
368  /*point2d[0] = point2d[0]*focallength_ + principalX_;
369  point2d[1] = point2d[1]*GetAspectratio()*focallength_ + principalY_;*/
370  point2d = K_*point2d;
371  return true;
372 }
373 
376  switch(model){
377  case DISTYPE_NONE:
378  return string("None");
379  case DISTYPE_RADIAL:
380  return string("Bouguet_Radial");
381  case DISTYPE_DEF:
382  return string("Bouguet_Full");
383  case DISTYPE_BROWN:
384  return string("Brown");
385  case DISTYPE_INVERSE_RAD:
386  return string("Inverse_Radial");
387  default:
388  return string("Unknown");
389  }
390 }
391 
392 #ifdef BIAS_HAVE_XML2
393 
395 XMLGetClassName(std::string& TopLevelTag, double& Version) const {
396  TopLevelTag = "ProjectionParametersPerspective";
397  Version = 0.1;
398  return 0;
399 }
400 
402 XMLOut(const xmlNodePtr Node, XMLIO& XMLObject) const {
403  xmlNodePtr theNode;
404  string TopLevelName;
405  double Version;
406  ProjectionParametersBase::XMLGetClassName(TopLevelName, Version);
407  theNode = XMLObject.addChildNode(Node, TopLevelName);
408  XMLObject.addAttribute(theNode, "Version", Version);
409  ProjectionParametersBase::XMLOut(theNode, XMLObject);
410 
411  xmlNodePtr childNode;
412  XMLObject.addAttribute(Node,"Focallength", focallength_);
413  XMLObject.addAttribute(Node,"Skew", skew_);
414  childNode = XMLObject.addChildNode(Node,string("Distortion"));
415 
416  //handling of advanced distortion types
417  if(distType_ != DISTYPE_NONE){
418  XMLObject.addAttribute(childNode, "k1", kc1_);
419  XMLObject.addAttribute(childNode, "k2", kc2_);
420  XMLObject.addAttribute(childNode, "p1", kc3_);
421  XMLObject.addAttribute(childNode, "p2", kc4_);
422  }
423  switch(distType_) {
424  case DISTYPE_NONE:
425  XMLObject.addAttribute(childNode, "Type", "DISTYPE_NONE");
426  break;
427  case DISTYPE_BROWN:
428  XMLObject.addAttribute(childNode, "Type", "DISTYPE_BROWN");
429  XMLObject.addAttribute(childNode, "r0", r0_);
430  break;
431  case DISTYPE_DEF:
432  XMLObject.addAttribute(childNode, "Type", "DISTYPE_DEF");
433  break;
434  case DISTYPE_RADIAL:
435  XMLObject.addAttribute(childNode, "Type", "DISTYPE_RADIAL");
436  break;
437  case DISTYPE_INVERSE_RAD:
438  XMLObject.addAttribute(childNode, "Type", "DISTYPE_INVERSE_RAD");
439  break;
440  case DISTYPE_RAD3:
441  XMLObject.addAttribute(childNode, "Type", "DISTYPE_RAD3");
442  break;
443  case DISTYPE_INVRAD3:
444  XMLObject.addAttribute(childNode, "Type", "DISTYPE_INVRAD3");
445  break;
446  default:
447  BIASWARN("Unknown distortion type. only default parameters have been saved." << distType_);
448  break;
449  }
450  return 0;
451 }
452 
453 
455 XMLIn(const xmlNodePtr Node, XMLIO& XMLObject) {
456 
457  string TopLevelName;
458  double Version;
459  ProjectionParametersBase::XMLGetClassName(TopLevelName, Version);
460 
461  xmlNodePtr childNode;
462  if ((childNode = XMLObject.getChild(Node, TopLevelName))==NULL) {
463  BIASERR("Error in xml, no tag" << TopLevelName);
464  return -1;
465  }
466  if (ProjectionParametersBase::XMLIn(childNode, XMLObject)!=0) return -1;
467 
468  focallength_ = XMLObject.getAttributeValueDouble(Node, "Focallength");
469  if (XMLObject.getAttributeByName(Node, "Skew")!=NULL)
470  skew_ = XMLObject.getAttributeValueDouble(Node, "Skew");
471  if ((childNode = XMLObject.getChild(Node, "Distortion"))!=NULL) {
472  kc1_ = XMLObject.getAttributeValueDouble(childNode, "k1");
473  kc2_ = XMLObject.getAttributeValueDouble(childNode, "k2");
474  kc3_ = XMLObject.getAttributeValueDouble(childNode, "p1");
475  kc4_ = XMLObject.getAttributeValueDouble(childNode, "p2");
476 
477  //check if distortion is not default case
478  xmlAttrPtr typeAttr = NULL;
479  typeAttr = XMLObject.getAttributeByName(childNode, "Type");
480  if(typeAttr!=NULL)
481  {
482  string typestr;
483  typestr = XMLObject.getAttributeValueString(typeAttr);
484 
485  if(typestr == string("DISTYPE_NONE"))
486  {
487  distType_ = DISTYPE_NONE;
488  }
489  else if(typestr == string("DISTYPE_BROWN"))
490  {
491  distType_ = DISTYPE_BROWN; //set type of distortion parameters
492  r0_ = XMLObject.getAttributeValueDouble(childNode, "r0");
493  }
494  else if(typestr == string("DISTYPE_DEF"))
495  {
496  distType_ = DISTYPE_DEF;
497  }
498  else if(typestr == string("DISTYPE_RADIAL"))
499  {
500  distType_ = DISTYPE_RADIAL;
501  }
502  else if(typestr == string("DISTYPE_INVERSE_RAD"))
503  {
504  distType_ = DISTYPE_INVERSE_RAD;
505  }
506  else if(typestr == string("DISTYPE_INVRAD3"))
507  {
508  distType_ = DISTYPE_INVRAD3;
509  }
510  else if(typestr == string("DISTYPE_RAD3"))
511  {
512  distType_ = DISTYPE_RAD3;
513  }
514  }
515  else
516  {
517  distType_ = DISTYPE_DEF;
518  }
519  }
520  ComputeK_();
521  return 0;
522 }
523 
524 #endif // BIAS_HAVE_XML2
525 
528 {
529  unsigned int imageWidth, imageHeight;
530  GetImageSize(imageWidth, imageHeight);
531 
532  HomgPoint2D p(0, 0);
533  Undistort(p);
534  p = invK_ * p;
535  p.Homogenize();
536 
537  double minX = p[0], maxX = p[0], minY = p[1], maxY = p[1];
538 
539  for (unsigned int x = 0; x < imageWidth; x++) {
540  p = HomgPoint2D(x, 0);
541  Undistort(p);
542  p = invK_ * p;
543  p.Homogenize();
544  if (p[0] < minX) minX = p[0];
545  if (p[0] > maxX) maxX = p[0];
546  if (p[1] < minY) minY = p[1];
547  if (p[1] > maxY) maxY = p[1];
548 
549  p = HomgPoint2D(x, imageHeight-1);
550  Undistort(p);
551  p = invK_ * p;
552  p.Homogenize();
553  if (p[0] < minX) minX = p[0];
554  if (p[0] > maxX) maxX = p[0];
555  if (p[1] < minY) minY = p[1];
556  if (p[1] > maxY) maxY = p[1];
557  }
558 
559  for (unsigned int y = 0; y < imageHeight; y++) {
560  p = HomgPoint2D(0, y);
561  Undistort(p);
562  p = invK_ * p;
563  p.Homogenize();
564  if (p[0] < minX) minX = p[0];
565  if (p[0] > maxX) maxX = p[0];
566  if (p[1] < minY) minY = p[1];
567  if (p[1] > maxY) maxY = p[1];
568 
569  p = HomgPoint2D(imageWidth-1, y);
570  Undistort(p);
571  p = invK_ * p;
572  p.Homogenize();
573  if (p[0] < minX) minX = p[0];
574  if (p[0] > maxX) maxX = p[0];
575  if (p[1] < minY) minY = p[1];
576  if (p[1] > maxY) maxY = p[1];
577  }
578 
579  double focalLengthX = idealImageWidth_ / (maxX - minX);
580  double focalLengthY = idealImageHeight_ / (maxY - minY);
581  double principalX = -focalLengthX * minX;
582  double principalY = -focalLengthY * minY;
583 
584  K.SetIdentity();
585  K[0][0] = focalLengthX;
586  K[1][1] = focalLengthY;
587  K[0][1] = skew_;
588  K[0][2] = principalX;
589  K[1][2] = principalY;
590 }
591 
593 SetIdealImageSize(unsigned int width, unsigned int height)
594 {
595  idealImageWidth_ = width;
596  idealImageHeight_ = height;
597 }
598 
600 SetIntrinsics(double minPhi, double maxPhi,
601  double minTheta, double maxTheta,
602  double angleStep, double aspectratio)
603 {
604  bool wrongAngles = false;
605  wrongAngles = (minPhi <= -M_PI/2.0) || (maxPhi >= M_PI/2.0) || (minPhi>=maxPhi);
606  wrongAngles = wrongAngles || (minTheta <= 0) || (maxTheta >= M_PI)
607  || (minTheta>=maxTheta);
608  wrongAngles = wrongAngles || (angleStep<=0);
609  if(wrongAngles) {
610  BIASERR("invalid angle values");
611  return -1;
612  }
613 
614  //establish an spherical coordinate frame that interpretes
615  //angles like described in the docu:
616  // phi around the H-Axis relative to the A-Axis and
617  // theta relative to the -H-Axis.
618  //For this the internal base of the spherical frame
619  // has to be rotated around the V-Axis by -90Deg.
620  SphericalCoordinates sphericalCoord;
621  CoordinateTransform3D sphericalBase; // will contain the canonical (cartesian) base,
622  // since calculations are performed relative to the local camera frame
623  // only rotation mentioned above has to be applied:
624 
625  Quaternion<double> rot(0, -sin(M_PI_4), 0, cos(M_PI_4));
626  sphericalBase.RotateLocalFrame(rot);
627  sphericalCoord.SetAffineBase(sphericalBase);
628 
629  //first determine the minimal stepsize within the plane
630  double minStepSize = 0;
631  // there are three cases of interest:
632  // a. the principle point lies in the image
633  // b. the other case
634  bool ppIsInPhiRange = (minPhi<0) && (0<maxPhi);
635  bool ppIsInThetaRange = (minTheta<M_PI/2.0) && (M_PI/2.0<maxTheta);
636  //case a
637  if(ppIsInPhiRange && ppIsInThetaRange){
638  minStepSize = tan(angleStep);
639  } else {
640  //determine angles closest to the pp
641  double phiClose = (fabs(minPhi) < fabs(maxPhi)) ? minPhi : maxPhi;
642  double thetaClose = (fabs(minTheta-M_PI/2.0) < fabs(maxTheta-M_PI/2.0)) ? minTheta : maxTheta;
643  if(ppIsInPhiRange) phiClose = 0.0;
644  if(ppIsInThetaRange) thetaClose = M_PI/2.0;
645 
646  Vector3<double> p;
647  HomgPoint3D ray;
648  sphericalCoord.GetCartesianRayFromFullPhi(phiClose, thetaClose, ray);
649  ray.GetEuclidean(p);
650  p/=p[2]; //delivers point on plane since all is calculated in the local cam-frame,
651  //therefore this is now the closest point to the principle axis on the border of the image, within the plane
652  //at distance z=1.
653  double radius = sqrt(p[0]*p[0] + p[1]*p[1]);
654  double alpha = atan(radius);
655  minStepSize = tan(alpha + angleStep) - radius;
656  }
657 
658  double idealSampleDistanceX = minStepSize / sqrt( 1.0 + 1.0/(aspectratio*aspectratio) );
659  BIASASSERT(idealSampleDistanceX>0);
660  //upper left corner
661  Vector3<double> pUL;
662  HomgPoint3D rayUL;
663  sphericalCoord.GetCartesianRayFromFullPhi(minPhi, minTheta, rayUL);
664  rayUL.GetEuclidean(pUL);
665  pUL/=pUL[2];
666  // cerr<<pUL<<endl;
667 
668  //lower right corner
669  Vector3<double> pLR;
670  HomgPoint3D rayLR;
671  sphericalCoord.GetCartesianRayFromFullPhi(maxPhi, maxTheta, rayLR);
672  rayLR.GetEuclidean(pLR);
673  pLR/=pLR[2];
674  //cout<<pLR<<endl;
675  //cout<<" determining intrinsics \n";
676 
677  // minStepSize is the chosen equidistant stepsize within the image plane
678  // at distance of z=1. pUL and pLR code the diagonal corners, hence the
679  // visible image size on the image plane at z=1.
680  double widthInSpace = pLR[0] - pUL[0];
681  BIASASSERT(widthInSpace>0);
682  double heightInSpace = pLR[1] - pUL[1];
683  BIASASSERT(heightInSpace>0);
684 
685  unsigned int width = static_cast<unsigned int>(rint( ceil(widthInSpace/idealSampleDistanceX) ));
686  unsigned int height = static_cast<unsigned int>(rint( ceil(aspectratio*heightInSpace/idealSampleDistanceX) ));
687  SetImageSize(width, height);
688  skew_ = 0;
689  focallength_ = static_cast<double>(width)/widthInSpace;
690  double focallengthY = static_cast<double>(height)/heightInSpace;
691  aspectratio_ = focallengthY/focallength_;
692 
693  principalX_ = -focallength_*pUL[0] - 0.5;
694  principalY_ = -focallengthY*pUL[1] - 0.5;
695  ComputeK_();
696 
697  return 0;
698 }
699 
702  unsigned int imgWidth, unsigned int imgHeight)
703 {
704 
705  if(imgWidth <= 0 && imgHeight <= 0) {
706  return -1;
707  }
708 
709  // points must lie on a plane orthogonal to the image plane
710  if (p[2]!=q[2]) {
711  return -2;
712  }
713 
714  if (p[2]==0) {
715  return -3;
716  }
717 
718  p = p / p[2];
719  q = q / q[2];
720 
721  SetImageSize(imgWidth, imgHeight);
722  skew_ = 0;
723 
724  Vector2<double> a(0.5,0.5);
725  Vector2<double> b(imgWidth - 0.5,imgHeight - 0.5);
726 
727  double k = 0;
728 
729  if (p[0]!=0) {
730  principalX_ = (b[0]*p[0]-a[0]*q[0]) / (p[0]-q[0]);
731  focallength_ = (a[0]-principalX_) / p[0];
732  } else {
733  principalX_ = a[0];
734  focallength_ = (b[0] - principalX_) / q[0];
735  }
736 
737  if (p[1]!=0) {
738  principalY_ = (b[1]*p[1]-a[1]*q[1]) / (p[1]-q[1]);
739  k = (a[1]-principalY_) / p[1];
740  } else {
741  principalY_ = a[1];
742  k = (b[1] - principalY_) / q[1];
743  }
744 
745  aspectratio_ = k / focallength_;
746 
747  ComputeK_();
748 
749  return 0;
750 }
751 
753 GetIdealImageSize(unsigned int& width, unsigned int& height) const
754 {
755  width = idealImageWidth_;
756  height = idealImageHeight_;
757 }
758 
761  K_.SetIdentity();
762  K_[0][0] = focallength_;
763  K_[1][1] = aspectratio_ * focallength_;
764  K_[0][1] = skew_;
765  K_[0][2] = principalX_;
766  K_[1][2] = principalY_;
767  invK_ = K_.Invert();
768 }
769 
770 ////////////////////////////////////////////////////////////////////////////////////
773  unsigned w = cartesianDepth.GetWidth();
774  unsigned h = cartesianDepth.GetHeight();
775  unsigned c = cartesianDepth.GetChannelCount();
776 
777  if(polarDepth.IsEmpty()) polarDepth.Init(w,h,c);
778  else if(polarDepth.GetWidth() != w || polarDepth.GetHeight() != h) polarDepth.ReInit(w,h,c);
779 
780  float ** idaPol = polarDepth.GetImageDataArray();
781  const float ** idaCart = cartesianDepth.GetImageDataArray();
782 
783 // for(unsigned y=0;y<h;y++){
784 // for(unsigned x=0;x<w;x++){
785 // for(unsigned k=0;k<c;k++){
786 // idaPol[y][x*c+k] =
787 // TransformCartesianToPolarCoordinates(HomgPoint2D(x,y,1.0),idaCart[y][x*c+k]);
788 // }
789 // }
790 // }
791 
792  double px=0,py=0; GetPrincipal(px,py);
793  double fx=0,fy=0; GetFocalLength(fx); fy=fx*GetAspectratio();
794  for(unsigned y=0;y<h;y++){
795  for(unsigned x=0;x<w;x++){
796  float alpha = atan(float((x-px)/fx));
797  float beta = atan(float((py-y)/ sqrt( pow((x-px)*(fy/fx),2) + pow(fy,2))));
798 
799  for(unsigned k=0;k<c;k++){
800  idaPol[y][x*c+k] = idaCart[y][x*c+k]/(cos(alpha)*cos(beta));
801  }
802  }
803  }
804  return 0;
805 }
806 
808 TransformCartesianToPolarCoordinates(const HomgPoint2D& pos, const float depthCartesian){
809 
810 // Vector3<double> pl = UnProjectLocal(pos);
811 // BIASASSERT(!Equal(pl[2], 0.0));
812 // pl /= pl[2];
813 // return depthCartesian * pl.NormL2();
814 
815  double px=0,py=0; GetPrincipal(px,py);
816  double fx=0,fy=0; GetFocalLength(fx); fy=fx*GetAspectratio();
817 
818  float alpha = atan(float((pos[0]-px)/fx));
819  float beta = atan(float((py-pos[1])/ sqrt( pow((pos[0]-px)*(fy/fx),2) + pow(fy,2))));
820 
821  return depthCartesian/(cos(alpha)*cos(beta));
822 }
823 
824 ////////////////////////////////////////////////////////////////////////////////////
827  unsigned w = polarDepth.GetWidth();
828  unsigned h = polarDepth.GetHeight();
829  unsigned c = polarDepth.GetChannelCount();
830 
831  if(cartesianDepth.IsEmpty())
832  cartesianDepth.Init(w,h,c);
833  else if(cartesianDepth.GetWidth() != w || cartesianDepth.GetHeight() != h ||
834  cartesianDepth.GetChannelCount() != c)
835  cartesianDepth.ReInit(w,h,c);
836 
837  const float ** idaPol = polarDepth.GetImageDataArray();
838  float ** idaCart = cartesianDepth.GetImageDataArray();
839 
840 // for(unsigned y=0;y<h;y++){
841 // for(unsigned x=0;x<w;x++){
842 // for(unsigned k=0;k<c;k++){
843 // idaCart[y][x*c+k] =
844 // TransformPolarToCartesianCoordinates(HomgPoint2D(x,y,1.0),idaPol[y][x*c+k]);
845 // }
846 // }
847 // }
848 
849  double px=0,py=0; GetPrincipal(px,py);
850  double fx=0,fy=0; GetFocalLength(fx); fy=fx*GetAspectratio();
851  for(unsigned y=0;y<h;y++){
852  for(unsigned x=0;x<w;x++){
853  float alpha = atan(float((x-px)/fx));
854  float beta = atan(float((py-y)/ sqrt( pow((x-px)*(fy/fx),2) + pow(fy,2))));
855  for(unsigned k=0;k<c;k++){
856  idaCart[y][x*c+k] = cos(alpha)*cos(beta)*idaPol[y][x*c+k];
857  }
858  }
859  }
860  return 0;
861 }
862 
864 TransformPolarToCartesianCoordinates(const HomgPoint2D& pos, const float depthPolar){
865 //
866 // Vector3<double> ray;
867 // ray = UnProjectToRay(pos);
868 // ray.Normalize();
869 // ray.MultIP(depthPolar);
870 // return ray[2];
871 
872  double px=0,py=0; GetPrincipal(px,py);
873  double fx=0,fy=0; GetFocalLength(fx); fy=fx*GetAspectratio();
874  float alpha = atan(float((pos[0]-px)/fx));
875  float beta = atan(float((py-pos[1])/ sqrt( pow((pos[0]-px)*(fy/fx),2) + pow(fy,2))));
876  return cos(alpha)*cos(beta)*depthPolar;
877 }
878 /////////////////////////////////////////////////////////////////////////////////////
881  const ProjectionParametersPerspective *pPPP =
882  dynamic_cast<const ProjectionParametersPerspective* >(pPPB);
883  // different projection model has a very different view
884  if (pPPP==NULL) {
885  BIASERR("View difference for different projection models requested !");
886  return DBL_MAX;
887  }
888 
889  Vector3<double> C0 = pPPP->GetC(), A0, A;
890 
891  RMatrix R = GetR(), R0 = pPPP->GetR();
892 
893  A[0] = R[0][2]; A[1] = R[1][2]; A[2] = R[2][2];
894  A.Normalize();
895 
896  A0[0] = R0[0][2]; A0[1] = R0[1][2]; A0[2] = R0[2][2];
897  A0.Normalize();
898 
899  // compute field of view, assuming const K !
900  KMatrix K0 = GetK();
901  double f = 0.5*(K0[0][0] + K0[1][1]);
902  double halfw = double(width_ + height_) / 4.0;
903  double coshalffieldofview = cos(atan(halfw/f));
904 
905  double newness = (GetC()-C0).NormL2();
906  newness += 1.0/(1.0-coshalffieldofview)*(1.0-fabs(A.ScalarProduct(A0)));
907  return newness;
908 }
909 
910 
913  bool IgnoreDistortion, bool Normalize)
914 {
915  if (!IgnoreDistortion || Normalize){
917  UnProjectCovLocal(pos, cov2D, IgnoreDistortion, Normalize);
918  }
919  // cout << "goooooood\n";
920  // linear error propagation:
921  // the function for the point is given by pu = Ki * p
922  // and hence the Jacobian J is given by Ki
923  // the cov transforms by J * cov * J^T = Ki * cov * KiT
924  Matrix3x3<double> Ki = K_.Invert(), KiT = Ki.Transpose(), tmp, tmp2;
925 
926  Ki.Mult(cov2D, tmp);
927  tmp.Mult(KiT, tmp2);
928 
929  return tmp2;
930 }
931 
934 {
935 
936  minZlocal_ = 1e100; // 179.9... deg fov
937 
938  // run over all border pixels of image
939  PixelIterator it;
940  GetFirstBorderPixel(it);
941  do {
942  // compute ray in camera coordinate system
943  Vector3<double> ray, p;
944  UnProjectLocal(HomgPoint2D(it.x, it.y), p, ray);
945  BIASASSERT(Equal(ray.NormL2(), 1.0, 1e-8));
946  if (ray[2] < minZlocal_) {
947  minZlocal_ = ray[2];
948  }
949  } while (GetNextBorderPixel(it));
950  // add 3% safety margin
951  if (minZlocal_<1e-10) minZlocal_=1e-10;
952  else minZlocal_ *= 0.97;
953 
954  cout<<"maximum viewing angle of this camera is "
955  <<acos(minZlocal_)*180.0/M_PI<<" degrees"
956  <<endl;
957 }
958 
959 
960 
964  const double zFar,
965  const bool flip,
966  const bool transpose)
967 {
968 
969  Matrix4x4<double> projGL = GetGLProjectionMatrix(zNear, zFar, flip);
970  Matrix4x4<double> res;
971 
972  projGL.Mult(Pose_.GetMatrix4x4(), res);
973  if(transpose)
974  res.Transpose();
975  return res;
976 
977 }
978 
981 GetGLProjectionMatrix(const double zNear,
982  const double zFar,
983  const bool flip,
984  const bool transpose)
985 {
986  return GetGLProjectionMatrix(zNear, zFar, Vector2<unsigned int>(0,0), width_, height_, flip);
987 }
988 
991 GetGLProjectionMatrix(const double zNear,
992  const double zFar,
993  const Vector2<unsigned int> upperLeft,
994  const unsigned int width,
995  const unsigned int height,
996  const bool flip,
997  const bool transpose)
998 {
999  BIASASSERT(zNear<zFar);
1000  BIASASSERT(zNear>0.0);
1001 
1002  KMatrix K;
1003 
1004 // if (useIdealK) {
1005 // params.GetIdealK(K);
1006 // } else {
1007  K = GetK();
1008 // }
1009 
1010  Matrix4x4<double> embededK;
1011  embededK.SetZero();
1012  for(unsigned int i=0; i<3; i++) {
1013  for(unsigned int j=0; j<3; j++) {
1014  embededK[i][j] = K[i][j];//
1015  }
1016  //embededK[i][3] = K[i][2];//principle point
1017  }
1018  embededK[2][2] = 1;//propagating z to new z
1019  embededK[3][3] = 1;//propagating w to new w
1020 
1021  // std::cout<<"embededK = "<<embededK<<std::endl;
1022 
1023  const double x0 = static_cast<double>(upperLeft[0]);
1024  const double y0 = static_cast<double>(upperLeft[1]);
1025 
1026  Matrix4x4<double> normalizingK;
1027  normalizingK.SetZero();
1028  normalizingK[0][0] = 2.0/static_cast<double>(width); //kxx
1029  normalizingK[0][2] = (1.0 - 2.0*x0)/static_cast<double>(width) - 1.0; //kxz
1030  if(!flip) {
1031  normalizingK[1][1] = -2.0/static_cast<double>(height); //kyy
1032  normalizingK[1][2] = (2.0*y0-1.0)/static_cast<double>(height) + 1.0; //kyz
1033  } else {
1034  normalizingK[1][1] = 2.0/static_cast<double>(height); //kyy
1035  normalizingK[1][2] = (1.0-2.0*y0)/static_cast<double>(height) - 1.0; //kyz
1036  }
1037  normalizingK[2][2] = (zFar + zNear)/(zFar - zNear); //kzz
1038  normalizingK[2][3] = -(1+normalizingK[2][2])*zNear; //kzw
1039 
1040  normalizingK[3][2] = 1.0;
1041 
1042  // std::cout<<"normalizingK = "<<normalizingK<<std::endl;
1043 
1044  Matrix4x4<double> res = normalizingK*embededK;
1045  if(transpose) res.Transpose();
1046  return res;
1047 }
virtual BIAS::Vector3< double > GetC() const
Get projection center.
virtual HomgPoint2D ProjectLocal(const Vector3< double > &point, bool IgnoreDistortion=false) const
calculates the projection of a point in the camera coordinate system to a pixel in the image plane of...
void addAttribute(const xmlNodePtr Node, const std::string &AttributeName, bool AttributeValue)
Add an attribute to a node.
Definition: XMLIO.cpp:156
void GetEuclidean(Vector3< HOMGPOINT3D_TYPE > &dest) const
calculate affine coordinates of this and write them to dest affine coordinates are projective coordin...
Definition: HomgPoint3D.hh:336
int SetIntrinsics(double minPhi, double maxPhi, double minTheta, double maxTheta, double angleStep, double aspectratio=1.0)
Method calculates K-Matrix and image size from specified angles.
class HomgPoint2D describes a point with 2 degrees of freedom in projective coordinates.
Definition: HomgPoint2D.hh:67
virtual int XMLGetClassName(std::string &TopLevelTag, double &Version) const
specialization of XML block name function
bool IsEmpty() const
check if ImageData_ points to allocated image buffer or not
Definition: ImageBase.hh:245
virtual int XMLOut(const xmlNodePtr Node, XMLIO &XMLObject) const
Specialization of XML write function.
static std::string GetRadialDistModelString(BIAS_ProjParaPersp_DISTORTION_TYPE model)
camera parameters which define the mapping between rays in the camera coordinate system and pixels in...
virtual void SetPrincipal(const double x, const double y)
Set principal point in pixels relative to top left corner, virtual overload to recalculate K_...
xmlNodePtr getChild(const xmlNodePtr ParentNode, const std::string &ChildName)
Get a child of a Parent node by specifying the childs name, NULL is returned if the ParentNode has no...
Definition: XMLIO.cpp:489
void ScalarProduct(const Vector3< T > &argvec, T &result) const
scalar product (=inner product) of two vectors, storing the result in result
Definition: Vector3.hh:603
HomgPoint2D & Homogenize()
homogenize class data member elements to W==1 by divison by W
Definition: HomgPoint2D.hh:215
void RotateLocalFrame(const Quaternion< double > &Q)
Applies the passed rotation to the orientation of the local frame.
virtual const bool DoIntrinsicsDiffer(const ProjectionParametersBase *p) const
virtual int XMLIn(const xmlNodePtr Node, XMLIO &XMLObject)
specialization of XML read function
bool DoesPointProjectIntoImageLocal(const Vector3< double > &localX, HomgPoint2D &x, bool IgnoreDistortion=false) const
Checks if 3D point projects into specified image and returns belonging 2D image point.
virtual int GetMinimalAngularSamplingStep(double &minAngleStep)
Delivers the assumed minimal angular distance between two optical rays belonging to integer image coo...
void GetCartesianRayFromFullPhi(const double &phi, const double &theta, HomgPoint3D &ray) const
Calculates the Euclidean ray belonging to the passed angles in the world coordinate frame...
void SetAffineBase(const CoordinateTransform3D &newAffineBase)
Sets the &quot;local&quot; coordinate frame of the spherical coordinates.
unsigned int GetWidth() const
Definition: ImageBase.hh:312
void SetIdealImageSize(unsigned int width, unsigned int height)
virtual int XMLOut(const xmlNodePtr Node, XMLIO &XMLObject) const
specialization of XML write function
virtual int XMLIn(const xmlNodePtr Node, XMLIO &XMLObject)
Specialization of XML read function.
int DistortNormalized(BIAS::HomgPoint2D &point2d) const
Undistort distorted coordinates using the standard distortion parameters and the parameter describing...
3D rotation matrix
Definition: RMatrix.hh:49
std::string getAttributeValueString(const xmlAttrPtr Attribute) const
Definition: XMLIO.cpp:716
void SetZero()
Sets all values to zero.
Definition: Matrix.hh:856
Wrapper class for reading and writing XML files based on the XML library libxml2. ...
Definition: XMLIO.hh:72
virtual Matrix3x3< double > UnProjectCovLocal(const HomgPoint2D &pos, const Matrix3x3< double > &cov2D, bool IgnoreDistortion=false, bool Normalize=false)
unprojects the covariance matrices to K=Identity camera Fast implementation for IgnorDistortion = tru...
void Mult(const Vector3< T > &argvec, Vector3< T > &destvec) const
matrix - vector multiplicate this matrix with Vector3, storing the result in destvec calculates: dest...
Definition: Matrix3x3.hh:302
void ReInit(const unsigned int &width, const unsigned int &height, const unsigned int nChannels=1, const enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true, const EColorModel colormodel=CM_Grey)
(Re-)Initialize Image data if required.
Definition: ImageBase.cpp:131
xmlNodePtr addChildNode(const xmlNodePtr ParentNode, const std::string &NewNodeName)
Add a child node to an incoming node with the given name.
Definition: XMLIO.cpp:131
bool IsAtInfinity() const
Definition: HomgPoint2D.hh:165
virtual bool Distort(BIAS::HomgPoint2D &point2d) const
Using the Matlab camera calibration toolbox parameters for a distortion of undistorted coordinates...
void Mult(const Vector4< T > &argvec, Vector4< T > &destvec) const
matrix - vector multiplicate this matrix with Vector4, storing the result in destvec, calculates: destvec = (this Matrix) * argvec
Definition: Matrix4x4.hh:121
int GetMinimalAngleInCorner_(const HomgPoint2D &corner, double &minAngle)
Helper function for minimal angle step calculation.
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Definition: ImageBase.hh:382
unsigned int height_
height of image in pixels
int TransformCartesianToPolarCoordinates(const BIAS::Image< float > &cartesianDepth, BIAS::Image< float > &polarDepth)
transforms an image from cartesian coordinates to polar coordinates
unsigned int GetHeight() const
Definition: ImageBase.hh:319
virtual BIAS::RMatrix GetR() const
Get orientation as rotation matrix R.
Matrix4x4 Transpose() const
Definition: Matrix4x4.hh:315
virtual HomgPoint3D UnProjectToPointByZ(const HomgPoint2D &pos, const double &zDistance, bool IgnoreDistortion=false) const
HomgPoint3D UnProjectToImagePlane(const HomgPoint2D &pos, const double &depth=1.0, bool IgnoreDistortion=false) const
map points from image onto unit diameter image plane in 3D.
class HomgPoint3D describes a point with 3 degrees of freedom in projective coordinates.
Definition: HomgPoint3D.hh:61
Can be used to run along the image border.
void Init(unsigned int Width, unsigned int Height, unsigned int channels=1, enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true)
calls Init from ImageBase storageType is ignored, just dummy argument
Definition: Image.cpp:421
bool Equal(const T left, const T right, const T eps)
comparison function for floating point values See http://www.boost.org/libs/test/doc/components/test_...
virtual bool Undistort(BIAS::HomgPoint2D &point2d) const
Using the Matlab camera calibration toolbox parameters for an undistortion of distorted coordinates...
xmlAttrPtr getAttributeByName(const xmlNodePtr Node, const std::string &attribute_name)
search for a specific attribute
Definition: XMLIO.cpp:650
unsigned int width_
width of image in pixels
double x
If using BorderPixel methods these are the coordinates of the pixel.
double focallength_
focal length is stored in pixel for cellSizeX
Matrix3x3< T > Transpose() const
returns transposed matrix tested 12.06.2002
Definition: Matrix3x3.cpp:167
Matrix4x4< double > GetGLModelviewProjectionMatrix(const double zNear, const double zFar, const bool flip, const bool transpose=false)
Calculates an ModelViewProjection matrix useable in OpenGL.
double getAttributeValueDouble(const xmlAttrPtr Attribute) const
Definition: XMLIO.cpp:736
int TransformPolarToCartesianCoordinates(const BIAS::Image< float > &polarDepth, BIAS::Image< float > &cartesianDepth)
transforms an image from polar coordinates to cartesian coordinates
virtual const bool DoIntrinsicsDiffer(const ProjectionParametersBase *p) const
void UpdateMinZLocal()
run along image border and compute maximum field of view, save in minzlocal
K describes the mapping from world coordinates (wcs) to pixel coordinates (pcs).
Definition: KMatrix.hh:48
Transforms 3d points between two different coodinate systems, e.g.
Matrix4x4< double > GetGLProjectionMatrix(const double zNear, const double zFar, const bool flip, const bool transpose=false)
Calculates an projection matrix useable in OpenGL.
virtual Matrix3x3< double > UnProjectCovLocal(const HomgPoint2D &pos, const Matrix3x3< double > &cov2D, bool IgnoreDistortion=false, bool Normalize=false)
unprojects the covariance matrices to K=Identity camera
virtual void UnProjectLocal(const HomgPoint2D &pos, Vector3< double > &pointOnRay, Vector3< double > &direction, bool IgnoreDistortion=false) const
calculates the viewing ray from the camera center (in the camera coordinate system) which belongs to ...
void GetIdealImageSize(unsigned int &width, unsigned int &height) const
virtual int XMLGetClassName(std::string &TopLevelTag, double &Version) const
Specialization of XML block name function.
Camera parameters which define the mapping between rays in the camera coordinate system and pixels in...
void Set(const HOMGPOINT2D_TYPE &x, const HOMGPOINT2D_TYPE &y)
set elementwise with given 2 euclidean scalar values.
Definition: HomgPoint2D.hh:174
bool GetCutOutParameters(const Vector2< int > &centerPoint, const unsigned int halfWidth, const unsigned int halfHeight, ProjectionParametersPerspective &cutOutParams) const
Shifts the principle point so that imagePoint-(halfWidth, halfHeight) is mapped to (0...
Transformation between affine and spherical coordinates.
virtual double ViewDifference(const ProjectionParametersBase *pPPB) const
compute scalar dissimilarity between two cameras based upon rough approximation of field of view over...
Vector3< T > & Normalize()
normalize this vector to length 1
Definition: Vector3.hh:663
void ComputeK_()
computes the cached KMatrix and its inverse call after every parameter change
double kc1_
lens undistortion parameters after Bouquet also used as parameters for distortion after Brown(...
double NormL2() const
the L2 norm sqrt(a^2 + b^2 + c^2)
Definition: Vector3.hh:633
T Normalize()
divide this by biggest absolute entry, returns biggest entry
Definition: Matrix3x3.cpp:580
class BIASGeometryBase_EXPORT HomgPoint2D
class BIASGeometryBase_EXPORT HomgPoint3D
void SetIdentity()
set the elements of this matrix to the identity matrix (possibly overriding the inherited method) ...
Definition: Matrix3x3.hh:429
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
Definition: Image.hh:153