博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
视觉标记定位aruco使用
阅读量:4083 次
发布时间:2019-05-25

本文共 5889 字,大约阅读时间需要 19 分钟。

转载自:

视觉标记定位aruco使用

2019-10-26 11:05:51 2657

分类专栏: 文章标签:

版权声明:本文为博主原创文章,遵循版权协议,转载请附上原文出处链接和本声明。

本文链接:

版权

本文的目的是实现生成一张marker broad图片,告诉标记检测程序tag在真实世界中的实际大小。

检测成功后得到marker的id,四个角点坐标,marker到相机的平移和旋转。

1.下载安装参考

opencv 中的aruco源码下载要到下面地址

https://github.com/opencv/opencv_contrib/tree/master/modules/aruco
https://github.com/opencv/opencv_contrib/releases/tag/3.3.0

2.生成单个marker图片

程序如下

#include 
#include
#include
#include "opencv2/core/core.hpp"#include
#include
#include
using namespace std;using namespace cv;int main(){ cv::Mat markerImage; cv::Ptr
dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); cv::aruco::drawMarker(dictionary, 23, 200, markerImage, 1); imwrite("./aruco_tag.png",markerImage); imshow("test", markerImage);//显示marker waitKey(); return 0;}

cv::aruco::drawMarker

第一个参数是之前创建的Dictionary对象。
第二个参数是marker的id,在这个例子中选择的是字典DICT_6X6_250 的第23个marker。注意到每个字典是由不同数目的Marker组成的,在这个例子中的字典中,有效的Id数字范围是0到249。不在有效区间的特定id将会产生异常。
三个参数,200,是输出Marker图像的大小。在这个例子中,输出的图像将是200x200像素大小。注意到这一参数需要满足能够存储特定字典 的所有位。举例来说,你不能为6x6大小的marker生成一个5x5图像(这还没有考虑到Marker的边界)。除此之外,为了避免变形,这一参数最好和位数+边界的大小成正比,或者至少要比marker的大小大得多(如这个例子中的200),这样变形就不显著了
第四个参数是输出的图像。
最终,最后一个参数是一个可选的参数,它指定了Marer黑色边界的大小。这一大小与位数数目成正比。例如,值为2意味着边界的宽度将会是2的倍数。默认的值为1。

3 . 打印并标定相机内参

注意,打印的时候如果用像素为200200的图像打印,实际打印大小为20cm20cm,那么一个像素对应1毫米。

内参标定就不介绍了,此实验使用内参为

intrinsic_matrix: !!opencv-matrix   rows: 3   cols: 3   dt: d   data: [ 420.019, 0., 330.8676, 0.,       419.6044, 217.8731, 0., 0., 1. ]distortion_vector: !!opencv-matrix   rows: 1   cols: 4   dt: d   data: [ -0.3549, 0.1151, -0.0035, -0.0029 ]

的相机拍出来的图像如下

在这里插入图片描述

4.检测marker并得到id和相对位移

确定好实际打印出来的marker的边长和内参就可以检测并计算了。

其中markerlength表示marker的实际物理长度。
使用上面的图像和内参程序如下

#include 
#include
#include
#include "opencv2/core/core.hpp"#include
#include
#include
#include
#include
#include
using namespace std;using namespace cv;int main(){ cv::Mat m_image=imread("./mark.jpg"); if(m_image.empty()) { cout<<"m_image is empty"<
(3, 3) << 420.019, 0.0, 330.8676, 0.0,419.6044, 217.8731, 0.0, 0.0, 1.0); cv::Mat distCoeffs=(cv::Mat_
(4, 1) << -0.3549, 0.1151, -0.0035, -0.0029); cv::Mat imageCopy; m_image.copyTo(imageCopy); cv::Ptr
dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); std::vector
ids; std::vector
> corners; cv::aruco::detectMarkers(m_image, dictionary, corners, ids);//检测靶标 // if at least one marker detected if (ids.size() > 0) { cv::aruco::drawDetectedMarkers(imageCopy, corners, ids);//绘制检测到的靶标的框 for(unsigned int i=0; i
rvecs, tvecs;   cv::aruco::estimatePoseSingleMarkers(corners[i], markerlength, intrinsics, distCoeffs, rvecs, tvecs);//求解旋转矩阵rvecs和平移矩阵tvecs cv::aruco::drawAxis(imageCopy,intrinsics,distCoeffs, rvecs[i], tvecs[i], 0.1); //3.rotaion vector to eulerAngles cv::Mat rmat; Rodrigues(rvecs[i], rmat); Eigen::Matrix3d rotation_matrix3d; cv2eigen(rmat,rotation_matrix3d); Eigen::Vector3d eulerAngle = rotation_matrix3d.eulerAngles(0,1,2);//(0,1,2)表示分别绕XYZ轴顺序,即 顺序,逆时针为正 cout<<"pitch "<
<<"yaw "<
<<"roll"<
<

其中

The parameters of detectMarkers are:
The first parameter is the image where the markers are going to be detected.
The second parameter is the dictionary object, in this case one of the predefined dictionaries (DICT_6X6_250).
The detected markers are stored in the markerCorners and markerIds structures:
markerCorners is the list of corners of the detected markers. For each marker, its four corners are returned in their original order (which is clockwise starting with top left). So, the first corner is the top left corner, followed by the top right, bottom right and bottom left.
markerIds is the list of ids of each of the detected markers in markerCorners. Note that the returned markerCorners and markerIds vectors have the same sizes.
The fourth parameter is the object of type DetectionParameters. This object includes all the parameters that can be customized during the detection process. This parameters are commented in detail in the next section.
The final parameter, rejectedCandidates, is a returned list of marker candidates, i.e. those squares that have been found but they do not present a valid codification. Each candidate is also defined by its four corners, and its format is the same than the markerCorners parameter. This parameter can be omitted and is only useful for debugging purposes and for ‘refind’ strategies (see refineDetectedMarkers() ).

5实验效果

输出

pitch 3.12894yaw -0.0187251roll-1.5281x= -0.011554y=-0.0038433z=0.17224

在这里插入图片描述

6.生成多个marker组成的board

参考http://www.pianshen.com/article/2639341324/

#include 
#include
#include
#include "opencv2/core/core.hpp"#include
#include
#include
using namespace std;using namespace cv;int main(){ int markersX = 5;//X轴上标记的数量 int markersY = 5;//Y轴上标记的数量 本例生成5x5的棋盘 int markerLength = 100;//标记的长度,单位是像素 int markerSeparation = 20;//每个标记之间的间隔,单位像素 int dictionaryId = cv::aruco::DICT_4X4_50;//生成标记的字典ID int margins = markerSeparation;//标记与边界之间的间隔 int borderBits = 1;//标记的边界所占的bit位数 bool showImage = true; Size imageSize; imageSize.width = markersX * (markerLength + markerSeparation) - markerSeparation + 2 * margins; imageSize.height = markersY * (markerLength + markerSeparation) - markerSeparation + 2 * margins; Ptr
dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); Ptr
board = aruco::GridBoard::create(markersX, markersY, float(markerLength), float(markerSeparation), dictionary); // show created board Mat boardImage; board->draw(imageSize, boardImage, margins, borderBits); if (showImage) { imwrite("./aruco_tag_board.png",boardImage); imshow("board", boardImage); waitKey(0); } return 0;}

参考文献

https://blog.csdn.net/A_L_A_N/article/details/83657878

你可能感兴趣的文章
JVM并发机制探讨—内存模型、内存可见性和指令重排序
查看>>
nginx+tomcat+memcached (msm)实现 session同步复制
查看>>
WAV文件解析
查看>>
WPF中PATH使用AI导出SVG的方法
查看>>
QT打开项目提示no valid settings file could be found
查看>>
java LinkedList与ArrayList迭代器遍历和for遍历对比
查看>>
所谓的进步和提升,就是完成认知升级
查看>>
如何用好碎片化时间,让思维更有效率?
查看>>
No.182 - LeetCode1325 - C指针的魅力
查看>>
Encoding Schemes
查看>>
带WiringPi库的交叉笔译如何处理二之软链接概念
查看>>
Java8 HashMap集合解析
查看>>
自定义 select 下拉框 多选插件
查看>>
Linux常用统计命令之wc
查看>>
fastcgi_param 详解
查看>>
搞定Java面试中的数据结构问题
查看>>
React Native(一):搭建开发环境、出Hello World
查看>>
mysql 跨机器查询,使用dblink
查看>>
Winform多线程
查看>>
MongoDB数据库插入、更新和删除操作详解
查看>>