1. 引言
筆者認為現階段AR技術的應用是還是比較坑爹的,大都是噱頭多但是實用的成分少,拿出來做做DEMO是可以,但是難以在實際的項目中落地產生實際的經濟價值。一方面是很難在業務上難以找到合適的應用場景(可能管線相關的項目算一個),另一方面技術上也存在一些難以突破的問題。不管是手持設備還是AR眼鏡,這些比較適合AR的硬件性能還是太弱了,導致其重建的空間信息與現實部分的空間信息存在較大的差距,這樣的話就談不上對現實的增強了。
不過筆者最近遇到了一個高空視頻全景AR的項目,感覺具有不錯的應用價值。具體可以參看這個案例:【數智實踐】AR云景全局掌控,為園區裝上“智慧之眼”,其中一張操作演示的的動態圖如下:
這個案例看起來與我們經常碰到的AR應用有所不同,不過筆者認為盡管這個案例可能沒有用到像AR Core/AR Kit這樣的AR組件,也不是這些組件提供的功能點,但也是AR技術的應用案例。所謂AR(Augmented Reality,增強現實),指的就是虛實結合,以達到對現實增強的效果。在這個案例中,“實”的部分就是高空攝像頭視頻畫面,“虛”的部分就是點的地理位置標注;更關鍵的地方在于,這些注記隨著攝像頭畫面的移動和縮放而移動,并不是固定在某個像素位置。從GIS的角度上來看,這似乎在操作一張地圖,這張地圖還是動態的。
在AR Core中,像這樣的功能被稱為運動追蹤,通常通過SLAM(simultaneous localization and mapping,實時定位和地圖構建)技術來實現。SLAM主要解決這樣的問題:一個機器人在未知環境中,通過計算機視覺等技術讓機器人知道自己的具體位置,進而描繪出此環境完全的地圖。但是筆者認為這個案例中應該用不到這種比較復雜的技術,基礎的GIS+測繪+計算機視覺技術足應該以實現這種效果。
2. 詳論
需要事先聲明的是,由于高空視頻全景AR的案例需要很多硬件上的操作和支持,筆者并沒有條件具體實現其中的功能,更多的是從理論上探究其中的實現原理,如果哪里說的不太對,也請讀者進行斧正。
2.1 靜止畫面
首先將這個問題簡化成最基本的場景,也就是無操作畫面靜止的情況(不是畫面中的視頻不會動,指的是拍攝的位置不會變化)。在這種情況下,注記實際代表的地理位置(物方坐標)是不會變化的,像素的位置(相方坐標)也不會變化,那么我們只需要關心注記的位置如何投射到視頻畫面中。很顯然,這個過程與相機標定的過程非常相似,已知一組點的物方坐標和像方坐標,那么可以標定出相機的內參和外參。具體可以參考筆者的這篇文章《一次實踐:給自己的手機攝像頭進行相機標定》。
在這個案例中,物方坐標可以通過GPS采集得到。不過GPS采集的點是WGS84地理坐標系的點。WGS84地理坐標系坐標是經緯度坐標,需要將其轉換成笛卡爾坐標,也就是ECEF(地心地固直角坐標系)坐標。ECEF坐標的值很大,最好進一步將其轉換成ENU(東北天站心坐標系)坐標,具體可參看筆者這篇文章《地心地固坐標系(ECEF)與站心坐標系(ENU)的轉換》。理論上使用投影坐標系也可以,不過筆者認為還是ENU坐標系更加嚴密一點。另一方面,像方坐標可以在視頻畫面中刺點得到。由于獲取像方點比較容易有誤差,因此最好選取一些有明顯特征的位置作為控制點來獲取物方坐標和像方坐標。
經過筆者驗證,即使獲取了一些控制點的物方坐標和像方坐標,仍然不能像《一次實踐:給自己的手機攝像頭進行相機標定》這篇文章一樣直接使用calibrateCamera
接口計算出攝像頭的內參和外參。這個接口要求對于非平面標定,需要一個初始的相機內參矩陣作為輸入。因為標定解算是一個非線性方程組迭代求解的過程,初始值差距太大就有很大概率求解失敗。因此,內參不能在這里進行聯合解算,還是要先進行預先解算,將攝像頭的內參標定好。
在獲取正確的內參之后,這個問題就簡化成了PnP(Perspective-n-Points)問題:通過世界空間的一組點(最少3個)的物方坐標和像方坐標,計算出攝像頭的外參(位置+姿態)。這個問題可以通過OpenCV的cv::solvePnP
接口來解決。實際上,這個過程就是《攝影測量學》中的后方交會。通過攝像機內參加上一組點的物方坐標和像方坐標,可以得到攝像機的外參,通常是三個旋轉參數,三個平移參數。
總結下來就是,對于不用操作攝像頭的靜止畫面,需要預先標定一次內參,然后通過實際的控制點標定一次外參。
2.2 縮放畫面
攝像頭靜止不動的單幅畫面比較好解決,但現在即使是一個普通的監控攝像頭,也具備調焦和旋轉角度的能力,當進行這些操作的時候,畫面的注記是如何隨著攝像頭的動作而移動呢?
如果我們知道一點三維可視化的知識就知道,三維場景中如果要放大一個區域,有兩種方式,一種是移動攝像頭,將其與物體靠近;另外一種就是調整攝像頭的焦距。調整焦距更加符合現實攝像頭的操作,一般來說,將焦距調的越長,能看清的場景就可以越遠,視場角也就會越小,就會產生畫面放大的效果。基于這個思想,我們只需要實時獲取在畫面縮放時的焦距,加上其他內參和外參,就可以解算出注記點物方坐標對應的相方坐標,并在畫面上做出調整即可。
話是這樣說,不過另外一個問題在于前面我們說到攝像頭的包括焦距的內參是通過相機標定的操作來實現的。我們要知道攝像頭執行了調焦操作,必須使用接入攝像頭對應的SDK,SDK會傳出具體的焦距嗎?傳出的焦距與我們標定的焦距不一致該怎么辦?對于專業相機,可能會提前將相機標定做好,會在SDK中傳出具體的內參包括焦距值。但是對于普通相機,可能就還是需要自己進行標定了。
根據筆者的設想,調整焦距的操作并不是線性調整而是調整到幾個固定的值,例如相機參數中經常可以看到的x0.5,x1.0,x2.0,x4.0這些值。也就是說,我們只需要在這些具體的調焦值時候進行相機標定,得到具體的攝像頭內參;然后通過SDK獲取這些調焦值,將其與攝像頭內參關聯上,就可以解算出正確的相方坐標,從而實現注記隨縮放的動態移動。
總結:對于進行實時調焦的攝像頭,要保證視頻畫面中的注記隨著畫面縮放而移動,需要預先進行有限次數的內參標定,然后通過實際的控制點標定一次外參。
2.3 縮放+旋轉
內參的問題比較好解決,最多預先在不同情況下標定內參的值就可以了。但是如果要實現旋轉就有點麻煩了,因為旋轉參數是外參,是無法事先進行標定的。另外,旋轉參數的獲取也很麻煩,要知道攝像頭旋轉了必須通過攝像頭SDK來獲取,但是SDK獲取的就一定的是我們想要的旋轉參數嗎?甚至我很懷疑是否能提供旋轉參數。
在接著進行論述之前,筆者需要先介紹一下線性代數的理論知識。在線性代數的觀點下,矩陣其實就是向量的張成空間。例如旋轉變換決定的旋轉矩陣,它的三個列向量這個三維坐標空間的三個基向量也就是基向量。旋轉矩陣可以看成是這樣的一個三維空間,一個X軸(1,0,0)、Y軸(0,1,0)、Z軸(0,0,1)標準笛卡爾坐標系經過旋轉變換后形成的坐標系空間,旋轉矩陣的三個列向量X、Y、Z軸的軸向量。
為了實時知道攝像頭是否旋轉了以及具體的旋轉量,我們假設攝像頭SDK一定會提供旋轉參數,通常是是類似于“左右旋轉-160度到+160度,上下旋轉-75度到+75度”之間這樣描述的數值。雖然我們并不知道這個攝像頭給出的旋轉決定的三維空間坐標系(相機坐標系)是如何描述的,但是我們可以將其復位到單位矩陣,也就是“左右旋轉0度,上下旋轉0度的位置”。在這個姿態下標定一次外參,令這個外參決定的旋轉矩陣為 R a R_a Ra?。接下來,攝像頭旋轉到任意位置的旋轉參數都可以基于這個 R a R_a Ra?來計算,因為在這種情況下,相當于是從世界坐標系通過旋轉變換到了相機坐標系,世界坐標系下的 R a R_a Ra?就是相機坐標系的單位矩陣。
如果“左右旋轉X度,上下旋轉Y度的位置”得到了一個旋轉矩陣為 R b R_b Rb?,那么攝像頭在任意旋轉姿態的旋轉矩陣就是:
R = R b ? R a R = R_b \cdot R_a R=Rb??Ra?
注意這里使用的右乘,先變換的變換在矩陣級聯的右邊。并且忽略了一些細節,比如左右手坐標系,坐標系的X、Y、Z軸的軸對應關系。
總結:對于攝像頭縮放+旋轉的情況,需要預先進行有限次數的內參標定,然后通過實際的控制點在相機坐標系原點位置標定一次相對外參標定,從而得到任意姿態的絕對外參。
2.3 移動+旋轉+縮放畫面
雖然筆者討論了只存在攝像頭旋轉的情況,但是筆者很懷疑一般的相機攝像頭是不是能做到只旋轉而不移動位置。傳感器是非常精密的設備,即使從外觀上看攝像機是旋轉了角度,但是很可能傳感器的成像中心已經產生了偏移。其實高空攝像頭可能會搭配專門的移動和旋轉的裝置,也就是所謂的“云臺”,可以通過電機驅動實現攝像頭的移動、旋轉、傾斜和俯仰。這樣的話,外參的平移量也需要我們自己進行標定了。
我們還是假設高空云臺相機的SDK能提供旋轉參數和平移參數,因為畢竟你要知道攝像頭動起來,就必須從攝像頭的SDK獲取參數。不過很顯然了,從攝像頭的SDK獲取參數不是攝像頭真正的外參,這里的外參應該是相對于整個高空云臺相機局部坐標系的參數。在這種情況與只旋轉的解法也比較相似,只不過計算要復雜一點。在平移參數為0,旋轉參數為0的位置標定外參,假設得到的結果是平移量決定的平移矩陣 T a T_a Ta?,旋轉量決定的旋轉矩陣 R a R_a Ra?。之后通過云臺移動相機,得到相對平移矩陣 T b T_b Tb?,相對旋轉矩陣 R b R_b Rb?,那么攝像頭在任意位置姿態的外參矩陣就是:
M = T b ? R b ? T a ? R a M ={T_b} \cdot {R_b} \cdot {T_a} \cdot {R_a} M=Tb??Rb??Ta??Ra?
其實這里有個問題,這里SDK提供的相對外參 T b T_b Tb?和 R b R_b Rb?怎么來的呢?其實也是要通過預先標定得到,不過相對外參的標定就有點復雜了,有時間再研究一下。
總結:對于攝像頭移動+旋轉+縮放的情況,需要預先進行有限次數的內參標定,然后通過實際的控制點在高空云臺相機局部坐標系的原點位置標定一次相對外參標定,從而得到任意位態的絕對外參。
3. 總結
從本文提供的解決思路可以看到,這個技術方案與攝像頭硬件的關系很大,不是純軟件能夠搞定的事情。因此最好能使用專業的工業級相機與計算機視覺相機,能夠通過SDK提供的API動態獲取這些內參和外參,它們分別是:
- 內參:焦距、主點、像素尺寸、畸變系數。
- 外參:三個位置參數,三個姿態參數。通常是相對于局部的相機坐標系的外參。
如果是普通相機,需要做的工作就多了,主要是:
- 進行內參和外參標定。
- 開發SDK輸出標定的內參和外參。
- 項目部署前在局部的相機坐標系的原點位置,通過一組控制點進行一次相對外參標定。
- 得到任意位態的絕對外參,加上內參實時計算出任意注記點的像素坐標。