来源OpenCV
http://docs.opencv.org/master/df/d4a/tutorial_charuco_detection.html
ArUco标记和板非常有用因为他们的快速检测和多功能性。 然而,ArUco标记的问题之一是,角落的位置的准确性不是太高,即使应用亚像素细分。
相反,棋盘模式的角落可以更准确地提炼因为每个角落周围是两个黑色方块。 然而,找到一个棋盘模式不像找到一个通用的ArUco板:它必须是完全可见,遮挡不允许。
ChArUco板试图结合这两种方式的好处:
ArUco部分用于插入棋盘角落的位置,这样它的多功能性标记板,因为它允许遮挡或部分视图。 此外,由于插值角落属于一个棋盘,他们非常准确的亚像素精度。
当精度高是必要的,比如在相机标定,Charuco板是一个更好的选择比标准Aruco板。
aruco模块提供了 简历:aruco::CharucoBoard
类代表一个Charuco板和继承的 板
类。
ChArUco余下的功能,这个类中定义:
定义一个 CharucoBoard
,它是必要的:
至于 GridBoard
对象,aruco模块提供了一个函数来创建 CharucoBoard
很容易。 这个函数是静态函数 cv::aruco::CharucoBoard::create()
:
每一个标记的id分配默认按升序,从0开始,喜欢 GridBoard:create()
。 这可以很容易地定制的访问id向量通过 board.ids
,就像在 板
父类。
一旦我们有 CharucoBoard
对象,我们可以创建一个图像打印它。 这可以完成了
{CharucoBoard::draw()```}
``` c++
cv::Ptr board = cv::aruco::CharucoBoard::create(5, 7, 0.04, 0.02, dictionary);
cv::Mat boardImage;
board->draw( cv::Size(600, 500), boardImage, 10, 1 );
boardImage
:输出图像。drawMarker()
函数。 默认值是1。输出图像将是这样的:
一个完整的工作包含在示例 create_board_charuco.cpp
模块内的样本文件夹。
注意:样品现在通过命令行通过输入 OpenCV命令行解析器 。 这个文件的示例参数
当你检测ChArUco板,你实际上是检测是棋盘上的每一个角落。
上的每一个角落ChArUco板都有一个唯一的标识符(id)。 这些id从0到角落的总数。
所以,发现ChArUco板包括:
std::vector charucoCorners
: list of image positions of the detected corners.std::vector charucoIds
: ids for each of the detected corners in charucoCorners
.ChArUco角落的检测是基于前面的检测标记。 因此,首先检测到标记,然后ChArUco角落从标记插入。
的功能检测ChArUco角落 CV::aruco::interpolateCornersCharuco()
。 这个例子展示了整个过程。 首先,检测到标记,然后ChArUco角落从这些标记将被内插。
cv::Mat inputImage;
cv::Mat cameraMatrix, distCoeffs;
// camera parameters are read from somewhere
readCameraParameters(cameraMatrix, distCoeffs);
cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::Ptr board = cv::aruco::CharucoBoard::create(5, 7, 0.04, 0.02, dictionary);
...
std::vector markerIds;
std::vector> markerCorners;
cv::aruco::detectMarkers(inputImage, board.dictionary, markerCorners, markerIds);
// if at least one marker detected
if(markerIds.size() > 0) {
std::vector charucoCorners;
std::vector charucoIds;
cv::aruco::interpolateCornersCharuco(markerCorners, markerIds, inputImage, board, charucoCorners, charucoIds, cameraMatrix, distCoeffs);
}
的参数 interpolateCornersCharuco()
函数是:
markerCorners
和 markerIds
:检测到标记 detectMarkers()
函数。inputImage
:标记检测的原始图像。 执行所需的图像亚像素细分ChArUco角落。板
: CharucoBoard
对象charucoCorners
和 charucoIds
:输出插入Charuco角落cameraMatrix
和 distCoeffs
:可选相机标定参数 在这种情况下,我们有电话 interpolateCornersCharuco()
提供摄像机标定参数。 然而这些参数是可选的。 没有这些参数类似的例子是:
cv::Mat inputImage;
cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::Ptr board = cv::aruco::CharucoBoard::create(5, 7, 0.04, 0.02, dictionary);
...
std::vector markerIds;
std::vector> markerCorners;
cv::Ptr params;
params->cornerRefinementMethod = cv::aruco::CORNER_REFINE_NONE;
cv::aruco::detectMarkers(inputImage, board.dictionary, markerCorners, markerIds, params);
// if at least one marker detected
if(markerIds.size() > 0) {
std::vector charucoCorners;
std::vector charucoIds;
cv::aruco::interpolateCornersCharuco(markerCorners, markerIds, inputImage, board, charucoCorners, charucoIds);
}
如果校准参数提供,ChArUco角落内插,首先,估计ArUco标记和一个粗略的姿势,然后,reprojecting ChArUco角落回到形象。
另一方面,如果不提供校准参数,ChArUco角落被计算相应的插值ChArUco平面和ChArUco图像之间的单应性投影。
使用单应性的主要问题是,插值更明智的图像失真。 实际上,单应性只使用最接近的执行标记每个ChArUco角落减少失真的影响。
当检测标记ChArUco板特别是当使用单应性,建议禁用标志的角落细化。 这个的原因是,由于接近棋盘的广场,构造过程可以产生重要的在角落位置偏差,这些偏差传播到插值ChArUco角落,产生不良的结果。
此外,只有那些角落里的两个周围标记返回。 如果任何周围的两个标记没有被检测到,这通常意味着有阻塞或区域的图像质量不好。 在任何情况下,最好不要考虑到角落里,因为我们想要确保插值ChArUco角落非常准确。
ChArUco角落已经插入后,进行亚像素细分。
一旦我们有插值ChArUco角落,我们可能会想画,看看他们的检测是正确的。 这可以很容易地使用完成 drawDetectedCornersCharuco()
功能:
图像
是将图像的角落(它将通常是相同的图像的角落发现了)。outputImage
将是一个克隆的 inputImage
的角落。charucoCorners
和 charucoIds
的发现Charuco角落吗 interpolateCornersCharuco()
函数。简历:标量
。这张图片:
结果将是:
在闭塞的存在。 像下面的图片,虽然有些角落清晰可见,并不是所有周围的标记已发现由于阻塞,因此,他们不是插值:
最后,这是一个完整的示例ChArUco检测(不使用校准参数):
cv::VideoCapture inputVideo;
inputVideo.open(0);
cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::Ptr board = cv::aruco::CharucoBoard::create(5, 7, 0.04, 0.02, dictionary);
cv::Ptr params;
params->cornerRefinementMethod = cv::aruco::CORNER_REFINE_NONE;
while (inputVideo.grab()) {
cv::Mat image, imageCopy;
inputVideo.retrieve(image);
image.copyTo(imageCopy);
std::vector ids;
std::vector> corners;
cv::aruco::detectMarkers(image, dictionary, corners, ids, params);
// if at least one marker detected
if (ids.size() > 0) {
cv::aruco::drawDetectedMarkers(imageCopy, corners, ids);
std::vector charucoCorners;
std::vector charucoIds;
cv::aruco::interpolateCornersCharuco(corners, ids, image, board, charucoCorners, charucoIds);
// if at least one charuco corner detected
if(charucoIds.size() > 0)
cv::aruco::drawDetectedCornersCharuco(imageCopy, charucoCorners, charucoIds, cv::Scalar(255, 0, 0));
}
cv::imshow("out", imageCopy);
char key = (char) cv::waitKey(waitTime);
if (key == 27)
break;
}
一个完整的工作包含在示例 detect_board_charuco.cpp
模块内的样本文件夹。
注意:样品现在通过命令行通过输入 OpenCV命令行解析器 。 这个文件的示例参数
ChArUco板的最终目标是找到角落非常准确地高精度校准或估计。
aruco模块提供了一个函数来执行ChArUco姿势容易估计。 就像在 GridBoard
的坐标系统 CharucoBoard
被放置在板平面与Z轴指出,集中在板的左下角。
造成估计的函数 estimatePoseCharucoBoard()
:
charucoCorners
和 charucoIds
参数的检测从charuco角落 interpolateCornersCharuco()
函数。CharucoBoard
对象。cameraMatrix
和 distCoeffs
摄像机标定参数为姿势估计是必要的。rvec
和 tvec
参数输出Charuco板的构成。 轴可以用 drawAxis()
检查姿势正确估计。 结果是:(X:红Y:绿色,Z:蓝色)
一个完整的例子与姿势估计ChArUco检测:
一个完整的工作包含在示例 detect_board_charuco.cpp
模块内的样本文件夹。
注意:样品现在通过命令行通过输入 OpenCV命令行解析器 。 这个文件的示例参数