前言
- 需要下载安装OpenCV工具包的朋友,请前往 此处 ;
- 系统要求:Windows系统,LabVIEW>=2018,兼容32位和64位。
calib3d 基本应用
OpenCV 的 calib3d 模块主要用于相机标定和三维重建。选板位于工具包的第一项,如下图(节选)。
其包含的函数众多,本文将主要讲解几种常用的功能。
1. 相机标定
相机标定是计算机视觉中的一个重要步骤,用于确定相机的内部参数和外部参数,以便能够准确地从图像中重建三维世界。
相机的内参包括:主点,焦距、畸变系数;
相机的外参是:世界坐标系相对于相机坐标系的旋转和平移向量;
- 坐标系定义
相机坐标系:相机的光学中心为原点,拍摄前方(光轴)为+Z,向右为+X,向下为+Y;
图像坐标系:图片左上角为原点,向右为+X,向下为+Y;
世界坐标系:描述真实物体的3D坐标系,根据实际情况自由设定;
做相机标定时,需要一种特殊的道具:标定板。常用的标定板有两种样式:“棋盘格” 和 “圆形网格”,后者又分为对称型和非对称型。
- 标定板的尺寸
对于棋盘格,每两个黑色方格的公共顶点,称为一个“角点”,其尺寸 PatternSize = (每行角点数 x 行数);
对于圆形网格(对称与非对称),以圆心点作为基准点,其尺寸 PatternSize = (每行圆心数 x 行数);
棋盘格和对称型圆形网格,行和列可以调换,但非对称型圆形网格的方向定义是固定的。
- 提取棋盘格的角点
固定相机,对着桌面上的一张棋盘格标定板,拍摄一张照片。
使用 findChessboardCorners 识别角点,使用 drawChessboardCorners 将结果可视化。
- 提取圆形网格的圆心
识别圆形网格,需要使用 findCirclesGrid 函数,通过 flags 参数切换 “对称型” 和 “非对称型”。
-
标定数据准备
相机标定需要两组数据:物体三维坐标(objectPoints)和 对应的二维投影(imagePoints)。
以上述棋盘格为例,findChessboardCorners 返回的 corners 就是这些角点的 imagePoints,基于图像坐标系。而这些角点在世界坐标系下的3D坐标,就是对应的 objectPoints。
假如我们以左上方第一个角点作为世界坐标系的原点,沿标定板第一行向右为X,沿第一列向下为Y,桌面为Z=0平面,设黑色方格的边长为 “单位1”,那么 Corners 对应的世界坐标 objectPoints 可以表示为:
(0,0,0), (1,0,0), (2,0,0), (3,0,0), (4,0,0), (5,0,0), (6,0,0), (7,0,0), (8,0,0), (9,0,0)
(0,1,0), (1,1,0), (2,1,0), (3,1,0), (4,1,0), (5,1,0), (6,1,0), (7,1,0), (8,1,0), (9,1,0)
…
(0,6,0), (1,6,0), (2,6,0), (3,6,0), (4,6,0), (5,6,0), (6,6,0), (7,6,0), (8,6,0), (9,6,0) -
开始标定
参考范例:examples/Molitec/OpenCV/calib3d/calib3d_1(calibrateCamera).vi
使用 calibrateCamera 函数进行标定,输入 objectPoints 和 imagePoints,输出相机内参和外参,如下图。
注意,calibrateCamera 支持同时输入多张标定板的数据。虽然我们只输入一张标定板,但也要将 imagePoints 和 objectPoints 分别绑定成 Mat数组 再送入calibrateCamera。另外还要创建两个空的Mat,用于承载输出的 cameraMatrix 和 distCoeffs。输出的内、外参矩阵的数据类型都是64F。
最后,使用LabVIEW自带的函数(位于 File IO >> XML >> LabVIEW Schema),将得到的内参和外参写入xml文件,以备后续使用。
- 结果分析
上例中,输出的 cameraMatrix 是相机的内参矩阵,包含主点(cx,cy)和焦距(fx,fy),对应位置如下。
输出的 distCoeffs 是畸变系数,rvecs 和 tvecs 分别是“旋转向量”数组和“平移向量”数组,代表每一张标定板坐标系相对于相机的旋转和平移向量。如果我们只输入了一张标定板的数据,那么只取数组的第一项即可。
注意,本例使用的3D坐标 objectPoints 是将黑色方格边长简化为 “单位1” 的结果。你也可以将其替换成真实尺寸,然后重新进行标定。你会发现,内参几乎不变,只有外参 tvecs 有变化。
2. 畸变矫正
- 用一台畸变严重的相机拍摄标定板,做一次相机标定,将内参和外参保存成文件,如:board2.xml;
- 以后此相机拍摄的每一张照片,都可以用 board2.xml 保存的参数 配合 undistort 函数进行畸变矫正;
- undistort 的输入Src 是矫正前的图像,cameraMatrix 和 distCoeffs 是相机内参(64F类型),输出Dst是矫正后的图像;
- 参考范例:examples/Molitec/OpenCV/calib3d/calib3d_4(undistort).vi
3. 位姿估计
已知物体的 objectPoints 和 imagePoints,以及相机的内参,求解物体坐标系相对于相机坐标系的位姿(平移和旋转),可以使用 solvePnP 函数来实现。
注意区别 solvePnP 与 calibrateCamera 的用法和功能,solvePnP 相当于在内参不变的前提下,求解新的外参。
- 以第1小节标定的相机为例,再用它拍摄一张照片,内容是一个小方块;
- 选取小方块上的7个关键点,自定义世界坐标系,确定它们的三维坐标 objectPoints ;
- 用任意方法(图像识别或手动描点),得到7个关键点对应的像素坐标 imagePoints;
- 从xml文件中载入相机内参;
- 调用 solvePnP 函数,求取小方块(坐标系)的位姿 rvec 和 tvec;
4. 二维投影
已知物体的 objectPoints 以及相机的内参和外参,求解对应的二维图像投影 imagePoints ,可以使用 projectPoints 函数来实现。
- 以第1小节标定的相机为例,我们尝试在2D图片上画出3D坐标轴的投影;
- 选取世界坐标系的原点 (0,0,0) 以及X、Y、Z 轴上的任意三点,组成 objectPoints ;
- 从xml文件中载入相机内参和外参;
- 调用 projectPoints 函数, 求取对应的 imagePoints ;
- 在投影点 imagePoints 中,将原点与其他三点分别连线,就形成了3D坐标轴;
- 参考范例:examples/Molitec/OpenCV/calib3d/calib3d_3(projectPoints).vi
5. 双目视觉
双目视觉是一种基于视差原理的三维感知技术,通过模拟人类双眼的视觉机制,利用两个摄像头从不同角度获取同一场景的图像,从而计算出物体的深度信息。
calib3d 模块下,为用户提供了大量处理 stereo 图像的函数和类。本文介绍其中一种:StereoBM 类。选板如图。
- 参考范例:examples/Molitec/OpenCV/calib3d/calib3d_5(StereoBM).vi;
- StereoBM 类可以对“左”、“右”眼画面进行匹配,并逐一像素计算“视差”;
- 视差越大,说明物体距离摄像头越近,反之越远;
- compute 返回结果类型为16S(16位有符号整数),通过Mat内置的 covertTo 方法,将其转换到 0~255 范围的8U矩阵,以便通过灰度图像直观显示视差结果(亮度越大,视差越大);
总结
- 本系列博文作为LabVIEW工具包—OpenCV的教程,将以专栏的形式陆续发布和更新。
- 对工具包感兴趣的朋友,欢迎下载试用:秣厉科技 - LabVIEW工具包 - OpenCV
- 各位看官有什么想法、建议、吐槽、批评,或新奇的需求,也欢迎留言讨论。