opencv实现摄像机标定(张正友的标定方法)

张正友算法的原理:

这里假定模板平面在世界坐标系Z=0的平面上:

opencv实现摄像机标定(张正友的标定方法)_第1张图片

如下图,其中,K为摄像机的内参数矩阵,[X Y 1]T为模板平面上点的齐次坐标,[u v 1]T为模板平面上点投影到图象平面上对应点的齐次坐标,[r1 r2 r3]和t 分别是摄像机坐标系相对于世界坐标系的旋转矩阵和平移向量。

opencv实现摄像机标定(张正友的标定方法)_第2张图片

根据旋转矩阵的性质,即r1Tr2=0和||r1||=||r2||=1,每幅图象可以获得以下两个对内参数矩阵的基本约束

opencv实现摄像机标定(张正友的标定方法)_第3张图片

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

 

OK,开始动手:

1.首先需要准备一张标定板(在一张A4纸上打印一幅黑白相间的类似国际象棋的棋盘图):注意:打印的应该是平的,不能用下图,下图只是告诉你长什么样。具体图片网上很easy就可以下载到。

opencv实现摄像机标定(张正友的标定方法)_第4张图片

2.将需要标定的摄像头固定好(注意是固定,就是说拍照过程中摄像头不要动)

3.将棋盘图放在摄像头的拍摄范围内,不断改变A4纸的方向和倾角,拍摄至少10张以上照片(理论上多一点会更准确一点)

注意:摄像头与图片之间的夹角不要太小,夹角太小误差就大。

4.附上源码:

/**
 * 程序实现功能:标定摄像头参数
 *                  输出:内参数矩阵、畸变系数、旋转向量、旋转矩阵、平移向量
 *         运行环境:Linux + opencv + eclipse (windows下也可以照常运行)
 */

#include 
#include 
#include 

using namespace std;

int image_width = 640;//待标定图片的宽度
int image_height = 480;//待标定图片的高度
const int ChessBoardSize_w = 5;//图片中可标定的行角点数
const int ChessBoardSize_h = 5;//图片中可标定的列角点数
const CvSize  ChessBoardSize = cvSize(ChessBoardSize_w,ChessBoardSize_h);
const int NPoints = ChessBoardSize_w*ChessBoardSize_h;//每张图片中的总角点数
const int NImages=7;//待标定的图片数
int corner_count[NImages] = {0};
float    SquareWidth = 19; //棋盘格子的边长19毫米。

CvMat *intrinsics;
CvMat *distortion_coeff;
CvMat *rotation_vectors;
CvMat *translation_vectors;
CvMat *object_points;
CvMat *point_counts;
CvMat *image_points;

//计算旋转矩阵需要
double R_matrix[9];
CvMat pr_vec;
CvMat pR_matrix;

void InitCorners3D(CvMat *Corners3D, CvSize ChessBoardSize, int NImages, float SquareSize);//得到定标点三维坐标矩阵

int main()
{
	IplImage     *current_frame_rgb; //彩色图像头
	IplImage     *current_frame_gray;//灰色图像头
	IplImage     *chessBoard_Img;//棋盘格图像头
	CvPoint2D32f corners[NPoints*NImages];//corners数组存放所有图片角点的坐标

	chessBoard_Img =cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 3);
	current_frame_gray = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 1);
	current_frame_rgb = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 3);

	int captured_frames=0;
	for(captured_frames=0;captured_frames=9&&captured_frames<=98)
			{//两位数的时候,需要拆分个位和十位然后加到filename的下标为0和1单元
				int j,jj;
				jj=(captured_frames+1)/10;
				j=(captured_frames+1)%10;
				filename[0]=jj+48;
				filename[1]=j+48;
			}
		else cout<<"error, too many images......."<data.ptr))[i];
		tranv[i] = ((float*)(translation_vectors->data.ptr))[i];
		rotv[i] = ((float*)(rotation_vectors->data.ptr))[i];
	}
        dist[3] = ((float*)(distortion_coeff->data.ptr))[3];
        
//外参数中的R就是旋转矩阵,t就是平移向量/////////////////////////////////////////////////////////////

        cout<<"----------------------------------------- "<

 

 

 

你可能感兴趣的:(opencv实现摄像机标定(张正友的标定方法))