Main MRPT website > C++ reference
MRPT logo
CCamModel.h
Go to the documentation of this file.
00001 /* +---------------------------------------------------------------------------+
00002    |          The Mobile Robot Programming Toolkit (MRPT) C++ library          |
00003    |                                                                           |
00004    |                       http://www.mrpt.org/                                |
00005    |                                                                           |
00006    |   Copyright (C) 2005-2011  University of Malaga                           |
00007    |                                                                           |
00008    |    This software was written by the Machine Perception and Intelligent    |
00009    |      Robotics Lab, University of Malaga (Spain).                          |
00010    |    Contact: Jose-Luis Blanco  <jlblanco@ctima.uma.es>                     |
00011    |                                                                           |
00012    |  This file is part of the MRPT project.                                   |
00013    |                                                                           |
00014    |     MRPT is free software: you can redistribute it and/or modify          |
00015    |     it under the terms of the GNU General Public License as published by  |
00016    |     the Free Software Foundation, either version 3 of the License, or     |
00017    |     (at your option) any later version.                                   |
00018    |                                                                           |
00019    |   MRPT is distributed in the hope that it will be useful,                 |
00020    |     but WITHOUT ANY WARRANTY; without even the implied warranty of        |
00021    |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
00022    |     GNU General Public License for more details.                          |
00023    |                                                                           |
00024    |     You should have received a copy of the GNU General Public License     |
00025    |     along with MRPT.  If not, see <http://www.gnu.org/licenses/>.         |
00026    |                                                                           |
00027    +---------------------------------------------------------------------------+ */
00028 #ifndef CCamModel_H
00029 #define CCamModel_H
00030 
00031 #include <mrpt/utils/TCamera.h>
00032 #include <mrpt/system/os.h>
00033 #include <mrpt/vision/utils.h>
00034 #include <mrpt/math/lightweight_geom_data.h>
00035 
00036 namespace mrpt
00037 {
00038         namespace vision
00039         {
00040                 /** This class represent a pinhole camera model for Monocular SLAM and implements some associated Jacobians
00041                  *
00042                  *  The camera parameters are accessible in the public member CCamModel::cam
00043                  *
00044                  * - Versions:
00045                  *    - First version: By Antonio J. Ortiz de Galistea.
00046                  *    - 2009-2010: Rewritten by various authors.
00047                  *
00048                  * \sa mrpt::utils::TCamera, CMonoSlam, the application <a href="http://www.mrpt.org/Application:camera-calib-gui" >camera-calib-gui</a> for calibrating a camera
00049                  * \ingroup mrpt_vision_grp 
00050                  */
00051                 class VISION_IMPEXP  CCamModel : public mrpt::utils::CLoadableOptions
00052                 {
00053                 public:
00054                         mrpt::utils::TCamera cam;  //!< The parameters of a camera
00055 
00056                         /** Default Constructor */
00057                         CCamModel();
00058 
00059                         /** This method loads the options from a ".ini"-like file or memory-stored string list.
00060                          */
00061                         void  loadFromConfigFile(
00062                                 const mrpt::utils::CConfigFileBase      &source,
00063                                 const std::string               &section);
00064 
00065                         /** This method displays clearly all the contents of the structure in textual form, sending it to a CStream. */
00066                         void  dumpToTextStream( CStream         &out) const;
00067 
00068                         /** Constructor from a ini file
00069                          */
00070                         CCamModel(const mrpt::utils::CConfigFileBase &cfgIni);
00071 
00072                         /** Jacobian for undistortion the image coordinates */
00073                         void  jacob_undistor_fm(const mrpt::vision::TPixelCoordf &uvd, math::CMatrixDouble &J_undist);
00074 
00075                         /** Calculate the image coordinates undistorted
00076                          */
00077                         void jacob_undistor(const mrpt::vision::TPixelCoordf &p, mrpt::math::CMatrixDouble &J_undist );
00078 
00079                         /**     Return the pixel position distorted by the camera
00080                          */
00081                         void  distort_a_point(const mrpt::vision::TPixelCoordf &p, mrpt::vision::TPixelCoordf &distorted_p);
00082 
00083                         /**     Return the pixel position undistorted by the camera
00084                          *      The input values 'col' and 'row' will be replace for the new values (undistorted)
00085                          */
00086                         void  undistort_point(const mrpt::vision::TPixelCoordf &p, mrpt::vision::TPixelCoordf &undistorted_p);
00087 
00088                         /**     Return the (distorted) pixel position of a 3D point given in coordinates relative to the camera (+Z pointing forward, +X to the right)
00089                          * \sa unproject_3D_point
00090                      */
00091                         void  project_3D_point(const mrpt::math::TPoint3D &p3D, mrpt::vision::TPixelCoordf &distorted_p) const;
00092 
00093                         /**     Return the 3D location of a point (at a fixed distance z=1), for the given (distorted) pixel position
00094                          * \sa project_3D_point
00095                          * \note Of course, there is a depth ambiguity, so the returned 3D point must be considered a direction from the camera focus, or a vector, rather than a meaninful physical point.
00096                      */
00097                         void  unproject_3D_point(const mrpt::vision::TPixelCoordf &distorted_p, mrpt::math::TPoint3D &p3D) const;
00098 
00099                         /** Jacobian of the projection of 3D points (with distortion), as done in project_3D_point \f$ \frac{\partial h}{\partial y} \f$, evaluated at the point p3D (read below the full explanation)
00100 
00101                         We define \f$ h = (h_x ~ h_y) \f$ as the projected point in pixels (origin at the top-left corner),
00102                         and \f$ y=( y_x ~ y_y ~ y_z ) \f$ as the 3D point in space, in coordinates relative to the camera (+Z pointing forwards).
00103 
00104                         Then this method computes the 2x3 Jacobian:
00105 
00106                         \f[
00107                         \frac{\partial h}{\partial y} =  \frac{\partial h}{\partial u} \frac{\partial u}{\partial y}
00108                         \f]
00109 
00110                         With:
00111 
00112                         \f[
00113                         \frac{\partial u}{\partial y} =
00114                         \left( \begin{array}{ccc}
00115                          \frac{f_x}{y_z} &  0 & - y \frac{f_x}{y_z^2} \\
00116                          0 & \frac{f_y}{y_z} & - y \frac{f_y}{y_z^2} \\
00117                         \end{array} \right)
00118                         \f]
00119 
00120                         where \f$ f_x, f_y \f$ is the focal length in units of pixel sizes in x and y, respectively.
00121                         And, if we define:
00122 
00123                         \f[
00124                          f = 1+ 2  k_1  (u_x^2+u_y^2)
00125                         \f]
00126 
00127                         then:
00128 
00129                         \f[
00130                         \frac{\partial h}{\partial u} =
00131                         \left( \begin{array}{cc}
00132                          \frac{ 1+2 k_1 u_y^2 }{f^{3/2}}  &  -\frac{2 u_x u_y k_1 }{f^{3/2}} \\
00133                          -\frac{2 u_x u_y k_1 }{f^{3/2}}  & \frac{ 1+2 k_1 u_x^2 }{f^{3/2}}
00134                         \end{array} \right)
00135                         \f]
00136 
00137                         \note JLBC: Added in March, 2009. Should be equivalent to Davison's WideCamera::ProjectionJacobian
00138                         \sa project_3D_point
00139                         */
00140                         void jacobian_project_with_distortion(const mrpt::math::TPoint3D &p3D, math::CMatrixDouble & dh_dy ) const;
00141 
00142 
00143                         /** Jacobian of the unprojection of a pixel (with distortion) back into a 3D point, as done in unproject_3D_point \f$ \frac{\partial y}{\partial h} \f$, evaluated at the pixel p
00144                         \note JLBC: Added in March, 2009. Should be equivalent to Davison's WideCamera::UnprojectionJacobian
00145                         \sa unproject_3D_point
00146                         */
00147                         void jacobian_unproject_with_distortion(const mrpt::vision::TPixelCoordf &p, math::CMatrixDouble & dy_dh ) const;
00148 
00149                         template<typename T> struct CameraTempVariables {
00150                                 T x_,y_;
00151                                 T x_2,y_2;
00152                                 T R;
00153                                 T K;
00154                                 T x__,y__;
00155                         };
00156                         template<typename T,typename POINT> void getTemporaryVariablesForTransform(const POINT &p,CameraTempVariables<T> &v) const      {
00157                                 v.x_=p[1]/p[0];
00158                                 v.y_=p[2]/p[0];
00159                                 v.x_2=square(v.x_);
00160                                 v.y_2=square(v.y_);
00161                                 v.R=v.x_2+v.y_2;
00162                                 v.K=1+v.R*(cam.k1()+v.R*(cam.k2()+v.R*cam.k3()));
00163                                 T xy=v.x_*v.y_,p1=cam.p1(),p2=cam.p2();
00164                                 v.x__=v.x_*v.K+2*p1*xy+p2*(3*v.x_2+v.y_2);
00165                                 v.y__=v.y_*v.K+p1*(v.x_2+3*v.y_2)+2*p2*xy;
00166                         }
00167 
00168                         template<typename T,typename POINT,typename PIXEL> inline void getFullProjection(const POINT &pIn,PIXEL &pOut) const    {
00169                                 CameraTempVariables<T> tmp;
00170                                 getTemporaryVariablesForTransform(pIn,tmp);
00171                                 getFullProjectionT(tmp,pOut);
00172                         }
00173 
00174                         template<typename T,typename PIXEL> inline void getFullProjectionT(const CameraTempVariables<T> &tmp,PIXEL &pOut) const {
00175                                 pOut[0]=cam.fx()*tmp.x__+cam.cx();
00176                                 pOut[1]=cam.fy()*tmp.y__+cam.cy();
00177                         }
00178 
00179                         template<typename T,typename POINT,typename MATRIX> inline void getFullJacobian(const POINT &pIn,MATRIX &mOut) const    {
00180                                 CameraTempVariables<T> tmp;
00181                                 getTemporaryVariablesForTransform(pIn,tmp);
00182                                 getFullJacobianT(pIn,tmp,mOut);
00183                         }
00184 
00185                         template<typename T,typename POINT,typename MATRIX> void getFullJacobianT(const POINT &pIn,const CameraTempVariables<T> &tmp,MATRIX &mOut) const        {
00186                                 T x_=1/pIn[0];
00187                                 T x_2=square(x_);
00188                                 //First two jacobians...
00189                                 CMatrixFixedNumeric<T,3,3> J21;
00190                                 T tmpK=2*(cam.k1()+tmp.R*(2*cam.k2()+3*tmp.R*cam.k3()));
00191                                 T tmpKx=tmpK*tmp.x_;
00192                                 T tmpKy=tmpK*tmp.y_;
00193                                 T yx2=-pIn[1]*x_2;
00194                                 T zx2=-pIn[2]*x_2;
00195                                 J21.set_unsafe(0,0,yx2);
00196                                 J21.set_unsafe(0,1,x_);
00197                                 J21.set_unsafe(0,2,0);
00198                                 J21.set_unsafe(1,0,zx2);
00199                                 J21.set_unsafe(1,1,0);
00200                                 J21.set_unsafe(1,2,x_);
00201                                 J21.set_unsafe(2,0,tmpKx*yx2+tmpKy*zx2);
00202                                 J21.set_unsafe(2,1,tmpKx*x_);
00203                                 J21.set_unsafe(2,2,tmpKy*x_);
00204                                 //Last two jacobians...
00205                                 T pxpy=2*(cam.p1()*tmp.x_+cam.p2()*tmp.y_);
00206                                 T p1y=cam.p1()*tmp.y_;
00207                                 T p2x=cam.p2()*tmp.x_;
00208                                 CMatrixFixedNumeric<T,2,3> J43;
00209                                 T fx=cam.fx(),fy=cam.fy();
00210                                 J43.set_unsafe(0,0,fx*(tmp.K+2*p1y+6*p2x));
00211                                 J43.set_unsafe(0,1,fx*pxpy);
00212                                 J43.set_unsafe(0,2,fx*tmp.x_);
00213                                 J43.set_unsafe(1,0,fy*pxpy);
00214                                 J43.set_unsafe(1,1,fy*(tmp.K+6*p1y+2*p2x));
00215                                 J43.set_unsafe(1,2,fy*tmp.y_);
00216                                 mOut.multiply(J43,J21);
00217                                 //cout<<"J21:\n"<<J21<<"\nJ43:\n"<<J43<<"\nmOut:\n"<<mOut;
00218                         }
00219                 private:
00220                         //These functions are little tricks to avoid multiple initialization.
00221                         //They are intended to initialize the common parts of the jacobians just once,
00222                         //and not in each iteration.
00223                         //They are mostly useless outside the scope of this function.
00224                         CMatrixFixedNumeric<double,2,2> firstInverseJacobian() const    {
00225                                 CMatrixFixedNumeric<double,2,2> res;
00226                                 res.set_unsafe(0,1,0);
00227                                 res.set_unsafe(1,0,0);
00228                                 return res;
00229                         }
00230                         CMatrixFixedNumeric<double,4,2> secondInverseJacobian() const   {
00231                                 CMatrixFixedNumeric<double,4,2> res;
00232                                 res.set_unsafe(0,0,1);
00233                                 res.set_unsafe(0,1,0);
00234                                 res.set_unsafe(1,0,0);
00235                                 res.set_unsafe(1,1,1);
00236                                 return res;
00237                         }
00238                         CMatrixFixedNumeric<double,3,4> thirdInverseJacobian() const    {
00239                                 CMatrixFixedNumeric<double,3,4> res;
00240                                 res.set_unsafe(0,1,0);
00241                                 res.set_unsafe(0,2,0);
00242                                 res.set_unsafe(1,0,0);
00243                                 res.set_unsafe(1,2,0);
00244                                 res.set_unsafe(2,0,0);
00245                                 res.set_unsafe(2,1,0);
00246                                 res.set_unsafe(2,2,1);
00247                                 res.set_unsafe(2,3,0);
00248                                 return res;
00249                         }
00250                 public:
00251                         template<typename POINTIN,typename POINTOUT,typename MAT22> void getFullInverseModelWithJacobian(const POINTIN &pIn,POINTOUT &pOut,MAT22 &jOut) const   {
00252                                 //Temporary variables (well, there are some more, but these are the basics)
00253                                 //WARNING!: this shortcut to avoid repeated initialization makes the method somewhat
00254                                 //faster, but makes it incapable of being used in more than one thread
00255                                 //simultaneously!
00256                                 static CMatrixFixedNumeric<double,2,2> J1(firstInverseJacobian());
00257                                 static CMatrixFixedNumeric<double,4,2> J2(secondInverseJacobian());
00258                                 static CMatrixFixedNumeric<double,3,4> J3(thirdInverseJacobian());
00259                                 static CMatrixFixedNumeric<double,2,3> J4;      //This is not initialized in a special way, although declaring it
00260                                 CArray<double,4> tmp1;
00261                                 CArray<double,2> tmp2;  //This would be a CArray<double,3>, but to avoid copying, we let "R2" lie in tmp1.
00262                                 //Camera Parameters
00263                                 double cx=cam.cx(),cy=cam.cy(),ifx=1/cam.fx(),ify=1/cam.fy();
00264                                 double K1=cam.k1(),K2=cam.k2(),p1=cam.p1(),p2=cam.p2(),K3=cam.k3();
00265                                 //First step: intrinsic matrix.
00266                                 tmp1[0]=(pIn[0]-cx)*ifx;
00267                                 tmp1[1]=(pIn[1]-cy)*ify;
00268                                 J1.set_unsafe(0,0,ifx);
00269                                 J1.set_unsafe(1,1,ify);
00270                                 //Second step: adding temporary variables, related to the distortion.
00271                                 tmp1[2]=square(tmp1[0])+square(tmp1[1]);
00272                                 double sK1=square(K1);
00273                                 double K12=sK1-K2;
00274                                 double K123=-K1*sK1+2*K1*K2-K3; //-K1³+2K1K2-K3
00275                                 //tmp1[3]=1-K1*tmp1[2]+K12*square(tmp1[2]);
00276                                 tmp1[3]=1+tmp1[2]*(-K1+tmp1[2]*(K12+tmp1[2]*K123));
00277                                 J2.set_unsafe(2,0,2*tmp1[0]);
00278                                 J2.set_unsafe(2,1,2*tmp1[1]);
00279                                 double jTemp=-2*K1+4*tmp1[2]*K12+6*square(tmp1[2])*K123;
00280                                 J2.set_unsafe(3,0,tmp1[0]*jTemp);
00281                                 J2.set_unsafe(3,1,tmp1[1]*jTemp);
00282                                 //Third step: radial distortion. Really simple, since most work has been done in the previous step.
00283                                 tmp2[0]=tmp1[0]*tmp1[3];
00284                                 tmp2[1]=tmp1[1]*tmp1[3];
00285                                 J3.set_unsafe(0,0,tmp1[3]);
00286                                 J3.set_unsafe(0,3,tmp1[0]);
00287                                 J3.set_unsafe(1,1,tmp1[3]);
00288                                 J3.set_unsafe(1,3,tmp1[1]);
00289                                 //Fourth step: tangential distorion. A little more complicated, but not much more.
00290                                 double prod=tmp2[0]*tmp2[1];
00291                                 //References to tmp1[2] are not errors! That element is "R2".
00292                                 pOut[0]=tmp2[0]-p1*prod-p2*(tmp1[2]+2*square(tmp2[0]));
00293                                 pOut[1]=tmp2[1]-p1*(tmp1[2]+2*square(tmp2[1]))-p2*prod;
00294                                 J4.set_unsafe(0,0,1-p1*tmp2[1]-4*p2*tmp2[0]);
00295                                 J4.set_unsafe(0,1,-p1*tmp2[0]);
00296                                 J4.set_unsafe(0,2,-p2);
00297                                 J4.set_unsafe(1,0,-p2*tmp2[1]);
00298                                 J4.set_unsafe(1,1,1-4*p1*tmp2[1]-p2*tmp2[0]);
00299                                 J4.set_unsafe(1,2,-p1);
00300                                 //As fast as possible, and without more temporaries, let the jacobian be J4*J3*J2*J1;
00301                                 jOut.multiply_ABC(J4,J3,J2);    //Note that using the other order is not possible due to matrix sizes (jOut may, and most probably will, be fixed).
00302                                 jOut.multiply(jOut,J1);
00303                         }
00304 
00305                 }; // end class
00306 
00307         } // end namespace
00308 } // end namespace
00309 #endif //__CCamModel_H



Page generated by Doxygen 1.7.5 for MRPT 0.9.5 SVN: at Thu Oct 13 21:25:36 UTC 2011