OpenCV学习——ArUco模块

2023-05-16

前提介绍:

        ArUco模块是OpenCV的contrib拓展库中一个模块,需要安装OpenCV的contrib拓展库才能正常使用。

ArUco标记:

        ArUco 标记是由宽黑色边框确定其标识符(id)的内部二进制矩阵组成的正方形标记,如图1所示。通俗地说,ArUco标记其实就是一种编码,就和我们日常生活中的二维码是相似的,只不过由于编码方式的不同,导致它们存储信息的方式、容量等等有所差异,所以在应用层次上也会有所不同——单个ArUco标记就可以提供足够的对应关系,例如有四个明显的角点及内部的二进制编码,所以ArUco标记被广泛用来增加从二维世界映射到三维世界时的信息量,便于发现二维世界与三维世界之间的投影关系,从而实现姿态估计相机矫正等应用。

        ArUco标记的黑色边框有助于其在图像中的快速检测,内部二进制编码用于识别标记和提供错误检测和纠正。ArUco标记尺寸的大小决定内部矩阵的大小,例如尺寸为4x4的标记由16位二进制数组成。

图1  id=0,字典为DICT_4X4_250的ArUco标记

总结:

        ArUco标记是一种基于二进制方形基准编码的标记,可用于摄像机姿态估计、相机矫正等。它的主要优点是检测简单、快速,并且具有很强的鲁棒性。

ArUco使用:

ArUco标记的创建:

        创建ArUco标记时,首先需要指定一个字典,这个字典表示的是创建出来的ArUco标记具有怎样的尺寸、怎样的编码等内容。

        使用getPredefinedDictionary()函数来声明使用的字典。在OpenCV中,提供了多种预定义字典,可以通过PREDEFINED_DICTIONARY_NAME来查看有哪些预定义字典。而且字典名称表示了该字典的ArUco标记数量和尺寸,例如DICT_7X7_50表示一个包含了50种7x7位标记的字典。

        指定好需要的字典后,就可以通过drawMarker()函数来绘制出ArUco标记。

函数解析:

dictionary = getPredefinedDictionary(Dictionary)

Dictionary预定义字典
dictionaryDictionary对象

drawMarker(dictionary,id,sidepixel,img,borderBist)

dictionaryDictionary对象
 
idmarker的id,表示绘制字典中的哪一个ArUco标记。每个字典由不同数量的标记组成,id的有效范围是[0,字典包含的标记数),超出有效范围的特定id会产生异常
sidepixel输出标记图像的尺寸,输出标记图像的尺寸为sidepixel×sidepixel(此参数应足够大以存储特定字典的位数,至少需要满足(sidepixel - 标记的边长)>= 2。并且为了避免输出标记图像变形,sidepixel应与(位数 + 边界)大小成比例,或者至少比标记尺寸大得多,以使变形不明显)
img输出的标记图像
borderBist(可选)用于指定标记黑色边框的宽度,例如borderBist=2表示边框的宽度等于两个内部像素的大小,默认值 borderBist=1。

示例代码:

cv::Mat marker; 
cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); 
cv::aruco::drawMarker(dictionary, 0, 200, marker, 1);

ArUco标记的检测:

        检测ArUco标记的是detectMarkers()函数。方便观察检测结果,通常需要进行可视化操作,也就是将检测到的ArUco标记绘制出来,此过程使用的是drawDetectedMarkers()函数

函数解析:

detectMarkers(img,dictionary,corners,ids,parameters,rejectedImgPoints)

img待检测标记的图像
dictionary同创建ArUco标记时所使用的字典。检测什么类型的ArUco标记就使用什么类型的字典
corners检测到的ArUco标记的角点列表,对于每个标记,其四个角点均按其原始顺序返回(从右上角开始顺时针顺序)
ids检测到的每个ArUco标记的 id
parametersDetectionParameters 类的对象,该对象包括在检测过程中可以自定义的所有参数
rejectedImgPoints抛弃的候选标记列表,即检测到的、但未提供有效编码的正方形。每个候选标记也由其四个角定义,其格式与第三个参数相同

drawDetectedMarkers(img,corners,ids,borderColor)

img待绘测标记的图像
corners检测到的ArUco标记的角点列表
ids检测到的每个标记对应到其所属字典中的id
borderColor绘制标记外框的颜色

示例代码:

auto dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME::DICT_4X4_250);
vector<vector<Point2f>>corners, rejectedImgPoints;
vector<int>ids;
auto parameters = aruco::DetectorParameters::create();
aruco::detectMarkers(test_image, dictionary, corners, ids, parameters, rejectedImgPoints);
aruco::drawDetectedMarkers(test_image, corners, ids, Scalar(0, 255, 0));

ArUco标记用作姿态估计:

        通过ArUco标记的检测来获取相机pose,需要知道相机的校准(Calibration)参数,即相机矩阵和畸变系数。(当用ArUco标记来检测相机pose时,可以单独地检测每个标记的pose。如果想要从一堆标记里检测出一个pose,需要的是ArUco板)。
  涉及到ArUco标记的相机pose是一个从标记坐标系到相机坐标系的三维变换。这是由一个旋转和一个平移向量确定的。
 

        每当我们每检测到一个aruco标记时,vector<vector<Point2f>>corners中就会获得一个检测到标记的角点列表,通过这个角点列表可以对该标记进行姿态估计。
        对ArUco标记的姿态估计可以使用estimatePoseSingleMarkers()函数,每个ArUco标记都将返回一个相对于相机的旋转向量和平移矢量,返回的点数组是将标记角点从每个标记坐标系转换到相机坐标系下的表示——标记坐标系原点位于标记的中心,Z轴垂直于标记平面,每个标记的四个角点在其坐标系中的坐标为:(-markerLength/2,markerLength/2,0),(markerLength/2,markerLength/2,0),(markerLength/2,-markerLength/2 ,0),(-markerLength/2,-markerLength/2,0)。markerLength是ArUco标记的边长。

        为了方便结果的可视化,可以使用drawAxis()函数来绘制坐标轴。

函数解析:
estimatePoseSingleMarkers(corners,markerLength,cameraMatrix,distCoeffs,rvecs,tvecs,_objPoints)

cornersdetectMarkers()返回的检测到标记的角点列表
markerLengthArUco标记的实际物理尺寸,也就是打印出来的ArUco标记的实际尺寸,一般以米为单位
cameraMatrix​​​​​​​相机的内参矩阵
distCoeffs相机的畸变参数
rvecs​​​​​​​vector<cv::Vec3d>类型的向量,其中每个元素为每个标记相对于相机的旋转向量
tvecsvector<cv::Vec3d>类型的向量,其中每个元素为每个标记相对于相机的平移向量
_objPoints每个标记角点的对应点数组

drawAxis(img,cameraMatrix,distCoeffs,rvec,tvec,length)

img待绘制坐标系的图像
cameraMatrix相机的内参矩阵
distCoeffs相机的畸变参数
rvec旋转向量
tvec平移向量
length坐标轴的长度,单位通常为米

示例代码:

cv::Mat cameraMatrix, distCoeffs;
vector<double> camera = { 657.1548323619423, 0, 291.8582472145741,0, 647.384819351103, 391.254810476919,0, 0, 1 };
cameraMatrix = Mat(camera);
cameraMatrix = cameraMatrix.reshape(1,3);
vector<double> dist = { 0.1961793476399528, -1.38146317350581, -0.002301820186177369, -0.001054637905895881, 2.458286937422959 };
distCoeffs = Mat(dist);
distCoeffs = distCoeffs.reshape(1, 1);

VideoCapture capture;
capture.open(0);
if (!capture.isOpened())
{
	cout << "can't open camera" << endl;
	exit(-1);
}

Mat frame;
while (capture.read(frame))
{
	Mat test_image;
	resize(frame, test_image, Size(800, 800));
	imshow("test_image", test_image);
	auto dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME::DICT_6X6_250);
	vector<vector<Point2f>>corners, rejectedImgPoints;
	vector<int>ids;
	auto parameters = aruco::DetectorParameters::create();
	aruco::detectMarkers(test_image, dictionary, corners, ids, parameters, rejectedImgPoints);
	aruco::drawDetectedMarkers(test_image, corners, ids, Scalar(0, 255, 0));

	std::vector<cv::Vec3d> rvecs;
	std::vector<cv::Vec3d> tvecs;
	cv::aruco::estimatePoseSingleMarkers(corners, 0.053, cameraMatrix, distCoeffs, rvecs, tvecs);
	for (int i = 0;i < rvecs.size();i++)
	{
		//绘制坐标轴,检查姿态估计结果
		cv::aruco::drawAxis(test_image, cameraMatrix, distCoeffs, rvecs[i], tvecs[i], 0.02);
	}
	imshow("pose", test_image);

	char ch = cv::waitKey(1);
	if (27 == ch)
	{
		break;
	}
}

参考博客:

https://blog.csdn.net/weixin_45224869/article/details/106305543

https://blog.csdn.net/Mufafafa/article/details/124464644

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenCV学习——ArUco模块 的相关文章

  • 使用 K 均值聚类 OpenCV 进行交通标志分割

    I used K Means Clustering to perform segmentation on this traffic sign as shown below 这些是我的代码 读取图像并模糊 img cv imread 000
  • 针对不同相机(RGB 和红外)的 StereoCalibrate

    我在校准两个摄像头时遇到问题 第一个是 RGB 第二个是红外 它们有不同的分辨率 我调整了大小并裁剪了更大的图像 焦距等等 例子 RGB 1920x1080 Infrared 512x424 如何相互校准它们 我应该在stereoCalib
  • 使用 Azure 机器学习检测图像中的符号

    4年前我发帖这个问题 https stackoverflow com q 6999920 411094不幸的是 得到的一些答案超出了我的技能水平 我刚刚参加了一次构建巡演会议 他们在会上谈论了机器学习 这让我想到了使用 ML 来解决我的问题
  • 附加信息:OpenCV:使用 c# 的不同大小的对象

    目前 我的 EmguCV c 代码面临问题 我试图从数据库中识别我的图像 但它不起作用 一旦检测到我的脸 它就会崩溃 然后会出现此错误 附加信息 OpenCV 不同大小的对象 我尝试寻找这个错误 但我一无所知 这是我的代码 Action f
  • 从单应性估计 R/T

    我一直在尝试计算 2 个图像中的特征 然后将这些特征传递回CameraParams R没有运气 特征已成功计算并匹配 但是问题是将它们传递回R t 我明白你必须分解Homography为了使这一点成为可能 我已经使用如下方法完成了 http
  • 如何获得垂直线穿过的完整内轴线?

    我有一个图像 我想获取穿过其中轴的像素 我尝试使用骨架化 and 中轴方法来获取它们 但这两种方法都返回比相应对象短的一维线 这是带有示例图像的代码 gt gt gt import skimage filter gt gt gt impor
  • 如何将图像从 np.uint16 转换为 np.uint8?

    我正在创建一个图像 image np empty shape height width 1 dtype np uint16 之后我将图像转换为 BGR 模型 image cv2 cvtColor image cv2 COLOR GRAY2B
  • 有人曾经在 MacOS 10.6 上使用过 OpenCV 和 Python 2.7 吗?

    在过去的 6 个月里 我一直断断续续地尝试让 OpenCV 在 MacOS 上与 Python 配合使用 每次有新版本发布时 我都会再次尝试并失败 我已经尝试过 64 位和 32 位 并且 xcode gcc 和 gcc 都是通过 macp
  • 在 Android 中使用 OpenCV 查找图像匹配

    我正在尝试构建一个 Android 应用程序 该应用程序可以比较设备相机拍摄的照片 以在一组图像中找到匹配项 我已经在 Android Studio 上配置了 OpenCV 但仅此而已 有人可以通过链接到资源或建议教程来提供帮助吗 Open
  • OpenCV,捕获的视频比原始相机视频运行得更快!

    我正在使用 openCV 从相机捕获视频并将其存储到 avi 文件 问题是当我完成捕获并运行 avi 文件时 视频流看起来速度很快 这是代码 void main CvCapture capture cvCaptureFromCAM 0 in
  • 在 Python 中使用音频流 RTMP 通过管道和 OpenCV 到 FFmpeg

    我正在尝试使用音频流式传输 FFmpeg 我将在下面展示我的代码 导入模块 import subprocess as sp 创建变量 rtmpUrl rtmp a rtmp youtube com live2 key camera path
  • 如何平滑循环列向量

    这是一个 OpenCV2 问题 我有一个矩阵代表closed空间曲线 cv Mat
  • 将向量 转换为大小为 (n x 3) 的 Mat,反之亦然

    我有 Point3d 向量 向量形式的点云 如果我使用 OpenCV 提供的转换 比如 cv Mat tmpMat cv Mat pts Here pts is vector
  • 使用 openCV 对图像中的子图像进行通用检测

    免责声明 我是计算机视觉菜鸟 我看过很多关于如何在较大图像中查找特定子图像的堆栈溢出帖子 我的用例有点不同 因为我不希望它是具体的 而且我不确定如何做到这一点 如果可能的话 但我感觉应该如此 我有大量图像数据集 有时 其中一些图像是数据集的
  • 如何使用Android opencv使图像的白色部分透明

    我无法链接超过 2 个网址 因此我将我的照片发布到此博客 请在这里查看我的问题 http blog naver com mail1001 220650041897 http blog naver com mail1001 220650041
  • OpenCV:将垫子除以标量的最简单方法是什么

    我认为标题中已经包含了很多内容 显然我可以迭代和划分 但我认为有一种内置的方法 我看见cvConvertScale但这不适用于类型cv Mat 我知道标量乘法的缩放运算 cv Mat M float alpha cv Mat Result
  • Python 中的 Lanczos 插值与 2D 图像

    我尝试重新缩放 2D 图像 灰度 图像大小为 256x256 所需输出为 224x224 像素值范围从 0 到 1300 我尝试了两种使用 Lanczos 插值来重新调整它们的方法 首先使用PIL图像 import numpy as np
  • 如何使用 OpencV 从 Firebase 读取图像?

    有没有使用 OpenCV 从 Firebase 读取图像的想法 或者我必须先下载图片 然后从本地文件夹执行 cv imread 功能 有什么办法我可以使用cv imread link of picture from firebase 您可以
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • 如何将本机库链接到 IntelliJ 中的 jar?

    我正在尝试在 IntelliJ 中设置 OpenCV 但是我一直在弄清楚如何告诉 IntelliJ 在哪里可以找到本机库位置 在 Eclipse 中 添加 jar 后 您可以在 Build Config 屏幕中设置 Native 库的位置

随机推荐

  • 字符串赋值指针变量与普通变量的区别

    普通变量和指针变量用字符串赋值时是有区别的 特别是数组与字符串 xff0c 数组名本质上是数组的首地址 在对指针 数组 xff08 名 xff09 用字符串同样如此 xff0c 赋值时同样为首地址 对于普通变量 xff0c 赋值操作实际上是
  • C语言中 井号#、双井号##

    在 C 语言中 xff0c 井号 34 34 是一个预处理器指令的符号 xff0c 用于在编译之前处理代码 预处理器指令以 34 34 开始 xff0c 以换行符结束 常见的预处理器指令包括 xff1a include xff1a 包含一个
  • C++中的双冒号::

    在C 43 43 中 xff0c 双冒号 xff08 xff09 被用作作用域解析运算符 类作用域解析运算符 在C 43 43 中 xff0c 如果要在类的定义外部定义或实现成员函数或静态成员变量 xff0c 则必须使用双冒号运算符来引用类
  • c++中::和.区别

    在C 43 43 中 xff0c 34 34 和 34 34 都是用于访问类的成员 xff08 包括成员函数和成员变量 xff09 的运算符 xff0c 但它们有一些重要的区别 34 34 被称为作用域解析运算符 xff0c 用于访问全局作
  • Widget::Widget(QWidget *parent)为什么要传入父级指针?

    Widget Widget QWidget parent QWidget parent 列表初始化语法来初始化基类QWidget的构造函数 ui new Ui Widget 初始化指向Ui Widget类对象的指针ui 在类的声明里定义Ui
  • 拷贝构造函数为什么要传入引用

    拷贝构造函数是用于创建一个新对象并将其初始化为另一个对象的副本的特殊构造函数 在拷贝构造函数中 xff0c 如果我们将参数作为值传递 xff0c 那么会发生对象复制 xff0c 这将导致无限递归的调用 xff0c 因为拷贝构造函数的调用需要
  • 使用vscode开发apicloud

    1 第一步 xff1a VScode安装apicloud插件 xff1b 2 第二步 xff1a 配置apicloud插件里面工作区的Apicloud Subdirectories路径 路径是 xff1a VUE目录 src 3 第三步 x
  • 构造函数的调用规则

    在面向对象编程中 xff0c 构造函数是用于创建对象的特殊函数 构造函数的调用规则如下 xff1a 当创建一个对象时 xff0c 会自动调用该对象的构造函数 构造函数的名称必须与类的名称相同 构造函数可以有多个重载版本 xff0c 但是必须
  • 深拷贝与浅拷贝

    深拷贝和浅拷贝是指在计算机编程中 xff0c 当需要复制一个对象时 xff0c 复制出来的副本与原对象之间的关系的不同 浅拷贝是指在复制对象时 xff0c 只复制了对象本身的值 xff0c 而没有复制对象包含的子对象 也就是说 xff0c
  • C++三种继承方式的区别

    访问方式分为两种 xff0c 一种是类内访问 xff0c 还有一种是类外访问 xff1b 所谓类内访问 xff0c 就是类内的函数中是使用了属性 xff1b 类外访问 xff0c 就是新建一个实例对象 xff0c 并访问这个对象的属性 xf
  • python爬虫之数据解析(BeautifulSoup)

    BeautifulSoup也是python爬虫常用的一种数据解析方法 xff0c 主要就两步 1 实例化一个Beautifulsoup对象 xff0c 平且将页面源码数据加载到该对象中 2 通过调用Beautifulsoup对象中相关的属性
  • 蓝桥杯嵌入式第十四届省赛题目解析

    前几天刚刚参加完第十四届的省赛 xff0c 这届题目比我想象中的要难 xff0c 其实想一想这也是应该的 xff0c 以前的知识点都被摸透了 xff0c 也是需要加入新的知识点了 xff0c 但是我还是想说能不能别在我参加的时候加大题目难度
  • dockerfile构建

    2 简答题 编写Dockerfile制作镜像 xff0c 生成镜像名为my build Nginx2 首先创建目录dockerfile nginx2 xff0c 保存Dockerfile文件 具体要求如下 xff1a 1 基于镜像cento
  • 安装虚拟机之后怎么配置虚拟环境、深度学习、深度强化学习环境安装

    安装步骤目录 一 配置虚拟机VMware安装包 amp Ubuntu的光盘映像文件 xff1a VMware安装Ubuntu安装 二 进入虚拟机配置环境深度 xff08 强化 xff09 学习环境的配置1 得知系统所自带python版本 x
  • 力扣-刷题方法总结(测试文章)

    知乎方面收集到的资料 xff08 非原创 xff0c 题主只是对其进行统一的整理 xff0c 方便后续查看 xff09 算法训练讲究循序渐进 xff1a 1 先从简单开始 xff0c 然后过度到中等 xff0c 再过渡到困难的进程 2 如何
  • 文件分隔符 ‘/‘(斜杠) 和 ‘\‘(反斜杠) 的使用

    前言 在学习时 xff0c 总会用到 Windows 和 Linux xff0c 输入路径时 xff0c 文件路径分隔符有时用 xff08 斜杠 xff09 xff0c 有时用 xff08 反斜杠 xff09 xff0c 属实不好区分 xf
  • VMware虚拟机安装Win11教程(解决常见报错)

    前言 今天闲来无事 xff0c 就想着装一下最新版的win11玩一下 xff0c 然后来来去去还是折腾了一些时间 xff0c 有遇到一些错误不过最好都找到了解决办法 xff0c 下面我就分享一下VMware虚拟机安装win11的详细步骤 V
  • vue打包后neditor不显示了

    原因是vue和vue template compiler 1 两者的版本不一致 xff1b 2 两者的版本低了 xff1b 例如 xff1a 我出问题的版本是 34 vue 34 34 2 5 10 34 34 vue template c
  • 【Docker常用命令】

    Docker常用命令 xff08 学习笔记 xff09 一 Docker基础命令二 Docker镜像命令三 Docker容器命令3 1 运行容器3 2 退出容器3 3 查看容器进程 xff0c 日志3 4 再次进入容器3 5 容器启停3 6
  • OpenCV学习——ArUco模块

    前提介绍 xff1a ArUco模块是OpenCV的contrib拓展库中一个模块 xff0c 需要安装OpenCV的 contrib拓展库 才能正常使用 ArUco标记 xff1a ArUco 标记是由 宽黑色边框 和 确定其标识符 xf