NEWSIO+ 教育系列01 自己訓練一個 AI02 從照片還原 3D03 深度學習
課程 02動手做 // 試試看

從照片
還原 3D

一台相機、幾張照片,怎麼算出東西在空間裡的位置?這份教材沿著 Structure from Motion(SfM) 的流程,把針孔模型、三角化、尺度歧義、特徵點和 bundle adjustment 做成可以拖曳的實驗台。

SEC.01 / PINHOLE

針孔模型:一個像素是一條射線

相機把 3D 點變成影像上的位置:u = f·X/Z + cx。Z 在投影時被除掉了,所以左右移動會改變成像位置,沿著同一條射線前後移動,成像位置完全不變。拖曳橘色的杯子,再用滑桿把杯子沿射線推遠、放大。

PROBE A / 針孔投影動手做 // 拖曳橘色杯子
杯子位置(相機座標)—
成像位置—
杯子 A:寬 10 cm—
灰色杯子 B:沿同一條射線—
俯視圖:相機在下方往上看。影像平面畫在鏡頭前方 f/600 公尺處(1 像素 = 1/600 公尺),這樣畫出來的相似三角形和公式一致。杯子 B 離得更遠,也更大,兩者成像的像素寬度相同,這就是深度歧義。
SEC.02 / TRIANGULATION

三角化:兩條射線的交點

同一個點被兩台相機看到,各給一條射線,交點就是它的 3D 位置。兩顆鏡頭平行、相距基線 B 時,兩張照片裡的位置差(視差)是 d = uL − uR = f·B / Z,反過來 Z = f·B / d。把點拉遠,看深度怎麼變得不確定。

PROBE B / 雙目三角化動手做 // 拖曳點,或按下「近」「遠」
左影像 uL / 右影像 uR—
視差 d = uL − uR—
深度 Z = f·B / d—
視差有 ±1 px 誤差時,Z 的範圍—
橘色粗線是「視差差 ±1 px」時深度的可能範圍。視差誤差固定時,深度誤差約隨 Z² 成長:基線 20 cm 時,0.5 m 處差約 2 mm,5 m 處差約 21 cm;按下「基線 = 5 cm」再看 5 m,會差到將近 1 公尺。加大基線或焦距能縮小範圍,但基線太大會讓遮擋變多、配對變難。
SEC.03 / SCALE

尺度歧義:看起來一樣的兩個世界

只用兩張單目照片,能確定相機的旋轉和平移方向(5 DoF),平移的大小確定不了。整個世界放大 k 倍,兩台相機和所有點一起放大,拍出來的像素完全一樣。拖動滑桿,只有標尺上的數字會變,兩張照片不會變。

PROBE C / 兩個世界,同一組像素動手做 // 拉動 k

世界 A

相機間距(基線)/ 物體距離—
左右影像上的位置—

世界 B(A 的 ×1 倍)

相機間距(基線)/ 物體距離—
左右影像上的位置—
所以 SfM 重建出來的是形狀正確、大小未定的模型。COLMAP 通常把第一對照片的基線定成 1 單位,之後所有東西都用這個單位。要換成公尺,得從外部給一段真實長度:
—
SEC.04 / FEATURES

特徵點:哪些地方值得配對

SfM 不配對每個像素,只挑「往任何方向移動,周圍都會變」的位置。把游標移到下面的建築圖上:天空與牆的直線邊界、平坦的牆面、窗角、樹葉,分數完全不一樣。

PROBE D / 這裡能當特徵點嗎?動手做 // 在圖上移動或點擊
這個位置是
—
變化最大的方向 λmax
—
變化最小的方向 λmin(角點要看它)
—
這個實驗台用結構張量的兩個特徵值(Harris 類型的角點量測)示範「兩個方向都有變化」。SIFT 實際上用 DoG 在尺度空間找極值,再用類似的條件篩掉邊緣點。注意窗戶那一排:每個窗角都是好點,但彼此長得一樣,配對時要靠比值測試丟掉。
SEC.05 / INCREMENTAL SFM

從兩張到很多張:加入、累積、微調

這是 2D 俯視版的增量式重建。橘色三角形是相機,從每台相機射出的細線是它「看到的方向」。步驟 1 只有前兩台相機。步驟 2 加入其餘相機,位姿誤差一台一台累積,細線沒有對準點。步驟 3 執行 bundle adjustment,把所有相機位姿和點一起調整,讓射線收斂回點上。

PROBE E / 位姿估計 → 三角化 → BUNDLE ADJUSTMENT動手做 // 依序按 1、2、3
目前階段—
—
重投影誤差(RMS)—
3D 點平均偏離真實位置—
相機位置平均偏離真實位置—
示意說明:初始估計是在真實值上加擾動模擬出來的,並沒有真的跑特徵配對與 PnP;第三步的最佳化是真的在解最小平方(Levenberg-Marquardt)。第 0 台相機的位姿和第 0、1 台的距離被固定,這就是用來固定尺度與座標系的做法:沒有這個固定,整個模型可以任意平移、旋轉、縮放而誤差不變。勾選「相機站遠一點」再跑一次步驟 3:重投影誤差一樣小,點的位置卻不一定更準。
SEC.06 / SUMMARY

Z 到底從哪來

針孔模型把每個像素變成一條射線,要得到射線上的哪一點,需要 Z。這堂課介紹了三條路,加上直接用感測器量:

方法Z 的來源尺度限制
SfM多視角三角化,加 bundle adjustment未知,要外部資訊(IMU、已知長度、GPS)場景要靜止;無紋理處沒有點;結果是稀疏點
Stereo視差,Z = f·B / d公制(基線已知)遮擋、反光、無紋理;深度誤差隨距離平方成長
學習式單目從訓練資料學到的先驗常是相對深度機器人需要公制距離,要另外校準尺度
深度相機感測器直接量(很多款內部其實是雙目加紅外線)公制範圍有限;戶外強光、透明與反光表面會失效

有了 Z 以後,下一步是把每一幀的點雲拼起來、估計相機位姿,建出一張持久的地圖。