杂记7--opencv的ar码模块学习

Posted 鸿_H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了杂记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
参数3200		表示输出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码
参数20.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的平移信息
参数60.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			板的平移姿态估计

注意一个点,markerCornersmarkerIds存储的并非所有检测到的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码模块学习的主要内容,如果未能解决你的问题,请参考以下文章

学习笔记FI-AR模块概述

Python学习杂记

学习杂记

Python学习杂记_6_字典常用操作

Python学习杂记_4_分支和循环

android 学习笔记 杂记1