Augmented Reality 101 in MATLAB

最近@Yu Jiang老師迷上了AR,伴隨著@weijia zhang的Oculus跳票N個月後終於要發貨的日子的臨近,我們來看看如何用MATLAB的Computer Vision System Toolbox實現簡單的增強現實(並沒有什麼關係。

首先

我們需要一點點背景知識,什麼是AR

簡單來說,現在大家普遍說的Augemented Reality就是將一個虛擬的物體放到你拍攝的實物圖像中。

想要做AR, 你必須回答一個問題

一個三維世界中的點(x,y,z)是如何呈現在圖像中(x,y)的呢?

我們用個高端手繪來簡單說明下。

下圖中,O_w坐標係為我們生活的三維世界。而右上角那個O_c坐標系,則是相機的坐標系,我們可以簡單的將相機的光心模擬成O_c的原點。而成像的平面(或是你相機的膠片,或是數碼相機的CCD),則為當中那個平面O_I,我們看到的圖片都是在這個平面上的。

接下來就是坐標系之間的轉換了,這裡需要回答一個問題。

要把O_w坐標系下的(x,y,z)放到O_I平面上的(x,y),一共要幾步?

答案是比把大象裝冰箱少一步

1.把O_w坐標系轉換到O_c坐標系

2.把O_c坐標系轉換到O_I坐標系

就像所有工科學生以為自己學的是工科,最後發現自己都在學數學一樣,這兩步都可以用兩次矩陣乘法來表示,因為莎士比亞說過,矩陣的實質就是空間轉換。

此處我們就不展開說明了,我們只要知道以下的事實

第一步轉換對應camera extrinsics(旋轉+平移)

第二步轉換對應camera intrinsics

而上圖中的P,就是O_wO_I的轉換,也就是將(x,y,z)放到平面上的(x,y)變換矩陣,也是extrinsics和intrinsics的組合,叫做camera matrix

然後

為了看看上述知識有什麼用,我們來把一個虛擬的三維立方體放到圖片中。

我們知道,要把三維變二維,需要知道camera matrix

要知道camera matrix, 我們需要intrinsics和extrinsics

確定intrinsics的步驟被稱為相機的標定(camera calibration),學習computer vision的同學很多都是用Caltech提供的工具。然而從R2014a開始,MATLAB的Computer Vision工具箱自帶了Camera Calibrator App。

確定extrinsics的方法有很多,最簡單的方法是利用一個已知大小,且可以簡單通過圖像處理被測量的平面物體, 這種物體被稱為visual fiducial. 傳統的fiducial marker是用一個簡單的棋盤格圖案。

當然marker的圖案並不局限於棋盤格,任何可以被快速識別的圖案都可以,比如被醜陋人類虐待的機器人手裡的那個箱子上類似二維碼的東西(應該是Prof. Olson的AprilTag)

(圖片來源)

說了這麼多,快來看看MATLAB裡面怎麼做吧!

我們省略確定camera intrinsics的步驟,可以參照MATLAB的官方文檔和Camera Calibrator的文檔,雖然MATLAB中的App很方便,但是拍照的過程異常枯燥,一般我們都是讓實習生做的。

myc:????????

當標定相機後,我們可以得到一個cameraParameters object, 這裡是變數cameraParams.

接下來我們來確定相機的extrinsics和camera matrix。MATLAB的Computer Vision toolbox中自帶的detectCheckerboardPoints,extrinsics, 和cameraMatrix函數,可以直接解決這個問題。

>> I = imread(myImage.jpg);n>>[im, newOrigin] = undistortImage(I, cameraParams, OutputView, full); %首先去除相片的畸變 n>>[pts,boardSize] = detectCheckerboardPoints(im); %找到相片中的fiducial markern>> scale = 25; %我們用的是25mm間隔的棋盤格n>> worldPoints = generateCheckerboardPoints(boardSize,scale); %生成三維世界中假想的一個棋盤格n>> [rotationMat,translation]=extrinsics(pts,worldPoints,cameraParams);%通過圖片中檢測到的棋盤格和其對應的三維世界中的棋盤格生成extrinsics(旋轉+平移)n>>camMat = cameraMatrix(cameraParams,rotationMat,translation); %通過intrinsics和extrinsics建立camera matrixn>>cube = Cubic(5*25); %自己寫的類,一個5*25邊長的立方體n>>imshow(im); %去除畸變的圖片n>>cube.render(gca,camMat); %根據camera matrix把立方體在棋盤格上畫出來n

而我們的Cubic類簡單定義如下

classdef Cubic < handlen propertiesn verticesn faces n scalen patchn endn n methodsn function this = Cubic(scale)n this.scale = scale; %邊長n this.vertices = scale*...n [0 0 0;n 0 0 -1;n 0 1 -1;n 0 1 0;n 1 0 0;n 1 1 0;n 1 0 -1;n 1 1 -1;]; %8個頂點n this.faces = ...n [1 4 3 2;n 7 8 3 2;n 3 4 6 8;n 5 6 8 7;n 1 4 6 5;n 1 2 7 5;]; %6個面 n endn n function render(this,ax,camMat)n % Homogeneous coordinates (x,y,1)n vert = [this.vertices,ones(size(this.vertices,1),1)];n % Transform vertices from 3d world into 2d image planen vert2d = vert*camMat;n % Homogenous coordinates (x,y,1) to (x,y)n for i = 1:size(vert2d,1)n vertImage(i,1:2) = vert2d(i,1:2)/vert2d(i,3);n endn % draw patchn if isempty(this.patch) || ~isvalid(this.patch)n hold(ax,on);n this.patch = patch(Faces,this.faces,Vertices,vertImage,facecolor,r,faceAlpha,0.5);n hold(ax,off);n elsen n this.patch.Vertices= vertImage;n endn drawnow;n n endn n function clear(this)n delete(this.patch) n endn endnendn

見證奇蹟的時刻到啦!

我變

我在牆上

因為我們通過extrinsics掌握了棋盤格和圖像平面的關係,這個虛擬的立方體是一直會待在棋盤格上的,不管視角如何變化,然而知乎並不能上傳gif……所以各位腦補下就好了。

這就是增強現實AR的簡單實現,如果大家仔細看的話會發現立方體並不立方,其原因有兩個

1. intrinsic不準,在camera calibration這一步myc嫌麻煩只粗略的用少量圖片進行了標定,誤差較大

Myc:怪我咯????

2. extrinsic不準,這些圖都是從視頻中截下來的,視頻拍攝存在抖動,會對棋盤格的檢測產生影響。

在實際操作中,標定的過程相對可控,所以誤差會較小,所以如何確定extrinsics是決定性的一步。visual fiducial無疑是最簡單的方式,然而有時條件不允許你在牆上給人家到處貼小廣告,於是問題就變得更複雜了。多數情況會採用SLAM再加硬體來提高精度,比如微軟的hololense.

想了解更多Computer Vision?

Multiple View Geometry in Computer Vision


推薦閱讀:

如何評價 hololens 的『滑鼠出屏』交互?
如何評價蘋果增強現實APP達到1000款 但開發者熱情大跌?
数码暴龙(宝贝)是否会像宠物小精灵一样推出口袋妖怪go这样的ar虚拟游戏?

TAG:MATLAB | 增强现实AR | 计算机视觉 |