Opencv摄像机的标定

坐标系:

                       世界坐标系:Xw,Yw,Zw;

                        摄像机坐标系:Xc,Yc,Zc;

                         图像坐标系:[x,y] ,[u,v]  (包含图像物理坐标系和图像像素坐标系)

 

 

这就是由世界坐标系映射到像素坐标系的齐次变换:

其中K为摄像机的内参矩阵,R为旋转变换,t为平移变换。

这其实就构成了摄像机标定的理论基础。

下面来介绍一种经典的方法张正友平面标定发:

基本原理:

    

 

这里假定模板平面在世界坐标系Z=0的平面上,K为内参矩阵,M=[X,Y,1],为模版平面上的其次坐标系,m=[u,v,1]为模板平面映射到图像平面的坐标系;

 

 

根据旋转矩阵的性质有:

这可得

           

由于摄像机有 5 个未知内参数,所以当所摄取得的图象数目大于等 3 时,就可以线性唯一求解出

opencv实现:

                      

#include<iostream>
#include<opencv2\opencv.hpp>
#include<vector>
#include<stdio.h>
using namespace cv;
using namespace std;
void show(char *windowname,Mat &img)
{
 namedWindow(windowname,1);
 imshow(windowname,img);
 waitKey(0);
}
void printmat(Mat &img)
{
 int row=img.rows;
 int col=img.cols;
 int i=0;
 int j=0;
 for(i=0;i<row;i++){
  for(j=0;j<col;j++){
   cout<<img.ptr<double>(i)[j]<<" ";
  }
  cout<<endl;
 }
}
void main()
{
 Mat src,src_gray;//图像矩阵
 Mat cameraMatrix(3,3,CV_32FC1);
 Mat distCoeffs;
 vector<Mat> rvecs;
 vector<Mat> tvecs;
 char filename[50];
 vector <Point2f> point_buf;
 vector <Point2f> test_point;
 vector <Point3f> object_buf;
 vector <vector <Point2f> > coner_point;
 vector <vector <Point3f> > object_point;
 int real_size=27.70; //标定板实际的尺寸为27.70mm
 Size bord_size(6,8);
 bool flag;
 int mat_size=0;
 int success=0;
 Point3f temp_object;
 double img_err;
 int i=0;
 int j=0;
 int w=0;
 int h=0;
 cout<<" begin search for the corners\n";
 for(i=1;i<15;i++) {
  sprintf(filename,"src//%d.jpg",i);
  src=imread(filename,1);
  flag=findChessboardCorners(src,bord_size,point_buf,CALIB_CB_ADAPTIVE_THRESH);
  if(flag) {
   success++;
   cvtColor(src,src_gray,CV_RGB2GRAY);
   cornerSubPix(src_gray, point_buf, Size(11, 11), Size(-1, -1),
                         TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
   coner_point.push_back(point_buf);
   drawChessboardCorners(src,bord_size,point_buf,flag);
   show(filename,src);
  }
 }
 cout<<"Searching the corners is ended\n";
 cout<<"begin calculate the object point\n";

  for(h=0;h<bord_size.height;h++){
   for(w=0;w<bord_size.width;w++){
    temp_object.x=(float)h*real_size;
    temp_object.y=(float)w*real_size;
    temp_object.z=0.0f;
    object_buf.push_back(temp_object);
   }
  }
  for(i=0;i<success;i++) {
         object_point.push_back(object_buf);
   }
 cout<<"calculate the object ended\n";
 cout<<"start the calibrateCamera\n";
 cameraMatrix.ptr<double>(0)[0]=1.0;
 cameraMatrix.ptr<double>(1)[1]=1.0;
 calibrateCamera(object_point,coner_point,src.size(),       
              cameraMatrix,distCoeffs,rvecs,tvecs );
 cout<<"ended the calibrateCamera\n";
 cout<<"摄像机的内参矩阵为:"<<endl;
 printmat(cameraMatrix);
 cout<<endl;
 cout<<"摄像机的畸变系数为:"<<endl;
 printmat(distCoeffs);
 cout<<endl;
 cout<<"test the  calibrateCamera\n";
 for(i=0;i<success;i++){
  projectPoints(object_point[i],rvecs[i],tvecs[i],cameraMatrix,distCoeffs,test_point);
  img_err=norm(test_point,coner_point[i]);
  cout<<"图像"<<i+1<<":总体误差"<<img_err<<endl;
  cout<<"图像"<<i+1<<":各点的平均误差"<<img_err/(bord_size.height*bord_size.width)<<endl;
 }
 for(i=0;i<success;i++){
  Mat r_mat(3,3,CV_32FC1);
  Rodrigues(rvecs[i],r_mat);
  cout<<"图像"<<i+1<<":旋转矩阵为"<<endl;
  printmat(r_mat);
  cout<<endl;
  cout<<"图像"<<i+1<<":平移矩阵为"<<endl;
  printmat(tvecs[i]);
  cout<<endl;
 }
}

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值