GSoC2011SfM  0.1
Google Summer of Code 2011: Structure from motion
D:/Travail/These/Determination caracteristiques camera/GSoC/SfM/src/CameraPinhole.cpp
00001 #include "CameraPinhole.h"
00002 
00003 using std::vector;
00004 using cv::Mat;
00005 using cv::Vec2d;
00006 using cv::Vec3d;
00007 using cv::Vec4d;
00008 using cv::Range;
00009 
00010 namespace OpencvSfM{
00011 
00012   CameraPinhole::CameraPinhole( cv::Mat intra_params/*=Mat::eye( 3, 3, CV_64F )*/,
00013      int img_w, int img_h,
00014     unsigned char wantedEstimation/*=FOCAL_PARAM|SKEW_PARAM|PRINCIPAL_POINT_PARAM*/ )
00015     :Camera( img_w, img_h)
00016   {
00017     CV_DbgAssert( intra_params.rows==3 && intra_params.cols==3 );
00018 
00019     intra_params.convertTo( this->intra_params_,CV_64F );
00020     this->inv_intra_params_ = intra_params.inv( );
00021     this->estimation_needed_ = wantedEstimation;
00022   }
00023 
00024   CameraPinhole::CameraPinhole(
00025     const std::vector< std::vector< cv::Point3f > >& objectPoints,
00026     const std::vector< std::vector<cv::Point2f > >& imagePoints,
00027     cv::Size imageSize, double aspectRatio/*=1.*/,
00028     int img_w, int img_h, unsigned char wantedEstimation )
00029     :Camera( img_w, img_h)
00030   {
00031     Mat intra=initCameraMatrix2D( objectPoints,imagePoints,imageSize,aspectRatio );
00032     //to be sure that newParams has correct type:
00033     intra.convertTo( this->intra_params_,CV_64F );
00034     this->inv_intra_params_ = intra_params_.inv( );
00035     this->estimation_needed_ = wantedEstimation;
00036   }
00037   CameraPinhole::~CameraPinhole( )
00038   {
00039     //TODO
00040   }
00041 
00042   uchar CameraPinhole::getNbMissingParams( ) const
00043   {
00044     int nbParams = 0;
00045     if( (estimation_needed_ & FOCAL_PARAM) != 0 )
00046       nbParams += 2;//2 focals
00047     if( (estimation_needed_ & SKEW_PARAM) != 0 )
00048       nbParams += 1;//1 param
00049     if( (estimation_needed_ & PRINCIPAL_POINT_PARAM) != 0 )
00050       nbParams += 2;//2 coord of principal point...
00051     return nbParams;
00052   }
00053 
00054   void CameraPinhole::updateIntrinsic( double* values, uchar nbVal, bool add )
00055   {
00056     if( !add )
00057       intra_params_ = Mat::zeros( 3, 3, CV_64F);
00058 
00059     double* ptrIntraParam=( double* )intra_params_.data;
00060     ptrIntraParam[ 8 ] = 1.0;
00061     if( nbVal >= 1 )
00062     {
00063       ptrIntraParam[ 0 ] += values[ 0 ];
00064       if( nbVal >= 3 )
00065       {
00066         ptrIntraParam[ 2 ] += values[ 1 ];
00067         ptrIntraParam[ 5 ] += values[ 2 ];
00068         if( nbVal >= 4 )
00069         {
00070           ptrIntraParam[ 4 ] = ptrIntraParam[ 0 ] * values[ 3 ];
00071           if( nbVal >= 5 )
00072           {
00073             ptrIntraParam[ 1 ] += values[ 4 ];
00074           }
00075         }
00076       }
00077     }
00078     this->inv_intra_params_ = intra_params_.inv( );
00079   }
00080 
00081   void CameraPinhole::updateIntrinsicMatrix( cv::Mat newParams,
00082     unsigned char intraValues/*=FOCAL_PARAM|SKEW_PARAM|PRINCIPAL_POINT_PARAM*/ )
00083   {
00084 
00085     CV_DbgAssert( !newParams.empty( ) || ( newParams.rows==3 ) || ( newParams.cols==3 ) );
00086     //to be sure that newParams has correct type:
00087     Mat correctMat;
00088     newParams.convertTo( correctMat,CV_64F );
00089 
00090     //now we can access to element using double array:
00091     double* ptrData=( double* )correctMat.data;
00092     double* ptrIntraParam=( double* )intra_params_.data;
00093 
00094     //first focal values:
00095     if( intraValues&FOCAL_PARAM )
00096     {
00097       ptrIntraParam[ 0 ]=ptrData[ 0 ];
00098       ptrIntraParam[ 4 ]=ptrData[ 4 ];
00099     }
00100     //skew param:
00101     if( intraValues&SKEW_PARAM )
00102       ptrIntraParam[ 1 ]=ptrData[ 1 ];
00103 
00104     //and principal point:
00105     if( intraValues&PRINCIPAL_POINT_PARAM )
00106     {
00107       ptrIntraParam[ 2 ]=ptrData[ 2 ];
00108       ptrIntraParam[ 5 ]=ptrData[ 5 ];
00109     }
00110   }
00111 
00112   vector<Vec4d> CameraPinhole::convertFromImageTo3Dray( std::vector< cv::Vec3d > points )
00113   {
00114     //TODO
00115     return vector<Vec4d>( );
00116   }
00117 
00118   vector<Vec2d> CameraPinhole::pixelToNormImageCoordinates( std::vector< cv::Vec2d > points ) const
00119   {
00120     vector<Vec2d> newCoordinates;
00121     double* ptrIntraParam=( double* )inv_intra_params_.data;
00122     //for each 2D point, use inv_intra to compute 2D point:
00123     vector<Vec2d>::iterator point=points.begin( );
00124     while( point!=points.end( ) )
00125     {
00127       //Can be done using matrix multiplication like this:
00129       /*
00130       Vec3d pointNorm( (*point )[ 0 ],( *point )[ 1 ],1 );
00131       Mat pointNormImageCoordinate=inv_intra_params_ * Mat( pointNorm );
00132       double * dataPointImageCoordinate = ( double * ) pointNormImageCoordinate.data;
00133       Vec2d point2D( dataPointImageCoordinate[ 0 ]/dataPointImageCoordinate[ 2 ],
00134         dataPointImageCoordinate[ 1 ]/dataPointImageCoordinate[ 2 ] );
00135       newCoordinates.push_back( point2D );
00136       */
00137 
00139       //But this is faster ( as intra matrix has only 5 values ) :
00140       newCoordinates.push_back( Vec2d( ptrIntraParam[ 0 ] * ( *point )[ 0 ] + ptrIntraParam[ 1 ] * ( *point )[ 1 ] + ptrIntraParam[ 2 ],
00141         ptrIntraParam[ 4 ] * ( *point )[ 1 ] + ptrIntraParam[ 5 ] ));
00142 
00143       point++;
00144     }
00145     return newCoordinates;
00146   }
00147 
00148   vector<Vec2d> CameraPinhole::normImageToPixelCoordinates( std::vector< cv::Vec2d > points ) const
00149   {
00150     vector<Vec2d> newCoordinates;
00151     //for each 2D point, use intra params to compute 2D point:
00152     double* ptrIntraParam=( double* )intra_params_.data;
00153 
00154     vector<Vec2d>::iterator point=points.begin( );
00155     while( point!=points.end( ) )
00156     {
00158       //Same as pixelToNormImageCoordinates, faster than using matrix multiplication:
00159       newCoordinates.push_back( Vec2d( (ptrIntraParam[ 0 ] * ( *point )[ 0 ] + ptrIntraParam[ 1 ] * ( *point )[ 1 ] + ptrIntraParam[ 2 ]) / ptrIntraParam[ 8 ],
00160         (ptrIntraParam[ 4 ] * ( *point )[ 1 ] + ptrIntraParam[ 5 ] ) / ptrIntraParam[ 8 ]));
00161 
00162       point++;
00163     }
00164     return newCoordinates;
00165   }
00166 
00167   double CameraPinhole::getFocal( ) const
00168   {
00169     Mat x1 = Mat::zeros( 3, 1, CV_64F );
00170     Mat x2 = Mat::zeros( 3, 1, CV_64F );
00171     x1.at<double>( 0,0 ) = intra_params_.at<double>( 0,2 );
00172     x1.at<double>( 1,0 ) = intra_params_.at<double>( 1,2 );
00173     x1.at<double>( 2,0 ) = 1.0;
00174     x2.at<double>( 0,0 ) = 0;
00175     x2.at<double>( 1,0 ) = 0;
00176     x2.at<double>( 2,0 ) = 1.0;
00177     Mat omega = ( intra_params_ * intra_params_.t( ) ).inv( );
00178 
00179     double upDivision = ( (Mat )( x1.t( ) * omega * x2 )).at<double>( 0,0 );
00180     double tmpDown1 = ( (Mat )( x1.t( ) * omega * x1 )).at<double>( 0,0 );
00181     double tmpDown2 = ( (Mat )( x2.t( ) * omega * x2 )).at<double>( 0,0 );
00182     tmpDown1 = sqrt( tmpDown1 );
00183     tmpDown2 = sqrt( tmpDown2 );
00184 
00185     double cosAngle = upDivision / ( tmpDown1 * tmpDown2 );
00186     double angle = acos( cosAngle );
00187 
00188     //instead of computing the focal using distance in pixels,
00189     //we use the distance in camera's coordinates:
00190     double origin_x = inv_intra_params_.at<double>( 0,2 ),
00191       origin_y = inv_intra_params_.at<double>( 1,2 );
00192     double distance = sqrt (  origin_x * origin_x + 
00193       origin_y * origin_y );
00194 
00195     return origin_y / tan( angle );
00196   }
00197 
00198 
00199   cv::Ptr<Camera> CameraPinhole::read( const cv::FileNode& node )
00200   {
00201     std::string myName=node.name( );
00202     if( myName != "CameraPinhole" )
00203     {
00204       std::string error = "CameraPinhole FileNode is not correct!\nExpected \"CameraPinhole\", got ";
00205       error += node.name();
00206       CV_Error( CV_StsError, error.c_str() );
00207     }
00208 
00209      Mat intra_params;
00210      unsigned char wantedEstimation;
00211     //load intra parameters:
00212     node[ "intra_params_" ] >> intra_params;
00213 
00214     node[ "estimation_needed_" ] >> wantedEstimation;
00215 
00216     return cv::Ptr<Camera>( new CameraPinhole(intra_params, wantedEstimation) );
00217   }
00218 
00219   void CameraPinhole::write( cv::FileStorage& fs ) const
00220   {
00221     fs << "CameraPinhole" << "{";
00222     fs << "intra_params_" << this->intra_params_;
00223     fs << "estimation_needed_" << this->estimation_needed_;
00224     fs << "}";
00225   }
00226 
00227 }
 All Classes Functions Variables