opencv摄像机标定(附源码已调试)
来源:互联网 发布:java如何实现抢单功能 编辑:程序博客网 时间:2024/06/08 19:08
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
- opencv摄像机标定(附源码已调试)
- opencv摄像机标定(附源码已调试)
- 摄像机标定(附源码)
- 基于OPENCV摄像机标定的源码
- opencv 摄像机标定 实时标定
- OPENCV版本的摄像机标定(张正友)
- OPENCV版本的摄像机标定(张正友)
- OPENCV版本的摄像机标定(张正友)
- Python+OpenCV学习(17)---摄像机标定
- 摄像机标定研究(Matlab+opencv+emgucv)
- Python+OpenCV学习(17)---摄像机标定
- OpenCV-摄像机模型与标定(一)
- OpenCV--摄像机标定
- 感谢 摄像机标定opencv
- OpenCV: 摄像机标定原理
- MFC+OPENCV摄像机标定
- Opencv摄像机的标定
- OpenCV: 摄像机标定原理
- js 模块defin化讲解
- Android用户界面对话框之警告对话框(ALertDialog)
- Linux下的串口系列---struct termios结构体
- LDAP学习——(2)OpenLdap安装
- dom4j读取xml文件的简单使用
- opencv摄像机标定(附源码已调试)
- 切分文件名提取文件扩展名或提取文件名
- 关于Eclipse不自动弹出提示(alt+/快捷键失效)
- Google Java Style
- JavaWeb SSI入门自学
- 刘东明应邀赴台湾担任金手指网络奖终审评委
- Android Fragment完全解析,关于碎片你所需知道的一切
- Oracle中时间段转换
- Telkomnika下的月刊和季刊的调查——(ISSN: 1693-6930)与(ISSN:2302-4046)的前生今世