【计算机视觉】 相机姿态估计之标记检测-检测ArUco板2

检测ArUco板

来源OpenCV http://docs.opencv.org/master/db/da9/tutorial_aruco_board_detection.html

1 效果图

板与轴

这是另一个例子与部分堵塞:


与遮挡

因为它可以观察到,尽管一些标记没有被发现,构成仍然可以估计的标记。


ArUco

ArUco是一组标记,就像一个标志,它提供了一个单一的姿势相机。

最受欢迎的是一个标记在同一平面上,因为它可以很容易地印刷:

然而,并不局限于这种安排,可以代表任何2 d或3 d布局。

板的区别和一组独立的标记,标记之间的相对位置是已知的先验。这允许的所有标记可用于估计相机的姿势对整个

当你使用一组独立的标志,你可以估计每个单独标记的姿势,因为你不知道在环境中相对位置的标记。

使用板的主要好处是:

· 姿势估计更多功能。 只有一些标记进行姿态估计是必要的。 因此,构成可以计算出即使在遮挡或部分观点的存在。

· 以来获得的姿势通常是更准确的点对应(标记角落)。

aruco模块允许使用。 主要的类  cv::aruco::Board 类定义布局:


class  Board {
public:
    std::vector<std::vector<cv::Point3f> > objPoints;
    cv::Ptr<cv::aruco::Dictionary> dictionary;
    std::vector<int> ids;
};

一个类型的对象  有三个参数:

·  objPoints结构的3 d板的角落位置参考系统,即它的布局。 对于每一个标记,它的四个角落都存储在标准的顺序,即按顺时针方向从左上角开始。

·  字典参数表示的标记字典属于标记。

· 最后id结构表明每个标记的标识符 objPoints对指定的 字典


板检测

检测类似于标准标志检测。唯一的区别是在姿态估计的步骤。 事实上,使用标志板,一个标准的标记检测应该做过评估构成。

aruco模块提供了一个特定的函数, estimatePoseBoard(),执行评估:


cv::Mat inputImage;
// camera parameters are read from somewhere
cv::Mat cameraMatrix, distCoeffs;
readCameraParameters(cameraMatrix, distCoeffs);
// assume we have a function to create the board object
cv::Ptr<cv::aruco::Board> board = cv::aruco::Board::create();
...
std::vector<int> markerIds;
std::vector<std::vector<cv::Point2f>> markerCorners;
cv::aruco::detectMarkers(inputImage, board.dictionary, markerCorners, markerIds);
// if at least one marker detected
if(markerIds.size() > 0) {
    cv::Vec3d rvec, tvec;
    int valid = cv::aruco::estimatePoseBoard(markerCorners, markerIds, board, cameraMatrix, distCoeffs, rvec, tvec);
}

estimatePoseBoard的参数是:

· markerCorners markerIds:检测到标记的结构 detectMarkers()函数。

·   对象定义了板布局及其id

· cameraMatrix distCoeffs:相机标定参数姿态估计的必要条件。

· rvec tvec预测:的构成。如果非空,那么作为初始猜测。

· 函数返回的标记用于估计总数构成。注意,并不是所有的提供的标记 markerCorners markerIds应该使用,因为只有中列出的标记的id吗 :id结构被认为是。

 drawAxis()函数可以用来检查获得的姿势。 例如:

gbmarkersaxis.png
Board with axis

And this is another example with the board partially occluded:

gbocclusion.png
Board with occlusions

因为它可以观察到,尽管一些标记没有被发现,构成仍然可以估计的标记。


网格板

创建  对象需要指定环境中的每个标记的角落位置。然而,在许多情况下,将只是一组标记在同一个平面上,在网格布局,所以它可以很容易地印刷和使用。

幸运的是,aruco模块提供的基本功能来创建和打印这些类型的标记。

 GridBoard类是一个专业类的继承  类代表和所有的标记在同一个平面上,在网格布局,如以下图片:


图像与aruco

具体的坐标系统在网格板放置在板平面,集中在左下角的Z指出,像下图(X:红Y:绿色,Z:蓝色):


板与轴

一个 GridBoard对象可以定义使用以下参数:

可以很容易地创建这个对象从这些参数使用  cv::aruco::GridBoard::create()静态函数:



一个 GridBoard对象可以定义使用以下参数:

· 标记在X方向上。

· 标记在Y方向上。

· 长度的标记。

· 的长度标记分离。

· 字典的标记。

· 所有标记的id(X * Y标记)。

可以很容易地创建这个对象从这些参数使用 cv::aruco::GridBoard::create() 静态函数:

cv::aruco::GridBoard board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary);

·

  • 第一个和第二个参数标记的数量分别在X和Y方向。
  • 第三个和第四个参数分别标记长度和标记分离。 他们可以在任何单位提供,记住,估计姿势这个委员会将以相同的单位(一般来说,使用米)。
  • 最后,提供了标记的字典。

所以,这个委员会将由5 x7 = 35标记。 每个标记的id分配,默认情况下,按升序开始0,所以他们将0,1,2,… 34岁。 这可以很容易地定制的访问id向量通过 board.ids,就像在 父类。

创建一个网格板后,我们可能需要打印它并使用它。 一个函数生成的形象 GridBoard中提供

 cv::aruco::GridBoard::draw().例如:


cv::Ptr<cv::aruco::GridBoard> board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary);
cv::Mat boardImage;
board->draw( cv::Size(600, 500), boardImage, 10, 1 );

  • 第一个参数是输出图像的像素大小。 在这种情况下600 x500像素。 如果这不是规模成正比,它将以图像为中心。
  • boardImage:输出图像。
  • 第三个参数(可选)边缘的像素,所以所有的标记都触碰图像边界。 在这种情况下,保证金是10。
  • 最后,标记边界的大小,类似 drawMarker()函数。 默认值是1。

输出图像将是这样的:

board.jpg

一个完整的工作示例创建包含在 create_board.cpp模块内的样本文件夹。

注意:样品现在通过命令行通过输入 OpenCV命令行解析器 。 这个文件的示例参数

"_output path_/aboard.png" -w=5 -h=7 -l=100 -s=10 -d=10

最后,一个完整的板检测的例子:

cv::VideoCapture inputVideo;
inputVideo.open(0);
cv::Mat cameraMatrix, distCoeffs;
// camera parameters are read from somewhere
readCameraParameters(cameraMatrix, distCoeffs);
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::Ptr<cv::aruco::GridBoard> board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary);
while (inputVideo.grab()) {
    cv::Mat image, imageCopy;
    inputVideo.retrieve(image);
    image.copyTo(imageCopy);
    std::vector<int> ids;
    std::vector<std::vector<cv::Point2f> > corners;
    cv::aruco::detectMarkers(image, dictionary, corners, ids);
    // if at least one marker detected
    if (ids.size() > 0) {
        cv::aruco::drawDetectedMarkers(imageCopy, corners, ids);
        cv::Vec3d rvec, tvec;
        int valid = estimatePoseBoard(corners, ids, board, cameraMatrix, distCoeffs, rvec, tvec);
        // if at least one board marker detected
        if(valid > 0)
            cv::aruco::drawAxis(imageCopy, cameraMatrix, distCoeffs, rvec, tvec, 0.1);
    }
    cv::imshow("out", imageCopy);
    char key = (char) cv::waitKey(waitTime);
    if (key == 27)
        break;
}


一个完整的工作包含在示例 detect_board.cpp模块内的样本文件夹。

注意:样品现在通过命令行通过输入 OpenCV命令行解析器 。 这个文件的示例参数

-c="_path_"/calib.txt" "_path_/aboard.png" -w=5 -h=7 -l=100 -s=10 -d=10

完善标记检测

ArUco也可以用来提高标记的检测。 如果我们有检测到标记的一个子集,属于,我们可以使用这些标记和会布局信息,试图找到先前没有被检测到的标记。

这可以通过使用 refineDetectedMarkers()之后不应调用函数,该函数调用 detectMarkers()

这个函数的主要参数是原始图像标记检测对象,检测到标记,检测到标记id和被拒绝的标志。

被拒绝的角落可以获得的 detectMarkers()函数,也称为标记的候选人。 这个候选人是方形的形状已经发现在原始图像,但是未能通过识别步骤(即内心编纂了太多错误),因此他们没有被认为是标记。

然而,这些候选人有时实际标记没有被正确地识别图像中由于高噪音,非常低的分辨率或其他相关问题影响到二进制代码提取。 的 refineDetectedMarkers()函数发现这些候选人之间的通讯和失踪的标记。 这个搜索是基于两个参数:

  • 候选人和失踪的投影之间的距离标记。 获得这些预测,必须发现至少一个的标志。 使用相机的参数获得的预测(相机畸变系数矩阵和)如果他们提供。 如果不是,从当地获得的预测单应性和只允许平面板(即Z坐标的所有角落标志应该是一样的)。 的 minRepDistance参数 refineDetectedMarkers()确定候选人之间的最小欧氏距离角落和预测标记(默认值10)。
  • 二进制编纂。 如果一个候选人超过最小距离条件下,分析了其内部位再来确定它是否实际上是将标记。 然而,在这种情况下,条件不是如此强大和允许的数量错误比特可以更高。 这是表示的 errorCorrectionRate3.0参数(默认值)。 如果提供了负值,内部位根本不分析,只有角落距离评估。

这是一个使用的例子 refineDetectedMarkers()功能:

cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::Ptr<cv::aruco::GridBoard> board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary);
std::vector<int> markerIds;
std::vector<std::vector<cv::Point2f>> markerCorners, rejectedCandidates;
cv::aruco::detectMarkers(inputImage, dictionary, markerCorners, markerIds, cv::aruco::DetectorParameters(), rejectedCandidates);
cv::aruco::refineDetectedMarkersinputImage, board, markerCorners, markerIds, rejectedCandidates);
// After calling this function, if any new marker has been detected it will be removed from rejectedCandidates and included
// at the end of markerCorners and markerIds

它还必须指出,在某些情况下,如果检测到标记的数量在第一时间太低(例如只有1或2标记),失踪的预测标记可以是糟糕的质量,产生错误的通讯。

查看更详细的实现模块样品。



  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
相机标定是计算机视觉中的一个重要步骤,用于确定相机的内参和畸变参数,以便进行准确的图像测量和姿态估计。而Aruco标定是一种特殊的标定,其中包含具有特定编码的黑白方块,用于相机标定和姿态估计。 要进行相机标定,首先需要准备一个Aruco标定。可以在OpenCV中使用`cv2.aruco.CharucoBoard()`函数创建一个Aruco标定对象,指定方块的数量、大小和编码等参数。然后,将该标定打印出来并粘贴在一个平面上。 接下来,需要采集一组包含Aruco标定的图像。确保在不同角度和距离下拍摄多张图像,以覆盖尽可能多的相机视角。可以使用OpenCV中的`cv2.aruco.detectMarkers()`函数检测图像中的Aruco标记,并使用`cv2.aruco.estimatePoseCharucoBoard()`函数估计标定的姿态。 一旦收集了足够数量的图像,就可以使用OpenCV中的`cv2.aruco.calibrateCameraCharuco()`函数来计算相机的内参和畸变参数。该函数将输入图像、Aruco标定的参数以及检测到的标记和姿态作为输入,并返回相机参数。 最后,可以使用得到的相机参数对未知图像进行校正,以获得更准确的测量结果。 需要注意的是,相机标定的精度和准确性取决于标定的质量、图像采集的多样性以及标定算法的准确性等因素。因此,在进行相机标定之前,建议仔细阅读相关文档并进行充分的实验和验证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值