增强现实ArUco二维码库的测试与应用
- 2019 年 10 月 8 日
- 筆記
ArUco标记是一种二维码强标记物,在机器人导航,增强现实等应用中作为摄像机姿态估计工具。相比于其他弱标记物,比如自然图片,自然物体,ArUco标记的检测是鲁棒的,快速的,简单的。
OpenCV中的ArUco模块包括标记物的生成,检测,求取摄像机姿态等功能。标记物有两类:ArUco,ChArUco,其中 ChArUco=ArUco + Chessboard 构成的。如下图所示。

ArUco Markers

ChArUco Definition
ChArUco标记物功能性得整合了ArUco标记以及传统的用于摄像机标定的棋盘格,这样我们更容易得到更准确的角点检测结果,所以即使整个ChArUco标记物有部分遮挡,该标记物也可被识别。而且ArUco作者也推荐使用这种标记物。
一个典型的ArUco应用案例包括:模版的生成,摄像头的标定,摄像机姿态的估计。下面我以ChArUco模块的应用为例。
模版的生成
功能
由于二维码的快速检测和他们的易用性,ArUco标记物或者标记板非常的有用。然而,ArUco标记物的问题之一就是它的角点检测的精度不高,甚至使用亚像素精度来优化,精度也不高。相反,常用于摄像机标定的棋盘格的角点检测精度非常高,因为棋盘格是由黑白方块交替摆放形成的标定板,每个角点的色彩变化非常突出,因此棋盘格的角点检测精度高而且快。然而,必须要把棋盘格完全暴露没有任何遮挡的情况下,才能检测到棋盘格。
所以,以ArUco + Chessboard为构成的标记物可以兼顾高精度和高效率以及鲁棒性。
流程
ArUco模块提供 cv::aruco::CharucoBoard 类来表达一个 CharucoBoard 版,该类继承自 Board 类。
导入aruco的charuco模块
#include <opencv2/aruco/charuco.hpp>
设定标记物参数
CharUco标记板的平面局部坐标系以左上角为原点,从左上角至右上角的方向为 X 正方向,从左上角至左下角的方向为 Y 正方向。
a) X方向的棋盘格方块的数目。
Eg: 5
b) Y方向的棋盘格方块的数目。
Eg: 7
c) 棋盘格方块的边长(像素)
Eg: 500
d) ArUco标记的边长(像素)
Eg: 400
e) 所有的ArUco模块内置的标记物的ids。
DICT_4X4_50 = 0, DICT_4X4_100 = 1, DICT_4X4_250 = 2, DICT_4X4_1000 = 3, DICT_5X5_50 = 4, DICT_5X5_100 = 5, DICT_5X5_250 = 6, DICT_5X5_1000 = 7, DICT_6X6_50 = 8, DICT_6X6_100 = 9, DICT_6X6_250 = 10, DICT_6X6_1000 = 11, DICT_7X7_50 = 12, DICT_7X7_100 = 13, DICT_7X7_250 = 14, DICT_7X7_1000 = 15, DICT_ARUCO_ORIGINAsL = 16; Eg: DICT_6X6_250
该常量的意思是这种类型的DICT可以提供250种不同的标记物,每一个标记物在内存中的大小为 6*6 bits。
函数
(1)
Ptr<Dictionary> getPredefinedDictionary()
定义一个
aruco::Dictionary
(2)
Ptr<CharucoBoard> CharucoBoard::create()
定义一个
aruco::CharucoBoard
示例

摄像头的标定
功能
ArUco模块也可用来标定摄像头。摄像头标定结果包括得到摄像机内参和扭曲系数。这些参数基本是固定的,除非摄像机的光学设备发生明显变化,摄像机标定只需要在应用前做一次即可。
通常我们使用OpenCV的标定函数calibrateCamera()。这个函数需要真实环境的点(三维)和其在摄像机平面的投影(二维)。通常我们使用标定板来获取这种三维点和二维点的对应关系,可以再看OpenCV的calibrateCamera()函数的详细文档。
使用ArUco模块,标定过程可以使用ArUco标记物和棋盘格的混合。实验证明,使用ArUco模块辅助的标定板更加鲁棒,精确。
流程
打印真实大小的ChArUco标定板。
a) X方向的棋盘格方块的数目
Eg: 5
b) Y方向的棋盘格方块的数目
Eg: 7
c) 棋盘格方块的边长(m)
Eg: 0.05
d) ArUco标记的边长(m)
Eg: 0.04
e) 所有的ArUco模块内置的标记物的ids
Eg: DICT_6X6_250
读取detector参数,这些参数为ArUco模块提供的参数,我们不用管。

把标定板放在某个位置,使用摄像头拍摄多张不同角度的照片,10~20张即可。如下图所示。

生成标定系数。这里我们假设我们使用的摄像头分辨率为

。

函数
aruco::DetectorParameters::create()
建立一个Detector的参数指针,包括一系列默认参数,详见文档。
aruco::detectMarkers()
在输入图片中找到marker,只有预先定义过的 dictionary type (eg: DICT_6X6_250)才可以被检测到。
aruco::refineDetectedMarkers()
优化检测到的marker。
aruco::interpolateCornersCharuco()
得到每一个marker上的角点集。
aruco::drawDetectedCornersCharuco()
在输入图片上画出检测到的角点集。
aruco::calibrateCameraCharuco()
标定摄像机。
示例

摄像机姿态的估计
功能
当我们从视频帧中检测一个ChArUco标定板,实际上检测的是标定板内部的每一个角点。每一个角点都被分配一个唯一的id。这些id从0到角点数目。在ChArUco标定板检测到后,因为ChArUco模块支持遮挡检测,所以未被遮挡的id也能检测到。如下图所示。

检测到标记点的ChArUco标定板

有部分遮挡的ChArUco标定板
如果提供了标定后的参数,我们可以求得每一个ArUco标定物的姿态,并重投影回ChArUco标定板上标记出每一个ArUco的位置。
流程
设定要检测的标定板参数,详见上一节。
输入摄像机标定参数。详见上一节。
读取detector参数。详见上一节。
检测每一帧的markers。
估计ChArUco版相对于摄像机的姿态。如图所示。

如图中,每一个id表示找到的ChArUco内部的角点。每一个绿色的方框表示ArUco标记物。把求取得标定板姿态用局部坐标系的形式画到标定板上。
函数
aruco::estimatePoseCharucoBoard(charucoCorners, charucoIds, charucoboard,camMatrix, distCoeffs, rvec, tvec);
检测CharucoBoard的姿态。
示例

精度以及性能
在这里我使用单独的ArUco标记物做精度以及性能测试。
流程
Maya虚拟测试环境
制作真实尺度的图片,并模拟一个摄像机路径。然后批渲染一秒共 24 帧图片。如下图所示。

使用Maya的脚本语言获取每个视点的 t 和 r 。

求取了平移和旋转的平均误差

平均一帧处理时间约为

。
我们使用Maya的数据来测试ROI条件下的识别精度,以及完整图片中识别Marker的效率。比如我们使用如下序列的图片集来测试识别Marker的效率。

我们使用如下序列的图片来测试ROI条件下的识别精度。

我们2倍的比例不断缩小Marker Map在视频帧的大小。直到识别到相邻的不同状态(失败、成功)的两帧,然后取两帧中Marker Map的大小差,以1个像素为递减值,直到识别到相邻的不同状态的两帧。取最后也即最小的像素大小的Marker Map作为我们的ROI测试精度。
识别单个Marker的速度为

。
ROI识别精度为

单一Marker大小。
文档提到的平移分辨率为

旋转角度分辨率为

。
我的分辨率与文档分辨率相差

,

。