前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【实战】使用ArUco标记实现增强现实

【实战】使用ArUco标记实现增强现实

作者头像
小白学视觉
发布2020-04-21 16:38:57
1.9K0
发布2020-04-21 16:38:57
举报

在本文中,我们将介绍ArUco标记以及如何使用OpenCV将其用于简单的增强现实任务,具体形式如下图的视频所示。

http://mpvideo.qpic.cn/0bf2k4abgaaa6uaaju44sjpfav6dcnlqaeya.f10003.mp4?dis_k=bc3c5e287fca100aff24a9a94f7ec9fa&dis_t=1587458276

一、什么是ArUco标记?

ArUco标记最初由S.Garrido-Jurado等人在2014年发表的论文Automatic generation and detection of highly reliable fiducial markers under occlusion中提出。ArUco的全称是Augmented Reality University of Cordoba,下面给出ArUco标记的一些示例。

ArUco标记作为基准标记放置在要成像的对象或场景上。它是一个背景为黑色的正方形,正方形内部的白色图案用来表示标记的唯一性,并且存储一些信息。黑色边界的目的是为了提高ArUco标记检测的准确性和性能。ArUco标记的尺寸可以任意的更改,为了成功检测可根据对象大小和场景选择合适的尺寸。在实际使用中,如果标记的尺寸太小,可能无法检测到它,这时可以选择更换较大尺寸的标记,或者将相机离标记更近一些。

在本文中,我们将ArUco标记放在图像相框的四个角上。当检测到这些标记时,便可以得到图像在相框中的位置,之后用其他图像替换原图像。并且当我们移动相机时,新替换的图片仍然具有正确的透视效果。

此外,在机器人应用中,可以将这些标记沿着仓库机器人的路径放置。当安装在机器人上的摄像头检测到这些标记时,由于每个标记都有唯一的ID,并且且标记在仓库中的放置位置已知,因此就可以知道机器人在仓库中的精确位置。

二、在OpenCV中生成ArUco标记

使用OpenCV可轻松生成这些标记。OpenCV中的Aruco模块总共有25个预定义的标记词典。每个词典中所有的Aruco标记均包含相同数量的块或位(例如4×4、5×5、6×6或7×7),且每个词典中Aruco标记的数量固定(例如50、100、250或1000)。接下来我们将展示如何在C++和Python中生成和检测各种aruco标记。

调用getPredefinedDictionary函数加载包含250个标记的字典,其中每个标记都是6×6位二进制模式。具体代码在下面给出。

C++代码

// Import the aruco module in OpenCV 
#include <opencv2/aruco.hpp>

Mat markerImage; 
// Load the predefined dictionary 
Ptr<cv::aruco::Dictionary>dictionary=aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); 
// Generate the marker 
aruco::drawMarker(dictionary, 33, 200, markerImage, 1);

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
markerImage = np.zeros((200, 200), dtype=np.uint8)
markerImage = cv.aruco.drawMarker(dictionary, 33, 200, markerImage, 1);

cv.imwrite("marker33.png", markerImage);

代码中drawMarker函数可以从由250个aruco标记组成的集合中选择给定id(第二个参数– 33)的标记,这250个标记的id由0~249表示。drawMarker函数的第三个参数决定生成的标记的大小,在上面的示例中,它将生成200×200像素的图像。第四个参数表示将要存储aruco标记的对象(上面的markerImage)。最后,第五个参数是边界宽度参数,它决定应将多少位(块)作为边界添加到生成的二进制图案中。

在上面的代码中,将在6×6生成的图形周围添加1位的边界,以在200×200像素的图像中生成7×7位的图像。上述代码生成的aruco标记如下图所示。

在实际应用时,我们可能需要生成多个标记。之后我们只需要将这些标记打印出来就可以直接使用了。

三、检测Aruco标记

将aruco标记放置在环境中后,我们需要检测它们并将其用于进一步处理。接下来我们介绍如何通过代码检测标记。

C++代码

// Load the dictionary that was used to generate the markers.
Ptr<Dictionary> dictionary = getPredefinedDictionary(DICT_6X6_250);

// Initialize the detector parameters using default values
Ptr<DetectorParameters> parameters = DetectorParameters::create();

// Declare the vectors that would contain the detected marker corners and the rejected marker candidates
vector<vector<Point2f>> markerCorners, rejectedCandidates;

// The ids of the detected markers are stored in a vector
vector<int> markerIds;

// Detect the markers in the image
detectMarkers(frame, 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 数组。

detectMarkers函数用于检测和确定标记角点的位置。第一个参数是带有标记的场景图像。第二个参数是用于生成标记的字典。成功检测到的标记将存储在markerCorners中,其ID存储在markerIds中。先前初始化的DetectorParameters对象作为传递参数。

四、增强现实应用

ArUco标记主要是为解决包括增强现实在内的各种应用场景下的相机姿态估计问题。OpenCV在其文档中详细描述了姿势估计过程。

本文中,我们将把ArUco标记用于增强现实应用程序,该程序可以将任何新场景叠加到现有图像或视频上。我们在家中选择一个带有相框的场景,并希望用新的图片替换原有图片,并查看新图片在墙上的样子。然后,我们尝试在影片中插入视频。为此,我们将打印ArUco标记,并粘贴到图像区域的四个角落,如下图所示,然后采集视频,并按顺序分别处理视频的每一帧。

对于每帧图像,首先检测标记。上图中用绿色线条绘制了检测到的ArUco标记。该标记的第一个角点有一个红色小圆圈,可以通过顺时针移动标记来访问第二,第三和第四点。

之后我们应用单应性变换将新的图像放置到视频中的相框位置。其过程与结果如下所示。

图像的替换过程我们可以通过如下代码实现:

C++代码

// Compute homography from source and destination points
Mat h = cv::findHomography(pts_src, pts_dst);

// Warped image
Mat warpedImage;

// Warp source image to destination based on homography
warpPerspective(im_src, warpedImage, h, frame.size(), INTER_CUBIC);

// Prepare a mask representing region to copy from the warped image into the original frame.
Mat mask = Mat::zeros(frame.rows, frame.cols, CV_8UC1);
fillConvexPoly(mask, pts_dst, Scalar(255, 255, 255));

// Erode the mask to not copy the boundary effects from the warping
Mat element = getStructuringElement( MORPH_RECT, Size(3,3) );
erode(mask, mask, element);

// Copy the masked warped image into the original frame in the mask region.
Mat imOut = frame.clone();
warpedImage.copyTo(imOut, mask);

Python代码

# Calculate Homography
h, status = cv.findHomography(pts_src, pts_dst)

# Warp source image to destination based on homography
warped_image = cv.warpPerspective(im_src, h, (frame.shape[1],frame.shape[0]))

# Prepare a mask representing region to copy from the warped image into the original frame.
mask = np.zeros([frame.shape[0], frame.shape[1]], dtype=np.uint8);
cv.fillConvexPoly(mask, np.int32([pts_dst_m]), (255, 255, 255), cv.LINE_AA);

# Erode the mask to not copy the boundary effects from the warping
element = cv.getStructuringElement(cv.MORPH_RECT, (3,3));
mask = cv.erode(mask, element, iterations=3);

# Copy the mask into 3 channels.
warped_image = warped_image.astype(float)
mask3 = np.zeros_like(warped_image)
for i in range(0, 3):
   mask3[:,:,i] = mask/255

# Copy the masked warped image into the original frame in the mask region.
warped_image_masked = cv.multiply(warped_image, mask3)
frame_masked = cv.multiply(frame.astype(float), 1-mask3)
im_out = cv.add(warped_image_masked, frame_masked)

在程序中,将新的场景图像角点作为源点(pts_src),并使用采集图像中图片框内的相应图片角点作为目标点(dst_src)。使用OpenCV中的findHomography函数计算源点和目标点之间的单应性函数h。然后将单应矩阵用于使新图像变形以适合目标框架。新图像被复制到目标帧中。对于视频素材,将此过程在每个帧上重复进行即可。

参考文献

OpenCV Documentation on ArUco markers

Automatic generation and detection of highly reliable fiducial markers under occlusion

Aruco project at Sourceforge

原文地址:https://www.learnopencv.com/augmented-reality-using-aruco-markers-in-opencv-c-python/

作者:Sunita Nayak

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小白学视觉 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档