Computer Vision Camera Calibration Report

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.





#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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值