
簡介計算機視覺中從二維圖像恢復(fù)三維深度信息是諸多應(yīng)用的基礎(chǔ)而立體匹配正是連接雙目圖像與深度數(shù)據(jù)的關(guān)鍵橋梁。通過計算左右相機圖像中對應(yīng)像素的水平偏移量即視差可以反推出場景深度進(jìn)而支撐三維重建、障礙物檢測與智能測距等任務(wù)。本文從最基礎(chǔ)的窗口匹配代價函數(shù)出發(fā)逐層剖析SAD、SSD與ZNCC三類經(jīng)典算法的數(shù)學(xué)原理與代碼實現(xiàn)并對比其在不同光照和噪聲條件下的魯棒性。隨后工程上廣泛應(yīng)用的OpenCV BM與SGBM算法被引入重點解釋半全局能量優(yōu)化和參數(shù)調(diào)優(yōu)策略。無論你是入門學(xué)生還是從事雙目視覺開發(fā)的工程師掌握這些基礎(chǔ)算法都能為后續(xù)深度估計和點云生成提供扎實的認(rèn)知底座幫助在實際場景中快速選型與排障。 如果你接觸過雙目視覺一定繞不開立體匹配。它的任務(wù)說簡單也簡單左右兩個相機拍攝同一塊場景找出左圖里每個像素在右圖中的對應(yīng)點這個對應(yīng)關(guān)系產(chǎn)生的橫向偏移就是視差。有了視差才談得上深度計算、三維重建、障礙物檢測和測距。最近我用 Python 把幾個最基礎(chǔ)的立體匹配算法從頭到尾實現(xiàn)并對比了一遍包括 SAD、SSD、ZNCC 這三個基于窗口代價函數(shù)的自由實現(xiàn)以及 OpenCV 直接可用的 BM、SGBM。這篇文章就把實現(xiàn)過程、關(guān)鍵原理、調(diào)參經(jīng)驗和踩坑記錄完整整理出來適合剛?cè)腴T雙目視覺的學(xué)生、準(zhǔn)備做雙目測距的工程師以及想搞清楚視差圖背后原理的開發(fā)者。先說結(jié)論如果你想快速拿到一張可用的視差圖直接用 OpenCV 的 SGBM 是最省力的方案但如果你想真正理解立體匹配在做什么手寫一遍 SAD 或 ZNCC 是繞不開的路。我建議按這個順序?qū)WSAD 理解窗口匹配的直覺ZNCC 理解光照魯棒性再看 BM 和 SGBM 如何把這些思想工程化。下面按這個思路展開。1. 立體匹配到底在解決什么問題在動手寫代碼之前先把問題的邊界框清楚。立體匹配不是單純在兩張圖上找相似區(qū)域它背后是一個完整的成像幾何模型。只有知道我們假設(shè)了什么、化簡了什么后面看算法和調(diào)參才不會一頭霧水。1.1 視差和深度一個反比關(guān)系雙目相機的核心是兩臺相距一定距離的相機這個距離叫基線baseline。由于兩臺相機位置不同同一個三維空間點在左右圖像里的成像位置不會一致這個位置差就是視差disparity通常記作 d x_left - x_right。在理想情況下匹配點只存在水平方向的偏移垂直方向的偏移為 0也就是極線校正后的標(biāo)準(zhǔn)雙目形態(tài)。深度 Z 和視差 d 的關(guān)系是反比Z f * B / d其中 f 是焦距B 是基線長度。這個公式告訴我們一個直觀結(jié)論物體離相機越近視差越大越遠(yuǎn)視差越小逼近無窮遠(yuǎn)時視差趨近 0。所以立體匹配輸出的視差圖本質(zhì)上是一張?zhí)N含深度信息的中間產(chǎn)物。拿到它之后配合相機內(nèi)參就能生成三維點云這也是很多三維重建項目的基礎(chǔ)。理解了這一層你就明白為什么匹配必須做對——某一個像素的視差錯了對應(yīng)的深度就會錯得離譜后續(xù)的點云和距離估計全部白費。1.2 經(jīng)典四步框架所有算法都能裝進(jìn)去2002 年 Scharstein 和 Szeliski 在立體匹配綜述里提出了一個經(jīng)典框架到現(xiàn)在依然適用。幾乎所有立體匹配算法都可以拆進(jìn)這四個步驟匹配代價計算對每個像素、在每一個候選視差下計算一個代價代價越小表示越相似。SAD、SSD、ZNCC 就是這一層最典型的代價函數(shù)。代價聚合單像素的代價對噪聲和弱紋理區(qū)域太敏感通常會在一個窗口或區(qū)域內(nèi)累加、加權(quán)讓匹配結(jié)果更穩(wěn)定。視差計算/優(yōu)化常見的做法是 WTAWinner Takes All也就是直接取最小代價對應(yīng)的視差作為結(jié)果SGBM 這類算法則會在代價基礎(chǔ)上加平滑約束進(jìn)行能量函數(shù)優(yōu)化。視差細(xì)化左右一致性檢查、亞像素插值、中值濾波、斑點濾波等用于消除誤匹配和孤立噪點。這套框架的好處是你可以把五種方法放在同一個骨架上對比SAD、SSD、ZNCC 停在第一二步BM 是工程化的局部匹配SGBM 則在第三步引入了全局能量優(yōu)化。理解了框架后面講每個算法時你就知道它卡在哪個環(huán)節(jié)、優(yōu)勢和短板在哪里。1.3 環(huán)境準(zhǔn)備、圖像校正與實驗數(shù)據(jù)代碼層面只需要三個東西Python 3.8 或更高版本、OpenCV、NumPy。OpenCV 提供了 BM 和 SGBM 的完整實現(xiàn)手寫部分只用 NumPy 就夠。import cv2 import numpy as np left_gray cv2.imread(left.png, cv2.IMREAD_GRAYSCALE) right_gray cv2.imread(right.png, cv2.IMREAD_GRAYSCALE) print(left_gray.shape, right_gray.shape)這里有一個容易被新手忽略的前提輸入圖像必須是極線校正后的雙目圖像對。極線校正rectification讓同名點只出現(xiàn)在同一水平線上這樣匹配搜索才能從二維平面搜索變成一維水平掃描。如果圖像沒有校正你在代碼里看到的正確匹配會全部錯位這不是算法的鍋是數(shù)據(jù)預(yù)處理沒做好。工程上可以用cv2.stereoRectify和cv2.initUndistortRectifyMap配合標(biāo)定參數(shù)做校正本文的討論默認(rèn)輸入已經(jīng)是校正好的圖像。測試數(shù)據(jù)建議用 Middlebury 數(shù)據(jù)集里的標(biāo)準(zhǔn)圖像對比如 Tsukuba、Cones這些圖都是公開的而且?guī)в?ground truth方便你評估算法好壞。自己拍的雙目圖也可以但務(wù)必確認(rèn)已經(jīng)校正。2. SSD、SAD、ZNCC三個基礎(chǔ)代價函數(shù)從數(shù)學(xué)到代碼這一節(jié)是整個主題的基石。SAD、SSD、ZNCC 都是局部立體匹配方法核心思路非常一致取左圖某個像素周圍的窗口在右圖同一行上、候選視差范圍內(nèi)滑動同樣大小的窗口計算兩個窗口之間的相似度最相似的位置對應(yīng)的偏移量就是這個像素的視差。區(qū)別只在于“相似度怎么定義”。2.1 SAD窗口內(nèi)絕對差求和SADSum of Absolute Differences是最直觀的代價函數(shù)。對左右兩個窗口內(nèi)的所有像素做差取絕對值再累加cost(d) Σ | L(xi, yj) - R(xi-d, yj) |這里的窗口大小是奇數(shù)比如 5x5i 和 j 遍歷窗口內(nèi)坐標(biāo)。代價越小說明兩個窗口內(nèi)容越接近。這個操作的本質(zhì)是假設(shè)窗口內(nèi)的像素在左右圖中顏色一致偏差主要來自噪聲和輕微視差變化絕對值和可以穩(wěn)定量化這種偏差。手寫實現(xiàn)如下這個版本刻意保留了三層循環(huán)方便對照原理def sad(left, right, max_disp, win_size5): h, w left.shape half win_size // 2 disp np.zeros((h, w), dtypenp.float32) for y in range(half, h - half): for x in range(half, w - half): best_d, best_cost 0, float(inf) for d in range(max_disp): if x - d half: break l_win left[y-half:yhalf1, x-half:xhalf1].astype(np.int16) r_win right[y-half:yhalf1, x-half-d:xhalf1-d].astype(np.int16) cost np.sum(np.abs(l_win - r_win)) if cost best_cost: best_cost cost best_d d disp[y, x] best_d return disp注意幾個細(xì)節(jié)左右圖要轉(zhuǎn)成 int16 再做減法避免 uint8 溢出搜索時如果x - d小于窗口半寬說明窗口已經(jīng)超出圖像邊界直接結(jié)束當(dāng)前候選視差循環(huán)最終每個像素取代價最小的視差。這個版本不是性能最優(yōu)的但它是理解算法的最佳版本。實測時你會發(fā)現(xiàn)當(dāng)左右圖像亮度一致、噪聲不大時SAD 的結(jié)果已經(jīng)相當(dāng)可用尤其是在紋理豐富的區(qū)域邊界的輪廓能比較清晰地還原出來。2.2 SSD平方差求和一個容易踩的取舍SSDSum of Squared Differences和 SAD 幾乎一樣只是把絕對差換成了平方差cost(d) Σ ( L(xi, yj) - R(xi-d, yj) )^2在代碼里只改一行把np.abs(l_win - r_win)換成(l_win - r_win) ** 2??雌饋聿顒e很小但數(shù)學(xué)上行為很不一樣平方會放大較大的像素差異因此在高紋理區(qū)域SSD 的匹配區(qū)分度會比 SAD 更高正確匹配和錯誤匹配之間的代價差距更明顯。但也正因為平方放大了異常值SSD 對噪聲、高光反射、左右圖曝光差異非常敏感。只要窗口里有幾個像素因為反光或者傳感器噪聲出現(xiàn)較大差異代價就會被這幾個點主導(dǎo)導(dǎo)致錯誤匹配。我在實驗里發(fā)現(xiàn)亮度和噪聲水平接近的圖像對SSD 和 SAD 差別不大一旦圖像里有高光區(qū)域SSD 的視差圖會出現(xiàn)比 SAD 更多的毛刺。所以如果你的數(shù)據(jù)源不太干凈SAD 的魯棒性反而比 SSD 好。這個對比值得記在心里更強的差異放大不代表更好的匹配它同時放大了噪聲。2.3 ZNCC歸一化之后光照變化不再是災(zāi)難ZNCCZero-mean Normalized Cross Correlation和前面兩個思路完全不同。它不是算差的累積而是算兩個窗口的相關(guān)系數(shù)ncc(d) Σ (L - mean_L) * (R - mean_R) / sqrt( Σ(L - mean_L)^2 * Σ(R - mean_R)^2 )實現(xiàn)時先把窗口內(nèi)像素減去窗口均值再做歸一化相關(guān)。這樣做的意義是什么減去均值等價于消除了窗口整體的亮度偏移除以標(biāo)準(zhǔn)差則消除了對比度縮放。也就是說左右圖即使整體亮度不一致、曝光有明顯差異ZNCC 依然能測出兩個窗口的“形狀”是否相似。在代碼里ZNCC 要尋找的是最大的相關(guān)系數(shù)而不是最小代價。這一點最容易搞反具體實現(xiàn)如下def zncc(left, right, max_disp, win_size5): h, w left.shape half win_size // 2 disp np.zeros((h, w), dtypenp.float32) for y in range(half, h - half): for x in range(half, w - half): best_d, best_score 0, -1.0 l_win left[y-half:yhalf1, x-half:xhalf1].astype(np.float32) l_mean l_win.mean() l_norm l_win - l_mean for d in range(max_disp): if x - d half: break r_win right[y-half:yhalf1, x-half-d:xhalf1-d].astype(np.float32) r_mean r_win.mean() r_norm r_win - r_mean num np.sum(l_norm * r_norm) den np.sqrt(np.sum(l_norm**2) * np.sum(r_norm**2)) score num / (den 1e-6) if score best_score: best_score score best_d d disp[y, x] best_d return disp注意den 1e-6是為了防止窗口內(nèi)像素完全相同時除零。ZNCC 的代價函數(shù)是三個里最抗光照變化的代價是計算量大很多。每個候選視差都要重復(fù)計算窗口均值、方差和乘積和純 Python 實現(xiàn)下速度幾乎是 SAD 的三到五倍。所以 ZNCC 適合在左右圖亮度差異明顯、或者多相機曝光不一致的場景使用比如室外自然光變化的環(huán)境。2.4 三個算法的實際效果對比我用標(biāo)準(zhǔn)測試圖對三個算法做了對比。先用 5x5 窗口、max_disp 設(shè)為 64在紋理豐富的區(qū)域三者都能得到基本合理的視差圖但在左右圖亮度差異明顯的模擬光照下SAD 和 SSD 的錯誤區(qū)域明顯增多ZNCC 基本不受影響。下面是幾個關(guān)鍵維度的總結(jié)指標(biāo)SADSSDZNCC匹配標(biāo)準(zhǔn)最小化代價最小化代價最大化相關(guān)系數(shù)抗光照變化較弱較弱強抗噪聲中等較差較好計算量較小較小大實現(xiàn)復(fù)雜度低低中典型適用場景亮度一致的圖像對高紋理區(qū)域曝光不一致或光照變化一個我常說的類比SAD 像拿直尺量差距SSD 像把差距平方后再量ZNCC 則是把兩段波形先對齊到同一水平線再比較形狀。量差距的方式對絕對亮度敏感比較形狀的方式對亮度不敏感這就是 ZNCC 在復(fù)雜光照下更穩(wěn)的根本原因。3. BM和SGBM工程級匹配算法的原理與調(diào)用手寫代價函數(shù)的過程能幫你建立直覺但真實項目里幾乎不會用純 Python 三層循環(huán)去跑匹配性能完全扛不住。OpenCV 提供的 BM 和 SGBM 才是工程主角。不過它們也不是黑盒理解了參數(shù)背后的意義你才能把它調(diào)好。3.1 BM塊匹配的工程化加速BMBlock Matching的思路和前面說的窗口匹配一脈相承。它把圖像劃分成塊在極線方向上滑動用 SAD 之類的代價函數(shù)計算匹配代價再用 WTA 選出視差。OpenCV 的StereoBM實現(xiàn)做了大量加速比如積分圖、紋理過濾所以它能在 CPU 上達(dá)到很高的幀率適合實時場景做初步深度估計。調(diào)用方式非常簡潔bm cv2.StereoBM_create(numDisparities80, blockSize15) disp_bm bm.compute(left_gray, right_gray).astype(np.float32) / 16.0注意numDisparities必須是 16 的倍數(shù)blockSize必須是奇數(shù)這兩個是硬性約束不符合會直接報錯或者行為異常。StereoBM的輸出也是定點格式需要除以 16 才能得到浮點視差細(xì)節(jié)我在后面展開。BM 的優(yōu)勢是快缺點是視差圖質(zhì)量相對一般弱紋理區(qū)域容易產(chǎn)生大面積空洞深度不連續(xù)處也容易出現(xiàn)“胖邊界”現(xiàn)象。但在資源受限的嵌入式設(shè)備上它往往是唯一現(xiàn)實的選擇。3.2 SGBM從局部到半全局的能量優(yōu)化SGBM 全稱 Semi-Global Block Matching核心思想來自 Hirschmuller 的經(jīng)典論文。它不再滿足于對每個像素獨立做 WTA而是把整個視差圖看作一個能量函數(shù)的解E(D) Σ C(p, d_p) Σ P1 * [|d_p - d_q| 1] Σ P2 * [|d_p - d_q| 1]第一項是數(shù)據(jù)項也就是像素 p 在視差 d_p 下的匹配代價第二三項是平滑項用于懲罰相鄰像素 p 和 q 之間視差不連續(xù)的情況。如果視差只差 1懲罰 P1如果視差跳變大于 1懲罰 P2。P2 要顯著大于 P1因為深度不連續(xù)處通常意味著物體邊界邊界上的視差跳變是合理的但也不能一點代價都不付否則會出現(xiàn)大量條紋狀誤匹配?!鞍肴帧边@三個字是理解 SGBM 的關(guān)鍵。全局優(yōu)化在整個二維平面上求解能量函數(shù)理論上效果最好但計算復(fù)雜度不可接受。SGBM 的折中做法是沿多個一維方向通常是 8 或 16 個方向做動態(tài)規(guī)劃的代價累積再把所有方向的累積代價加起來。一維路徑上的動態(tài)規(guī)劃很高效多個方向疊加后又能在一定程度上模擬二維平滑約束這就是它在效果和性能之間取得平衡的原因。3.3 代碼調(diào)用和參數(shù)細(xì)節(jié)OpenCV 里對應(yīng)的是StereoSGBM創(chuàng)建方式如下sgbm cv2.StereoSGBM_create( minDisparity0, numDisparities80, blockSize11, P18 * 3 * blockSize ** 2, P232 * 3 * blockSize ** 2, disp12MaxDiff1, uniquenessRatio10, speckleWindowSize100, speckleRange32, modecv2.STEREO_SGBM_MODE_SGBM_3WAY ) disp_sgbm sgbm.compute(left_gray, right_gray).astype(np.float32) / 16.0參數(shù)說明參數(shù)作用備注numDisparities最大視差范圍必須是 16 的倍數(shù)動態(tài)范圍約為 16 的整數(shù)倍blockSize匹配窗口邊長必須為奇數(shù)常見 3 到 21P1視差變化 1 時的小懲罰值越大視差圖越平滑但細(xì)節(jié)越弱P2視差跳變時的大懲罰通常取 P1 的 4 到 10 倍disp12MaxDiff左右一致性檢查閾值超限標(biāo)記為無效視差uniquenessRatio最小代價與次小代價的差異比例低于閾值視為匹配不唯一speckleWindowSize斑點濾波窗口濾除孤立小區(qū)域spearackRange斑點內(nèi)視差波動范圍過大容易誤濾真實邊緣mode算法模式SGBM_3WAY 更快HH 更精確但更慢官方示例里的P18 * 3 * blockSize^2、P232 * 3 * blockSize^2是很好的起點后面調(diào)參時可以在這個基礎(chǔ)上縮放。3.4 后處理和可視化SGBM 和 BM 的compute輸出類型是int16里面存的其實是乘以 16 后的定點視差。為什么要乘 16因為 OpenCV 想保留四位小數(shù)精度的亞像素信息又不使用浮點存儲所以先做定點放大。拿到輸出后必須除以 16否則視差圖數(shù)值看起來全都是放大的后續(xù)點云計算也會全部出錯??梢暬霸僮鲆淮螝w一化def disp_to_visual(disp): return cv2.normalize(disp, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) cv2.imshow(BM, disp_to_visual(disp_bm)) cv2.imshow(SGBM, disp_to_visual(disp_sgbm))如果視差圖里有大量負(fù)值那些是無效視差歸一化時應(yīng)先屏蔽否則會把顯示范圍壓扁disp_valid disp.copy() disp_valid[disp_valid 0] 04. 跑實驗時踩過的坑與調(diào)參心得基礎(chǔ)算法不難真正讓新手崩潰的是那些藏在細(xì)節(jié)里的坑。這一節(jié)集中記錄我實際跑實驗時反復(fù)踩過、又花了不少時間才繞過的問題。直接照做可以幫你少走很多彎路。4.1 極線校正是匹配的地基第一個大坑拿沒有校正過的雙目圖像直接喂給 BM 或 SGBM結(jié)果十有八九是一團糟。匹配算法為了效率假設(shè)同名點在同一水平線上搜索時才敢只在水平方向掃描。沒有校正的圖像同名點有垂直偏移水平搜索根本找不到正確匹配。這個問題在自拍圖像里特別常見很多人以為雙目匹配算法“能自動處理”實際上不行。正確流程是先標(biāo)定相機、畸變校正、極線校正再把校正后的圖像輸入匹配算法。哪怕你用cv2.StereoBM_create這樣的高抽像 API 也一樣預(yù)處理這一關(guān)不過后面全是白搭。4.2 numDisparities和blockSize的硬性約束numDisparities必須是 16 的倍數(shù)不是的話 OpenCV 計算時會自動調(diào)整或者直接報錯。實際設(shè)值時我習(xí)慣根據(jù)目標(biāo)深度范圍先反推如果基線和焦距已知最小可測距離對應(yīng)最大視差那就把numDisparities設(shè)成剛好覆蓋需要的最大視差再取整到 16 的倍數(shù)。blockSize必須是奇數(shù)因為窗口要對稱。窗口過小噪聲影響明顯弱紋理區(qū)域全是洞窗口過大視差圖過度平滑物體邊緣會被磨掉。從 5x5 開始往上試通常比較合理我常用 9 到 15 之間的值。4.3 SGBM參數(shù)調(diào)試順序與常見問題SGBM 參數(shù)多一起調(diào)很難定位問題。我的習(xí)慣是按順序來先調(diào)numDisparities和blockSize讓整體輪廓出來再調(diào)P1、P2控制平滑度最后用uniquenessRatio和斑點參數(shù)清理噪點。實際中常見的現(xiàn)象和應(yīng)對現(xiàn)象可能原因調(diào)整策略大片橫條紋或空洞P1、P2 太小平滑約束不足增大 P1/P2物體邊緣被磨平P2 過大減小 P2或減小 P2 與 P1 的比值孤立亮點、白色噪點遮擋或誤匹配增大 speckleWindowSize檢查 disp12MaxDiff弱紋理區(qū)域全是洞blockSize 過小增大 blockSize視差整體偏小或偏大numDisparities 沒覆蓋到位重新估計視差范圍還有一個很多教程沒講清的點modecv2.STEREO_SGBM_MODE_HH在理論上能做更復(fù)雜的優(yōu)化效果通常更好但耗時是SGBM_MODE_SGBM_3WAY的幾倍。如果你的場景不是離線處理先用SGBM_3WAY它速度更快參數(shù)調(diào)整到位的程度下質(zhì)量差距沒那么夸張。4.4 手寫算法太慢的優(yōu)化思路純 Python 的 SAD、SSD、ZNCC 實現(xiàn)跑標(biāo)準(zhǔn)測試圖怎么說呢速度慢到可以泡杯咖啡。這不是算法本身的問題是解釋型語言三層 for 循環(huán)的原罪。如果你只是為了理解原理建議縮小輸入圖像或者把max_disp限制在較小范圍比如 32保證實驗?zāi)芘芡?。如果確實需要用 Python 實現(xiàn)但有性能要求幾個方向用 NumPy 向量化窗口滑動用膨脹后的 shift 技巧批量計算 SAD或者用scipy.ndimage做滑動窗口聚合。更進(jìn)一步可以用 Numba 對循環(huán)做 JIT 加速1 到 2 個數(shù)量級的提升是有的。OpenCV 自己的 BM 已經(jīng)高度優(yōu)化如果你不是要復(fù)現(xiàn)論文而是做應(yīng)用直接用庫就好不要重復(fù)造輪子。4.5 無效視差和后處理是提質(zhì)的最后一步SGBM 里disp12MaxDiff是左右一致性檢查的閾值。正常做法是從左圖算一次視差從右圖也算一次視差同名點互查如果兩個方向得到的視差差值超過閾值就認(rèn)為這個點是誤匹配或遮擋點直接置為無效。disp12MaxDiff1時左右一致性差超過 1 就判為無效比較嚴(yán)格如果無效區(qū)域太多可以放寬到 2 或 3。斑點濾波參數(shù)speckleWindowSize和speckleRange也很實用。前者指定多大的孤立區(qū)域算斑點后者指定斑點內(nèi)部允許的視差波動范圍。比如speckleWindowSize100表示面積小于 100 像素的區(qū)域如果跟周圍視差不一致就會被濾掉并填充周圍的值。我最初直接復(fù)制網(wǎng)上參數(shù)時發(fā)現(xiàn)真實裂縫邊緣也被誤濾了后來把speckleRange調(diào)小才保住邊緣這類參數(shù)一定要結(jié)合自己的數(shù)據(jù)微調(diào)。5. 五個算法放在一起怎么選五種算法的核心思想已經(jīng)講完最后落到選型。選型沒有絕對的對錯關(guān)鍵是匹配場景和資源約束。5.1 橫向?qū)Ρ戎笜?biāo)SADSSDZNCCBMSGBM匹配策略局部窗口局部窗口局部窗口局部塊半全局優(yōu)化速度慢手寫慢手寫最慢手寫快中等精度一般一般較好中等高抗光照變化弱弱強中中邊界保持一般一般一般一般好實現(xiàn)方式手寫手寫手寫OpenCVOpenCV典型場景教學(xué)理解教學(xué)理解光照復(fù)雜研究實時初步估計離線/高精度前面三列是“學(xué)習(xí)向”算法后面兩列是“工程向”算法。從學(xué)習(xí)到工程本質(zhì)上是同一套匹配思想的不同實現(xiàn)深度。5.2 按場景選型實時視覺定位、機器人避障這類對幀率敏感的場合BM 是首選。它速度快、資源占用低雖然視差圖質(zhì)量一般但配合后續(xù)濾波和置信度判斷已經(jīng)足夠支撐很多決策任務(wù)。在嵌入式設(shè)備上我通常還會配合降采樣圖像分辨率降到 640 或更低再把numDisparities限制在 64 以內(nèi)幀率可以跑到非常理想。離線三維重建、工業(yè)尺寸測量、高精度深度估計首選 SGBM。它需要更多計算時間但換來的視差圖平滑度和邊緣保持能力對重建質(zhì)量影響很大。尤其是物體輪廓要求嚴(yán)格的場景SGBM 的邊界表現(xiàn)明顯優(yōu)于 BM。光照變化強烈的室外場景ZNCC 這類歸一化相關(guān)系數(shù)的優(yōu)勢最大但手寫性能差。你可以在 BM 或 SGBM 基礎(chǔ)上自己做預(yù)處理比如直方圖均衡化也能部分緩解光照問題。真正的工業(yè)場景里我一般建議在采集端就盡量統(tǒng)一曝光比算法端硬扛要可靠得多。5.3 做完基礎(chǔ)算法之后還可以干什么如果你已經(jīng)把這五個算法跑通了下一步的擴展方向很明確。一是亞像素細(xì)化。WTA 得到的視差是整數(shù)級用代價曲線在最小值附近做拋物線擬合可以插值出亞像素精度。對三維重建來說亞像素細(xì)化帶來的深度精度提升非常可觀。二是置信度評估。匹配代價曲線的峰值尖銳程度可以反映這個視差猜測的置信度。代價曲線越尖銳說明匹配越唯一代價曲線非常平緩說明這個像素可能落在弱紋理區(qū)域?qū)?yīng)的匹配結(jié)果要打問號。給視差圖附帶置信度是后續(xù)濾波和融合的好依據(jù)。三是結(jié)合相機內(nèi)參生成三維點云。有了視差圖、焦距、基線和主點每對匹配點都能反投影出三維坐標(biāo)。這一步做完你的立體匹配才算真正接入三維視覺的完整鏈路。四是往深度學(xué)習(xí)的立體匹配方向走?,F(xiàn)在基于 cost volume 的深度學(xué)習(xí)方法在精度上已經(jīng)明顯超過傳統(tǒng)算法但它依然沿用“匹配代價計算、代價聚合、視差優(yōu)化”這個框架只是把這些模塊換成了神經(jīng)網(wǎng)絡(luò)。傳統(tǒng)算法的理解積累在看深度學(xué)習(xí)論文時會發(fā)揮很大作用。最后談一點個人體會。立體匹配知識點乍看很散但它其實是二維圖像走向三維空間的一條必經(jīng)之路。我自己的學(xué)習(xí)建議是先手寫一遍 SAD哪怕跑得慢也要把窗口匹配、代價最小化的直覺建立起來然后用 OpenCV 的 SGBM 把參數(shù)一個一個試過去觀察每個參數(shù)對結(jié)果的影響最后回頭對照四步框架你會發(fā)現(xiàn)所有算法都能裝進(jìn)同一個骨架里。我自己踩過最深的坑是過早迷戀高精度算法反而忽略了基礎(chǔ)代價函數(shù)和預(yù)處理的作用。先把基礎(chǔ)打牢再談復(fù)雜的優(yōu)化這條路看起來慢實際最快。本文還有配套的精品資源點擊獲取