Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ProjectionParametersCylindric.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 #include "Geometry/ProjectionParametersCylindric.hh"
26 #include <Base/Common/CompareFloatingPoint.hh>
27 
28 using namespace std;
29 using namespace BIAS;
30 
31 
33 Distort(BIAS::HomgPoint2D& point2d) const
34 {
35  BIASERR("unfinished");
36  BIASABORT;
37  return false;
38 }
39 
42 {
43  BIASERR("unfinished");
44  BIASABORT;
45  return false;
46 }
47 
50 {
51  //normal coordinates are mapped into image as follows:
52  //(x, phi) -> ( x * focallengthX_ + principalX_,
53  // phi * focallengthPhi_ + principalY_)
54  focallengthX_ = double(width_)/(xMax_-xMin_);
55  //xMin_ is mapped to first column
56  principalX_ = (-1.0)*xMin_*focallengthX_;
57  focallengthPhi_ = double(height_)/(phiMax_-phiMin_);
58  //phiMin_ is mapped to first row
59  principalY_ = (-1.0)*phiMin_*focallengthPhi_;
60 }
61 
62 
65 {
66  xMin_ = (-1.0)*principalX_/focallengthX_;
67  xMax_ = double(width_)/focallengthX_ + xMin_;
68  phiMin_ = (-1.0)*principalY_/focallengthPhi_;
69  phiMax_ = double(height_)/focallengthPhi_ + phiMin_;
70 }
71 
72 
75  bool IgnoreDistortion) const
76 {
77 //if (!IgnoreDistortion) {
78 // BIASERR("Distortion is not implemented for cylindric projections!");
79 // BIASABORT;
80 //}
81 
82  HomgPoint2D res;
83  if (Equal(point.NormL2(), 0.0)) {
84  res.SetZero();
85  return res;
86  }
87 
88  // Translate and rotate point vector according to the cylinder's orientation
90  AxisRotationInv_.MultVec(point, p);
91  if (Equal(p[1], 0.0) && Equal(p[2], 0.0)) {
92  return HomgPoint2D(0, 0, 0);
93  }
94  if (UseAxisOffset_) {
95  // Calculate 3D intersection point of vector with cylinder hull
96  double a = p[2]*AxisOffsetInv_[2] + p[1]*AxisOffsetInv_[1];
97  double b = AxisOffsetInv_[2]*AxisOffsetInv_[2] +
98  AxisOffsetInv_[1]*AxisOffsetInv_[1];
99  double c = p[2]*p[2] + p[1]*p[1];
100  double scale = a/c + sqrt((a*a / c - b + 1.0) / c);
101  p = scale * p - AxisOffsetInv_;
102  } else {
103  // Calculate 3D intersection point of vector with cylinder hull
104  double scale = 1.0/sqrt(p[1]*p[1] + p[2]*p[2]);
105  p.MultIP(scale);
106  }
107  Vector2<double> xPhi;
108  ProjectToNormalizedCoords_(p, xPhi);
109 
110  // Calculate 2D coordinates of intersection point in cylinder hull image
111  res[0] = xPhi[0]*focallengthX_+principalX_;
112  res[1] = xPhi[1]*focallengthPhi_+principalY_;
113  res[2] = 1.0;
114  return res;
115 }
116 
117 
118 int ProjectionParametersCylindric::
119 ProjectLocal(const Vector3<double>& point, HomgPoint2D &p2d,
120  bool IgnoreDistortion) const
121 {
122  p2d = ProjectLocal(point, IgnoreDistortion);
123  return 0;
124 }
125 
126 
127 HomgPoint3D ProjectionParametersCylindric::
128 UnProjectToImagePlane(const HomgPoint2D& pos,
129  const double& depth,
130  bool IgnoreDistortion) const
131 {
132  Vector3<double> d, p;
133  UnProjectLocal(pos, p, d, IgnoreDistortion);
134  double radius = sqrt(d[2]*d[2] + d[1]*d[1]);
135  if (Equal(radius, 0.0))
136  return HomgPoint3D(0, 0, 0, 0);
137  d *= depth / radius;
138  if (Equal(d.NormL2(), 0.0))
139  return HomgPoint3D(0, 0, 0, 0);
140  HomgPoint3D local(d);
141  return Pose_.LocalToGlobal(local);
142 }
143 
144 
147  Vector3<double>& direction, bool IgnoreDistortion) const
148 {
149  // Normalize unprojected 3D point (resulting from 2D point pos) to length 1
150  direction = UnProjectToCylinderPoint(pos, IgnoreDistortion);
151  direction.Normalize();
152  pointOnRay = Vector3<double>(0.0);
153 }
154 
155 
157 UnProjectToPointLocal(const HomgPoint2D &pos, const double &depth,
158  bool IgnoreDistortion) const
159 {
160  Vector3<double> p, d;
161  UnProjectLocal(pos, p, d, IgnoreDistortion);
162  d *= depth;
163  return d;
164 }
165 
166 
169  bool IgnoreDistortion) const
170 {
171  // Calculate 3D point on hull of cylinder with radius 1 relative to
172  // the camera center, where 2D point given lies on cylinder hull image.
173  Vector3<double> p;
174  double phi;
175  p[0] = (pos[0]-principalX_)/focallengthX_;
176  phi = (pos[1]-principalY_)/focallengthPhi_;
177  p[1] = sin(phi);
178  p[2] = cos(phi);
179  // Rotate resulting vector according to the cylinder's orientation
180  Vector3<double> res;
181  AxisRotation_.MultVec(p, res);
182  // Translate according to cylinder's offset
183  if (UseAxisOffset_) {
184  res += AxisOffset_;
185  }
186  return res;
187 }
188 
189 
192 {
193  if (ProjectionParametersBase::DoIntrinsicsDiffer(p)) {
194  return true;
195  }
196  const ProjectionParametersCylindric* ppc =
197  dynamic_cast<const ProjectionParametersCylindric*>(p);
198  if (ppc == NULL) {
199  return true;
200  }
201  if (focallengthPhi_ != ppc->focallengthPhi_) {
202  return true;
203  }
204  if (focallengthX_ != ppc->focallengthX_) {
205  return true;
206  }
207  return false;
208 }
209 
210 
213  HomgPoint2D &p, bool IgnoreDistortion) const
214 {
215  p = ProjectLocal(localP, IgnoreDistortion);
216  p.Homogenize(); //neccessary ?
217  return (p[0] >= 0.0 && p[1] >= 0.0 &&
218  p[0] <= (double)(width_-1) && p[1] <= (double)(height_-1));
219 }
220 
221 
223 SetCylinderRotation(const Vector3<double> &rotAxis, double rotAngle,
224  const ProjectionCylinderAxisEnum axisType)
225 {
226  BIAS::Quaternion<double> rotation;
227  rotation.SetValueAsAxisRad(rotAxis, rotAngle);
228  SetCylinderRotation(rotation, axisType);
229 }
230 
231 
234  const ProjectionCylinderAxisEnum axisType)
235 {
236  AxisRotation_ = rotation;
237  if (axisType == AXIS_PARALLEL) {
238  BIAS::Quaternion<double> axisRot;
239  axisRot.SetValueAsAxisRad(Vector3<double>(0.0, -1.0, 0.0), 0.5*M_PI);
240  AxisRotation_.Mult(axisRot);
241  } else if (axisType != AXIS_ORTHOGONAL) {
242  BIASERR("ProjectionParametersCylindric::SetCylinderRotation(): "
243  "Invalid axis type given!");
244  }
245  AxisRotationInv_ = AxisRotation_.Inverse();
246  AxisRotationInv_.MultVec(AxisOffset_, AxisOffsetInv_);
247 }
248 
249 
252 {
253  if (axisType == AXIS_ORTHOGONAL) {
254  AxisRotation_.SetValueAsAxisRad(Vector3<double>(0.0, 1.0, 0.0), 0.0);
255  AxisRotationInv_ = AxisRotation_.Inverse();
256  AxisRotationInv_.MultVec(AxisOffset_, AxisOffsetInv_);
257  } else if (axisType == AXIS_PARALLEL) {
258  AxisRotation_.SetValueAsAxisRad(Vector3<double>(0.0, -1.0, 0.0), 0.5*M_PI);
259  AxisRotationInv_ = AxisRotation_.Inverse();
260  AxisRotationInv_.MultVec(AxisOffset_, AxisOffsetInv_);
261  } else {
262  BIASERR("ProjectionParametersCylindric::SetCylinderType(): "
263  "Invalid axis type given!");
264  }
265 }
266 
267 
270 {
271  AxisOffset_ = offset;
272  AxisRotationInv_.MultVec(AxisOffset_, AxisOffsetInv_);
273  UseAxisOffset_ = !(Equal(AxisOffset_.NormL2(), 0.0));
274 }
275 
276 
277 /** @brief Takes the difference of the cylinder centers weighted by
278  the cylinders' orientation difference to model the
279  view difference. Minimal difference 0 is achived, if
280  both cylinder coincide. Difference increases with cylinder
281  center distance |M0-M1| and cylinder axis angle difference.
282  */
285 {
286  const ProjectionParametersCylindric *pPPC =
287  dynamic_cast<const ProjectionParametersCylindric* >(pPPB);
288  // different projection model has a very different view
289  if (pPPC == NULL) {
290  BIASERR("View difference for different projection models requested !");
291  return DBL_MAX;
292  }
293  Vector3<double> C0 = pPPC->GetC();
294  Vector3<double> C1 = GetC();
295  RMatrix R0 = pPPC->GetR();
296  RMatrix R1 = GetR();
298  Vector3<double> V1 = R1*AxisRotation_.MultVec(Vector3<double>(0,0,1));
299  Vector3<double> M0 = C0 + V0 * 0.5*(pPPC->xMax_ - pPPC->xMin_);
300  Vector3<double> M1 = C1 + V1 * 0.5*(xMax_ - xMin_);
301  double phi = acos(V0.ScalarProduct(V1));
302  return (M0-M1).NormL2()*(1.0 - fabs(sin(phi)));
303 }
304 
305 
306 #ifdef BIAS_HAVE_XML2
307 
308 int ProjectionParametersCylindric::
309 XMLGetClassName(std::string &TopLevelTag, double &Version) const
310 {
311  TopLevelTag = "ProjectionParametersCylindric";
312  Version = 0.1;
313  return 0;
314 }
315 
316 
317 int ProjectionParametersCylindric::
318 XMLOut(const xmlNodePtr Node, XMLIO &XMLObject) const
319 {
320  xmlNodePtr theNode;
321  string TopLevelName;
322  double Version;
323  ProjectionParametersBase::XMLGetClassName(TopLevelName, Version);
324  theNode = XMLObject.addChildNode(Node, TopLevelName);
325  XMLObject.addAttribute(theNode, "Version", Version);
326  ProjectionParametersBase::XMLOut(theNode, XMLObject);
327 
328  // write "focal length" scale factors to xml
329  XMLObject.addAttribute(Node, "FocallengthX", focallengthX_);
330  XMLObject.addAttribute(Node, "FocallengthPhi", focallengthPhi_);
331 
332  // write cylinder rotation to xml
333  //XMLObject.addAttribute(Node, "CylinderAxisRotation",
334  // BIAS::Vector<double>(AxisRotation_).GetSTLVec());
335  // deprecated xml format for rotations, quaternion should be used instead!
336  double angle;
338  AxisRotation_.GetAxisAngle(axis, angle);
339  XMLObject.addAttribute(Node, "CylinderAxisRotAxis",
340  BIAS::Vector<double>(axis).GetSTLVec());
341  XMLObject.addAttribute(Node, "CylinderAxisRotAngle", angle);
342 
343  // write cylinder translation to xml
344  XMLObject.addAttribute(Node, "CylinderAxisTranslation",
345  BIAS::Vector<double>(AxisOffset_).GetSTLVec());
346 
347  return 0;
348 }
349 
350 
351 int ProjectionParametersCylindric::
352 XMLIn(const xmlNodePtr Node, XMLIO &XMLObject)
353 {
354  string TopLevelName;
355  double Version;
356  ProjectionParametersBase::XMLGetClassName(TopLevelName, Version);
357 
358  xmlNodePtr childNode = XMLObject.getChild(Node, TopLevelName);
359  if (!childNode) {
360  BIASERR("Error in XML, tag " << TopLevelName << " not found!");
361  return -1;
362  }
363  if (ProjectionParametersBase::XMLIn(childNode, XMLObject) != 0) return -1;
364 
365  // read "focal length" scale factors from xml
366  focallengthX_ = XMLObject.getAttributeValueDouble(Node, "FocallengthX");
367  focallengthPhi_ = XMLObject.getAttributeValueDouble(Node, "FocallengthPhi");
368 
369  // read cylinder rotation from xml
370  xmlAttrPtr quatAttr = XMLObject.getAttributeByName(Node, "CylinderAxisRotation");
371  if (quatAttr) {
372  std::vector<double> quat = XMLObject.getAttributeValueVecDbl(quatAttr);
373  BIASASSERT(quat.size() == 4);
374  SetCylinderRotation(Quaternion<double>(quat[0], quat[1], quat[2], quat[3]));
375  } else {
376  // deprecated xml format, quaternion should be used instead!
377  std::vector<double> axis =
378  XMLObject.getAttributeValueVecDbl(Node, "CylinderAxisRotAxis");
379  BIASASSERT(axis.size() == 3);
380  double angle = XMLObject.getAttributeValueDouble(Node, "CylinderAxisRotAngle");
381  SetCylinderRotation(Vector3<double>(axis[0], axis[1], axis[2]), angle);
382 //#ifdef BIAS_DEBUG
383 // Quaternion<double> quat;
384 // quat.SetValueAsAxisRad(Vector3<double>(axis[0], axis[1], axis[2]), angle);
385 // BIASWARN("Deprecated cylindric projection parameter XML format found!\n"
386 // << "Use quaternion " << quat << " instead of angle/axis representation "
387 // << "for orientation (" << angle << " rad around axis "
388 // << Vector3<double>(axis[0], axis[1], axis[2]) << ")!");
389 //#endif
390  }
391 
392  // read cylinder translation from xml
393  std::vector<double> offset =
394  XMLObject.getAttributeValueVecDbl(Node, "CylinderAxisTranslation");
395  BIASASSERT(offset.size() == 3);
396  SetCylinderOffset(Vector3<double>(offset[0], offset[1], offset[2]));
397 
398  UpdateFromQuasiK_();
399  return 0;
400 }
401 
402 #endif // BIAS_HAVE_XML2
virtual BIAS::Vector3< double > GetC() const
Get projection center.
virtual Vector3< double > UnProjectToPointLocal(const HomgPoint2D &pos, const double &depth, bool IgnoreDistortion=false) const
Calculates a 3D point in a local camera coordinate system specified by camSystem, which belongs to th...
void addAttribute(const xmlNodePtr Node, const std::string &AttributeName, bool AttributeValue)
Add an attribute to a node.
Definition: XMLIO.cpp:156
class HomgPoint2D describes a point with 2 degrees of freedom in projective coordinates.
Definition: HomgPoint2D.hh:67
virtual double ViewDifference(const ProjectionParametersBase *pPPB) const
Calculates difference of cylinder centers weighted with orientation angle up to now.
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 SetZero()
set all values to 0
Definition: Vector3.hh:559
bool DoesPointProjectIntoImageLocal(const BIAS::Vector3< double > &localP, HomgPoint2D &p, bool IgnoreDistortion=false) const
Checks if 3D point projects into specified image and returns belonging 2D image point.
double focallengthPhi_
quasi K (principle point already contained in base class)
int MultVec(const Vector3< QUAT_TYPE > &vec, Vector3< QUAT_TYPE > &res) const
rotates the given Vector qith the quaternion ( q v q* ) the resulting vector is given in res ...
Definition: Quaternion.hh:136
std::vector< double > getAttributeValueVecDbl(const xmlAttrPtr Attribute) const
Definition: XMLIO.cpp:747
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...
3D rotation matrix
Definition: RMatrix.hh:49
void SetCylinderOffset(const Vector3< double > &offset)
virtual bool Undistort(BIAS::HomgPoint2D &point2d) const
Interface defintion for lens undistortion function, implemented by derived classes.
Wrapper class for reading and writing XML files based on the XML library libxml2. ...
Definition: XMLIO.hh:72
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
Quaternion< double > AxisRotation_
Rotation of cylinder axis.
virtual BIAS::RMatrix GetR() const
Get orientation as rotation matrix R.
virtual const bool DoIntrinsicsDiffer(const ProjectionParametersBase *p) const
class HomgPoint3D describes a point with 3 degrees of freedom in projective coordinates.
Definition: HomgPoint3D.hh:61
void UpdateQuasiK_()
Uses normalized coordinate ranges and image dimensions to calculate internals.
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_...
xmlAttrPtr getAttributeByName(const xmlNodePtr Node, const std::string &attribute_name)
search for a specific attribute
Definition: XMLIO.cpp:650
Camera parameters which define the mapping between rays in the camera coordinate system and pixels in...
double getAttributeValueDouble(const xmlAttrPtr Attribute) const
Definition: XMLIO.cpp:736
virtual Vector3< double > UnProjectToCylinderPoint(const HomgPoint2D &pos, bool IgnoreDistortion=false) const
Calculates the 3D point on the cylinder hull local to the camera which belongs to the image position ...
void UpdateFromQuasiK_()
uses internal params to calculate normalized coordinate ranges.
void SetCylinderType(const ProjectionCylinderAxisEnum axisType)
virtual void UnProjectLocal(const HomgPoint2D &pos, Vector3< double > &pointOnRay, Vector3< double > &direction, bool IgnoreDistortion=false) const
Calculates the view ray, which belongs to the given position on the image plane, in local coordinates...
void SetCylinderRotation(const Vector3< double > &rotAxis, double rotAngle, const ProjectionCylinderAxisEnum axisType=AXIS_ORTHOGONAL)
Camera parameters which define the mapping between rays in the camera coordinate system and pixels in...
ProjectionCylinderAxisEnum
Enumeration of typical directions of the cylinder axis, i.e.
Vector3< T > & Normalize()
normalize this vector to length 1
Definition: Vector3.hh:663
double NormL2() const
the L2 norm sqrt(a^2 + b^2 + c^2)
Definition: Vector3.hh:633
void SetValueAsAxisRad(const Vector3< QUAT_TYPE > &axis, QUAT_TYPE angle)
sets the quaternion with given rotation axis and angle (in rad)
Definition: Quaternion.hh:183
virtual bool Distort(BIAS::HomgPoint2D &point2d) const
Interface defintion for lens distortion function, implemented by derived classes. ...