杂记7--opencv的ar码模块学习
背景:项目需要用到marker知识,所以到官网上临时补一些知识。
概要:主要介绍marker一些接口的含义,纯属个人理解,有误则希望大佬不吝赐教
1、
涉及ar码操作学习,其头文件为:
#include <opencv2/aruco.hpp>
1)创建marker
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);
cv::imwrite("marker23.png", markerImage);
参数1: dictionary :表示marker字典类型为DICT_6X6_250,使用构造函数进行创建
参数2: 23 表示准备绘制的ar码在该字典里面的编号id为23
参数3: 200 表示输出ar码图片像素为200x200
参数4: markerImage 保存的是输出ar图片dictionary表示的是marker数据集
可以参考:
const char* keys ="{@outfile |<none> | Output image }""{d | | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2,""DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, ""DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12,""DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL = 16}""{cd | | Input file with custom dictionary }""{id | | Marker id in the dictionary }""{ms | 200 | Marker size in pixels }""{bb | 1 | Number of bits in marker borders }""{si | false | show generated image }";
}
2)marker检测函数detectMarkers()解析:
cv::Mat inputImage;
...
std::vector<int> markerIds;
std::vector<std::vector<cv::Point2f>> markerCorners, rejectedCandidates;
cv::Ptr<cv::aruco::DetectorParameters> parameters = cv::aruco::DetectorParameters::create();
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::aruco::detectMarkers(inputImage, dictionary, markerCorners, markerIds, parameters, rejectedCandidates);
参数1 inputImage : 表示包含 ar码marker的图片=
参数2: dictionary : 表示ar码来自哪个字典类型
参数3: markerCorners : 该容器作用是保存的是检测出来的ar码参数4: markerIds : 作用记录检测出来的ar码存储在markerCorners在字典中的编号
参数5: parameters : DetectorParameters类的实例化对象,其包含了检测ar码过程所涉及的所有自定义的参数
参数6: rejectedCandidates : 保存没有检测出来有效的ar码 marker
参考:https://docs.opencv.org/4.x/d5/dae/tutorial_aruco_detection.html
3)绘制marker框框 drawDetectedMarkers()
在上一步骤检出ar码后,下一步检测是否真的检查正确,这时候需要使用绘制marker框框来验证,此时可使用函数drawDetectedMarkers():
cv::Mat outputImage = inputImage.clone();
cv::aruco::drawDetectedMarkers(outputImage, markerCorners, markerIds);
参数1 : outputImage 表示输入的图片
参数2 : markerCorners 来自detectMarkers()函数获取得到保存了ar码容器
参数3 : markerIds 来自detectMarkers()函数获取的,记录检测出来的ar码存储在markerCorners的ar码在字典中的编号
参考:https://docs.opencv.org/4.x/d5/dae/tutorial_aruco_detection.html
4)姿态信息函数estimatePoseSingleMarkers()
在检测校验检测出来的ar码之后,我们需要做的是从ar码里面获取对应的姿态信息,姿态信息函数estimatePoseSingleMarkers():
cv::Mat cameraMatrix, distCoeffs;
// You can read camera parameters from tutorial_camera_params.yml
readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is located in detect_markers.cpp
std::vector<cv::Vec3d> rvecs, tvecs;
cv::aruco::estimatePoseSingleMarkers(markerCorners, 0.05, cameraMatrix, distCoeffs, rvecs, tvecs);
参数1: markerCorners 来自detectMarkers()函数,意义为存储检测出来的ar码
参数2: 0.05 ar码的尺寸,单位一般为米(也可以为其他单位,如mm),注意尺寸单位和姿态估计变换矩阵单位一致
参数3: cameraMatrix 相机内参
参数4: distCoeffs 相机畸变参数
参数5: rvecs 该容器保存的是markerCorners里面每个ar的旋转信息
参数6: tvecs 该容器保存的是markerCorners里面每个ar的平移信息
相机内参和畸变参数可以查看:https://blog.csdn.net/weixin_43206570/article/details/84797361
5)打印姿态信息cv::drawFrameAxes()
姿态信息获取后,可以打印出检验出来的姿态信息进行校验,参考函数cv::drawFrameAxes()
inputImage.copyTo(outputImage);
for (int i = 0; i < rvecs.size(); ++i) {
auto rvec = rvecs[i];
auto tvec = tvecs[i];
cv::drawFrameAxes(outputImage, cameraMatrix, distCoeffs, rvec, tvec, 0.1);
}
参数1: outputImage 绘制ar码的图片
参数2: cameraMatrix 相机内参
参数3: distCoeffs 相机畸变参数
参数4: rvec 该容器保存的是markerCorners里面每个ar的旋转信息
参数5: tvecs 该容器保存的是markerCorners里面每个ar的平移信息
参数6: 0.1 轴线长度,单位同rvec、tvecs,一般为米
以下为一个简单ar码,从检测到姿态估计的完整过程:
cv::VideoCapture inputVideo;
inputVideo.open(0);
cv::Mat cameraMatrix, distCoeffs;
// You can read camera parameters from tutorial_camera_params.yml读取相机参数
readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is located in detect_markers.cpp
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
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);//绘制检测框
std::vector<cv::Vec3d> rvecs, tvecs;
cv::aruco::estimatePoseSingleMarkers(corners, 0.05, cameraMatrix, distCoeffs, rvecs, tvecs);//姿态估计
// draw axis for each marker
for(int i=0; i<ids.size(); i++)
cv::drawFrameAxes(imageCopy, cameraMatrix, distCoeffs, rvecs[i], tvecs[i], 0.1);//绘制姿态
}
cv::imshow("out", imageCopy);//显示图片
char key = (char) cv::waitKey(waitTime);
if (key == 27)
break;
}
其他内容为解析一些自定义检测过程参数事情,后续想要学习,可以打开链接加以学习
参考:https://docs.opencv.org/4.x/d5/dae/tutorial_aruco_detection.html
2、利用ar 码集(注意跟上一节的单个ar码检测到姿态估计区别)进行姿态估计
单独检测一个ar码和 board 码检测的区别,board码可以知道各个ar码之间的相对位置而单独ar码不知,也就是有一个先验值。
boards好处:
姿态估计更加丰富;获取的姿态更加准确
1)头文件
#include <opencv2/aruco.hpp>
2)Board类
class Board {
public:
std::vector<std::vector<cv::Point3f> > objPoints;
cv::Ptr<cv::aruco::Dictionary> dictionary;
std::vector<int> ids;
};
参数1: objPoints 角点位置列表,就是存储所有ar码四个角点位置信息
参数2: dictionary 表示board上面使用的ar码归属字典
参数3: ids 存储的是objPoints 里面的ar码对应在字典里面的编号
参考:https://docs.opencv.org/4.x/d5/dae/tutorial_aruco_detection.html
3)Board detection
板检测和marker检测类似,唯一差别在于姿态估计上。板在board姿态估计之前,务必进行一次marker检测
cv::Mat inputImage;
// camera parameters are read from somewhere
cv::Mat cameraMatrix, distCoeffs; //相机的内参、相机畸变参数
// You can read camera parameters from tutorial_camera_params.yml
readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is located in detect_board.cpp
// assume we have a function to create the board object
cv::Ptr<cv::aruco::Board> board = cv::aruco::Board::create();
...
std::vector<int> markerIds;//ar码在字典中的编号,对应markerCorners中ar码
std::vector<std::vector<cv::Point2f>> markerCorners;// 所有ar码
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);
}
参数1: markerCorners 存储的是板上的ar码
参数2: markerIds 存储的是存储ar码在字典中的编号
参数3: board 记录板的布局和ar码的id(?)
参数4: cameraMatrix 相机内参
参数5: distCoeffs 相机畸变参数
参数6: rvec 板的旋转姿态估计
参数7: tvec 板的平移姿态估计
注意一个点,markerCorners和markerIds存储的并非所有检测到的ar信息,而是在存储在Board::ids里面给到的ar编号所属信息。
参考:https://docs.opencv.org/4.x/db/da9/tutorial_aruco_board_detection.html
3、延伸
marker可以提供一些姿态信息,比如我想直到图像里面的某个平面的姿态信息,那么,我们可以给平面贴上一些marker,构造board,调用opencv接口可以返回变换矩阵信息,那么我们根据预设的board信息就可以直到某个平面的姿态信息。
#####################
不积硅步,无以至千里
好记性不如烂笔头
觉得nice,记得点赞收藏
相关文章:
杂记7--opencv的ar码模块学习
背景:项目需要用到marker知识,所以到官网上临时补一些知识。 概要:主要介绍marker一些接口的含义,纯属个人理解,有误则希望大佬不吝赐教 1、 涉及ar码操作学习,其头文件为: #include <op…...
[项目设计]高并发内存池
目录 1、项目介绍 2、高并发内存池整体框架设计 3、thread cache <1>thread cache 哈希桶对齐规则 <2>Thread Cache类设计 4、Central Cache <1>Central Cache类设计 5、page cache <1>Page Cache类设计 6、性能分析 <1>定长内存池实现…...
28岁才转行软件测试,目前32了,我的一些经历跟感受
我是92年的,算是最早的90后,现在跟你介绍的时候还恬不知耻的说我是90后,哈哈,计算机专业普通本科毕业。在一个二线城市,毕业后因为自身能力问题、认知水平问题,再加上运气不好,换过多份工作&…...
Python导入模块的3种方式
很多初学者经常遇到这样的问题,即自定义 Python 模板后,在其它文件中用 import(或 from...import) 语句引入该文件时,Python 解释器同时如下错误:ModuleNotFoundError: No module named 模块名意思是 Pytho…...
select 与 where、order by、limit 子句执行优先级比较
当 select 和 其他三种语句的一者或者多者同时出现时,他们之间是存在执行先后顺序的。 他们的优先级顺序是:where > select > order by > limit 目录 1、select 与 where 2、select 与 order by 3、order by 与 limit 4、优先级证明 1、s…...
Linux内核并发与竞争-原子操作
一.原子操作的概念首先看一下原子操作,原子操作就是指不能再进一步分割的操作,一般原子操作用于变量或者位操作。假如现在要对无符号整形变量 a 赋值,值为 3,对于 C 语言来讲很简单,直接就是: a3但是 C 语言…...
Java笔记-泛型的使用
参考: Java 泛型,你了解类型擦除吗? 泛型的使用 1、泛型的定义 可以广泛使用的类型,一种较为准确的说法就是为了参数化类型,或者说可以将类型当作参数传递给一个类或者是方法。 2、泛型的使用 2.1泛型类 public c…...
特斯拉无人驾驶解读
来源于Tesla AI Day Tesla无人驾驶算法的核心任务就是如何理解我们所看到的一切呢?也就是说,不使用高端的设备,比如激光雷达,仅仅使用摄像头就能够将任务做得很好。Tesla使用环绕型的8个摄像头获得输入。 第一步是特征提取模块Backbone,无论什么任务都离不开特征…...
生物素-琥珀酰亚胺酯Biotin-NHS;CAS号:35013-72-0;可对溶液中的抗体,蛋白质和任何其他含伯胺的大分子进行简单有效的生物素标记。
结构式: 生物素-琥珀酰亚胺酯Biotin NHS CAS号:35013-72-0 英文名称:Biotin-NHS 中文名称:D-生物素 N-羟基琥珀酰亚胺酯;生物素-琥珀酰亚胺酯 CAS号:35013-72-0 密度:1.50.1 …...
Maven_第五章 核心概念
目录第五章 其他核心概念1、生命周期①作用②三个生命周期③特点2、插件和目标①插件②目标3、仓库第五章 其他核心概念 1、生命周期 ①作用 为了让构建过程自动化完成,Maven 设定了三个生命周期,生命周期中的每一个环节对应构建过程中的一个操作。 …...
【深度学习】人脸识别工程化落地
文章目录前言1、facenet2、使用2.1.其它blog2.2 实践总结前言 老早以前就希望能写一篇关于人脸识别的工程化落地的案例,一年前做疲劳驾驶时使用的dlib插件,它封装好了,人脸检测、对齐、相似度计算三个部分,就是插件比较难装,但同时也少了很多…...
AOP面向切面编程思想。
目录 一、AOP工作流程 1、基本概念 2、AOP工作流程 二、AOP核心配置 1、AOP切入点表达式 2、AOP通知类型 三、AOP通知获取数据 1、获取参数 2、获取返回值 3、获取异常 四、AOP事务管理 1、Spring事务简介 2、Spring事务角色 3、事务属性 一、AOP工作流程 1、…...
实验7-变治技术及动态规划初步
目录 1.统计个数 2.数塔dp -A 3.Horspool算法 4.计数排序 5.找零问题1-最少硬币 1.统计个数 【问题描述】有n个数、每个元素取值在1到9之间,试统计每个数的个数 【输入形式】第一行,n的值;第二行...
JVM垃圾回收机制GC理解
目录JVM垃圾回收分代收集如何识别垃圾引用计数法可达性分析法引用关系四种类型: 强、软、弱、虚强引用软引用 SoftReference弱引用 WeakReferenceWeakHashMap软引用与虚引用的使用场景虚引用与引用队列引用队列虚引用 PhantomReference垃圾回收算法引用计数复制 Cop…...
C++中的容器
1.1 线性容器1)std::array看到这个容器的时候肯定会出现这样的问题:为什么要引入 std::array 而不是直接使用 std::vector?已经有了传统数组,为什么要用 std::array?先回答第一个问题,与 std::vector 不同,…...
2023备战金三银四,Python自动化软件测试面试宝典合集(五)
接上篇八、抓包与网络协议8.1 抓包工具怎么用 我原来的公司对于抓包这块,在 App 的测试用得比较多。我们会使用 fiddler 抓取数据检查结果,定位问题,测试安全,制造弱网环境;如:抓取数据通过查看请求数据,请…...
SpringDI自动装配BeanSpring注解配置和Java配置类
依赖注入 上篇博客已经提到了DI注入方式的构造器注入,下面采用set方式进行注入 基于set方法注入 public class User {private String name;private Address address;private String[] books;private List<String> hobbys;private Map<String,String>…...
2月面经:真可惜...拿了小米的offer,字节却惨挂在三面
我是2月份参加字节跳动和华为的面试的,虽然我只拿下了小米的offer,但是我自己也满足了,想把经验分享出来,进而帮助更多跟我一样想进大厂的同行朋友们,希望大家可以拿到理想offer。 自我介绍 我是16年从南京工业大学毕…...
磐云PY-B8 网页注入
文章目录1.使用渗透机场景windows7中火狐浏览器访问服务器场景中的get.php,根据页面回显获取Flag并提交;2.使用渗透机场景windows7中火狐浏览器访问服务器场景中的post.php,根据页面回显获取Flag并提交;3.使用渗透机场景windows7中…...
多传感器融合定位十-基于滤波的融合方法Ⅰ其二
多传感器融合定位十-基于滤波的融合方法Ⅰ其二3. 滤波器基本原理3.1 状态估计模型3.2 贝叶斯滤波3.3 卡尔曼滤波(KF)推导3.4 扩展卡尔曼滤波(EKF)推导3.5 迭代扩展卡尔曼滤波(IEKF)推导4. 基于滤波器的融合4.1 状态方程4.2 观测方程4.3 构建滤波器4.4 Kalman 滤波实际使用流程4…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
