您的位置:首页 > 运维架构

opencv摄像机标定(附源码已调试)

2014-01-09 10:00 429 查看














opencv摄像机标定(附源码已调试)

最近在左摄像机标定,要求反投影的误差在1个像素内,发现matlab工具箱更好,opencv比较好些因为有了现成的函数。

以下是用opencv2.1安装包只带的照片做的实验,运行的平台为vs2008+opencv2.1 ,windows xp

#include <cv.h>

#include <highgui.h>

#include <iostream>

using namespace std;

void PrintMat(CvMat*);

void FputMat(FILE *,CvMat *);

int main(int argc ,char * argv[])

{

/*读入图像*/

CvSize image_size;

int n_board=9;//图像数目

int sn_board=0;//成功找到角点的图像数目

int board_w=6;

int board_h=9;

int board_n=board_h*board_w;//每幅图像的角点数

CvSize patter_size=cvSize(board_w,board_h);//每幅图像的角点数

CvPoint2D32f * corners=new CvPoint2D32f[board_n];//一幅图像的角点数组

CvMat * object_points= cvCreateMat(board_n*n_board,3,CV_32FC1);

CvMat * image_points=cvCreateMat(board_n*n_board,2,CV_32FC1);

CvMat * point_counts=cvCreateMat(n_board,1,CV_32SC1);

for(int i=1;i<=n_board;i++)

{

/*读入图像*/

char path[100]="F:\\vs2008test\\mycalib_0\\right0";

char num[10];

itoa(i,num,10);

strcat(num,".jpg");

IplImage *SourceImg=cvLoadImage(strcat(path,num),CV_LOAD_IMAGE_COLOR);

image_size=cvGetSize(SourceImg);//图像的大小

IplImage *SourceImgGray=cvCreateImage(image_size,IPL_DEPTH_8U,1);

cvCvtColor(SourceImg,SourceImgGray,CV_BGR2GRAY);

cvNamedWindow("MyCalib",CV_WINDOW_AUTOSIZE);

cvShowImage("MyCalib",SourceImg);

cvWaitKey(NULL);

/*提取角点精确到亚像素*/

int corner_count;

if(0==cvFindChessboardCorners(SourceImgGray,patter_size,corners,&corner_count,CV_CALIB_CB_ADAPTIVE_THRESH|CV_CALIB_CB_FILTER_QUADS))

{ cout<<"......无法找出第"<<i<<"幅图的角点"<<endl;

cvWaitKey(NULL);

cvReleaseImage(&SourceImgGray);

cvReleaseImage(&SourceImg);

continue;

//return -1;

}

else

{

cvFindCornerSubPix(SourceImgGray,corners,corner_count,cvSize(11,11),cvSize(-1,-1),cvTermCriteria(

CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,0.1));//CvSize win 和matlab标定工具箱类似

cvDrawChessboardCorners(SourceImg,patter_size,corners,corner_count,1);

cvShowImage("MyCalib",SourceImg);

//cvSaveImage("F:\\vs2008test\\mycalib_0\\11.jpg",SourceImg);

}

cvWaitKey(0);

for (int j=0;j<board_n;j++)

{

CV_MAT_ELEM(*image_points,float,sn_board*board_n+j,0)=corners[j].x;

CV_MAT_ELEM(*image_points,float,sn_board*board_n+j,1)=corners[j].y;

CV_MAT_ELEM(*object_points,float,sn_board*board_n+j,0)=float(j/board_w);

CV_MAT_ELEM(*object_points,float,sn_board*board_n+j,1)=float(j%board_w);

CV_MAT_ELEM(*object_points,float,sn_board*board_n+j,2)=0.0f;

CV_MAT_ELEM(*point_counts,int,sn_board,0)=board_n;

}

sn_board++;

cvReleaseImage(&SourceImgGray);

cvReleaseImage(&SourceImg);

cout<<"......成功找出第"<<i<<"幅图的角点"<<endl;

}

cout<<"......一共成功获得"<<sn_board<<"幅图像的角点"<<"......无法获得"<<n_board-sn_board<<"幅图像的角点"<<endl;

//重新赋值

CvMat * object_points0= cvCreateMat(board_n*sn_board,3,CV_32FC1);

CvMat * image_points0=cvCreateMat(board_n*sn_board,2,CV_32FC1);

CvMat * point_counts0=cvCreateMat(sn_board,1,CV_32SC1);

for (int i=0;i<sn_board*board_n;i++)

{

CV_MAT_ELEM(*image_points0,float,i,0)=CV_MAT_ELEM(*image_points,float,i,0);

CV_MAT_ELEM(*image_points0,float,i,1)=CV_MAT_ELEM(*image_points,float,i,1);

CV_MAT_ELEM(*object_points0,float,i,0)=CV_MAT_ELEM(*object_points,float,i,0);

CV_MAT_ELEM(*object_points0,float,i,1)=CV_MAT_ELEM(*object_points,float,i,1);

CV_MAT_ELEM(*object_points0,float,i,2)=0.0f;

}

for (int i=0;i<sn_board;i++)

{

CV_MAT_ELEM(*point_counts0,int,i,0)=CV_MAT_ELEM(*point_counts,int,i,0);

}

cvReleaseMat(&object_points);

cvReleaseMat(&point_counts);

cvReleaseMat(&image_points);

/*摄像机标定并求得内部参数*/

CvMat * camera_matrix=cvCreateMat(3,3,CV_32FC1);

CvMat * distortion_coeffs=cvCreateMat(1,4,CV_32FC1);

CvMat * rotation_vectors=cvCreateMat(sn_board,3,CV_32FC1);

CvMat * translation_vectors=cvCreateMat(sn_board,3,CV_32FC1);

int flags=0;

cvCalibrateCamera2(object_points0,image_points0,point_counts0,image_size,camera_matrix

//,distortion_coeffs,NULL,NULL,flags);

,distortion_coeffs,rotation_vectors,translation_vectors,0);

//输出结果

printf("/*****摄像机内部参数*****/\n");

PrintMat(camera_matrix);

printf("/*****畸变参数k1,k2,p1,p2*****/\n");

PrintMat(distortion_coeffs);

cvWaitKey(NULL);

//保存数据

cout<<"......保存内部参数与畸变参数"<<endl;

cvSave("camera_matrix1111.xml",camera_matrix);

cvSave("distortion_coeffs.xml",distortion_coeffs);

FILE *fp=NULL;

if ((fp=fopen("F:\\vs2008test\\mycalib_0\\mycalib_0\\camera_matrix.txt","w"))==NULL)

{

printf("无法打开文件!");

exit(1);

}

FputMat(fp,camera_matrix);

fclose(fp);

if ((fp=fopen("F:\\vs2008test\\mycalib_0\\mycalib_0\\distortion_coeffs.txt","w"))==NULL)

{

printf("无法打开文件!");

exit(1);

}

FputMat(fp,distortion_coeffs);

fclose(fp);

//误差分析

CvMat * object_points2=cvCreateMat(board_n,3,CV_32FC1);

CvMat * image_points2=cvCreateMat(board_n,2,CV_32FC1);

CvMat * rotation_vectors2=cvCreateMat(1,3,CV_32FC1);

CvMat * translation_vectors2=cvCreateMat(1,3,CV_32FC1);

CvMat * Err=cvCreateMat(sn_board*board_n,2,CV_32FC1);

for(int k=0;k<sn_board;k++)

{

for (int i=0;i<board_n;i++)//取一幅图的数据

{

CV_MAT_ELEM(*object_points2,float,i,0)=CV_MAT_ELEM(*object_points0,float,k*board_n+i,0);

CV_MAT_ELEM(*object_points2,float,i,1)=CV_MAT_ELEM(*object_points0,float,k*board_n+i,1);

CV_MAT_ELEM(*object_points2,float,i,2)=0.0f;

}

for (int i=0;i<3;i++)

{

CV_MAT_ELEM(*rotation_vectors2,float,0,i)=CV_MAT_ELEM(*rotation_vectors,float,k,i);

CV_MAT_ELEM(*translation_vectors2,float,0,i)=CV_MAT_ELEM(*translation_vectors,float,k,i);

}

cvProjectPoints2(object_points2,rotation_vectors2,translation_vectors2,camera_matrix,

distortion_coeffs,image_points2);

for (int i=0;i<board_n;i++)

{

CV_MAT_ELEM(*Err,float,k*board_n+i,0)=CV_MAT_ELEM(*image_points0,float,k*board_n+i,0)-CV_MAT_ELEM(*image_points2,float,i,0);

CV_MAT_ELEM(*Err,float,k*board_n+i,1)=CV_MAT_ELEM(*image_points0,float,k*board_n+i,1)-CV_MAT_ELEM(*image_points2,float,i,1);

}

}

//PrintMat(Err);

CvMat * Err_abs=cvCreateMat(board_n*sn_board,2,CV_32FC1);

cvAbs(Err,Err_abs);

CvScalar Dmean;

CvScalar Ddev;

cvAvgSdv(Err_abs,&Dmean,&Ddev);

printf("/*****反投影误差分析*****/\n");

cout<<"......绝对值误差矩阵的平均值:"<<endl;

cout<<Dmean.val[0]<<endl;

cout<<"......绝对值误差矩阵的标准差:"<<endl;

cout<<Ddev.val[0]<<endl;

cout<<"......保存误差矩阵"<<endl;

cvSave("err.xml",Err);

if ((fp=fopen("F:\\vs2008test\\mycalib_0\\mycalib_0\\err.txt","w"))==NULL)

{

printf("无法打开文件!");

exit(1);

}

FputMat(fp,Err);

fclose(fp);

cvReleaseMat (&object_points2);

cvReleaseMat (&image_points2);

cvReleaseMat (&rotation_vectors2);

cvReleaseMat (&translation_vectors2);

cvReleaseMat (&Err);

cvReleaseMat (&Err_abs);

//释放总变量

cvWaitKey(NULL);

cvReleaseMat(&object_points0);

cvReleaseMat(&point_counts0);

cvReleaseMat(&image_points0);

cvReleaseMat(&camera_matrix);

cvReleaseMat(&distortion_coeffs);

cvReleaseMat(&rotation_vectors);

cvReleaseMat(&translation_vectors);

delete [] corners;

cvDestroyWindow("MyCalib");

}

void PrintMat(CvMat* arry)

{

for (int i=0;i<arry->rows;i++)

{

for (int j=0;j<arry->cols;j++)

{

printf("%f",CV_MAT_ELEM(*arry,float,i,j));

if(j<arry->cols-1)

printf(",");

}

printf("\n");

}

}

void FputMat(FILE * fp,CvMat * arry)

{

for (int i=0;i<arry->rows;i++)

{

for (int j=0;j<arry->cols;j++)

{

fprintf(fp,"%f",CV_MAT_ELEM(*arry,float,i,j));

if(j<arry->cols-1)

fprintf(fp,",");

}

fprintf(fp,"\n");

}

}

实验结果



9幅图像中其中一幅图像



标定过程出项的问题:

opencv的cvCalibrateCamera2 之用一幅图像也得到标定结果,这点和摄像机标定的理论有也不符,至少应在在2幅图像。

个人觉得cvFindChessboardCorners这个函数不是十分的智能,比如上例中第7、8图就无法找出,另外你把标定板倒一个,cvFindChessboardCorners也会找不出来,因为行数和列数倒个了。

相对于matlab标定工具箱来说,虽然matlab工具箱没有那么智能,但是把所有图像的角点找出来是没有问题的而却精度比opencv的还要高

原文 http://hi.baidu.com/lin65505578/item/fcb30f34031003f9e7bb7aa8
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: