技术标签: OpenCV 学习之旅 无人机 定位 Aruco
目录
ArUco标记可以用于增强现实、相机姿势估计和相机校准等应用场景,具体如无人机的自主降落地标、机器人定位。标记中白色部分为唯一标识的二进制编码。
通过为每个码生成唯一标记,可以获取到更丰富的信息。在OpenCV中有25个预定义的标记字典。字典中的所有标记都包含相同数量的块或位(4×4、5×5、6×6 或 7×7),并且每个字典包含固定数量的标记(50、100、250 或 1000)。
C++:
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
// 导入aruco库
#include <opencv2/aruco.hpp>
using namespace std;
using namespace cv;
Mat markerImage;
// 加载预定义字典
Ptr<cv::aruco::Dictionary> dictionary = aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
// 生成标记
int id = 33; // 唯一标记
int pixsize = 200; // 图像的像素大小
aruco::drawMarker(dictionary, id, pixsize , markerImage, 1);
imshow("markerImage", markerImage);
waitKey();
Python:
import cv2 as cv
import numpy as np
# Load the predefined dictionary
dictionary = cv.aruco.Dictionary_get(cv.aruco.DICT_6X6_250)
# Generate the marker
ixsize = 200 # 图像的像素大小
id = 33 # 唯一标记
markerImage = np.zeros((ixsize , ixsize ), dtype=np.uint8)
markerImage = cv.aruco.drawMarker(dictionary, id, ixsize , markerImage, 1);
cv.imwrite("marker33.png", markerImage);
对于cv.aruco.drawMarker函数:
C++:
// 加载用于生成标记的字典。
Ptr<cv::aruco::Dictionary> dictionary = getPredefinedDictionary(cv::aruco::DICT_6X6_250);
// 使用默认值初始化检测器参数
Ptr<cv::aruco::DetectorParameters> parameters = cv::aruco::DetectorParameters::create();
// 声明将包含检测到的标记角和被拒绝的候选标记的向量
vector<vector<Point2f>> markerCorners, rejectedCandidates;
// 检测到的标记的id存储在一个向量中
vector<int> markerIds;
// 检测标记
detectMarkers(markerImage, dictionary, markerCorners, markerIds, parameters, rejectedCandidates);
Python:
#Load the dictionary that was used to generate the markers.
dictionary = cv.aruco.Dictionary_get(cv.aruco.DICT_6X6_250)
# Initialize the detector parameters using default values
parameters = cv.aruco.DetectorParameters_create()
# Detect the markers in the image
markerCorners, markerIds, rejectedCandidates = cv.aruco.detectMarkers(frame, dictionary, parameters=parameters)
对于每个成功的标记物检测,将按左上角、右上角、右下角、左下角的顺序检测标记的四个角点。在C++中,这4个检测到的角点被存储为点的向量,并且图像中的多个标记一起存储在点的向量向量中。在Python中,它们被存储为数组的Numpy数组。
在打印、剪切和放置场景中的标记时,重要的是在标记的黑色边界周围保留一些白色边框,以便可以轻松检测到它们。因此对于上面生成的Aruco图不能直接用,可以使用以下代码来增加白边:
#include <iostream>
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/aruco.hpp>
using namespace std;
using namespace cv;
vector<Mat> generateAruco(int nums, int pixSize=200, int border=1) {
vector<Mat> markerImages;
Ptr<cv::aruco::Dictionary> dictionary = aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
for (int i = 0; i < nums; ++i) {
Mat tempImage;
aruco::drawMarker(dictionary, i, pixSize, tempImage, border);
markerImages.push_back(tempImage);
}
return markerImages;
}
void detectAruco(const Mat& markerImage, vector<vector<Point2f>> &markerCorners, vector<vector<Point2f>> &rejectedCandidates, vector<int> &markerIds) {
// 加载用于生成标记的字典。
Ptr<cv::aruco::Dictionary> dictionary = getPredefinedDictionary(cv::aruco::DICT_6X6_250);
// 使用默认值初始化检测器参数
Ptr<cv::aruco::DetectorParameters> parameters = cv::aruco::DetectorParameters::create();
// 检测标记
detectMarkers(markerImage, dictionary, markerCorners, markerIds, parameters, rejectedCandidates);
}
int main(int argc, char* argv[])
{
vector<Mat> markerImages = generateAruco(1);
Mat markerImage = markerImages[0];
vector<vector<Point2f>> markerCorners;
vector<vector<Point2f>> rejectedCandidates;
vector<int> markerIds;
cv::copyMakeBorder(markerImage, markerImage, 5, 5, 5, 5, cv::BORDER_CONSTANT, Scalar(255,0,0));
detectAruco(markerImage, markerCorners, rejectedCandidates, markerIds);
cout << markerIds.size() << endl;
imshow("markerImage", markerImage);
waitKey();
return 0;
}
在OpenCV中使用ArUco Markers的增强现实(C++ / Python)
ArUco: a minimal library for Augmented Reality applications based on OpenCV
(更:这个好像不对??)创建Aruco中Board(与GridBoard不同,Board不限于网格形,可以是任意排列的2D、3D图形)时,出现类型错误objPoints.type() == CV_32FC3 || objPoints.type() == CV_32FC1 in function 'create',需要转换类型:
if (markerCorners.empty()) {
cout<<"无可用Marker"<<endl;
return 0;
}
std::vector< std::vector< Point3f > > objPoints;
for (auto corner: markerCorners) {
vector< Point3f > temp;
for (int i = 0; i < 4; ++i) {
temp.emplace_back(Point3f(corner[i].x, corner[i].y, 0));
}
objPoints.emplace_back(temp);
}
cv::Ptr<cv::aruco::Board> board = cv::aruco::Board::create(objPoints, dictionary, markerIds);
而对于创建GridBoard时候不需要转换,只用提供额外参数就行(毕竟已经是网格形了):
cv::Ptr<cv::aruco::GridBoard> board =
cv::aruco::GridBoard::create(5, //每行多少个Marker
7, //每列多少个Marker
0.04, //marker长度
0.01, //marker之间的间隔
dictionary); //字典
相对于上面创建的Board,此处有两种方式来检测:单次检测、一起检测。
对于单次检测,是分开每次检测一个,分别估计位姿:
// 估计相机位姿(相对于每一个marker)
cv::aruco::estimatePoseSingleMarkers(markerCorners, 0.055, cameraMatrix, distCoeffs, rvecs, tvecs);
输出:
R_{camera<---marker} :[-0.0003413119903118433, 0.9999500428020713, 0.009989765075384124;
0.9998031880569347, 0.0001430703615183937, 0.0198384647103005;
0.01983604439689155, 0.00999457007618388, -0.9997532895228086]
t_{camera<---marker} :[0.236643, 0.554003, 1.73982]
R_{camera<---marker} :[-0.9987024032747158, -0.04667896450031111, 0.02036133508603012;
-0.03554963247130007, 0.9252917858620086, 0.3775861949905609;
-0.03646550869605953, 0.3763724024014953, -0.9257505503028689]
t_{camera<---marker} :[-0.353789, 0.2201, 1.68946]
R_{camera<---marker} :[0.9926712669967025, 0.0045609525196265, 0.120759899765092;
0.01132149090445043, -0.998402461553577, -0.05535655884769745;
0.1203145025458768, 0.05631804751473418, -0.9911370732654825]
t_{camera<---marker} :[0.164678, 0.105936, 1.38113]
R_{camera<---marker} :[0.974149731293016, -0.09977617778369052, -0.2026746539866854;
-0.04192481488856337, -0.961439121983884, 0.2718034668936692;
-0.2219788524123525, -0.2562801768879826, -0.9407687601190632]
t_{camera<---marker} :[0.745065, 0.110989, 1.73927]
R_{camera<---marker} :[0.001805456772273173, -0.995139605508609, -0.09845763491986455;
-0.9661010203335827, -0.02715349161609959, 0.2567323633737377;
-0.2581580113733717, 0.09465650237159776, -0.9614544127115553]
t_{camera<---marker} :[0.153552, -0.265153, 1.90376]
而一起检测,是对所有的一起检测后,算一个总的位姿:(比较适用于需要高精度、有遮挡、有形变的情况)
// 估计相机位姿(相对于 aruco 板)
int valid = cv::aruco::estimatePoseBoard(markerCorners, markerIds, board, cameraMatrix, distCoeffs, rvec, tvec);
输出:
R_{camera<---marker} :[0.009618842263444671, -0.07316045611916067, -0.997273796674688;
-0.7388014820617763, -0.672599545516235, 0.04221636501022974;
-0.6738544709184865, 0.7363812864486647, -0.06052068234393715]
t_{camera<---marker} :[-5.07066, 571.684, -24.9751]
文章浏览阅读401次。可以使用position进行固定样式position:stickyCss position:sticky 初探_css 粘性 +2020
文章浏览阅读4.6k次。一、课题背景概述文本挖掘是一门交叉性学科,涉及数据挖掘、机器学习、模式识别、人工智能、统计学、计算机语言学、计算机网络技术、信息学等多个领域。文本挖掘就是从大量的文档中发现隐含知识和模式的一种方法和工具,它从数据挖掘发展而来,但与传统的数据挖掘又有许多不同。文本挖掘的对象是海量、异构、分布的文档(web);文档内容是人类所使用的自然语言,缺乏计算机可理解的语义。传统数据挖掘所处理的数据是结构化_特征选择创新点
文章浏览阅读1.1k次。下面是asp.net连接远程Oracle数据库服务器步骤:1.asp.net连接oracle服务器需要添加Sytem.Data.OracleClient命名空间,将System.Data.OracleClient.dll加入到项目中。2.连接时需要ConnectionString字符串,出现在web.config文件中,如下所示: 如下所示: C_aspnet连接oracle
文章浏览阅读583次,点赞12次,收藏15次。应该是每一章一个博客,顺便在每篇博客的最后放一些PAT上坑爹的知识点类的题,估计期末就是只考这个,最讨厌这种要死记硬背的东西了,哪有算法题有意思。(模板先暂时搁置,现在主要把《算法竞赛进阶指南刷一遍》)的,没有太多的时间)。
文章浏览阅读87次。虽然大多数应用程序都可以进行双开,但对于一些涉及敏感信息或需要特殊权限的应用程序来说,开启双开可能会导致安全风险或功能异常。因此,在尝试双开功能时,用户需要谨慎考虑哪些应用程序适合进行双开。对于许多用户来说,他们可能需要同时使用多个相同的应用程序以满足不同的需求。这意味着用户可以在同一部手机上同时登录多个相同的应用程序,满足用户在工作和生活中各种需求。3:信任设置完成后,您可以尝试再次打开应用,这时就不会再有问题了。1:当您进入下载并启动它的时候,可能会遇到无法打开的问题,需要进行一些设置。
文章浏览阅读207次,点赞10次,收藏2次。本文将介绍PSO的基本原理和几种改进的变种算法,包括PSO-PID、PSO-AM、PSO-BP以及果蝇模型在PSO中的应用。另一种改进的PSO算法是PSO-BP,它结合了BP神经网络和PSO的特点,用于解决神经网络中的权重优化问题。在PSO-BP中,粒子的速度和位置被编码为神经网络的权重,通过PSO算法更新权重,从而提高神经网络的学习性能和泛化能力。PSO-PID,PSO-AM,PSO-BP,FOA.通过粒子群能够很好的解决优化问题,对于学习PSO的初学者有很大的帮助,另外提供一个果蝇模型。
文章浏览阅读1.2w次,点赞30次,收藏187次。通用快捷键:快捷键作用Ctrl+Shift+P,F1展示全局命令面板Ctrl+P快速打开最近打开的文件Ctrl+Shift+N打开新的编辑窗口Ctrl+Shift+W关闭编辑器基础编辑快捷键:快捷键作用Ctrl + X剪切Ctrl + C复制Alt + up/down移动上下行Shift + Alt up/down上下复制当前行Ctrl + Shift + K删除当前行Ctrl + Enter_vscode shezhikj
文章浏览阅读3.4k次。Ubuntu 16.04 parted 对 GPT 格式硬盘 (12 TB) 分区1. sudo fdisk -lstrong@foreverstrong:~$ fdisk -lfdisk: cannot open /dev/loop1: Permission deniedfdisk: cannot open /dev/loop2: Permission deniedfdisk: cannot open /dev/loop3: Permission deniedfdisk: cannot ope_ubuntu parted
文章浏览阅读646次。if(test_form.addEventListener) { test_form.addEventListener("submit", my_onsubmit_function,false);} elseif(test_form.attachEvent) { test_form.attachEvent("onsubmit",my_onsubmit_functio_js form表达增加addeventlistener
文章浏览阅读8.7k次,点赞4次,收藏40次。一、手动卸载VS2015主体。 打开控制面板-程序-程序功能,找到VS2015,右键更改,然后卸载,等待卸载完成。二、下载TotalUninstaller工具。链接:https://pan.baidu.com/s/1nd2RV-t29gG-hBWAJO0cvA提取码:bjul三、解压下载的文件并以管理员身份运行Setup.ForcedUninstall.exe四、在弹出的命令行窗口中输入“Y”,然后回车,等待卸载完成。提示:可以重复几次这个操作,..._vs2015卸载工具
文章浏览阅读3k次,点赞7次,收藏12次。简单的说,激活的意思就是如果这个靠近的某个落脚点,就把它算成某个落脚点的值. 在训练模型的时候,机器会调整这些权重,这些权重会用某个落脚点的值来表示。总的来看,模型量化的精度损失取决于多种因素,包括所使用的量化策略、模型的特性,以及实际应用中的需求等。现在,我们把这个0到1之间的范围称为一个权重,看成一片连续的水面,上面表中的值看成一个一个的“落脚点”。依此类推,你有2的n次方种方法来表示这个范围,这里的n就是比特的位数。就是说,你仅用少量的精度损失的代价节省了大量的存储空间,是非常划算的。_大模型量化等级是什么意思
文章浏览阅读88次。上文分析了OpenGL ES渲染的实现。本文边可以分析video画面是如何在Android端窗口上显示的了。