上一篇博客中介紹了從拍攝圖像到獲取視差圖以及深度圖的過程,現在開始介紹利用視差圖或者深度圖進行虛擬視點的合成。虛擬視點合成是指利用已知的參考相機拍攝的圖像合成出參考相機之間的虛擬相機位置拍攝的圖像,能夠獲取更多視角下的圖片,在VR中應用前景很大。
視差圖可以轉換為深度圖,深度圖也可以轉換為視差圖。視差圖反映的是同一個三維空間點在左、右兩個相機上成像的差異,而深度圖能夠直接反映出三維空間點距離攝像機的距離,所以深度圖相較於視差圖在三維測量上更加直觀和方便。
- 利用視差圖合成虛擬視點
- 利用深度圖合成虛擬視點
一、利用視差圖合成虛擬視點
由於視差圖反映的是三維空間點在左、右兩個相機上成像的差異,並且由於提前進行了立體校正,這種差異就反映在圖像的同一行上。在立體匹配的SGBM算法中就是以其中某一副為參考圖像,在另一幅圖像的同一行上搜索匹配點。因此在合成虛擬視點時也只需在同一行上平移虛擬攝像機位置即可。流程如下:
(1). 假設視差圖中某一個像素點的視差值為dmax,也就是說從左攝像機camL到右攝像機camR之間,該像素點的視差值變化范圍為0~dmax。為了方便介紹我將其歸一化到alpha取值范圍為0~1。
(2).那么如果我要獲取alpha=0.5位置時候虛擬相機位置的圖像呢,那么此時該像素點和左圖像匹配點的坐標差異就是0.5 * dmax,和右圖像匹配點的坐標差異也是0.5 * dmax;如果alpha=0.3,那么此時該像素點和左圖像匹配點的坐標差異就是0.3 * dmax,和右圖像匹配點的坐標差異也是0.7 * dmax;
(3).根據上面提到的原理,顯而易見,合成新視點時候只需要將左圖像的像素點位置向右移動alpha *dmax,或者右圖像的像素點向左移動(1-alpha)*dmax,就可以得到alpha位置處虛擬相機拍攝的虛擬視點圖像。
合成虛擬視圖即可以利用左參考圖像和對應的左視差圖,也可以利用右參考圖像和對應的右視差圖,更好的是都利用上得到兩幅虛擬視點圖像,然后做圖像融合,比如基於距離的線性融合等。
在算法的實現中,又有兩種選擇,一個是正向映射,一個是反向映射(逆向映射)。
1.正向映射
① 將原參考圖像中整數像素點根據其對應上視差值平移到新視圖上。
② 平移后像素點坐標可能不是整數,為了獲取整數坐標,采用最近鄰插值,將原圖像像素值賦值到新坐標位置。
③ 由於最近鄰插值會損失精度,因此在物體的邊緣會出現鋸齒效應。
2.反向映射
① 利用參考視點的視差圖dispL,算出虛擬視點位置的視差圖dispV;
② 由於遮擋等因素影響,dispV肯定會出現空洞和裂紋,所以需要做一個空洞填充holeFilling;
③ 利用dispV將虛擬視點圖像中的整數坐標平移到參考視點位置下的坐標,此時也可能不是整數,而是浮點數坐標。這就面臨一個從哪里取值的問題。
④ 取參考視點圖像浮點數坐標附近4個點的像素值,用雙線性插值算出對應虛擬視點圖像位置處的像素值即可。
⑤ 由於雙線性插值屬於一種加權平均的思想,能夠有效避免精度損失造成的鋸齒現象,但是算法復雜度要高。
下面給出利用左視點圖像和對應視差圖獲取虛擬視點位置圖像的效果(反向映射+雙線性插值):
不進行空洞填充

空洞填充

二、利用深度圖合成虛擬視點
和利用視差圖合成新視點一樣,利用深度圖合成新視點也有兩種選擇:1. 正向映射 2. 反向映射。由於正向映射比較簡單並且效果不理想,因此目前大多采用反向映射方法。
已知內參矩陣K,下面仍然以左圖像imgL和depthL為參考圖像,獲取alpha=0.5位置處的虛擬視點圖像,簡要步驟如下:
(1). 利用內參矩陣K, 將depthL映射到三維空間點,平移到虛擬相機坐標下后,重投影到虛擬視點圖像平面,得到虛擬視點位置處的深度圖depthV;
(2). 對depthV進行空洞填充;
(3). 利用內參矩陣K和深度圖depthV,將虛擬視點圖像imgV上的坐標點反向投影到三維空間點,平移后再重投影到參考圖像imgL上, 在imgL上利用雙線性插值獲取imgV上的像素值。
具體流程如下:
(1). 利用內參矩陣K,以及參考深度圖depthL,如下圖,將參考圖像坐標點(u, v)投影到參考相機的攝像機坐標系下,得到對應的三維空間點(X, Y, Z),計算方法如下:
d * u = fx * X + cx *Z d * v = fy * Y + cy * Z d = Z
其中d是深度值,fx, fy, cx, cy均從內參矩陣中得到,那么(X, Y, Z)可以表示如下:
X = ( u - cx ) * d / fx Y = ( v - cy ) * d / fy Z = d
參考深度圖depthL 參考左圖像imgL

(2). 將三維點(X, Y, Z)平移到虛擬攝像機坐標系下,得到虛擬攝像機坐標系下的三維點(X1, Y1, Z1), 計算如下:
X1 = X - alpha * baseline Y1 = Y Z1 = Z
(3). 將(X1, Y1, Z1)重投影到虛擬視點圖上,得到坐標(u1, v1):
u1 = ( fx * X1 + cx * d ) / d v1 = ( fy * Y1 + cy * d ) / d d = Z1
//注意此處d != 0
利用最近鄰插值得到虛擬視點深度圖depthV。如下圖所示,alpha=0.5位置虛擬視點深度圖:

(4). 對depthV進行空洞填充。填充后depthV如下圖:

(5). 利用depthV和內參矩陣K,反向重復上述操作。將虛擬視點圖像imgV坐標點反向投影到三維點,平移,再重投影到參考視圖imgL上,在imgL上利用雙線性插值得到imgV上的像素值。從而獲取虛擬視點圖像imgV,如下圖:

(6). 綜合上述步驟,可以獲取alpha從0 到 1, 也就是從左相機位置到右相機位置的一系列虛擬視點圖像,gif動圖展示如下:

上面效果中在深度不連續區域有較為明顯的失真,這是由於該區域為遮擋區域,無法計算出准確的視差值,可以通過觀察前面立體匹配博客的視差圖或者深度圖看出。而采用的空洞填充將附近的視差值填充過去,所以會造成前景出現在背景部分,出現較為明顯的偽影。去除偽影也有很多種方法,比如結合右參考相機合成同樣位置的虛擬視點,然后將兩個視點融合等方法。
其實3D Warping技術的核心就是下面幾條語句,二維圖像點到三維空間點,平移,旋轉,再重投影到新的二維圖像點。上面沒有加入旋轉,旋轉的話就是直接用三維點乘以3x3的旋轉矩陣后平移,然后再重投影。
float dep = pDepthV[i*imgW + j]; if (dep < 0.001) continue; //反投影 float X = (j - cx)*dep / fx; float Y = (i - cy)*dep / fy; float Z = dep; //平移 float X2 = X + offsetX; float Y2 = Y; float Z2 = Z; //重投影 float uf = (fx*X2 + cx* Z2) / dep; float vf = (fy*Y2 + cy * Z2) / dep;
