




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、精选优质文档-倾情为你奉上计算机视觉摄像机标定实验报告实验名称 基于OpenCV的摄像机标定实验项目 1、 学会使用OpenCV2、利用OpenCV进行摄像机标定,编程实现,给出实验结果及其分析。实验仪器设备电脑+Visual Studio 2010+openCV.2.4.8。实验原理1、 理论知识如图,(u、v)表示以像素为单位的图像坐标系的坐标,(X、Y)表示以mm为单位的图像坐标系的坐标,在X、Y坐标系中,原点O1定义在摄像机光轴与图像平面的交点,该点一般位于图像中心,但是由于制造原因,很多情况下会有偏移,若O1在U、V坐标系中坐标为(u0,v0),每一个像素在X轴与Y轴方向上的无力尺寸
2、为dx、dy,则图像任意一个像素在两个坐标系下的坐标有如下关系: 如图,Oc点为摄像机光心,Xc轴和Yc轴与图像的X轴与Y轴平行,Zc轴为摄像机光轴,它与图像平面垂直。光轴与图像平面的交点,极为图像坐标系的原点,由点Oc与Xc、Yc、Zc轴组成的直角坐标系称为摄像机坐标系,OOc为摄像机焦距:由于摄像机可以安放在环境中任意位置,所以在环境中选择一个基准坐标系来描述摄像机位置,并用它描述环境中任何物体的位置,该坐标系为世界坐标系。它有Xw、Yw和Zw轴组成,摄像机坐标系与世界坐标系之间的关系可以用旋转矩阵与平移向量t来描述。 总体来说,世界坐标系到图像坐标系的关系可总结如下:
3、; 摄像头成像几何关系,其中Oc 点称为摄像头(透镜)的光心,Xc 轴和Yc 轴与图像的x轴和Y轴平行,Zc 轴为摄像头的光轴,它与图像平面垂直。光轴与图像平面的交点O1 ,即为图像坐标系的原点。由点Oc 与Xc 、Yc 、Zc 轴组成的坐标系称为摄像头坐标系,Oc O1 的距离为摄像头焦距,用f表示。 又称为线性摄像机模型,任何空间点M在图像中的投影位置m,为光心Oc与M的连线OcM与图像平面的交点。此时有比例关系如下: 将上面的世界坐标到摄像机坐标的转换代入,最后皆可以得到世界坐标系与摄像机坐标系之间的关系:alph=f/dx, beta=f/dy,分别代表了以X轴与Y
4、轴方向上的像素为单位表示的等效焦距。gamma在较高精度的相机模型中引入,表示图像平面中以像素为单位的坐标轴倾斜程度的量度,gamma=alpha*tan(theta) theta是相机CCD阵列v轴的偏斜角度。由针孔模型我们可以知道,如果一直摄像机的内外参数,就知道投影矩阵M,这时候对任何空间点就可以求出其对应图像坐标,但是如果已知空间某点的像点m位置(u,v)即使已经知道摄像机内外参数,Xw也不能唯一确定,因为在投影过程中消去了Zc的信息。 在上面的式子中M是3x4不可逆矩阵,当已知M与(u,v)时,由公式得到的三个方程中消去z,只可以得关于Xw,Yw与Zw的两个线性方程,这个方
5、程组即为射线OP的方程,也就是说,投影点为m的所有点均在该射线上,所以,该空间是不能唯一确定的。摄像头由于光学透镜的特性使得成像存在着径向畸变,可由三个参数k1,k2,k3确定;由于装配方面的误差,传感器与光学镜头之间并非完全平行,因此成像存在切向畸变,可由两个参数p1,p2确定。单个摄像头的定标主要是计算出摄像头的内参(焦距f和成像原点cx,cy、五个畸变参数(一般只需要计算出k1,k2,p1,p2,对于鱼眼镜头等径向畸变特别大的才需要计算k3)以及外参(标定物的世界坐标)。 OpenCV 中使用的求解焦距和成像原点的算法是基于张正友的方法,而求解畸变参数是基于 Brown 的方法
6、; 设(u、v)为理想的图像像素坐标,相对应的, 为真实获得的像素坐标。则(x,y)就为理想的图像物理坐标, 为实际获得的图像物理坐标,可以得到如下的关系式:我们知道,(u0,v0)在求摄像机内参的时候可以知道, 在圆心提取排序后也可以知道,(u,v)可以通过OpenCV中cvProjectpoints函数求得反投影残差。(x,y)可以通过 和 求出,于是克得到如下公式:设Dk=d,所以可以求出畸变系数k1,k2.在求得了径向畸变的系数以后,就可以如下得到成像仪某点理想的径向位置其中,r就是当前点的所在透镜半径,k3只有在精度很高的时候才用得到 切向畸变主要包括离心畸变和薄
7、棱镜畸变,其中,离心畸变是由摄像机的镜头中各个透镜的光轴不能完全重合造成的。离心畸变其数学模型可以表示为:薄棱镜畸变是由镜头设计和制造缺陷等误差造成(比如镜头与摄像机像面之间有很小的倾角,其不仅会引起径向偏差,而且会引起切向误差)其数学模型为:综合考虑径向畸变和切向畸变,就需要对小孔成像模型进行修正,理想的图像点归一化坐标为p=(x,y)T,有畸变的图像点的归一化坐标为Pd=(xd,yd)T之间关系为: 2、 用到的OPENCV函数FindChessboardCorners 寻找棋盘图的内角点位置 int cvFindChessboardCorners( const vo
8、id*image, CvSize pattern_size,CvPoint2D32f* corners,int* corner_count=NULL,int flags=CV_CALIB_CB_ADAPTIVE_THRESH ); image 输入的棋盘图,必须是8位的灰度或者彩色图像。 pattern_size 棋盘图中每行和每列角点的个数。 corners 检测到的角点 corner_count 输出,角点的个数。如果不是NULL,函数将检测到的角点的个数存储于此变量。 flags 各种操作标志,可以是0或者下面值的组合: CV_CALIB_CB_ADAPTIVE_THRESH
9、- 使用自适应阈值(通过平均图像亮度计算得到)将图像转换为黑白图,而不是一个固定的阈值。 CV_CALIB_CB_NORMALIZE_IMAGE - 在利用固定阈值或者自适应的阈值进行二值化之前,先使用cvNormalizeHist来均衡化图像亮度。 CV_CALIB_CB_FILTER_QUADS - 使用其他的准则(如轮廓面积,周长,方形形状)来去除在轮廓检测阶段检测到的错误方块。 函数cvFindChessboardCorners试图确定输入图像是否是棋盘模式,并确定角点的位置。如果所有角点都被检测到切它们都被以一定顺序排布(一行一行地,每行从左到右),函数返回非零值,否则在函数不能发现
10、所有角点或者记录它们地情况下,函数返回0。例如一个正常地棋盘图右8x8个方块和7x7个内角点,内角点是黑色方块相互联通地位置。这个函数检测到地坐标只是一个大约地值,如果要精确地确定它们的位置,可以使用函数cvFindCornerSubPix。 FindCornerSubPix 寻找棋盘图的内角点位置精确角点位置 void cvFindCornerSubPix( const CvArr* image, CvPoint2D32f* corners,
11、0; int count, CvSize win, CvSize zero_zone, CvTermCriteria criteria );image 输入图像. corners 输
12、入角点的初始坐标,也存储精确的输出坐标 count 角点数目 win 搜索窗口的一半尺寸。如果win=(5,5) 那么使用 5*2+1 × 5*2+1 = 11 × 11 大小的搜索窗口 zero_zone 死区的一半尺寸,死区为不对搜索区的中央位置做求和运算的区域。它是用来避免自相关矩阵出现的某些可能的奇异性。当值为 (-1,-1) 表示没有死区。 criteria 求角点的迭代过程的终止条件。即角点位置的确定,要么迭代数大于某个设定值,或者是精确度达到某个设定值。 criteria 可以是最大迭代数目,或者是设定的精确度,也可以是它们的组合。 函数cvFindCorne
13、rSubPix通过迭代来发现具有子象素精度的角点位置,或如图所示的放射鞍点(radial saddle points)。 子象素级角点定位的实现是基于对向量正交性的观测而实现的,即从中央点q到其邻域点p 的向量和p点处的图像梯度正交(服从图像和测量噪声)。考虑以下的表达式: i=DIpiT·(q-pi)其中,DIpi表示在q的一个邻域点pi处的图像梯度,q的值通过最小化i得到。通过将i设为0,可以建立系统方程如下: sumi(DIpi·DIpiT)·q - sumi(DIpi·DIpiT·pi) = 0其中q的邻域(搜索窗)中的梯度被累加。调用
14、第一个梯度参数G和第二个梯度参数b,得到: q=G-1·b该算法将搜索窗的中心设为新的中心q,然后迭代,直到找到低于某个阈值点的中心位置。 DrawChessBoardCorners 绘制检测到的棋盘角点 void cvDrawChessboardCorners( CvArr* image,CvSize pattern_size,CvPoint2D32f*corners,int count,int pattern_was_found ); image 结果图像,必须是8位彩色图像。 pattern_size 每行和每列地内角点数目。 corners 检测到地角点数
15、组。 count 角点数目。 pattern_was_found 指示完整地棋盘被发现(0)还是没有发现(=0)。可以传输cvFindChessboardCorners函数的返回值。 当棋盘没有完全检测出时,函数cvDrawChessboardCorners以红色圆圈绘制检测到的棋盘角点;如果整个棋盘都检测到,则用直线连接所有的角点。 CalibrateCamera2利用定标来计算摄像机的内参数和外参数void cvCalibrateCamera2 ( const CvMat* object_points,
16、160; constCvMat* image_points,const CvMat* point_counts, CvSizeimage_size, CvMat* intrinsic_matrix,
17、160; CvMat*distortion_coeffs, CvMat* rotation_vectors=NULL, CvMat*translation_vectors=NULL, int flags=0 ); object_points 定标点的世界坐标,为3xN或者Nx3的矩阵,这里N是所有视图中点的总数。 image_points 定标点的图像坐标,为2xN或者Nx2的矩阵,这里N是所有视图中点的总数。 poi
18、nt_counts 向量,指定不同视图里点的数目,1xM或者Mx1向量,M是视图数目。 image_size 图像大小,只用在初始化内参数时。intrinsic_matrix 输出内参矩阵(A) ,如果指定CV_CALIB_USE_INTRINSIC_GUESS和(或)CV_CALIB_FIX_ASPECT_RATION,fx、 fy、 cx和cy部分或者全部必须被初始化。 distortion_coeffs 输出大小为4x1或者1x4的向量,里面为形变参数k1, k2, p1, p2。 rotation_vectors 输出大小为3xM或者Mx3的矩阵,里面为旋转向量(旋转矩阵的紧凑表示方式
19、,具体参考函数cvRodrigues2) translation_vectors 输出大小为3xM或Mx3的矩阵,里面为平移向量。 flags 不同的标志,可以是0,或者下面值的组合: · CV_CALIB_USE_INTRINSIC_GUESS- 内参数矩阵包含fx,fy,cx和cy的初始值。否则,(cx,cy)被初始化到图像中心(这儿用到图像大小),焦距用最小平方差方式计算得到。注意,如果内部参数已知,没有必要使用这个函数,使用cvFindExtrinsicCameraParams2则可。 · CV_CALIB_FIX_PRI
20、NCIPAL_POINT- 主点在全局优化过程中不变,一直在中心位置或者在其他指定的位置(当CV_CALIB_USE_INTRINSIC_GUESS设置的时候)。 · CV_CALIB_FIX_ASPECT_RATIO- 优化过程中认为fx和fy中只有一个独立变量,保持比例fx/fy不变,fx/fy的值跟内参数矩阵初始化时的值一样。在这种情况下, (fx, fy)的实际初始值或者从输入内存矩阵中读取(当CV_CALIB_USE_INTRINSIC_GUESS被指定时),或者采用估计值(后者情况中fx和fy可能被设置为任意值,只有比值被使用)。 ·
21、60; CV_CALIB_ZERO_TANGENT_DIST 切向形变参数(p1, p2)被设置为0,其值在优化过程中保持为0。 函数cvCalibrateCamera2从每个视图中估计相机的内参数和外参数。3维物体上的点和它们对应的在每个视图的2维投影必须被指定。这些可以通过使用一个已知几何形状切具有容易检测的特征点的物体来实现。这样的一个物体被称作定标设备或者定标模式,OpenCV有内建的把棋盘当作定标设备方法(参考cvFindChessboardCorners)。目前,传入初始化的内参数(当CV_CALIB_USE_INTRINSIC_GUESS被设置时)只支持平面定标设备(物
22、体点的Z坐标必须时全0或者全1)。不过3维定标设备依然可以用在提供初始内参数矩阵情况。在内参数和外参数矩阵的初始值都计算出之后,它们会被优化用来减小反投影误差(图像上的实际坐标跟cvProjectPoints2计算出的图像坐标的差的平方和)。 实验内容实验代码如下:#include <string>#include <iostream>#include <cv.h>#include <highgui.h>using namespace std;int main()int cube_length=5;IplImage* frame = NULL;i
23、nt number_image=12;char *str1;str1=".jpg"char filename20=""IplImage * show; int a=1;int number_image_copy = number_image;CvSize board_size=cvSize(5,7);int board_width=board_size.width;int board_height=board_size.height;int total_per_image=board_width*board_height;CvPoint2D32f * i
24、mage_points_buf = new CvPoint2D32ftotal_per_image;CvMat * image_points=cvCreateMat(number_image*total_per_image,2,CV_32FC1);CvMat * object_points=cvCreateMat(number_image*total_per_image,3,CV_32FC1);CvMat * point_counts=cvCreateMat(number_image,1,CV_32SC1);CvMat * intrinsic_matrix=cvCreateMat(3,3,CV
25、_32FC1);CvMat * distortion_coeffs=cvCreateMat(5,1,CV_32FC1);int count;int found;int step;int successes=0;while(a<=number_image_copy)sprintf_s (filename,"%d.jpg",a);show=cvLoadImage(filename,-1);cvNamedWindow("SrcPicture",1);cvShowImage("SrcPicture",show);found=cvFind
26、ChessboardCorners(show,board_size,image_points_buf,&count,CV_CALIB_CB_ADAPTIVE_THRESH|CV_CALIB_CB_FILTER_QUADS);if(found=0)cout<<"第"<<a<<"帧图片无法找到棋盘格所有角点!nn"cvNamedWindow("FindCornerPoints",1);cvShowImage("FindCornerPoints",show);cvWaitKey
27、(0);elsecout<<"第"<<a<<"帧图像成功获得"<<count<<"个角点.n"cvNamedWindow("FindCornerPoints",1);IplImage * gray_image= cvCreateImage(cvGetSize(show),8,1);cvCvtColor(show,gray_image,CV_BGR2GRAY);cout<<"获取源图像灰度图过程完成.n"cvFindCorne
28、rSubPix(gray_image,image_points_buf,count,cvSize(11,11),cvSize(-1,-1),cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,0.01);cout<<"灰度图亚像素化过程完成.n"cvDrawChessboardCorners(show,board_size,image_points_buf,count,found);cout<<"在源图像上绘制角点过程完成.nn"cvShowImage("FindCorn
29、erPoints",show);cvWaitKey(0);if(total_per_image=count)step=successes*total_per_image;for(int i=step,j=0;j<total_per_image;+i,+j)CV_MAT_ELEM(*image_points,float,i,0)=image_points_bufj.x;CV_MAT_ELEM(*image_points,float,i,1)=image_points_bufj.y;CV_MAT_ELEM(*object_points,float,i,0)=(float)(j/cu
30、be_length);CV_MAT_ELEM(*object_points,float,i,1)=(float)(j%cube_length);CV_MAT_ELEM(*object_points,float,i,2)=0.0f;CV_MAT_ELEM(*point_counts,int,successes,0)=total_per_image;successes+;a+;cvReleaseImage(&show);cvDestroyWindow("FindCornerPoints");cvDestroyWindow("SrcPicture");
31、cout<<"*n"cout<<number_image<<"帧图片中,标定成功的图片为"<<successes<<"帧.n"cout<<number_image<<"帧图片中,标定失败的图片为"<<number_image-successes<<"帧.nn"cout<<"*nn"cout<<"按任意键开始计算摄像机内参数.nn&quo
32、t;IplImage * show_colie=cvLoadImage("7.jpg",-1);CvMat * object_points2=cvCreateMat(successes*total_per_image,3,CV_32FC1);CvMat * image_points2=cvCreateMat(successes*total_per_image,2,CV_32FC1);CvMat * point_counts2=cvCreateMat(successes,1,CV_32SC1);for(int i=0;i<successes*total_per_imag
33、e;+i)CV_MAT_ELEM(*image_points2,float,i,0)=CV_MAT_ELEM(*image_points,float,i,0);CV_MAT_ELEM(*image_points2,float,i,1)=CV_MAT_ELEM(*image_points,float,i,1);CV_MAT_ELEM(*object_points2,float,i,0)=CV_MAT_ELEM(*object_points,float,i,0);CV_MAT_ELEM(*object_points2,float,i,1)=CV_MAT_ELEM(*object_points,fl
34、oat,i,1);CV_MAT_ELEM(*object_points2,float,i,2)=CV_MAT_ELEM(*object_points,float,i,2);for(int i=0;i<successes;+i)CV_MAT_ELEM(*point_counts2,int,i,0)=CV_MAT_ELEM(*point_counts,int,i,0);cvReleaseMat(&object_points);cvReleaseMat(&image_points);cvReleaseMat(&point_counts);CV_MAT_ELEM(*int
35、rinsic_matrix,float,0,0)=1.0f;CV_MAT_ELEM(*intrinsic_matrix,float,1,1)=1.0f;CvMat * rotation_vectors=cvCreateMat(successes,3,CV_32FC1);CvMat * translation_vectors=cvCreateMat(successes,3,CV_32FC1);cvCalibrateCamera2(object_points2,image_points2,point_counts2,cvGetSize(show_colie),intrinsic_matrix,di
36、stortion_coeffs,/NULL,NULL,0);rotation_vectors,translation_vectors,0);cout<<"摄像机内参数矩阵为:n"cout<<CV_MAT_ELEM(*intrinsic_matrix,float,0,0)<<" "<<CV_MAT_ELEM(*intrinsic_matrix,float,0,1)<<" "<<CV_MAT_ELEM(*intrinsic_matrix,float,0,2)<&
37、lt;"nn"cout<<CV_MAT_ELEM(*intrinsic_matrix,float,1,0)<<" "<<CV_MAT_ELEM(*intrinsic_matrix,float,1,1)<<" "<<CV_MAT_ELEM(*intrinsic_matrix,float,1,2)<<"nn"cout<<CV_MAT_ELEM(*intrinsic_matrix,float,2,0)<<" &quo
38、t;<<CV_MAT_ELEM(*intrinsic_matrix,float,2,1)<<" "<<CV_MAT_ELEM(*intrinsic_matrix,float,2,2)<<"nn"cout<<"摄像机旋转矩阵为:n"cout<<CV_MAT_ELEM(*rotation_vectors,float,0,0)<<" "<<CV_MAT_ELEM(*rotation_vectors,float,0,1)<
39、<" "<<CV_MAT_ELEM(*rotation_vectors,float,0,2)<<"nn"cout<<CV_MAT_ELEM(*rotation_vectors,float,1,0)<<" "<<CV_MAT_ELEM(*rotation_vectors,float,1,1)<<" "<<CV_MAT_ELEM(*rotation_vectors,float,1,2)<<"nn"c
40、out<<CV_MAT_ELEM(*rotation_vectors,float,2,0)<<" "<<CV_MAT_ELEM(*rotation_vectors,float,2,1)<<" "<<CV_MAT_ELEM(*rotation_vectors,float,2,2)<<"nn"cout<<"摄像机平移矩阵为:n"cout<<CV_MAT_ELEM(*translation_vectors,float,0,0)
41、<<" "<<CV_MAT_ELEM(*translation_vectors,float,0,1)<<" "<<CV_MAT_ELEM(*translation_vectors,float,0,2)<<"nn"cout<<CV_MAT_ELEM(*translation_vectors,float,1,0)<<" "<<CV_MAT_ELEM(*translation_vectors,float,1,1)<<
42、;" "<<CV_MAT_ELEM(*translation_vectors,float,1,2)<<"nn"cout<<CV_MAT_ELEM(*translation_vectors,float,2,0)<<" "<<CV_MAT_ELEM(*translation_vectors,float,2,1)<<" "<<CV_MAT_ELEM(*translation_vectors,float,2,2)<<"nn"cout<<"畸变系数矩阵为:n&quo
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 有效护理计划制定试题及答案
- 深度剖析2025年卫生资格考试的试题及答案
- 医学研究设计试题及答案解析
- 2025年医师考试值得深入的问题试题及答案
- 行政管理2025年必考知识网点试题及答案
- 行政管理公共预算试题及答案
- 构建执业药师知识体系的试题及答案
- 主管护师临床案例处理试题及答案
- 临床药学服务模式创新探讨试题及答案
- 2025年文化创新试题及答案
- 生理学基础题库(46道)
- GB/T 17395-2024钢管尺寸、外形、重量及允许偏差
- DB5101-T135-2021城市公园分类分级管理规范
- 小学生中医药文化知识科普传承中医文化弘扬国粹精神课件
- 2024年福建省中考历史试卷(含标准答案及解析)
- 代持存款合同协议书
- 蛋糕店产品与服务方案
- 国开《会计学概论》网核模拟测试答案
- 2023年度健康体检大数据蓝皮书-美年健康+中关村美年健康产业研究院
- ASME材料-设计许用应力
- 数字贸易学 课件 第15章 数字支付与数字货币
评论
0/150
提交评论