本文共 1840 个字数,平均阅读时长 ≈ 5分钟
实验目的
- 了解开源图像处理库OpenCV的结构,掌握OpenCV的基本使用方法。
- 了解开源图像处理库OpenCV的基本模块功能,掌握常用图像处理方法。
- 掌握摄像机标定算法,学会使用OpenCV进行摄像机标定。
实验性质
验证性实验。
实验要求
- C++集成开发环境(QT5或VS2015及以上)
- 使用OpenCV进行单目摄像机标定
- 使用OpenCV进行双目摄像机标定
实验内容
- 掌握OpenCV开源图像库的基本使用方法
- 使用OpenCV进行单目摄像机标定
- 使用OpenCV进行双目摄像机标定
实验步骤
1、下载安装OpenCV4.x
官网下载: https://opencv.org/opencv-4-6-0/
2、摄像机标定原理
摄像机标定的目标,是要建立三维世界坐标系与二维图像坐标系之间的对应关系。在单目视觉中,这种对应关系是一对多的,即二维图像中的一个像素点对应着三维空间中的一条直线;在双目视觉中,可以通过两幅二维图像上的对应像素点计算得到三维世界坐标系与二维图像坐标系的一一对应关系。由此便可以得到物体的三维坐标值。
摄像机安装位置参数为外部参数,摄像机镜头畸变参数为非线性模型内部参数。标定过程即是求出摄像机的内部参数和外部参数,从而得到上述坐标转换的旋转矩阵和平移向量。
图中,摄像机坐标系为OXcYcZc,而计算机图像坐标系O0uv与图像平面坐标系O1xy的转换关系为:
u = sux + u0
v = svy + v0
写成矩阵形式为:
其中,su、sv分别为x、y轴方向单位长度对应的像素点数;u0、v0为镜头光学中心位置,单位为mm。
请用矩阵形式写出计算机图像平面坐标系O₀uv与世界坐标系的转换关系:
实际上,摄像机镜头成像并不是理想的透视成像,而是存在径向变形、偏心变形、薄棱镜变形等因素影响下产生不同程度的畸变。由于畸变因素作用,使空间点成像并不在线性模型描述的位置(x,y),而是在受到镜头失真影响而偏移的平面坐标(x^',y^' )。
其中,∆x、∆y为非线性畸变值,与像点在图像中的位置有关。一般镜头畸变同时存在径向畸变和切向畸变,切向畸变是由于透镜与摄像头传感器平面或图像平面不平行而产生的,多是由于透镜安装到镜头模组上的偏差导致,通常较小。实际应用中多只考虑径向畸变,径向畸变常用距图像中心径向距离的泰勒级数展开的前几项来表示:
k₁、k₂为非线性畸变参数,r^2=(x^'-u_0 )^2+(y^'-v_0 )^2。
摄像机的标定方法很多,大致可分为传统标定技术和自标定技术。
传统标定技术: 需要在摄像机前放置一个特定的标定物,并人为地提供一组已知坐标的特征基元,摄像机通过寻找这些已知特征的基元来实现标定
自标定技术: 比较灵活,不需要特定的参照物,它利用环境的刚体性,通过对比多幅图像中的对应点来计算摄像机模型
OpenCV采用介于传统标定方法和自标定方法之间的一种方法,由张正友提出。这种方法不需要知道摄像机运动的具体信息,比传统标定方法更灵活,同时仍需要一个特定的标定物以及一组已知的特征基元的坐标,这一点不如自标定灵活。它通过在至少3个不同的位置获取标定物的图像,计算出摄像机所有的内外参数。
标定算法描述参考知乎:https://zhuanlan.zhihu.com/p/36371959
OpenCV源码在其sample/data目录下面一个自带的棋盘图(chessboard.png),显示如下:
在标定的时候,算法要求提供的棋盘格的宽度与高度,还有他们的间隔距离。需要特别注意是这里的宽高是指他们的内部交叉点的个数,以上图为例,它的大小为7x7而不是8x8。间隔是指棋盘格之间的距离,可以用像素距离表示,也可以用实际毫米为单位表示。
3、标定常用函数
findChessboardCorners()
bool findChessboardCorners( InputArray image, Size patternSize, OutputArray corners, int flags = CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE );
函数功能: 确定输入图像是否是棋盘模式,并确定角点的位置。如果所有角点都被检测到且它们都被以一定顺序排布(一行一行地,每行从左到右), 数返回非零值,否则在函数不能发现所有角点或者记录它们地情况下,函数返回0
cv::drawChessboardCorners()
drawChessboardCorners( InputOutputArray image, Size patternSize, InputArray corners, bool patternWasFound );
函数功能: 用于标定摄像机时绘制被成功标定的角点
find4QuadCornerSubpix()
drawChessboardCorners( InputOutputArray image, Size patternSize, InputArray corners, bool patternWasFound );
函数功能: 查找棋盘角的亚像素精确位置。尝试近似分隔棋盘格字段(“四边形”)的线并返回这些线的交叉点。
cornerSubPix()
void cornerSubPix( InputArray image, InputOutputArray corners, Size winSize, Size zeroZone, TermCriteria criteria );
函数功能:优化角点位置,获得棋盘格上的亚像素角点。
calibrateCamera()
double calibrateCamera( InputArrayOfArrays objectPoints,InputArrayOfArrays imagePoints, Size imageSize,InputOutputArray cameraMatrix, InputOutputArray distCoeffs,OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,int flags = 0, TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON) );
函数功能: 通过多个视角的2D/3D对应,求解出该相机的内参数和每一个视角的外参数
initUndistortRectifyMap()
void initUndistortRectifyMap(InputArray cameraMatrix, InputArray distCoeffs, InputArray R, InputArray newCameraMatrix, Size size, int m1type, OutputArray map1, OutputArray map2)
函数功能: 这个函数使用于计算无畸变和修正转换关系。
4、单目摄像机标定
打开标定配置参数文件default.xml,设置参数:
- 棋盘格的宽度和高度(两个方向的角点数量),根据实际情况设置。
<!-- Number of inner corners per a item row and column. (square, circle) --> <BoardSize_Width>9</BoardSize_Width> <BoardSize_Height>6</BoardSize_Height>
- 每格的宽度
<!-- The size of a square in some user defined metric system (pixel, millimeter)--> <Square_Size>50</Square_Size>
- 选择输入方式
程序提供了3种输入方式。如果摄像机已连接电脑,可以使用input_camera方式。该方式只需要设置视频输入设备号,对于笔记本而言,通常0表示笔记本内置摄像头,1表示外置摄像头。
- 编译OpenCV标定程序
标定程序将实现以下功能
- 确定失真矩阵
- 确定摄像机矩阵
- 摄像机、视频和图像文件列表的输入
- 从XML/YAML文件进行配置
- 将结果保存到XML/YAML文件中
- 计算重投影误差
程序只有一个参数。其配置文件的名称。如果没有,它将尝试打开一个名为“default.xml”。
运行标定程序,摄像机将拍摄25幅图片并识别角点,如下图
标定结果保存在程序中指定的结果文件中
请在实验报告中说明结果文件中各项数据的意义(阅读代码,并在网上查阅相关资料)<nr_of_frames>25</nr_of_frames> <!-- 图像的宽和高度 --> <image_width>640</image_width> <image_height>480</image_height> <!-- 棋盘格的宽度11和高度8 --> <board_width>11</board_width> <board_height>8</board_height> <!-- 单元格的尺寸 --> <square_size>50.</square_size> <!-- 相机类型 --> <fisheye_model>0</fisheye_model> <!-- 尺寸自适应 --> <fix_aspect_ratio>1.</fix_aspect_ratio> <!-- 相机内部参数矩阵data为值Rows 和 cols为行和列Dt表示数据类新 --> <camera_matrix type_id="opencv-matrix"><rows>3</rows><cols>3</cols> <dt>d</dt> <data> 7.0111172389870558e+02 0. 3.1950000000000000e+02 0. 7.0111172389870558e+02 2.3950000000000000e+02 0. 0. 1. </data> </camera_matrix> <!-- 畸变系数Row和cols为维度Data包含畸变系数实际的值 --> <avg_reprojection_error> <!-- 为平均投影误差值 --> <distortion_coefficients type_id="opencv-matrix"> <rows>5</rows> <cols>1</cols> <dt>d</dt> <data> 7.2399710954221264e-02 4.5114674802590399e-01 0. 0. -3.8163393536623835e+00 </data> </distortion_coefficients> <avg_reprojection_error>4.1946356118960665e-01</avg_reprojection_error> <extrinsic_parameters type_id="opencv-matrix"> <rows>25</rows> <cols>6</cols> </extrinsic_parameters> <!-- 数据类型为double --> <dt>d</dt> <data> <!-- 数据太长这里省略 --> </data> <image_points type_id="opencv-matrix"> <rows>25</rows> <cols>88</cols> <!-- 数据类型为浮点 --> <dt>"2f"</dt> <data> 1.96974991e+02 3.05226959e+02 2.15540726e+02 3.04309814e+02 2.34028198e+02 3.03369354e+02 2.52492340e+02 3.02424805e+02 2.70655762e+02 3.01588440e+02 2.88653290e+02 3.00733093e+02 3.06717133e+02 2.99980408e+02 3.24438385e+02 2.99227295e+02 3.42079742e+02 2.98437469e </data> <!-- 这里也是数据太长省略 --> <grid_points> 0. 0. 0. 50. 0. 0. 100. 0. 0. 150. 0. 0. 200. 0. 0. 250. 0. 0. 300. 0. 0. 350. 0. 0. 400. 0. 0. 450. 0. 0. 500. 0. 0. 0. 50. 0. 50. 50. 0. 100. 50. 0. 150. 50. 0. 200. 50. 0. 250. 50. 0. 300. 50. 0. 350. 50. 0. 400. 50. 0. 450. 50. 0. 500. 50. 0. 0. 100. 0. 50. 100. 0. 100. 100. 0. 150. 100. 0. 200. 100. 0. 250. 100. 0. 300. 100. 0. 350. 100. 0. 400. 100. 0. 450. 100. 0. 500. 100. 0. 0. 150. 0. 50. 150. 0. 100. 150. 0. 150. 150. 0. 200. 150. 0. 250. 150. 0. 300. 150. 0. 350. 150. 0. 400. 150. 0. 450. 150. 0. 500. 150. 0. 0. 200. 0. 50. 200. 0. 100. 200. 0. 150. 200. 0. 200. 200. 0. 250. 200. 0. 300. 200. 0. 350. 200. 0. 400. 200. 0. 450. 200. 0. 500. 200. 0. 0. 250. 0. 50. 250. 0. 100. 250. 0. 150. 250. 0. 200. 250. 0. 250. 250. 0. 300. 250. 0. 350. 250. 0. 400. 250. 0. 450. 250. 0. 500. 250. 0. 0. 300. 0. 50. 300. 0. 100. 300. 0. 150. 300. 0. 200. 300. 0. 250. 300. 0. 300. 300. 0. 350. 300. 0. 400. 300. 0. 450. 300. 0. 500. 300. 0. 0. 350. 0. 50. 350. 0. 100. 350. 0. 150. 350. 0. 200. 350. 0. 250. 350. 0. 300. 350. 0. 350. 350. 0. 400. 350. 0. 450. 350. 0. 500. 350. 0. </grid_points> </image_points> </avg_reprojection_error>
这里面是相片的标定,坐标为像素点
评论 (0)