Computer Vision Camera Calibration Report
2015-10-23 12:44
309 查看
Computer Vision Camera Calibration Report
I use the linear camera calibration method as follow step:
1Get the points in corner images
2Set the object points relative with image points
3Substitutie all points in matrix of [R t] to build the big matrix P
4Use SVD method to solve matrix P, when the eigenvalue is minimum, thecorresponding eigenvector is the least square solution of M.
5Use the formula to restore the parameters from matrix M.
Thecode shows in FLX_calib.cpp, write in C++ as a class.
Ibuild the object point and the axis shows in the picture:
Here is my calibrate result:
From the result I shows, I findthat the camera parameter get from the linear method is very close to theresult get from OpenCV’s calibrateCamera function.
I use the linear camera calibration method as follow step:
1Get the points in corner images
2Set the object points relative with image points
3Substitutie all points in matrix of [R t] to build the big matrix P
4Use SVD method to solve matrix P, when the eigenvalue is minimum, thecorresponding eigenvector is the least square solution of M.
5Use the formula to restore the parameters from matrix M.
Thecode shows in FLX_calib.cpp, write in C++ as a class.
Ibuild the object point and the axis shows in the picture:
Here is my calibrate result:
From the result I shows, I findthat the camera parameter get from the linear method is very close to theresult get from OpenCV’s calibrateCamera function.
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; class FLX_15S_CalibCamera { public: Mat Src_Image,Gray_Image,Corners_buf,Show_Image,WorldPoints,Mat_P,Mat_M,Mat_PtP; Mat Eigen_Values,Eigen_Vectors; double u0,v0,theta,alpha,beta; Mat r1t,r2t,r3t; Mat t; Size BoardSize; int Board_Element_Length,Board_Width,Board_Height,Total_Corners; String FileName; FLX_15S_CalibCamera(char *BoardFile,int size_w,int size_h,int size_l) { FileName=BoardFile; Src_Image=imread(FileName,1); cvtColor( Src_Image, Gray_Image, CV_BGR2GRAY ); Show_Image=Src_Image.clone(); BoardSize=Size(size_w,size_h); Board_Element_Length=size_l; Board_Width=size_w; Board_Height=size_h; Total_Corners=size_w*size_h; WorldPoints= Mat::zeros(size_w*size_h, 1, CV_32FC3 ); Mat_P= Mat::zeros(size_w*size_h*2, 12, CV_32FC1 ); GetSubpixCorner(); BuildWorldPoint(); PlotAssist(); BuildMatrixP(); M_estimate(); GetParamFromM(); } /*获取图片的角点坐标并进一步精确坐标到亚像素*/ int GetSubpixCorner(void) { findChessboardCorners(Src_Image,BoardSize,Corners_buf,1); find4QuadCornerSubpix(Gray_Image,Corners_buf,BoardSize); drawChessboardCorners(Show_Image,BoardSize,Corners_buf,0); if(Corners_buf.rows!=Total_Corners)return 0; return 1; } /*建立世界坐标系,并在图上画出*/ void BuildWorldPoint(void) { int x_Factor[10] = {4,3,2,1,0,0,0,0,0,0}; int y_Factor[10] = {0,0,0,0,0,1,2,3,4,5}; for(int i = 0; i < Board_Height; ++i) for( int j = 0; j < Board_Width; ++j ) { int k = i*Board_Width+j; WorldPoints.at<Vec3f>(k,0)[0]=(float)Board_Element_Length*x_Factor[j]; WorldPoints.at<Vec3f>(k,0)[1]=(float)Board_Element_Length*y_Factor[j]; WorldPoints.at<Vec3f>(k,0)[2]=(float)Board_Element_Length*(Board_Height-1-i); PlotAssist(i,j,k,x_Factor,y_Factor);//在图像上显示点角点位置和坐标,最终画出世界坐标系的坐标轴 } } /*根据公式,构造P矩阵*/ void BuildMatrixP(void) { float Image_Points_ui; float Image_Points_vi; float World_Points_ij; for(int i=0;i<Total_Corners;i++) { Image_Points_ui=Corners_buf.at<Vec2f>(i,0)[0]; Image_Points_vi=Corners_buf.at<Vec2f>(i,0)[1]; for(int j=0;j<3;j++) { World_Points_ij=WorldPoints.at<Vec3f>(i,0)[j]; Mat_P.at<float>(i*2,j)=World_Points_ij; Mat_P.at<float>(i*2,j+4)=0; Mat_P.at<float>(i*2,j+8)=-Image_Points_ui*World_Points_ij; Mat_P.at<float>(i*2+1,j)=0; Mat_P.at<float>(i*2+1,j+4)=World_Points_ij; Mat_P.at<float>(i*2+1,j+8)=-Image_Points_vi*World_Points_ij; } Mat_P.at<float>(i*2,3)=1; Mat_P.at<float>(i*2+1,7)=1; Mat_P.at<float>(i*2,11)=-Image_Points_ui; Mat_P.at<float>(i*2+1,11)=-Image_Points_vi; } } /*利用SVD进行最小二乘估计,求得最佳M矩阵*/ void M_estimate() { Mat_PtP=Mat_P.t()*Mat_P; eigen(Mat_PtP,Eigen_Values,Eigen_Vectors); Mat_M=Eigen_Vectors.row(11).clone(); } /*利用公式从M矩阵恢复出摄像机内外参*/ void GetParamFromM() { Mat a1=Mat_M.colRange(0,3); Mat a2=Mat_M.colRange(4,7); Mat a3=Mat_M.colRange(8,11); double pLo=1/cv::norm(a3); u0=pLo*pLo*a1.dot(a3); v0=pLo*pLo*a2.dot(a3); Mat a1a3=a1.cross(a3); Mat a2a3=a2.cross(a3); theta=acos(-a1a3.dot(a2a3)/norm(a1a3)/norm(a2a3)); alpha=pLo*pLo*norm(a1a3)*sin(theta); beta=pLo*pLo*norm(a2a3)*sin(theta); r3t=pLo*a3; r1t=a2a3/norm(a2a3); r2t=r3t.cross(r1t); t=Mat::zeros(3,1,CV_32FC1); Mat b=Mat::zeros(3,1,CV_32FC1); b.at<float>(0,0)=Mat_M.at<float>(0,3); b.at<float>(1,0)=Mat_M.at<float>(0,7); b.at<float>(2,0)=Mat_M.at<float>(0,11); float K[9] = {alpha,-alpha/tan(theta),u0,0,beta/sin(theta),v0,0,0,1}; Mat Mat_K(3,3,CV_32FC1); InitMat(Mat_K,K); t=pLo*Mat_K.inv()*b; } /*打印结果*/ void ShowParam() { cout<<"The Image File: "<<FileName<<endl; cout<<"Intrinsic Parameters:"<<endl; cout<<"alpha = "<<alpha<<endl; cout<<"beta = "<<beta <<endl; cout<<"theta = "<<theta<<endl; cout<<" u0 = "<<u0<<endl; cout<<" v0 = "<<v0 <<endl; cout<<"Extrinsic Parameters:"<<endl; cout<<" R = "<<r1t<<endl; cout<<" = "<<r2t<<endl; cout<<" = "<<r3t<<endl; cout<<" t = "<<t<<endl; } /*利用OpenCV中自带的CalibrateCamera函数进行参数解算并打印*/ void Show_Opencv_CalibrateCamera_Result(void) { vector<vector<Point2f> > imagePoints; vector<Point2f> pointBuf_vec; for(int i=0;i<80;i++) { Point2f temp; temp.x=Corners_buf.at<Vec2f>(i,0)[0]; temp.y=Corners_buf.at<Vec2f>(i,0)[1]; pointBuf_vec.push_back(temp); } imagePoints.push_back(pointBuf_vec); vector<vector<Point3f> > objectPoints; vector<Point3f> object_pointBuf_vec; int x_Factor[10] = {4,3,2,1,0,0,0,0,0,0}; int y_Factor[10] = {0,0,0,0,0,1,2,3,4,5}; for(int i = 0; i < 8; ++i) for( int j = 0; j < 10; ++j ) { Point3f newpoint=Point3f((float)20*x_Factor[j],(float)20*y_Factor[j],(float)20*(10-1-i)); object_pointBuf_vec.push_back(newpoint); } objectPoints.push_back(object_pointBuf_vec); vector<Mat> rvecs; vector<Mat> tvecs; Mat cameraMatrix; Mat distCoeffs; Size ImageSize=Size(Src_Image.cols,Src_Image.rows); cameraMatrix = Mat::eye(3, 3, CV_64F); //仅使用一张角点图,C++中新版Opencv的calibrateCamrea需要有初始的内参Fx,Fy,Cx,Cy这几个参数初值进行迭代。 cameraMatrix.at<double>(0,0)=ImageSize.width; cameraMatrix.at<double>(1,1)=ImageSize.height; cameraMatrix.at<double>(0,2)=ImageSize.width/2; cameraMatrix.at<double>(1,2)=ImageSize.height/2; distCoeffs = Mat::zeros(8, 1, CV_64F); calibrateCamera(objectPoints, imagePoints, ImageSize, cameraMatrix,distCoeffs, rvecs, tvecs,1); CvMat RotationVector=Mat(rvecs.at(0)); CvMat *cvRotationMatrix=cvCreateMat(3,3,CV_64FC1); //将旋转向量转化为旋转矩阵 cvRodrigues2(&RotationVector,cvRotationMatrix); Mat RotationMatrix=Mat(cvRotationMatrix); //打印标定的参数 cout<<"CompareWith_OpenCV_calibrateCamera: "<<endl; cout<<"Intrinsic Parameters Matrix: "<<endl; cout<<cameraMatrix<<endl; cout<<"Rotate Matrix: "<<endl; cout<<RotationMatrix<<endl; cout<<"Translate Vector: "<<endl; cout<<Mat(tvecs.at(0))<<endl; cout<<"DistCoeffs Matrix: "<<endl; cout<<distCoeffs<<endl; } private: char msg[20]; Point Point_O,Point_X,Point_Y,Point_Z; /*画世界坐标系的辅助函数*/ void PlotAssist(int i,int j,int k,int *x_Factor,int *y_Factor) { sprintf(msg,"(%g,%g,%g)",WorldPoints.at<Vec3f>(k,0)[0],WorldPoints.at<Vec3f>(k,0)[1],WorldPoints.at<Vec3f>(k,0)[2]); if(x_Factor[j]==0&&y_Factor[j]==0&&(Board_Height-1-i)==0) Point_O=Point((int)Corners_buf.at<Vec2f>(k,0)[0],(int)Corners_buf.at<Vec2f>(k,0)[1]); if(x_Factor[j]==x_Factor[0]&&y_Factor[j]==0&&(Board_Height-1-i)==0) Point_X=Point((int)Corners_buf.at<Vec2f>(k,0)[0],(int)Corners_buf.at<Vec2f>(k,0)[1]); if(x_Factor[j]==0&&y_Factor[j]==y_Factor[Board_Width-1]&&(Board_Height-1-i)==0) Point_Y=Point((int)Corners_buf.at<Vec2f>(k,0)[0],(int)Corners_buf.at<Vec2f>(k,0)[1]); if(x_Factor[j]==0&&y_Factor[j]==0&&(7-i)==(Board_Height-1)) Point_Z=Point((int)Corners_buf.at<Vec2f>(k,0)[0],(int)Corners_buf.at<Vec2f>(k,0)[1]); putText(Show_Image,msg,Point((int)Corners_buf.at<Vec2f>(k,0)[0],(int)Corners_buf.at<Vec2f>(k,0)[1]),CV_FONT_HERSHEY_SIMPLEX,0.3, Scalar(0, 0, 255, 0)); } /*画世界坐标系的辅助函数*/ void PlotAssist(void) { putText(Show_Image,"O",Point_O,CV_FONT_HERSHEY_SIMPLEX,0.8, Scalar(255, 0, 255, 0),2); putText(Show_Image,"X",Point_X,CV_FONT_HERSHEY_SIMPLEX,0.8, Scalar(0, 0, 255, 0),2); putText(Show_Image,"Y",Point_Y,CV_FONT_HERSHEY_SIMPLEX,0.8, Scalar(0, 255, 0, 0),2); putText(Show_Image,"Z",Point_Z,CV_FONT_HERSHEY_SIMPLEX,0.8, Scalar(255, 0, 0, 0),2); line(Show_Image,Point_O,Point_X,Scalar(0, 0, 255, 0),2); line(Show_Image,Point_O,Point_Y,Scalar(0, 255, 0, 0),2); line(Show_Image,Point_O,Point_Z,Scalar(255, 0, 0, 0),2); } /*矩阵初始化辅助函数*/ void InitMat(Mat& m,float* num) { for(int i=0;i<m.rows;i++) for(int j=0;j<m.cols;j++) m.at<float>(i,j)=*(num+i*m.rows+j); } }; int main(void) { FLX_15S_CalibCamera IMG_A("A.jpg",10,8,20); namedWindow( "IMG_A", CV_WINDOW_AUTOSIZE ); imshow( "IMG_A", IMG_A.Show_Image ); IMG_A.ShowParam(); cout<<endl; IMG_A.Show_Opencv_CalibrateCamera_Result(); cout<<endl; cout<<endl; FLX_15S_CalibCamera IMG_B("B.jpg",10,8,20); namedWindow( "IMG_B", CV_WINDOW_AUTOSIZE ); imshow( "IMG_B", IMG_B.Show_Image ); IMG_B.ShowParam(); cout<<endl; IMG_B.Show_Opencv_CalibrateCamera_Result(); cvWaitKey(); return 0; }
相关文章推荐
- Java, C++ 单例模式与静态成员初始化对比
- nginx安装后出现502 Bad Gateway 错误解决办法
- eclipse 设置虚拟机的内存大小
- 多项式的运算之链表实现
- 自定义RatingBar(自定义view的实践)
- Ubuntu使用命令行下载jdk
- Linux 命令 used today
- 微信公众平台开发问答
- Droid@screen:在PC屏幕上显示Android手机屏幕
- win10字体锯齿严重很模糊该怎么消除?
- Redis学习笔记八、事务
- 【DSP开发】利用CCS5.4开发基于DSP6455的JPEG2000图像解压缩过程
- 含有LOB 字段表的迁移示例
- ABAP LOOP AT中使用AT FIRST,AT NEW,AT END OF,AT LAST
- jQuery验证控件jquery.validate.js使用说明+中文API
- 求最大公约数 1.0
- 1. CentOS的版本说明
- 玩真的,薄艺电视焕新家装进行时
- Redis学习笔记五、Key数据类型
- UITableView使用AutoLayout动态计算cell高度