天天看點

【實戰】使用ArUco标記實作增強現實

在本文中,我們将介紹ArUco标記以及如何使用OpenCV将其用于簡單的增強現實任務,具體形式如下圖的視訊所示。

一、什麼是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标記的尺寸可以任意的更改,為了成功檢測可根據對象大小和場景選擇合适的尺寸。在實際使用中,如果标記的尺寸太小,可能無法檢測到它,這時可以選擇更換較大尺寸的标記,或者将相機離标記更近一些。在本文中,我們将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 cvimport numpy as np
# Load the predefined dictionarydictionary = cv.aruco.Dictionary_get(cv.aruco.DICT_6X6_250)
# Generate the markermarkerImage = 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标記将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 valuesPtr<DetectorParameters> parameters = DetectorParameters::create();
// Declare the vectors that would contain the detected marker corners and the rejected marker candidatesvector<vector<Point2f>> markerCorners, rejectedCandidates;
// The ids of the detected markers are stored in a vectorvector<int> markerIds;
// Detect the markers in the imagedetectMarkers(frame, dictionary, markerCorners, markerIds, parameters, rejectedCandidates);      
#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 valuesparameters =  cv.aruco.DetectorParameters_create()
# Detect the markers in the imagemarkerCorners, markerIds, rejectedCandidates = cv.aruco.detectMarkers(frame, dictionary, parameters=parameters)      

對于每次成功檢測到标記,将按從左上,右上,右下和左下的順序檢測标記的四個角點。在C ++中,将這4個檢測到的角點存儲為點矢量,并将圖像中的多個标記一起存儲在點矢量容器中。在Python中,它們存儲為Numpy 數組。detectMarkers函數用于檢測和确定标記角點的位置。第一個參數是帶有标記的場景圖像。第二個參數是用于生成标記的字典。成功檢測到的标記将存儲在markerCorners中,其ID存儲在markerIds中。先前初始化的DetectorParameters對象作為傳遞參數。四、增強現實應用ArUco标記主要是為解決包括增強現實在内的各種應用場景下的相機姿态估計問題。OpenCV在其文檔中較長的描述了姿勢估計過程。本文中,我們将把ArUco标記用于增強現實應用程式,該程式可以将任何新場景疊加到現有圖像或視訊上。我們在家中選擇一個帶有相框的場景,并希望用新的圖檔替換原有圖檔,并檢視新圖檔在牆上的樣子。然後,我們嘗試在影片中插入視訊。為此,我們将列印ArUco标記,并粘貼到圖像區域的四個角落,如下圖所示,然後采集視訊,并按順序分别處理視訊的每一幀。

【實戰】使用ArUco标記實作增強現實

對于每幀圖像,首先檢測标記。上圖中用綠色線條繪制了檢測到的ArUco标記。該标記的第一個角點有一個紅色小圓圈,可以通過順時針移動标記來通路第二,第三和第四點。之後我們應用單應性變換将新的圖像放置到視訊中的相框位置。其過程與結果如下所示。

【實戰】使用ArUco标記實作增強現實

圖像的替換過程我們可以通過如下代碼實作:C++代碼

// Compute homography from source and destination pointsMat h = cv::findHomography(pts_src, pts_dst);
// Warped imageMat warpedImage;
// Warp source image to destination based on homographywarpPerspective(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 warpingMat 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);      
# Calculate Homographyh, status = cv.findHomography(pts_src, pts_dst)
# Warp source image to destination based on homographywarped_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 warpingelement = 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 markersAutomatic generation and detection of highly reliable fiducial markers under occlusionAruco project at Sourceforge作者:Sunita Nayak

繼續閱讀