Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ProjectionParametersSphericalFast.hh
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 #ifndef __BIAS_ProjectionParametersSphericalFast_hh__
27 #define __BIAS_ProjectionParametersSphericalFast_hh__
28 #include "bias_config.h"
29 
30 #include <Base/Common/BIASpragmaStart.hh>
31 #include <Geometry/ProjectionParametersBase.hh>
32 #include <Geometry/ProjectionParametersPerspective.hh>
33 #include <MathAlgo/Interpolator.hh>
34 #include <Base/ImageUtils/BresenhamCircle.hh>
35 #include <MathAlgo/PolynomialSolve.hh>
36 
37 namespace BIAS {
38 
39  /** @class ProjectionParametersSphericalFast
40  * @ingroup g_geometry
41  @brief spherical camera that uses polynomial only and should therefore be faster
42  than other spherical camera
43  @author sedlazeck
44  */
45  class BIASGeometry_EXPORT ProjectionParametersSphericalFast:
47  public:
48 
49  ProjectionParametersSphericalFast(const unsigned int width = 0,
50  const unsigned int height = 0)
51  : ProjectionParametersBase(width, height) {
52  radius_=0;
53  maxCamAngle_=0;
54  // init polynomials as identity function
55  coeffsDist_.resize(5, 0.0);
56  coeffsDist_[0] = 1.0;
57  coeffsUndist_.resize(5, 0.0);
58  coeffsUndist_[0] = 1.0;
59  }
60 
61 
62  ProjectionParametersSphericalFast(const double radius,
63  const double maxAngle,
64  const unsigned int width,
65  const unsigned int height)
66  : ProjectionParametersBase(width, height) {
67  radius_=radius;
68  maxCamAngle_=maxAngle;
69  // init polynomials as identity function
70  coeffsDist_.resize(5, 0.0);
71  coeffsDist_[0] = 1.0;
72  coeffsUndist_.resize(5, 0.0);
73  coeffsUndist_[0] = 1.0;
74  }
75 
77  *this = P;
78  }
79 
83  radius_ = P.radius_;
84  maxCamAngle_ = P.maxCamAngle_;
85  coeffsDist_ = P.coeffsDist_;
86  coeffsUndist_ = P.coeffsUndist_;
87  return *this;
88  }
89 
91 
92  /** @brief call this to start a run at the outer boundary of an image.
93  *
94  * You get the first boundary position in it, e.g. (0,0) for a perspective
95  * image. Feed this into GetNextBorderPixel to get the next position.
96  * Special implmentation here, because we need to run around the FOV
97  * circle. NOT YET IMPLEMENTED, PLEASE DO !
98  */
99  virtual void GetFirstBorderPixel(PixelIterator& it);
100 
101  /** @brief call this iteratively to run at the outer boundary of an image.
102  *
103  * All returned coordinates must have valid local rays in the camera
104  * coordinate system (e.g. in fisheye cams, we run at the fov circle) and
105  * must be in the image. Two subsequent coordinates must not be more
106  * distant than 1 pixel. NOT YET IMPLEMENTED, PLEASE DO !
107  * @param it must be initialized by GetFirstBorderPixel
108  * @return false if the returned position closes the loop around the image
109  */
110  virtual bool GetNextBorderPixel(PixelIterator& it);
111 
112 
113  virtual const bool
114  DoIntrinsicsDiffer(const ProjectionParametersBase* p) const;
115 
116  virtual bool Distort(BIAS::HomgPoint2D& point2d) const;
117 
118  virtual bool Undistort(BIAS::HomgPoint2D& point2d) const;
119 
120 
121 
122  bool DoesPointProjectIntoImageLocal(const BIAS::Vector3<double>& localX,
123  HomgPoint2D& x,
124  bool IgnoreDistortion = false) const;
125 
126  /** @brief calculates the projection of a point in the local camera
127  coordinate system to a pixel in the image plane of the camera. The
128  only case when this function may not compute the 2d point is when the
129  camera center and the 3d point coincide. This case is indicated
130  by a return value of (0, 0, 0). In all other cases, a 2d point must be
131  computed, *particularily* when the 3d point is behind the camera
132  or when the resulting 2d point is at infinity.*/
134  bool IgnoreDistortion = false) const {
135  HomgPoint2D retVal_hom2D;
136  ProjectionParametersSphericalFast::ProjectLocal(point, retVal_hom2D, IgnoreDistortion);
137  return retVal_hom2D;
138  }
139 
140  /** @brief calculates the projection of a point in the local camera
141  coordinate system to a pixel in the image plane of the camera. The
142  only case when this function may not compute the 2d point is when the
143  camera center and the 3d point coincide. This case is indicated
144  by a return value of zero. In all other cases, a 2d point must be
145  computed, *particularily* when the 3d point is behind the camera
146  or when the resulting 2d point is at infinity.
147 
148  In the simplest case perspective pinhole projection x = K * point
149  where point is transformed of X using point = (R^T | -R^T C) X
150  @author woelk 08/2008 (c) www.vision-n.de */
151  virtual int ProjectLocal(const Vector3<double>& point, HomgPoint2D &p2d,
152  bool IgnoreDistortion = false) const;
153 
154  /** @brief map points from image onto unit diameter image plane in 3D.
155  * Chosen is the spherical image plane with radius of one from the
156  * image center.
157  */
158  HomgPoint3D UnProjectToImagePlane(const HomgPoint2D& pos,
159  const double& depth = 1.0,
160  bool IgnoreDistortion = false) const;
161 
162 
163  /** @brief calculates the viewing ray from the camera center (in the
164  camera coordinate system) which belongs to the image position pos
165  e.g. (0,0,1) means optical axis
166  */
167  virtual void
168  UnProjectLocal(const HomgPoint2D& pos, Vector3<double>& origin,
169  Vector3<double>& direction, bool IgnoreDistortion = false) const;
170 
171  /** @brief covariant virtual copy constructor for use in Projection */
173  return new ProjectionParametersSphericalFast(*this);
174  }
175 
176  /** @brief Return radius of spherical image in pixels. */
177  inline double GetRadius() const {
178  return radius_;
179  }
180 
181  /** @brief Set radius of spherical image in pixels. */
182  inline void SetRadius(const double r) {
183  radius_ = r;
184  }
185 
186  /** @brief Get maximal camera angle (in rad), i.e. azimuth angle of rays
187  corresponding to the outer rim of the image. */
188  inline double GetMaxCamAngle() const {
189  return maxCamAngle_;
190  }
191 
192  /** @brief Set maximal camera angle (in rad), i.e. azimuth angle of rays
193  corresponding to the outer rim of the image.
194  @param[in] maxCamAngle New maximal camera angle to set (in rad)
195  @attention If undistortion polynomial is set, it will be recalculated
196  with default sampling. Use RecalculateUndistortion instead
197  if you want to reset undistortion and max. camera angle
198  by yourself.
199  */
200  void SetMaxCamAngle(const double maxCamAngle);
201 
202  /** @brief Recalculate undistortion polynomial for new maximal camera angle.
203  @param[in] maxCamAngle New maximal camera angle to set (in rad)
204  @attention If new max. camera angle is larger than former, the
205  undistortion polynomial is extrapolated linearly beyond the
206  former range which may result in strange behaviour!
207  */
208  void RecalculateUndistortion(const double maxCamAngle);
209 
210  /** @brief Set undistortion polynomial from corresponding undistorted and
211  distorted azimuth angles (in rad) and image radius (in pixels).
212  @param[in] undistAngles Vector of undistorted azimuth angles (in rad)
213  @param[in] distAngles Vector of corresponding distorted angles
214  @param[in] radius Radius of spherical image to set (in pixels)
215  */
216  int SetUndistortion(const std::vector<double>& undistAngles,
217  const std::vector<double>& distAngles,
218  const double radius);
219 
220 
221  /** @brief Set undistortion polynomial from from polynomial coefficients
222  of undistortion (mapping radius to z coordinate) or distortion
223  (mapping theta to radius) function.
224  @param[in] maxCamAngle Maximal azimuth angle corresponding to the
225  outer rim of the spherical image
226  @param[in] coefficients Vector of polynomial coefficients to
227  estimate the undistortion polynomial from
228  @param[in] undistCoeffs Specifies if the given polynomial coefficients
229  describe the undistortion, or distortion.
230  */
231  int InitPolyCoeffs(const double maxCamAngle,
232  const std::vector<double>& coefficients,
233  const bool undistCoeffs = true);
234 
235  /** @brief Adapt internal parameters to resampled image.
236  @param ratio 2.0 = downsample by 2, 0.5 = upsample by 2
237  @param offset Offset for principal point (applied before down/upsampling!)
238  \attention Delivers only correct results if ratio is chosen
239  to rescale image size to integral image dimensions
240  in both directions. Image size is rounded!
241  */
242  virtual void Rescale(double ratio, const double offset = 0.0) {
243  ProjectionParametersBase::Rescale(ratio, offset);
244  radius_ /= ratio;
245  }
246 
247  virtual void Rescale(unsigned int width, unsigned int height){
248  unsigned int oldwidth = width_;
249  ProjectionParametersBase::Rescale(width, height);
250  radius_ /= ((double)oldwidth/(double)width_);
251  }
252 
253  virtual double ViewDifference(const ProjectionParametersBase* pPPB) const;
254 
255  /** @brief Returns a fake KMatrix for the fisheye camera.
256 
257  Uses MaxAngle_ to limit maxangle, then calls PPB::GetFakeK.
258  The FoV of the KMatrix is specified by maxangle (PI*80/180 for 160deg)
259  or the max fisheye angle, if this is <160deg.
260  @param resolution The resolution parameter influences the
261  Resolution of the perspective image that is represented by the camera.
262  0 - The perspective image has the same size as the fisheye image
263  1 - The perspective image has the same resolution as the fisheye
264  image in the center (highest resolution)
265  2 - The perspective image has the same resolution as the fisheye
266  image near the border (lowest resolution)
267  @param imgsize returns the image size
268  @param maxangle maximum theta in rad, e.g. (PI*80/180 for 160deg fov)
269  @author streckel 05/2006
270  */
271  virtual BIAS::KMatrix GetFakeKMatrix(double& imgsize, int resolution=0,
272  const double& maxangle = 1.4) const;
273 
274  /** @brief stupid reimplementation since this class does not inherit
275  function from base class (gcc) */
276  virtual BIAS::KMatrix GetFakeKMatrix(int resolution=0,
277  const double& maxangle = 1.4) const {
278  return ProjectionParametersBase::GetFakeKMatrix(resolution, maxangle);
279  }
280 
281  /** Calculates perspective camera with specified viewing angle and
282  * optical axis aligned with the optical ray corresponding to viewCenter
283  * in spherical camera.
284  * @param viewCenter pixel position in spherical image that is the
285  * center of the perspective cutout.
286  * @param perspHalfViewingAngle half field of view of the cutout in Degree
287  * @pp returning cutout parameters
288  * \returns false if perspective cut out could not be calculated.
289  * @author streckel 08/2006
290  */
291  bool GetPerspectiveCutOutParameters(const BIAS::HomgPoint2D& viewCenter,
292  const double perspHalfViewingAngleDEG,
294 
295  /** @brief calculates a 3D point in
296  a local camera coordinate system specified by camSystem, which
297  belongs to the image position pos in cam with distance depth to the
298  camera center cam. Overload to habe return value (0,0,0)
299  for undefined or out of image radius pixels.
300  @author streckel */
301  virtual Vector3<double> UnProjectToPointLocal(const HomgPoint2D& pos,
302  const double& depth,
303  bool IgnoreDistortion = false) const;
304 
305 
306  /** @brief Estimates undistortion polynomial mapping z coordinates to
307  radius according to Scaramuzza's Matlab toolbox.
308 
309  Scaramuzza's undistortion polynomial is a function z(radius) which
310  typically has a local extremum at radius = 0 and therefore can not
311  have a linear monomial.
312  @author koeser 04/2007
313  */
314  int EstimateUndistortionPolynomial(std::vector<double>& coefficients,
315  const unsigned int degree = 5);
316 
317  /** @brief Estimates distortion polynomial mapping angle theta to radius
318  according to Scaramuzza's Matlab toolbox.
319 
320  Scaramuzza's distortion polynomial is a function radius(theta) which
321  is usually close to linear for fisheye cameras and SHOULD therefore
322  have a linear monomial.
323  @author koeser 04/2007
324  */
325  int EstimateDistortionPolynomial(std::vector<double>& coefficients,
326  const unsigned int degree = 5);
327 
328  /** @brief Returns polynomial coefficients of angle correction polynomial
329  (aka undistortion polynomial) mapping distorted to undistorted
330  azimuth angles.
331  @param[out] coeffs Returns coefficients of undistortion polynomial
332  */
333  inline void GetPolyCoeffs(std::vector<double> &coeffsdist,
334  std::vector<double> &coeffsundist) const {
335  coeffsdist = coeffsDist_;
336  coeffsundist = coeffsUndist_;
337  }
338 
339  void TestPolynomialInversion();
340 
341 
342 #ifdef BIAS_HAVE_XML2
343  /** @brief specialization of XML block name function */
344  virtual int XMLGetClassName(std::string& TopLevelTag,
345  double& Version) const;
346 
347  /** @brief specialization of XML write function */
348  virtual int XMLOut(const xmlNodePtr Node, XMLIO& XMLObject) const;
349 
350  /** @brief specialization of XML read function */
351  virtual int XMLIn(const xmlNodePtr Node, XMLIO& XMLObject);
352 #endif
353 
354  friend std::ostream& operator<<(std::ostream &os,
356 
357  inline double EvaluatePolynomial(const double x,
358  const std::vector<double>& coeff) const {
359 
360 
361  register int n = (int)coeff.size() - 1;
362 
363  // std::cout << "evalPoly degree " << n << std::endl;
364 
365  double result = 0.0;
366  while (n>0){
367  result = (result + coeff[n])*x*x;
368  n--;
369  }
370  result = (result + coeff[0])*x;
371 
372  return result;
373  }
374 
375  int FitPolynomial(std::vector<double>& coefficients,
376  std::vector<double>& a,
377  std::vector<double>& b,
378  unsigned int degree);
379 
380  // long names to avoid global symbol clashes
381  std::vector<double> myvaluesPolynomial;
382  std::vector<double> mylocationsPolynomial;
383 
384  protected:
385 
386  /** @brief Transforms a coordinate pair of image coordinates x, y in the
387  uncalibrated spherical image, to a calibrated pair of polar coordinates
388  phi, theta.
389  @author Birger Streckel */
390  void TransfCoordImage2Sphere_ (const HomgPoint2D& Source,
391  double &theta, double &phi) const;
392 
393 
394 
395  /** @brief Transforms a calibrated pair of polar coordinates phi, theta
396  to a coordinate pair of image coordinates x, y in the uncalibrated
397  spherical image.
398  @author Birger Streckel */
399  void TransfCoordSphere2Image_ (double theta, double phi,
400  HomgPoint2D &Source) const;
401 
402 
403 
404  /** @brief theta and phi are periodic in 2*M_PI, if they are out of a
405  suitable range, try to find best equivalent angle by adding 2*l*M_PI
406  @return 0 on success, <0 indicates that at least one angle is invalid
407  @author koeser 10/2004 */
408  void EnforceNormalRange_(double& theta, double& phi) const;
409 
410 
411 
412 
413 
414 
415  // image radius if image is spherical
416  double radius_;
417 
418  // Maximum image angle of the fisheye camera = half the fov in rad
419  double maxCamAngle_;
420 
421  // these are the polynom coefficients
422  std::vector<double> coeffsDist_;
423  std::vector<double> coeffsUndist_;
424 
425 
426 
427  //bresenham-circle for running allong fov area
429 
430  //projects pixels outside the image onto the image border
431  void ProjectOutsidePositions_(int& posX, int& posY);
432 
433 
434  };
435 
436  /////////////// inline code ///////////////////////
437  inline std::ostream& operator<<(std::ostream &os,
439  {
440  os<<"ProjectionParametersSphericalFast:"<<std::endl;
441  os<<"Principal: "<<p.principalX_<< " " <<p.principalY_<<std::endl;
442  os<<"Radius: "<<p.radius_<<std::endl;
443  os<<"MaxCamAngle: "<<p.maxCamAngle_<<std::endl;
444  os<<"Coefficients:"<<std::endl;
445  for (unsigned int i=0; i<p.coeffsDist_.size(); i++) {
446  os<< "distortion coeff " << i << " " << p.coeffsDist_[i] <<std::endl;
447  }
448  for (unsigned int i=0; i<p.coeffsUndist_.size(); i++) {
449  os<< "undistortion coeff " << i << " " << p.coeffsUndist_[i] <<std::endl;
450  }
451 
452  return os;
453  }
454 
455 } // end namespace
456 
457 
458 #include <Base/Common/BIASpragmaEnd.hh>
459 
460 #endif
461 
virtual BIAS::KMatrix GetFakeKMatrix(double &imgsize, int resolution=0, const double &maxangle=1.4) const
Returns a fake KMatrix for the camera.
ProjectionParametersSphericalFast(const double radius, const double maxAngle, const unsigned int width, const unsigned int height)
class HomgPoint2D describes a point with 2 degrees of freedom in projective coordinates.
Definition: HomgPoint2D.hh:67
spherical camera that uses polynomial only and should therefore be faster than other spherical camera...
Scans a circle using Bresenham&#39;s integer arithmetic algorithm.
camera parameters which define the mapping between rays in the camera coordinate system and pixels in...
virtual void Rescale(double ratio, const double offset=0.0)
Adapt internal parameters to resampled image.
ProjectionParametersSphericalFast(const ProjectionParametersSphericalFast &P)
double GetRadius() const
Return radius of spherical image in pixels.
Wrapper class for reading and writing XML files based on the XML library libxml2. ...
Definition: XMLIO.hh:72
virtual BIAS::KMatrix GetFakeKMatrix(int resolution=0, const double &maxangle=1.4) const
stupid reimplementation since this class does not inherit function from base class (gcc) ...
virtual HomgPoint2D ProjectLocal(const Vector3< double > &point, bool IgnoreDistortion=false) const
calculates the projection of a point in the local camera coordinate system to a pixel in the image pl...
virtual ProjectionParametersSphericalFast * Clone() const
covariant virtual copy constructor for use in Projection
double EvaluatePolynomial(const double x, const std::vector< double > &coeff) const
class HomgPoint3D describes a point with 3 degrees of freedom in projective coordinates.
Definition: HomgPoint3D.hh:61
std::ostream & operator<<(std::ostream &os, const Array2D< T > &arg)
Definition: Array2D.hh:260
Can be used to run along the image border.
ProjectionParametersSphericalFast & operator=(const ProjectionParametersSphericalFast &P)
K describes the mapping from world coordinates (wcs) to pixel coordinates (pcs).
Definition: KMatrix.hh:48
void GetPolyCoeffs(std::vector< double > &coeffsdist, std::vector< double > &coeffsundist) const
Returns polynomial coefficients of angle correction polynomial (aka undistortion polynomial) mapping ...
double principalX_
principal point in pixel coordinates (one for all zoom settings)
void SetRadius(const double r)
Set radius of spherical image in pixels.
double GetMaxCamAngle() const
Get maximal camera angle (in rad), i.e.
virtual void Rescale(double ratio, const double offset=0.0)
Adapt internal parameters to resampled image.
Camera parameters which define the mapping between rays in the camera coordinate system and pixels in...
ProjectionParametersSphericalFast(const unsigned int width=0, const unsigned int height=0)
virtual void Rescale(unsigned int width, unsigned int height)
adapt internal parameters to new image size
virtual ProjectionParametersBase & operator=(const ProjectionParametersBase &p)