1.介绍
Aruco码是由宽黑色边框和确定其标识符(id)的内部二进制矩阵组成的正方形标记。它的黑色边框有助于其在图像中的快速检测,内部二进制编码用于识别标记和提供错误检测和纠正。单个aruco 标记就可以提供足够的对应关系,例如有四个明显的角点及内部的二进制编码,所以aruco 标记被广泛用来增加从二维世界映射到三维世界时的信息量,便于发现二维世界与三维世界之间的投影关系,从而实现姿态估计、增强现实等应用。
2.码的创建
首先我们要指定一个字典,这个字典表示的是创建出来的aruco 标记具有怎样的尺寸、怎样的编码等我们使用:APlgetPredefined Dictionary ()来声明我们使用的字典。 些预定义字典。而且字典名称表示了该字典的aruco 标记数量和尺寸,例如DICT_7X7_50表示一个包含了50种7x7位标记的字典。
在OpenCv中提供了多种预定义字典,我们可以通过PREDEFINED_DICTIONARY_NAME来查看:
auto dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
可使用的字典:
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
Aruco码和Aruco码板的创建:
#include <opencv2/highgui.hpp>
#include <opencv2/aruco.hpp>
using namespace cv;
namespace {
const char* about = "Create an ArUco grid board image main -w=2 -h=2 -l=10 -s=5 -d=16 -si=true ";
const char* keys =
"{@outfile |<none> | Output image }"
"{w | | Number of markers in X direction }"
"{h | | Number of markers in Y direction }"
"{l | | Marker side length (in pixels) }"
"{s | | Separation between two consecutive markers in the grid (in pixels)}"
"{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}"
"{mid | 0 | markerboard start id}"
"{m | | Margins size (in pixels). Default is marker separation (-s) }"
"{bb | 1 | Number of bits in marker borders }"
"{si | false | show generated image }";
}
int main(int argc, char *argv[]) {
CommandLineParser parser(argc, argv, keys);
parser.about(about);
if(argc < 7) {
parser.printMessage();
return 0;
}
int markersX = parser.get<int>("w");
int markersY = parser.get<int>("h");
int markerLength = parser.get<int>("l");
int markerSeparation = parser.get<int>("s");
int dictionaryId = parser.get<int>("d");
int margins = markerSeparation;
if(parser.has("m")) {
margins = parser.get<int>("m");
}
int borderBits = parser.get<int>("bb");
bool showImage = parser.get<bool>("si");
int marker_st_id = parser.get<int>("mid");
String out = parser.get<String>(0);
if(!parser.check()) {
parser.printErrors();
return 0;
}
Size imageSize;
imageSize.width = markersX * (markerLength + markerSeparation) - markerSeparation + 2 * margins;
imageSize.height =
markersY * (markerLength + markerSeparation) - markerSeparation + 2 * margins;
Ptr<aruco::Dictionary> dictionary =
aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
Ptr<aruco::GridBoard> board = aruco::GridBoard::create(markersX, markersY, float(markerLength),
float(markerSeparation), dictionary, marker_st_id);
// show created board
Mat boardImage;
board->draw(imageSize, boardImage, margins, borderBits);
if(showImage) {
imshow("board", boardImage);
waitKey(0);
}
imwrite(out, boardImage);
return 0;
}
3.检测和姿态估计
3.1 Aruco标记的检测
cv::aruco::detectMarkers()
cv::aruco::detectMarkers(image_, dictionary_, corners, ids, detectorParams_, rejected);
参数:
(1)image :输入的需要检测标记的图像。
(2)dictionary :进行检测的字典对象指针,这里的字典就是我们创建aruco 标记时所使用的字典,检测什么类型的aruco 标记就使用什么类型的字典。
(3)corners :检测到的aruco 标记的角点列表,其四个角点均按其原始顺序返回 (从左上角开始顺时针旋转)。
(4)ids:检测到的每个标记的id,需要注意的是第三个参数和第四个参数具有相同的大小。
(5)parameters:Detection parameters 类的对象,该对象包括在检测过程中可以自定义的所有参数。
(6)参数rejectedImgPoints
3.2 单个Aruco码的姿态估计
cv::aruco::estimatePosesingleMarkers()
cv::aruco::estimatePoseSingleMarkers(corners, markerLength, intrinsic_matrix_, distortion_matrix_, rvecs, tvecs, _objPoints);
参数:
(1)corners :detectMarkers ()返回的检测到标记的角点列表;
(2)markerLength :aruco 标记的实际物理尺寸,也就是打印出来的aruco标记的实际尺寸,以m为单位;
(3)intrinsic_matrix_ :相机的内参矩阵;
(4)distortion_matrix_ :相机的畸变参数;
(5)rvecs : 标记相对于相机的旋转向量。
(6)tvecs : 标记相对于相机的平移向量。
(7)_objPoints :每个标记角点的对应点数组。
通过检测到的corners,并分别对每个标记进行姿态估计。 因此,每个aruco 标记都将返回一个相对于相机的旋转向量和平移矢量,返回的点数组是将标记角点从每个标记坐标系转换到相机坐标系下的表示。 标记坐标系原点位于标记的中心,Z轴垂直于标记平面,每个标记的四个角点在其坐标系中的坐标为:(-markerLength/ 2, markerLength/2,0) (markerLength/ 2, markerLength/ 2, 0) (markerLength/2,-markerLength/2,0) (-markerLength /2,-markerLength /2,0),其中,markerLength 是aruco 标记的实际边长。
3.3 单个Aruco码板的姿态估计
1.创建aruco码板
cv::aruco::GridBoard::create()
// create board object
cv::Ptr<cv::aruco::GridBoard> gridboard =
cv::aruco::GridBoard::create(markersX, markersY, markerlength, markerseparation, dictionary_, ids[0]);
board.markerboard_ptr = gridboard.staticCast<cv::aruco::Board>();
参数:
(1)markersX: 码板的横向码的个数;
(2)markersY: 码板的纵向码的个数;
(3)markerlength: 每一个码的边长,单位m;
(4)markerseparation: 两个码之间的间隔宽度,单位m;
(5)dictionary_:字典;
(6)ids[0]:码板的第一个码的id值;
2.姿态估计
cv::aruco::estimatePoseBoard()
cv::aruco::estimatePoseBoard(corners, ids, markerboard_ptr, intrinsic_matrix_, distortion_matrix_, rvec, tvec);
码板识别的坐标系是以码板的左下角为坐标原点建立的坐标系,如图所示。
3.4 Aruco码可视化
1.坐标轴的可视化
cv::aruco::drawAxis()
cv::aruco::drawAxis(image_, intrinsic_matrix_, distortion_matrix_, rvecs[i], tvecs[i], markerLength * 2.5f);
参数:
(1)image_ :绘制坐标轴的图像;
(2)intrinsic_matrix_ :相机的内参矩阵;
(3)distortion_matrix_ :相机的畸变参数;
(4)rvecs:旋转向量;
(5)tvecs:平移向量;
(6)markerLength :绘制坐标轴的长度,单位为m。
2.标记的可视化
cv::aruco::drawDetectedMarkers()文章来源:https://www.toymoban.com/news/detail-433904.html
cv::aruco::drawDetectedMarkers(image_, board.match_corners, board.match_ids);
参数:
(1)image :绘制标记的图像;
(2)corners :检测到的aruco 标记的角点列表;
(3)ids:检测到的每个标记对应到其所属字典中的id ;
(4)borderColor :绘制标记外框的颜色;
4.应用
1.增强现实
2.激光雷达和相机的联合标定
还有很多其他的应用,这里就不举例了。文章来源地址https://www.toymoban.com/news/detail-433904.html
到了这里,关于Opencv之Aruco码的检测和姿态估计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!