OpenCV 4.11.0
开源计算机视觉库
|
上一篇教程: ArUco 棋盘的检测
下一篇教程: 菱形标记的检测
ArUco 标记和棋盘由于其快速的检测速度和多功能性而非常有用。然而,ArUco 标记的一个问题是,即使应用了亚像素细化,其角点的精度也不是很高。
相反,棋盘图案的角点可以更精确地细化,因为每个角点都被两个黑色方块包围。然而,查找棋盘图案不如查找 ArUco 棋盘那样通用:它必须完全可见,并且不允许遮挡。
ChArUco 棋盘试图结合这两种方法的优点。
ArUco 部分用于插值棋盘角点的位置,使其具有标记棋盘的多功能性,因为它允许遮挡或部分视图。此外,由于插值角点属于棋盘,因此在亚像素精度方面非常准确。
当需要高精度时,例如在相机标定中,Charuco 棋盘比标准 ArUco 棋盘更好。
在本教程中,您将学习
您可以在 samples/cpp/tutorial_code/objectDetection/detect_board_charuco.cpp
中找到此代码。
这是一个关于如何实现目标列表中所有内容的示例代码。
aruco 模块提供了 cv::aruco::CharucoBoard
类,该类表示 Charuco 棋盘,并继承自 cv::aruco::Board
类。
此类以及其余 ChArUco 功能定义在
要定义一个cv::aruco::CharucoBoard
,需要以下参数:
对于cv::aruco::GridBoard
对象,aruco 模块提供了方便创建cv::aruco::CharucoBoard
的方法。可以使用cv::aruco::CharucoBoard
构造函数通过这些参数轻松创建此对象。
每个标记的 ID 默认情况下按升序排列,从 0 开始,就像cv::aruco::GridBoard
构造函数一样。可以通过访问board.ids
向量(类似于cv::aruco::Board
父类)轻松自定义。
获得cv::aruco::CharucoBoard
对象后,可以创建一个图像来打印它。有两种方法可以做到这一点:
doc/patter_tools/gen_pattern.py
,参见创建校准图案。cv::aruco::CharucoBoard::generateImage()
。函数cv::aruco::CharucoBoard::generateImage()
在cv::aruco::CharucoBoard 类中提供,可以使用以下代码调用:
cv::aruco::generateImageMarker()
函数。默认值为 1。输出图像将如下所示:
完整的示例包含在samples/cpp/tutorial_code/objectDetection/
中的create_board_charuco.cpp
文件中。
示例create_board_charuco.cpp
现在通过cv::CommandLineParser
从命令行接收输入。对于此文件,示例参数将如下所示:
检测 ChArUco 棋盘格时,实际上检测的是棋盘的每个角点。
ChArUco 棋盘格上的每个角点都有一个唯一的标识符 (ID) 分配。这些 ID 从 0 到棋盘上的角点总数。ChArUco 棋盘格检测步骤可以分解为以下步骤:
包含要检测的标记的原始图像。该图像对于在 ChArUco 角点执行亚像素细化是必要的。
readCameraParameters
的参数是:
此函数将这些参数作为输入,并返回一个布尔值,指示相机校准参数是否有效。对于无需校准的 Charuco 角点检测,不需要此步骤。
ChArUco 角点的检测基于先前检测到的标记。因此,首先检测标记,然后从标记插值 ChArUco 角点。检测 ChArUco 角点的方法是cv::aruco::CharucoDetector::detectBoard()
。
detectBoard 的参数是:
image
- 输入图像。charucoCorners
- 检测到的角点的图像位置的输出列表。charucoIds
- charucoCorners
中每个检测到的角点的输出 ID。markerCorners
- 检测到的标记角点的输入/输出向量。markerIds
- 检测到的标记的标识符的输入/输出向量。如果 markerCorners 和 markerIds 为空,则该函数将检测 aruco 标记和 ID。
如果提供校准参数,则 ChArUco 角点通过首先根据 ArUco 标记估计粗略姿态,然后将 ChArUco 角点重新投影回图像来进行插值。
另一方面,如果未提供校准参数,则通过计算ChArUco平面与ChArUco图像投影之间的对应单应性来插值ChArUco角点。
使用单应性的主要问题是插值对图像畸变更敏感。实际上,仅使用每个ChArUco角点最近的标记进行单应性变换,以减少畸变的影响。
在检测ChArUco棋盘的标记时,尤其是在使用单应性时,建议禁用标记的角点细化。原因是由于棋盘方格的邻近性,亚像素过程可能会导致角点位置产生较大的偏差,而这些偏差会传播到ChArUco角点插值,从而产生较差的结果。
此外,只返回其两个周围标记都已找到的角点。如果两个周围标记中的任何一个未被检测到,这通常意味着该区域存在遮挡或图像质量不好。无论如何,最好不考虑该角点,因为我们希望确保插值的ChArUco角点非常精确。
插值ChArUco角点后,进行亚像素细化。
一旦我们插值了ChArUco角点,我们可能希望绘制它们以查看它们的检测是否正确。这可以使用cv::aruco::drawDetectedCornersCharuco()
函数轻松完成
imageCopy
是将绘制角点的图像(通常与检测角点的图像相同)。outputImage
将是带有已绘制角点的inputImage
的克隆。charucoCorners
和charucoIds
是从cv::aruco::CharucoDetector::detectBoard()
函数检测到的ChArUco角点。cv::Scalar
。对于此图像
结果将是
在存在遮挡的情况下,如下面的图像所示,尽管某些角点清晰可见,但由于遮挡,并非所有周围标记都被检测到,因此它们没有被插值。
示例视频
完整的运行示例包含在samples/cpp/tutorial_code/objectDetection/
内的detect_board_charuco.cpp
中。
示例detect_board_charuco.cpp
现在通过cv::CommandLineParser
通过命令行接收输入。对于此文件,示例参数将如下所示:
ChArUco棋盘的最终目标是非常精确地找到角点,以进行高精度校准或姿态估计。
aruco模块提供一个函数,可以轻松地执行ChArUco姿态估计。与cv::aruco::GridBoard
一样,cv::aruco::CharucoBoard
的坐标系放置在棋盘平面内,Z轴指向内部,并位于棋盘的左下角。
objPoints
对应于指向平面内的Z轴。逆时针方向的objPoints
对应于指向平面外的Z轴。参见PR https://github.com/opencv/opencv_contrib/pull/3174要对charuco棋盘执行姿态估计,应使用cv::aruco::CharucoBoard::matchImagePoints()
和cv::solvePnP()
charucoCorners
和charucoIds
参数是从cv::aruco::CharucoDetector::detectBoard()
函数检测到的charuco角点。cameraMatrix
和distCoeffs
是姿态估计所需的相机校准参数。rvec
和tvec
参数是ChArUco棋盘的输出姿态。cv::solvePnP()
如果姿态估计正确则返回true,否则返回false。失败的主要原因是姿态估计的角点不足或在同一条线上。可以使用cv::drawFrameAxes()
绘制轴线,以检查姿态是否正确估计。结果将是:(X:红色,Y:绿色,Z:蓝色)
完整的运行示例包含在samples/cpp/tutorial_code/objectDetection/
内的detect_board_charuco.cpp
中。
示例detect_board_charuco.cpp
现在通过cv::CommandLineParser
通过命令行接收输入。对于此文件,示例参数将如下所示: