转载自:https://lightsail.blog.csdn.net/article/details/102752780

视觉标记定位aruco使用

沧海飞帆 2019-10-26 11:05:51 2657 收藏 14

分类专栏: SLAM 文章标签: opencv aruco定位

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

本文链接:https://blog.csdn.net/ktigerhero3/article/details/102752780

版权

本文的目的是实现生成一张marker broad图片,告诉标记检测程序tag在真实世界中的实际大小。
检测成功后得到marker的id,四个角点坐标,marker到相机的平移和旋转。

1.下载安装参考

opencv 中的aruco源码下载要到下面地址
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 <opencv2/opencv.hpp>
#include <opencv2/aruco.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include "opencv2/core/core.hpp"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>using namespace std;
using namespace cv;int main()
{cv::Mat markerImage;cv::Ptr<cv::aruco::Dictionary> 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);//显示markerwaitKey();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-matrixrows: 3cols: 3dt: ddata: [ 420.019, 0., 330.8676, 0.,419.6044, 217.8731, 0., 0., 1. ]
distortion_vector: !!opencv-matrixrows: 1cols: 4dt: ddata: [ -0.3549, 0.1151, -0.0035, -0.0029 ]

的相机拍出来的图像如下

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

确定好实际打印出来的marker的边长和内参就可以检测并计算了。
其中markerlength表示marker的实际物理长度。
使用上面的图像和内参程序如下

#include <opencv2/opencv.hpp>
#include <opencv2/aruco.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include "opencv2/core/core.hpp"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <eigen3/Eigen/Core>
#include <eigen3/Eigen/Geometry>
#include <opencv2/core/eigen.hpp>using namespace std;
using namespace cv;int main()
{cv::Mat m_image=imread("./mark.jpg");if(m_image.empty()){cout<<"m_image  is empty"<<endl;return 0;}//read paradouble markerlength=0.105;cv::Mat intrinsics = (Mat_<double>(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_<double>(4, 1) <<  -0.3549, 0.1151, -0.0035, -0.0029);cv::Mat  imageCopy;m_image.copyTo(imageCopy);cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);std::vector<int> ids;std::vector<std::vector<cv::Point2f>> corners;cv::aruco::detectMarkers(m_image, dictionary, corners, ids);//检测靶标// if at least one marker detectedif (ids.size() > 0) {cv::aruco::drawDetectedMarkers(imageCopy, corners, ids);//绘制检测到的靶标的框for(unsigned int i=0; i<ids.size(); i++){std::vector<cv::Vec3d> rvecs, tvecs;cv::aruco::estimatePoseSingleMarkers(corners[i], markerlength, intrinsics, distCoeffs, rvecs, tvecs);//求解旋转矩阵rvecs和平移矩阵tvecscv::aruco::drawAxis(imageCopy,intrinsics,distCoeffs, rvecs[i], tvecs[i], 0.1);//3.rotaion vector to eulerAnglescv::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 "<<eulerAngle.x()<<"yaw "<<eulerAngle.y()<<"roll"<<eulerAngle.z()<<endl;cout<<"x= "<<tvecs[i][0]<<"y="<<tvecs[i][1]<<"z="<<tvecs[i][2]<<endl;}}cv::imshow("out", imageCopy);cv::waitKey();return 0;
}

其中
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.5281
x= -0.011554y=-0.0038433z=0.17224

6.生成多个marker组成的board

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

#include <opencv2/opencv.hpp>
#include <opencv2/aruco.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include "opencv2/core/core.hpp"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>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;//生成标记的字典IDint 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<aruco::Dictionary> dictionary =aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));Ptr<aruco::GridBoard> board = aruco::GridBoard::create(markersX, markersY, float(markerLength),float(markerSeparation), dictionary);// show created boardMat 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

视觉标记定位aruco使用相关推荐

  1. 城市场景中自动驾驶车辆基于高精度地图的视觉语义定位

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 来源丨自动驾驶专栏 论文链接:https://ieeexplore.ieee.org/document ...

  2. 计算机视觉与深度学习 | 复杂环境下的视觉同时定位与地图构建(SLAM)

    ========================================== 博主github:https://github.com/MichaelBeechan 博主CSDN:https:/ ...

  3. android室内定位传感器辅助pdr jar,基于PDR辅助的视觉室内定位算法的研究

    1引言由于室内环境复杂多变,人们对于室内位置服务的要求也越来越高.一系列的定位技术如Wi-Fi定位.蓝牙定位.惯性导航系统(INS, Inertial NavigationS y s t e m).基 ...

  4. 机器人视觉引导定位介绍

    机器视觉都有怎样的应用? 机器视觉的应用主要分为四大类别,包括引导.识别.测量和检验(英文首字母缩写:GIGI),GIGI表示Guidance(引导).Inspection(检验).Gauging(测 ...

  5. 九点标定,贴合,视觉引导定位通用方法

    九点标定,贴合,视觉引导定位通用方法 来看看常见的几种情况.第一种情况 眼在手外,U轴不旋转,相机固定不动, 上往下看引导机器人移动 可以使用机器人走9个点(这种方式在精度要求较高的时候不推荐 ,就算 ...

  6. 视觉引导定位带领视觉行业高速发展!

    我们不难发现,在当今环境机器使用视觉引导定位的例子已经越来越多,逐渐替代了人工,自动化的趋势已经无法避免,可以说机器视觉引导定位等技术正在带领视觉行业高速发展 在全球低碳经济风暴.产业结构升级.产能过 ...

  7. 如何选择良好的视觉引导定位技术?

    利用机器进行视觉引导定位的方法有很多,如立体视觉和摄影测量.飞行时间.结构光.光编码和激光三角测量等.特定应用程序的理想技术取决于其需求.为了确定是否需要应用理想的机器视觉引导定位技术,请考虑应用程序 ...

  8. 关于视觉重定位(VPS)的工作经验分享

      在AR领域也呆了不短时间了,也一直在做视觉定位相关的工作,这里分享一下有意思的工作方向,感兴趣的可以讨论或者联系我即可.   首先简单区分AR和VR的区别,VR 属于虚拟现实 ,即是由实入虚的过程 ...

  9. 显著性目标检测和视觉重定位

    显著性目标检测 一.Highly Efficient Salient Object Detection with 100K Parameters 本文旨在通过提高网络计算效率来缓解计算花费与模型性能之 ...

最新文章

  1. Follow Me:CCIE RS--新版CCIE Routing Switching 考纲要点
  2. Curl 采集乱码 gzip 原因及解决方案 utf-8
  3. 如何从字符串中删除文本?
  4. TCP 连接的前世今生
  5. Python的3种执行方式
  6. WSDM 2022 | 基于元学习的多场景多任务商家建模
  7. pursuit of happiness
  8. asp微信会员卡管理系统,超小的源码_带asp微信支付源码
  9. 烂泥:ubuntu中使用virt-manager图形化新建虚拟机
  10. 树莓派3B 开启串口
  11. MySQL是怎么保证主备一致的?
  12. 数字电子技术基础第三版杨志忠_阎石《数字电子技术基础》(第6版)笔记和课后习题(含考研真题)详解复习笔记资料...
  13. 【MFC学习笔记-作业7-小型画图软件】【】
  14. js页面跳转并传递参数
  15. java二路归并排序算法_二路归并排序的java实现
  16. LTE中SRB---无线资源承载
  17. 模型量化论文阅读#3----Up or Down? Adaptive Rounding for Post-Training Quantization
  18. python一切皆对象 对象都有类_Python小世界:彻底搞懂Python一切皆对象!!!
  19. Python经典练习题——求水仙花数
  20. Redis源码分析之PSYNC同步

热门文章

  1. 三国志战略版:Daniel_煮酒论赤壁-论水战
  2. Rervese.kr题解 Assassin菜逼之路
  3. angular-详细信息-页面折叠状态
  4. 防止被00后整顿?一公司招聘要求员工不能起诉公司
  5. mysql表关联的索引命中失败 range checked for each record
  6. 解读最佳实践:倚天 710 ARM 芯片的 Python+AI 算力优化 | 龙蜥技术
  7. python做股票系统_GitHub - Suking/stock: stock,股票系统。使用python进行开发。
  8. 计算机如何高效识别图像?
  9. MyBatis打印日志查询0条数据库却可以查到
  10. 迅速成为炙手可热的新一代程序员看《Ajax基础教程》