文档介绍:该【基于OpenCV立体视觉标定和校正剖析 】是由【花双韵芝】上传分享,文档一共【28】页,该文档可以免费在线阅读,需要了解更多关于【基于OpenCV立体视觉标定和校正剖析 】的内容,可以使用淘豆网的站内搜索功能,选择自己适合的文档,以下文字是截取该文章内的部分文字,如需要获得完整电子版,请下载此文档到您的设备,方便您编辑和打印。基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析1/28基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正这几天学****双目视觉标定,分别使用了两种工具:OpenCV和Matlab。Matlab的见效特别坚固,但是一开始OpenCV的见效很糟糕,要不是出现中断就是标定出来的结果数值很大。经过了几天的不断调试和更正,终于把OpenCV的立体视觉标定和校正的程序写出来了。立体标准时计算空间上的两台摄像机几何关系的过程,立体校正则是对个体图像进行纠正,保证这些图像可以从平面对准的两幅图像获得。程序的框架以下:,左右相机的图像的名字分别存放在两个txt中,程序分别经过这两个txt文件读取对应的图片序列。主注意:我们假设已经将摄像机排列好了,其图像扫描线是大概物理对齐,从而使得每台摄像机实质上都拥有相同的视场。文件基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/,并分别标定左右相机内参矩阵和畸变向量调用cvFindChessboardCorners找出图像中的角点,此后调用cvFindCornerSubPix计算亚像素精度角点地址,将全部找出来的角点地址压入一个矩阵序列中,以及初始化角点在世界坐基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析标系的对应地址序列,本程序的世界坐标系长度单位取标定板放个边长。此后用cvCalibrateCamera2分别标定做右相机的内参矩阵和畸变系数向量。将该过程封装成一个函数,详尽过程请参照程序说明:[cpp]viewplaincopy/*单个相机标定函数:输入参数:基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析constchar*imageListCvMat*object_pointsCvMat*image_pointsIN保存图片名的txt文件OUT世界坐标系点的矩阵OUT图像坐标系矩阵基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析CvMat*intrinsic_matrixCvMat*distortion_coeffsintn_boardsintboard_wintboard_hCvSize*imgSizeOUT返回的内参数矩阵OUT返回的畸变向量IN图片的数量IN每张图片x方向角点数量IN每张图片y方向角点数量OUT每张图片的像素尺寸基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析*/基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析staticvoidSingleCalib(constchar*imageList,CvMat*object_points,CvMat*image_points,CvMat*intrinsic_matrix,CvMat*distortion_coeffs,intn_boards,intboard_w,intboard_h,CvSize*imgSize){//定义文件类FILE*f;fopen_s(&f,imageList,"rt");intboard_n=board_w*board_h;//每张图片中角点总数量CvSizeboard_sz=cvSize(board_w,board_h);//角点尺寸矩阵CvPoint2D32f*corners=newCvPoint2D32f[board_w*board_h];//定义用于存放每张图片角点数量的一维点数组CvMat*point_counts=cvCreateMat(n_boards,1,CV_32SC1);//向量,每个元素代表每张基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析图片角点的数量esses=0;//找到全部角点的图片数量intstep=0;//用于记录每张图片角点的初步地址基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析9/28基于OpenCV立体视觉标定和校正分析//文件读取不行功:基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析if(!f){基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析fprintf(stderr,"cannotopenfile%s\n",imageList);//要读写,得知道从哪里读,往哪里基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析写吧?stderr--标准错误输出设备基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析return;}基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析//利用i循环读取文件中的字符,此后用于读取图片基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析for(inti=0;;i++){基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析//读取图片charbuf[1024];//存放读取的字符数组intcount=0,result=0;//count找的的角点数量,result找角点结果标志,全部角点基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析找到非零,否者为0;基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析if(!fgets(buf,sizeof(buf)-3,f))//提取文件的字符存放到bufbreak;size_tlen=strlen(buf);//len为字符数组的长度while(len>0&&isspace(buf[len-1]))//intisspace(intc)检查参数c可否为空格字符,也就是判断可否为空格('')、定位字符('\t')、CR('\r')、换行('\n')buf[--len]='\0';//、垂直定位字符('\v')或翻页('\f')的情基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析况。,既在非空白字符的后边以为增加‘\0’基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析if(buf[0]=='#')//开头为'#',结束此次循环基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析continue;基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析IplImage*img=cvLoadImage(buf,0);//读取图片if(!img)break;//获得图片尺寸*imgSize=cvGetSize(img);//提取角点result=cvFindChessboardCorners(img,cvSize(board_w,board_h),corners,&count,CV_CALIB_CB_ADAPTIVE_THRESH|CV_CALIB_CB_NORMALIZE_IMAGE);if(result){//Calibrationwillsufferwithoutsubpixelinterpolation函数cvFindCornerSubPix经过迭代来发现拥有亚象素精度的角点地址cvFindCornerSubPix(img,corners,count,cvSize(11,11),cvSize(-1,-1),cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,));/*TermCriteria迭代算法的停止准则:基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析typedefstructCvTermCriteria0d{inttype;CV_TERMCRIT_ITER和CV_TERMCRIT_EPS二值之一,也许基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析24/28基于OpenCV立体视觉标定和校正分析二者的组合intmax_iter;最大迭代次数doubleepsilon;结果的精确性}基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析一般表示迭代停止的条件,若是为CV_TERMCRIT_ITER作为停止条件,若是为CV_TERMCRIT_EPS则用精度作为迭代条件,,则用最大迭代次数基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析若是为CV_TERMCRIT_ITER+CV_TERMCRIT_EPS精度作为迭代条件,看哪个条件先满足。*/则用最大迭代次数也许基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析开始保存角点的其实地址step=esses*board_n;//将角点从数组corners压入矩阵image_points;以及给对应的object_points赋值for(inti=step,j=0;j<board_n;++i,++j){CV_MAT_ELEM(*image_points,float,i,0)=corners[j].x;CV_MAT_ELEM(*image_points,float,i,1)=corners[j].y;CV_MAT_ELEM(*object_points,float,i,0)=(j/board_w);CV_MAT_ELEM(*object_points,float,i,1)=(j%board_w);CV_MAT_ELEM(*object_points,float,i,2)=;}//给对应图片的point_counts赋值CV_MAT_ELEM(*point_counts,int,esses,0)=board_n;esses++;}//释放该角点图像cvReleaseImage(&img);}//关闭文件fclose(f);//初始化相机内参矩阵CV_MAT_ELEM(*intrinsic_matrix,float,0,0)=;CV_MAT_ELEM(*intrinsic_matrix,float,1,1)=;//标定相机的内参矩阵和畸变系数向量cvCalibrateCamera2(object_points,image_points,point_counts,*imgSize,intrinsic_matrix,distortion_coeffs,NULL,NULL,0);}基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/,计算两摄像机相对旋转矩阵R,平移向量第2步获得了在世界坐标系和图片坐标系下角点地址序列,T,本征矩阵E,基础矩阵F以及两个相机的内参矩阵和畸变基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析系数向量,此后调用cvStereoCalibrate计算摄像机相对旋转矩阵R,平移向量T,本征矩阵E,基础矩阵F,,并同时调整第2步计算的做右相机内参矩阵和畸变系数向量。但是处于个人****惯还是喜欢将该过程封装到一个函数里:[cpp]viewplaincopystaticvoidStereoCalib(CvMat*_left_object_points,CvMat*_left_image_points,CvMat*_right_image_points,CvMat*left_intrinsic,CvMat*right_intrinsic,CvMat*left_distortion,CvMat*right_distortion,CvMat*_R,CvMat*_T,CvMat*_E,CvMat*_F,int_n_boards,int_board_w,int_board_h,CvSize_imgSize){intboard_n=_board_w*_board_h;//每张图片中角点总数量//初始化Number_perImgCvMat*Number_perImg=cvCreateMat(1,_n_boards,CV_32SC1);int*pInt;pInt=(int*)(Number_perImg->);for(inti=0;i<_n_boards;++i){*pInt=board_n;pInt++;}//Show(用于调试)/*for(inti=0;i<_n_boards;i++){cout<<CV_MAT_ELEM(*Number_perImg,int,0,i)<<endl;}*///,_T,_E,_F,,并同时调整Number_perImg,left_intrinsic,D_left,right_intrinsic,D_rightcvStereoCalibrate(_left_object_points,_left_image_points,_right_image_points,Number_perImg,left_intrinsic,left_distortion,right_intrinsic,right_distortion,_imgSize,_R,_T,_E,_F,cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,100,1e-5),CV_CALIB_FIX_ASPECT_RATIO+CV_CALIB_ZERO_TANGENT_DIST+CV_CALIB_SAME_FOCAL_LENGTH);}[cpp]viewplaincopy基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析30/28基于OpenCV立体视觉标定和校正分析计算获得以下的结果(到目前为止还是很顺利的嘛!):基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/。下面经过另一种方法检查标定结果的误差,经过检查图像上的点与另一幅图像的极线的距离远近来议论标定精度。第一,经过cvUndistortPoints( )对原始点进行去畸变办理,此后使用puteCorrespondEplilines( )来计算极线,此后计算这些点和极线的距离(理想状况下,距离为0),累计这些距离的绝对误差,此后求其均匀值。详尽过程我也把它封装成一个函数:[cpp]viewplaincopy/*计算标定误差函数CvMat*left_image_pointsIN左相机图像坐标系点的矩阵CvMat*right_image_pointsIN右相机图像坐标系点的矩阵CvMat*left_intrinsicINandOUT左相机的内参矩阵,经立体标定调整后输出CvMat*right_intrinsicINandOUT右相机的内参矩阵,经立体标定调整后输出CvMat*left_distortionINandOUT左相机的畸变向量,经立体标定调整后输出CvMat*right_distortionINandOUT右相机的畸变向量,经立体标定调整后输出CvMat*_FOUT基础矩阵intn_boardsIN图片的数量intboard_wIN每张图片x方向角点数量intboard_hIN每张图片y方向角点数量*/基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析32/28基于OpenCV立体视觉标定和校正分析doubleCalib_Quality_Check(CvMat*_left_image_points,CvMat*_right_image_points,CvMat*left_intrinsic,CvMat*right_intrinsic,CvMat*left_distortion,CvMat*right_distortion,CvMat*_F,int_n_boards,int_board_w,int_board_h){intboard_n=_board_w*_board_h;//每张图片中角点总数量//定义极线CvMat*Lines1=cvCreateMat(1,_n_boards*board_n,CV_32FC3);CvMat*Lines2=cvCreateMat(1,_n_boards*board_n,CV_32FC3);//校正点的畸变<spanstyle="font-family:Arial,Helvetica,sans-serif;">cvUndistortPoints</span><spanstyle="font-family:Arial,Helvetica,sans-serif;">(_left_image_points,_left_image_points,left_intrinsic,D_left,0,left_intrinsic);//代码运行到这里出现中断</span><spanstyle="font-family:Arial,Helvetica,sans-serif;">cvUndistortPoints</span><spanstyle="font-family:Arial,Helvetica,sans-serif;">(_right_image_points,_right_image_points,right_intrinsic,D_right,0,right_intrinsic);</span>//计算极线puteCorrespondEpilines(_left_image_points,1,_F,Lines1);puteCorrespondEpilines(_right_image_points,2,_F,Lines2);//计算左相机图像点和极线的距离floata,b,c;//极线系数ax+by+c=0doubleerr,avgErr=0;//误差变量float*p_temp=(float*)cvPtr2D(_left_image_points,0,0);//用于临时计算的点float*l_temp=(float*)cvPtr2D(Lines2,0,0,0);//用于临时计算的极线for(inti=0;i<_n_boards*board_n;i++){//提取点坐标x=*p_temp;y=*(p_temp+1);p_temp+=2;//提取极线系数a=*l_temp;b=*(l_temp+1);c=*(l_temp+2);l_temp+=3;//计算点到直线的距离err=fabs(a*x+b*y+c)/sqrt(a*a+b*b);//累加误差avgErr+=err;}//计算右相机图像点和极线的距离p_temp=(float*)cvPtr2D(_right_image_points,0,0);//用于临时计算的点l_temp=(float*)cvPtr2D(Lines1,0,0);//用于临时计算的极线基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析33/28基于OpenCV立体视觉标定和校正分析for(inti=0;i<_n_boards*board_n;i++){//提取点坐标x=*p_temp;y=*(p_temp+1);p_temp+=2;//提取极线系数a=*l_temp;b=*(l_temp+1);c=*(l_temp+2);l_temp+=3;//计算点到直线的距离err=fabs(a*x+b*y+c)/sqrt(a*a+b*b);//累加误差avgErr+=err;}//求误差的均匀值avgErr/=(_n_boards*board_n);returnavgErr;}基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析34/28基于OpenCV立体视觉标定和校正分析这时候代码运行到cvUndistortPoints( )出现中断,查察源码sources中对应的函数可以发基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析现函数基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析[cpp]viewplaincopyvoidcvUndisto(constCvMat*_src,CvMat*_dst,constCvMat*_cameraMatrix,constCvMat*_distCoeffs,constCvMat*_R,constCvMat*_P)中有这么一句话:基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析[cpp]viewplaincopyCV_ASSERT(CV_IS_MAT(_src)&&CV_IS_MAT(_dst)&&(_src->rows==1||_src->cols==1)&&(_dst->rows==1||_dst->cols==1)&&CV_ARE_SIZES_EQ(_src,_dst)&&(CV_MAT_TYPE(_src->type)==CV_32FC2||CV_MAT_TYPE(_src->type)CV_64FC2)&&(CV_MAT_TYPE(_dst->type)==CV_32FC2||CV_MAT_TYPE(_dst->type)CV_64FC2));====基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析既输入参数变量CvMat*_src,CvMat*_dst必定切合以上的条件,详尽代表什么自己查找相关宏的定义,这里不一一列出,我们输入的参数是基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析[cpp]viewplaincopyCvMat*left_image_points=cvCreateMat(n_boards*board_n,2,CV_32FC1);//左相机图片坐标中的角点CvMat*right_image_points=cvCreateMat(n_boards*board_n,2,CV_32FC1);//右相机图片坐标中的角点基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析所以因为最后两句的判断而出错。[cpp]viewplaincopy(CV_MAT_TYPE(_src->type)==CV_32FC2||CV_MAT_TYPE(_src->type)==CV_64FC2)&&(CV_MAT_TYPE(_dst->type)==CV_32FC2||CV_MAT_TYPE(_dst->type)==CV_64FC2))所以需要先对参数进行调整,更正计算误差函数为:[cpp]viewplaincopy/*计算标定误差函数基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析41/28基于OpenCV立体视觉标定和校正分析CvMat*left_image_pointsCvMat*right_image_pointsCvMat*left_intrinsicCvMat*right_intrinsicCvMat*left_distortionCvMat*right_distortionIN左相机图像坐标系点的矩阵IN右相机图像坐标系点的矩阵INandOUT左相机的内参矩阵,经立体标定调整后输出INandOUT右相机的内参矩阵,经立体标定调整后输出INandOUT左相机的畸变向量,经立体标定调整后输出INandOUT右相机的畸变向量,经立体标定调整后输出基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析CvMat*_FOUT基础矩阵基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析intn_boardsintboard_wintboard_hINININ图片的数量每张图片x方向角点数量每张图片y方向角点数量基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析*/基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析doubleCalib_Quality_Check(CvMat*_left_image_points,CvMat*_right_image_points,CvMat*left_intrinsic,CvMat*right_intrinsic,CvMat*left_distortion,CvMat*right_distortion,CvMat*_F,int_n_boards,int_board_w,int_board_h){intboard_n=_board_w*_board_h;//每张图片中角点总数量//整理LeftPoints。因为_left_image_points数据种类是_n_boards*board_n*3*CV_32FC1,left数据种类是1*_n_boards*board_n*CV_32FC2,对参数进行变换CvMat*left=cvCreateMat(1,_n_boards*board_n,CV_32FC2);float*p=(float*)cvPtr2D(left,0,0);floatx,y;for(inti=0;i<_n_boards*board_n;++i){x=CV_MAT_ELEM(*_left_image_points,float,i,0);y=CV_MAT_ELEM(*_left_image_points,float,i,1);*p=x;p++;*p=y;p++;}//整理LeftPoints。因为_left_image_points数据种类是_n_boards*board_n*3*CV_32FC1,left数据种类是1*_n_boards*board_n*CV_32FC2,对参数进行变换CvMat*right=cvCreateMat(1,_n_boards*board_n,CV_32FC2);p=(float*)cvPtr2D(right,0,0);for(inti=0;i<_n_boards*board_n;++i)基于OpenCV立体视觉标定和校正分析基于OpenCV立体视觉标定和校正分析28/28基于OpenCV立体视觉标定和校正分析{x=CV_MAT_ELEM(*_right_image_points,float,i,0);y=CV_MAT_ELEM(*_right_image_points,float,i,1);*p=