用单目相机和apriltag二维码aruco实现单目定位

目录

一、核心流程与代码框架

1. ‌环境准备‌

2. ‌ArUco定位实现

3. ‌AprilTag定位实现(需额外安装Apriltag库)

二、关键优化点

1‌.亚像素角点优化

2‌ 多标签联合定位

三、性能指标(实测)

四、常见问题

‌检测失败‌

‌位姿抖动‌


ArUco在OpenCV中已经集成,而AprilTag可能需要额外的库,比如Apriltag库或者apriltag_ros,需要提前标定相机,获取camera_matrix和dist_coeffs,并在代码中加载这些参数

大致步骤是:

  1. 加载相机参数。
  2. 初始化二维码检测器(ArUco或AprilTag)。
  3. 捕获图像帧。
  4. 检测二维码并获取角点。
  5. 使用solvePnP计算位姿。
  6. 可视化结果,比如绘制坐标系或边界框

对于ArUco,可以使用detectMarkers函数来检测,然后估计位姿。

对于AprilTag,需要调用特定的检测函数,比如detector.detect().

一、核心流程与代码框架

1. ‌环境准备

  • 依赖库‌:OpenCV >=4.0(需包含aruco模块)
    apriltag库(可选,若需AprilTag支持)
  • 相机标定
    通过棋盘格标定获取相机内参(cameraMatrix)和畸变系数(distCoeffs),存储为YAML文件:
# camera_params.yaml示例
camera_matrix: !!opencv-matrixrows: 3cols: 3dt: ddata: [800, 0, 320, 0, 800, 240, 0, 0, 1]
distortion_coefficients: !!opencv-matrixrows: 1cols: 5dt: ddata: [0.1, -0.2, 0, 0, 0]

2. ‌ArUco定位实现

#include <opencv2/opencv.hpp>
#include <opencv2/aruco.hpp>int main() {// 加载相机参数cv::FileStorage fs("camera_params.yaml", cv::FileStorage::READ);cv::Mat cameraMatrix, distCoeffs;fs["camera_matrix"] >> cameraMatrix;fs["distortion_coefficients"] >> distCoeffs;// 初始化ArUco检测器cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);cv::aruco::ArucoDetector detector(dictionary);// 打开摄像头cv::VideoCapture cap(0);cv::Mat frame;while (cap.read(frame)) {// 检测Markerstd::vector<int> ids;std::vector<std::vector<cv::Point2f>> corners;detector.detectMarkers(frame, corners, ids);if (!ids.empty()) {// 定义Marker物理尺寸(单位:米)float markerLength = 0.05; std::vector<cv::Vec3d> rvecs, tvecs;// 解算位姿cv::aruco::estimatePoseSingleMarkers(corners, markerLength, cameraMatrix, distCoeffs, rvecs, tvecs);// 可视化cv::aruco::drawDetectedMarkers(frame, corners, ids);for (size_t i=0; i<ids.size(); i++) {cv::drawFrameAxes(frame, cameraMatrix, distCoeffs, rvecs[i], tvecs[i], 0.05);std::cout << "ID: " << ids[i] << " tvec: " << tvecs[i] << " rvec: " << rvecs[i] << std::endl;}}cv::imshow("ArUco定位", frame);if (cv::waitKey(10) == 27) break;}return 0;
}

3. ‌AprilTag定位实现(需额外安装Apriltag库)

#include <apriltag/apriltag.h>
#include <apriltag/tag36h11.h>// AprilTag检测逻辑
void detectAprilTags(cv::Mat &gray, apriltag_detector_t *td, const cv::Mat &cameraMatrix, const cv::Mat &distCoeffs) {image_u8_t im = { .width = gray.cols, .height = gray.rows, .stride = gray.cols, .buf = gray.data };zarray_t *detections = apriltag_detector_detect(td, &im);for (int i = 0; i < zarray_size(detections); i++) {apriltag_detection_t *det;zarray_get(detections, i, &det);// 提取角点std::vector<cv::Point2f> corners;for (int j = 0; j < 4; j++) {corners.emplace_back(det->p[j][0], det->p[j][1]);}// 定义3D坐标(假设标签边长为0.1米)std::vector<cv::Point3f> objPoints = {{-0.05f, -0.05f, 0}, {0.05f, -0.05f, 0},{0.05f, 0.05f, 0}, {-0.05f, 0.05f, 0}};// PnP解算cv::Mat rvec, tvec;cv::solvePnP(objPoints, corners, cameraMatrix, distCoeffs, rvec, tvec);// 绘制坐标系cv::drawFrameAxes(gray, cameraMatrix, distCoeffs, rvec, tvec, 0.1);}apriltag_detections_destroy(detections);
}

二、关键优化点

1‌.亚像素角点优化

cv::cornerSubPix(gray, corners, cv::Size(5,5), cv::Size(-1,-1), 
                 cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::MAX_ITER, 30, 0.01));

 

2‌ 多标签联合定位

// 加权平均所有检测到的标签位姿 cv::Mat avgRvec, avgTvec; for (auto &rvec : rvecs) 

三、性能指标(实测)

场景精度(平移误差)角度误差处理速度(FPS)
静态标签(1m)<1cm<0.5°60
动态跟踪(2m)<2cm<1°30

四、常见问题

  1. 检测失败

    • 确保标签尺寸与代码中markerLength参数一致13
    • 调整图像对比度或添加直方图均衡化
  2. 位姿抖动

    • 对连续帧的tvec/rvec应用卡尔曼滤波27
    • 增加标签物理尺寸以提高角点检测精度

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/81948.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tinyrenderer笔记(透视矫正)

tinyrenderer个人代码仓库&#xff1a;tinyrenderer个人练习代码 引言 还要从上一节知识说起&#xff0c;在上一节中我为了调试代码&#xff0c;换了一个很简单的正方形 obj 模型&#xff0c;配上纹理贴图与法线贴图进行渲染&#xff0c;得了下面的结果&#xff1a; what&…

MySQL的内置函数与复杂查询

目录 前言 一、聚合函数 1.1日期函数 1.2字符串函数 1.3数学函数 1.4其它函数 二、关键字周边 2.1关键字的生效顺序 2.2数据源 2.3可以使用聚合函数的关键字 前言 在前面几篇文章中&#xff0c;讲解了有关MySQL数据库、数据库表的创建、数据库表的数据操作等等。本文我…

见多识广4:Buffer与Cache,神经网络加速器的Buffer

目录 前言传统意义上的Buffer与Cache一言以蔽之定义与主要功能BufferCache 数据存储策略二者对比 神经网络加速器的bufferInput BufferWeight BufferOutput Buffer与传统buffer的核心区别总结 前言 知识主要由Qwen和Kimi提供&#xff0c;我主要做笔记。 参考文献&#xff1a; …

内存的位运算

示例&#xff1a;提取和设置标志位 假设我们有一个32位的整数&#xff0c;其中不同的位代表不同的标志。例如&#xff1a; 位0&#xff1a;是否开启日志&#xff08;0表示关闭&#xff0c;1表示开启&#xff09; 位1&#xff1a;是否启用调试模式&#xff08;0表示禁用&#…

linux -shell原理与运用

1---shell的工作方式和功能 shell的工作方式: shell本身也是一个应用程序,存储在/bin 或者是/user/bin中 登录的时候 会根据/etc/passwd文件载入shell默认执行 shell启动后,就会显示命令提示符,等待用户输入命令 命令的逻辑: 首先会判断时内部命令还是外部命令,如果是内部…

js获取uniapp获取webview内容高度

js获取uniapp获取webview内容高度 在uni-app中&#xff0c;如果你想要获取webview的内容高度&#xff0c;可以使用uni-app提供的bindload事件来监听webview的加载&#xff0c;然后通过调用webview的invokeMethod方法来获取内容的高度。 以下是一个示例代码&#xff1a; <te…

Windows系统升级Nodejs版本

什么是nodejs Node.js 是一个免费、开源、跨平台的 JavaScript 运行时环境, 它让开发人员能够创建服务器 Web 应用、命令行工具和脚本。 NodeJs官网 网址&#xff1a;Node.js — 在任何地方运行 JavaScript 可以通过网址下载安装&#xff0c;通过官网可以看到现在最新版本为22…

Relay算子注册(在pytorch.py端调用)

1. Relay算子注册 (C层) (a) 算子属性注册 路径: src/relay/op/nn/nn.cc RELAY_REGISTER_OP("hardswish").set_num_inputs(1).add_argument("data", "Tensor", "Input tensor.").set_support_level(3).add_type_rel("Identity…

【JavaEE】网络原理之初识(1.0)

目录 ​编辑 局域网与广域网 IP地址和端口号 实现简单的服务器客户端交互 简单理解socket TCP和UDP的差别&#xff08;初识&#xff09; socket面对udp DatagramSocket API DatagramSocket 构造方法 DatagramSocket 方法&#xff1a; DatagramPacket API Data…

Redis数据结构ZipList,QuickList,SkipList

目录 1.ZipList 1.2.解析Entry&#xff1a; 1.3Encoding编码 1.4.ZipList连锁更新问题 2.QuickList SkipList跳表 RedisObject 五种数据类型 1.ZipList redis中的ZipList是一种紧凑的内存储存结构&#xff0c;主要可以节省内存空间储存小规模数据。是一种特殊的双端链表…

laravel 12 监听syslog消息,并将消息格式化后存入mongodb

在Laravel 12中实现监听Syslog消息并格式化存储到MongoDB&#xff0c;需结合日志通道配置、Syslog解析和MongoDB存储操作。以下是具体实现方案&#xff1a; 一、环境配置 安装MongoDB扩展包 执行以下命令安装必要的依赖&#xff1a; composer require jenssegers/mongodb ^4.0确…

【STM32项目实战】一文了解单片机的SPI驱动外设功能

前言&#xff1a;在前面我有文章介绍了关于单片机的SPI外设CUBEMX配置&#xff0c;但是要想使用好SPI这个外设我们还必须对其原理性的时序有一个详细的了解&#xff0c;所以这篇文章就补充一下SPI比较偏向底层的时序性的逻辑。 1&#xff0c;SPI简介 SPI是MCU最常见的对外通信…

【挖洞利器】GobyAwvs解放双手

【渗透测试工具】解放双手&Goby配合Awvs渗透测试利器\x0a通过Goby和Awvs 解放双手https://mp.weixin.qq.com/s/SquRK8C5cRpWmfGbIOqxoQ

LangChain4j(15)——RAG高级之跳过检索

之前的文章中&#xff0c;我们介绍了RAG的使用&#xff0c;但是&#xff0c;每次提问时&#xff0c;都会通过RAG进行检索。有时&#xff0c;检索是不必要执行的&#xff0c;比如&#xff0c;当用户只是说“你好”时。于是&#xff0c;我们需要有条件的跳过检索过程。 跳过决策…

【SDRS】面向多模态情感分析的情感感知解纠缠表征转移

abstract 多模态情感分析(MSA)旨在利用多模态的互补信息对用户生成的视频进行情感理解。现有的方法主要集中在设计复杂的特征融合策略来整合单独提取的多模态表示,忽略了与情感无关的信息的干扰。在本文中,我们提出将单模表征分解为情感特定特征和情感独立特征,并将前者融…

Sui 上线两周年,掀起增长「海啸」

两年前的 5 月 3 日&#xff0c;Sui 的主网正式发布&#xff0c;将在开发网和测试网上验证过的下一代技术承诺变为现实。这一新兴网络旨在优化现有区块链技术&#xff0c;结合高性能计算环境与安全性、可验证性及韧性。 随着 Sui 迎来两周年&#xff0c;这股浪潮已成长为「海啸…

深入理解 mapper-locations

mybatis-plus.mapper-locations: classpath*:/mapper/**/*.xml 是 MyBatis/MyBatis-Plus 在 Spring Boot 配置文件&#xff08;如 application.yml 或 application.properties&#xff09;中的一项关键配置&#xff0c;用于指定 MyBatis Mapper XML 文件的存放路径。以下是详细…

电容的作用

使用多个电容是从电容的实际等效模型去考虑的(也就是从SI&#xff0c;信号完整性方面&#xff09;。只考虑一个实际电容时&#xff0c;它的阻抗曲线是一个类似于倒三角形的形状&#xff0c;只在谐振频率点(与等效串联电感形成)处的阻抗最小。因此相当于只在这一个频率点处及附近…

移植的本质是什么

有断时间我就在想&#xff0c;为什么freertos&#xff0c;lvgl等等的移植都是把库文件放进来&#xff0c;直接点击编译&#xff0c;然后把bug都处理完成就移植成功了&#xff0c;为什么呢&#xff1f; 明明我一个函数都没调用&#xff0c;为什么会有一堆错误&#xff0c;莫名其…

广告场景下的检索平台技术

检索方向概述 数据检索领域技术选型大体分为SQL事务数据库、NoSQL数据库、分析型数据库三个类型。 SQL数据库的设计思路是采用关系模型组织数据&#xff0c;注重读写操作的一致性&#xff0c;注重数据的绝对安全。为了实现这一思路&#xff0c;SQL数据库往往会牺牲部分性能&…