![]() |
OpenCV 4.12.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 从命令行获取输入。对于此文件,示例参数将如下所示: