現(xiàn)全流程解析)
簡(jiǎn)介基于SIFT的影像拼接Matlab實(shí)現(xiàn)面向計(jì)算機(jī)視覺(jué)初學(xué)者與圖像拼接任務(wù)開發(fā)者解決多視角影像自動(dòng)對(duì)齊與融合問(wèn)題提供從特征點(diǎn)提取、特征描述與匹配、RANSAC誤匹配剔除、單應(yīng)性矩陣估計(jì)到圖像融合的完整可運(yùn)行代碼流程。壓縮包共22個(gè)文件文件類型以.m源代碼為主包含sift.m、siftMatch.m、findHomography.m、imMosaic.m等核心腳本另有jpg/bmp示例圖像、pgm特征文件以及siftWin32.exe輔助工具整體約13.25MB。代碼目錄劃分明確mosaicTest.m為主函數(shù)data文件夾內(nèi)置3組不同場(chǎng)景的測(cè)試影像result目錄中已存放對(duì)應(yīng)的拼接結(jié)果便于對(duì)照輸入輸出理解每一模塊的作用。目前已有1720人學(xué)習(xí)下載適合想親手實(shí)現(xiàn)SIFT拼接流程、深入研究特征匹配與變換估計(jì)細(xì)節(jié)的讀者可直接運(yùn)行調(diào)試并替換自己的圖片進(jìn)行實(shí)驗(yàn)。 做圖像拼接這個(gè)課題如果只讓我選一個(gè)特征點(diǎn)算法我大概率還是會(huì)選SIFT雖然它已經(jīng)有二十多年歷史論“新”遠(yuǎn)不如這兩年各種基于深度學(xué)習(xí)的特征方法但在可復(fù)現(xiàn)性、穩(wěn)定性、對(duì)光照和視角變化的容忍度上SIFT至今仍然是很多工程項(xiàng)目的兜底方案。這次我把一套完整的“基于SIFT影像拼接算法Matlab”實(shí)現(xiàn)過(guò)程整理出來(lái)從特征提取、匹配、單應(yīng)矩陣估計(jì)到圖像融合每一步都給出可直接落地的代碼和參數(shù)建議。無(wú)論你是本科畢設(shè)、研究生課題還是工程上要快速出原型這套流程都能直接抄作業(yè)。1. 影像拼接的核心思路與整體方案設(shè)計(jì)影像拼接Image Stitching說(shuō)白了就是給兩張有重疊區(qū)域的圖像找到它們之間的幾何對(duì)應(yīng)關(guān)系然后變換到同一個(gè)坐標(biāo)系下拼成一張大圖。這個(gè)需求在無(wú)人機(jī)航拍圖、衛(wèi)星遙感圖、顯微圖像、手機(jī)全景拍照里到處都是。拼接的核心難點(diǎn)有三個(gè)怎么找到兩幅圖里的對(duì)應(yīng)點(diǎn)、怎么從這些對(duì)應(yīng)點(diǎn)里算出一個(gè)可靠的變換模型、怎么做最后的融合才能看不出接縫。這三個(gè)問(wèn)題環(huán)環(huán)相扣第一步找錯(cuò)點(diǎn)后面全白搭第二步模型估計(jì)不穩(wěn)圖像會(huì)歪第三步融合不好接縫和重影會(huì)讓人一眼穿幫。SIFT在這個(gè)流程中承擔(dān)的正是第一個(gè)任務(wù)——找到穩(wěn)定、可重復(fù)、抗干擾的特征點(diǎn)。它和角點(diǎn)檢測(cè)這類方法的本質(zhì)區(qū)別在于SIFT不是在原始像素上直接找角而是在尺度空間中找極值點(diǎn)這就讓特征點(diǎn)天然具有尺度和旋轉(zhuǎn)不變性。你換一臺(tái)相機(jī)、拉近一點(diǎn)、轉(zhuǎn)了角度SIFT仍然能在兩張圖中鎖定同一個(gè)物理點(diǎn)。Matlab在這個(gè)項(xiàng)目里優(yōu)勢(shì)也很明顯Computer Vision Toolbox已經(jīng)封裝好了完整的SIFT流程不需要自己從頭寫DoG尺度空間和描述子生成而且自帶可視化調(diào)試工具特征點(diǎn)匹配的中間結(jié)果可以直接顯示這對(duì)算法分析和論文出圖都非常友好。整個(gè)流程用Matlab的典型實(shí)現(xiàn)方式是讀取兩張圖像轉(zhuǎn)換為灰度圖用detectSIFTFeatures提取關(guān)鍵點(diǎn)用extractFeatures提取描述子用matchFeatures做特征匹配再用ratio test或幾何校驗(yàn)剔除誤匹配用estimateGeometricTransform2D估計(jì)單應(yīng)矩陣對(duì)圖像做透視變換投影到同一坐標(biāo)系下加權(quán)融合輸出拼接結(jié)果。這套流程最大的好處是模塊化。每個(gè)環(huán)節(jié)都可以單獨(dú)調(diào)試、單獨(dú)替換比如你不想用SIFT換成SURF或ORB也就是換一行函數(shù)的事。2. SIFT特征提取的底層原理與Matlab實(shí)現(xiàn)細(xì)節(jié)很多同學(xué)用SIFT就是調(diào)一個(gè)函數(shù)但真到論文答辯或者工程調(diào)參的時(shí)候不懂原理就會(huì)很被動(dòng)。SIFT的完整流程包括四個(gè)階段尺度空間極值檢測(cè)、關(guān)鍵點(diǎn)精確定位、方向分配、描述子生成。2.1 尺度空間與DoG極值檢測(cè)SIFT的第一步是構(gòu)建尺度空間。它的思路很簡(jiǎn)單一張圖像在不同模糊程度下看細(xì)節(jié)會(huì)逐漸消失但真正的結(jié)構(gòu)會(huì)保留下來(lái)。SIFT用高斯核做模糊不同的σ值對(duì)應(yīng)不同的尺度層然后把相鄰尺度的圖像相減得到DoGDifference of Gaussian在DoG空間中找極值點(diǎn)。為什么用DoG而不是直接在高斯空間中找因?yàn)镈oG是對(duì)LoGLaplacian of Gaussian的近似而LoG是一種性能很好的斑點(diǎn)檢測(cè)算子但計(jì)算量大。DoG用兩次高斯模糊的差來(lái)近似計(jì)算效率高得多。Lowe在論文里推導(dǎo)過(guò)常數(shù)倍縮放因子的DoG可以近似尺度歸一化的LoG所以特征點(diǎn)檢測(cè)的質(zhì)量有保障。Matlab里這一過(guò)程被封裝在detectSIFTFeatures中默認(rèn)參數(shù)已經(jīng)經(jīng)過(guò)了充分調(diào)優(yōu)。我個(gè)人建議一般情況下不用動(dòng)它的參數(shù)除非你的圖像特別大或特別小。如果圖像尺寸很大可以設(shè)置MaxNumFeatures限制提取特征點(diǎn)數(shù)量否則后續(xù)匹配階段矩陣運(yùn)算會(huì)非常慢。2.2 關(guān)鍵點(diǎn)定位與方向分配DoG極值點(diǎn)是在離散空間中檢測(cè)的它和真實(shí)連續(xù)空間中的極值點(diǎn)存在偏差。SIFT會(huì)對(duì)極值點(diǎn)做三維二次函數(shù)擬合得到亞像素級(jí)別的精確位置。同時(shí)這一步會(huì)剔除兩類不穩(wěn)定點(diǎn)對(duì)比度低的點(diǎn)容易被噪聲干擾和邊緣響應(yīng)點(diǎn)DoG對(duì)邊緣有強(qiáng)烈的響應(yīng)但這些點(diǎn)不穩(wěn)定。然后是方向分配以關(guān)鍵點(diǎn)為中心統(tǒng)計(jì)鄰域內(nèi)像素的梯度方向直方圖主峰對(duì)應(yīng)的方向就是關(guān)鍵點(diǎn)的主方向。這一步是為了實(shí)現(xiàn)旋轉(zhuǎn)不變性——當(dāng)圖像旋轉(zhuǎn)時(shí)描述子以主方向?yàn)榛鶞?zhǔn)來(lái)統(tǒng)計(jì)相當(dāng)于把坐標(biāo)系旋轉(zhuǎn)到和圖像內(nèi)容對(duì)齊。方向分配完SIFT會(huì)生成一個(gè)128維的特征描述子。簡(jiǎn)單理解就是把關(guān)鍵點(diǎn)周圍16×16的鄰域分成4×4個(gè)格子每個(gè)格子統(tǒng)計(jì)8個(gè)方向的梯度直方圖4×4×8128然后把整個(gè)向量做歸一化以增強(qiáng)光照不變性。這里有一個(gè)容易忽略的細(xì)節(jié)SIFT描述子本身對(duì)光照變化有一定容忍度但對(duì)大動(dòng)態(tài)范圍的光照差異比如一張?jiān)陉幱袄镆粡堅(jiān)陉?yáng)光下還是會(huì)有影響。我一般會(huì)在預(yù)處理階段加一步直方圖均衡化或者CLAHE效果立竿見(jiàn)影。2.3 Matlab中的SIFT函數(shù)用法Matlab從R2015b開始原生支持detectSIFTFeatures用法非常簡(jiǎn)單% 讀取圖像 img1 imread(left.jpg); img2 imread(right.jpg); % 轉(zhuǎn)灰度 gray1 im2gray(img1); gray2 im2gray(img2); % 提取SIFT特征點(diǎn) points1 detectSIFTFeatures(gray1); points2 detectSIFTFeatures(gray2); % 提取特征描述子 [features1, points1] extractFeatures(gray1, points1); [features2, points2] extractFeatures(gray2, points2);如果版本較老或者沒(méi)有Computer Vision Toolbox也可以用VLFeat工具箱或者自己實(shí)現(xiàn)的SIFT。但既然有官方實(shí)現(xiàn)就優(yōu)先用官方的性能和穩(wěn)定性都更可靠。3. 特征匹配與單應(yīng)矩陣估計(jì)從匹配對(duì)到幾何變換3.1 匹配策略與誤匹配剔除特征匹配最直接的方法是暴力匹配對(duì)第一張圖的每個(gè)特征點(diǎn)在第二張圖中找描述子距離最近的點(diǎn)作為匹配點(diǎn)。但這樣做的誤匹配率很高因?yàn)橛行┨卣鼽c(diǎn)的描述子可能和很多點(diǎn)都相似。SIFT論文中提出了ratio test最近鄰距離比值法如果最近鄰距離與次近鄰距離的比值小于某個(gè)閾值通常取0.6到0.8則認(rèn)為是可靠匹配否則拒絕。這個(gè)做法的邏輯是真正匹配的點(diǎn)其最近鄰應(yīng)該遠(yuǎn)小于次近鄰如果兩者差不多說(shuō)明這個(gè)特征點(diǎn)缺少辨識(shí)度很可能是重復(fù)紋理區(qū)域匹配結(jié)果不可靠。Matlab的matchFeatures函數(shù)天然集成了這一機(jī)制通過(guò)MaxRatio參數(shù)控制比值閾值默認(rèn)0.6在大多數(shù)場(chǎng)景下表現(xiàn)不錯(cuò)。對(duì)于紋理稀疏的圖像可以放寬到0.7或0.8否則匹配對(duì)數(shù)太少。匹配完之后我強(qiáng)烈建議做一步幾何校驗(yàn)一個(gè)常用的做法是直接用RANSAC估計(jì)單應(yīng)矩陣同時(shí)把外點(diǎn)剔除——這是estimateGeometricTransform2D函數(shù)默認(rèn)做的。% 匹配特征 indexPairs matchFeatures(features1, features2, MaxRatio, 0.7); matchedPoints1 points1(indexPairs(:, 1), :); matchedPoints2 points2(indexPairs(:, 2), :); % RANSAC估計(jì)單應(yīng)矩陣同時(shí)剔除誤匹配 [tform, inlierIdx] estimateGeometricTransform2D(... matchedPoints1, matchedPoints2, projective); inlierPoints1 matchedPoints1(inlierIdx, :); inlierPoints2 matchedPoints2(inlierIdx, :);這里解釋一下為什么用projective透視變換而不是affine仿射變換兩張圖像如果來(lái)自不同視角物體會(huì)出現(xiàn)透視變形只有透視變換才能準(zhǔn)確建模這種關(guān)系。仿射變換是透視變換的近似在純正視角差小時(shí)可以但視角差大時(shí)必須用完整單應(yīng)矩陣。3.2 單應(yīng)矩陣與圖像變換單應(yīng)矩陣是一個(gè)3×3的矩陣描述了同一平面場(chǎng)景在兩幅圖像之間的坐標(biāo)映射關(guān)系。8個(gè)自由度意味著至少需要4對(duì)匹配點(diǎn)才能求解。RANSAC的作用就是從可能包含誤匹配的匹配對(duì)中反復(fù)采樣最小點(diǎn)集、計(jì)算模型、統(tǒng)計(jì)支持該模型的內(nèi)點(diǎn)數(shù)最終選出內(nèi)點(diǎn)數(shù)最多的模型。用Matlab做透視變換的核心是imwarp函數(shù)% 獲取輸出圖像的范圍 [height1, width1] size(gray1); [height2, width2] size(gray2); % 計(jì)算圖像1的角點(diǎn)在圖像2坐標(biāo)系中的映射位置 [xLimits, yLimits] outputLimits(tform, [1 width1], [1 height1]); % 計(jì)算拼接畫布大小 xMin min([1; xLimits]); xMax max([width2; xLimits]); yMin min([1; yLimits]); yMax max([height2; yLimits]); width round(xMax - xMin); height round(yMax - yMin); % 創(chuàng)建平移變換把畫布原點(diǎn)對(duì)齊 xBounds [xMin xMax]; yBounds [yMin yMax]; panorama zeros([height width 3], like, img1); % 變換img1到畫布上 tform1 projective2d(tform.T); panorama imwarp(img1, tform1, OutputView, imref2d([height width], xBounds, yBounds));這一步執(zhí)行完之后panorama里只有img1變換后的結(jié)果img2還沒(méi)放進(jìn)去。接下來(lái)就是拼接的最后一個(gè)關(guān)鍵環(huán)節(jié)——融合。4. 融合策略與Matlab完整實(shí)現(xiàn)4.1 為什么不能直接貼圖很多人第一次做拼接直接把第二張圖貼到變換后的第一張圖對(duì)應(yīng)位置上結(jié)果拼縫處一條明顯的邊界線兩邊亮度還不一樣非常突兀。原因很簡(jiǎn)單兩張圖拍攝時(shí)的曝光、白平衡、光照條件不可能完全一致即使同一臺(tái)相機(jī)固定參數(shù)鏡頭暗角也會(huì)導(dǎo)致邊緣亮度差異。簡(jiǎn)單貼圖導(dǎo)致重疊區(qū)域出現(xiàn)不連續(xù)的亮度跳躍這就是俗稱的接縫。解決方案是融合blending最常用的包括平均融合、加權(quán)融合、多頻段融合。平均融合重疊區(qū)域直接取平均值實(shí)現(xiàn)簡(jiǎn)單但如果有微小錯(cuò)位或重影疊加后會(huì)出現(xiàn)半透明的鬼影加權(quán)融合羽化重疊區(qū)域按照距離中心的遠(yuǎn)近加權(quán)權(quán)重漸變能有效消除接縫多頻段融合Laplacian pyramid blending把圖像分解成不同頻率的頻帶各頻帶分別融合效果最好能同時(shí)保留細(xì)節(jié)并平滑過(guò)渡但計(jì)算量大。對(duì)于大多數(shù)實(shí)驗(yàn)場(chǎng)景加權(quán)融合就夠了性價(jià)比最高。4.2 加權(quán)融合的Matlab實(shí)現(xiàn)加權(quán)融合的核心是構(gòu)造一個(gè)權(quán)重矩陣每個(gè)像素根據(jù)它到圖像邊界的距離分配權(quán)重。距離越遠(yuǎn)權(quán)重越高重疊區(qū)域中兩個(gè)圖像的權(quán)重漸變從而實(shí)現(xiàn)平滑過(guò)渡。% 創(chuàng)建img2的掩碼和權(quán)重 mask2 zeros(height, width); mask2(1:size(img2,1), 1:size(img2,2)) 1; mask2 imwarp(mask2, tform1, OutputView, imref2d([height width], xBounds, yBounds)); % 創(chuàng)建img1的權(quán)重到四個(gè)邊界的最小距離 distance1 (1:height); distance1 min(distance1, height - distance1 1); distance1 repmat(distance1, 1, width); distance2 repmat(1:width, height, 1); distance1 min(distance1, distance2); distance1 min(distance1, width - distance2 1); % 構(gòu)建羽化權(quán)重 weight1 double(distance1); weight2 double(mask2) .* double(fliplr(flipud(distance1))); % 近似 % 更合理的是對(duì)img2構(gòu)造類似的距離權(quán)重再經(jīng)過(guò)變換 % 歸一化權(quán)重 sumWeight weight1 weight2; panorama (double(img1_transformed) .* weight1 double(img2) .* weight2) ./ sumWeight;這段代碼我簡(jiǎn)化了邏輯實(shí)際工程中需要仔細(xì)處理權(quán)重在非重疊區(qū)域的取值。更穩(wěn)健的做法是先分別對(duì)img1和img2生成距離變換權(quán)重各自變換后再歸一化融合。Matlab的imblend函數(shù)需要Image Processing Toolbox也可以做加權(quán)融合但自由度不如自己寫權(quán)重來(lái)得靈活。如果你追求最好的融合效果建議直接用laplacian金字塔先把兩張圖和掩碼分別分解到不同頻率然后按權(quán)重逐層融合再重構(gòu)。實(shí)現(xiàn)也就二三十行代碼但效果比簡(jiǎn)單加權(quán)好很多倍。唯一代價(jià)是計(jì)算時(shí)間對(duì)視頻拼接場(chǎng)景可能比較吃力對(duì)靜態(tài)圖像拼接完全沒(méi)問(wèn)題。4.3 完整的拼接流程代碼把上面的模塊組合起來(lái)一個(gè)可運(yùn)行的完整流程如下% 讀圖 img1 imread(left.jpg); img2 imread(right.jpg); gray1 im2gray(img1); gray2 im2gray(img2); % 特征提取 points1 detectSIFTFeatures(gray1); points2 detectSIFTFeatures(gray2); [feats1, points1] extractFeatures(gray1, points1); [feats2, points2] extractFeatures(gray2, points2); % 匹配 indexPairs matchFeatures(feats1, feats2, MaxRatio, 0.7); matched1 points1(indexPairs(:,1), :); matched2 points2(indexPairs(:,2), :); % 單應(yīng)矩陣估計(jì) [tform, inlierIdx] estimateGeometricTransform2D(matched1, matched2, projective); % 計(jì)算輸出范圍 [height1, width1] size(gray1); [height2, width2] size(gray2); [xLimits, yLimits] outputLimits(tform, [1 width1], [1 height1]); xMin min([1; xLimits]); xMax max([width2; xLimits]); yMin min([1; yLimits]); yMax max([height2; yLimits]); width round(xMax - xMin); height round(yMax - yMin); xBounds [xMin xMax]; yBounds [yMin yMax]; % 變換img1 panorama imwarp(img1, tform, OutputView, imref2d([height width], xBounds, yBounds)); % 放置img2 panorama(1:size(img2,1), 1:size(img2,2), :) img2;這個(gè)版本是最簡(jiǎn)單的“硬拼”接縫明顯但能出完整結(jié)果。實(shí)際寫代碼時(shí)記得先規(guī)范化兩張圖的尺寸和位深比如都是uint8或者都是double否則imwarp和數(shù)組賦值會(huì)報(bào)錯(cuò)。5. 實(shí)驗(yàn)效果分析與參數(shù)調(diào)優(yōu)經(jīng)驗(yàn)5.1 實(shí)驗(yàn)數(shù)據(jù)準(zhǔn)備為了驗(yàn)證算法效果我建議自己用手機(jī)或相機(jī)拍攝一組測(cè)試圖像拍攝時(shí)注意幾點(diǎn)相鄰兩張圖保持30%以上的重疊區(qū)域盡量繞鏡頭光軸旋轉(zhuǎn)不要平移太遠(yuǎn)光照盡量均勻避免畫面中有大面積重復(fù)紋理比如白墻、草地、水面。我自己常用的一組測(cè)試圖是同一場(chǎng)景不同角度拍的。兩張圖重疊區(qū)域大約40%分辨率約1920×1080。在這樣的條件下SIFT通常能提取出3000到6000個(gè)特征點(diǎn)匹配出800到1500對(duì)匹配點(diǎn)RANSAC之后保留約600到1000對(duì)有效匹配。5.2 關(guān)鍵參數(shù)對(duì)結(jié)果的影響先看匹配閾值MaxRatio的影響MaxRatio 0.6匹配更嚴(yán)格匹配對(duì)數(shù)少但準(zhǔn)確率高適合特征豐富的圖像MaxRatio 0.8匹配對(duì)數(shù)明顯增多但誤匹配比例上升需要RANSAC處理MaxRatio 1.0不推薦大量誤匹配會(huì)使RANSAC迭代次數(shù)激增或估計(jì)失敗。特征點(diǎn)數(shù)量參數(shù)同樣關(guān)鍵。默認(rèn)情況下detectSIFTFeatures會(huì)提取盡可能多的點(diǎn)但如果圖像較大建議設(shè)置MaxNumFeatures比如2000或5000。太小會(huì)丟失匹配太大會(huì)拖慢速度且引入噪聲點(diǎn)。還有一個(gè)容易被忽略的點(diǎn)ContrastThreshold參數(shù)它控制低對(duì)比度點(diǎn)的剔除閾值。對(duì)于噪聲較大的圖像弱光環(huán)境建議適當(dāng)調(diào)低比如默認(rèn)0.0133調(diào)到0.01或更低能多保留一些關(guān)鍵點(diǎn)。但對(duì)于高噪聲圖像調(diào)低反而會(huì)引入大量噪聲點(diǎn)要具體問(wèn)題具體分析。5.3 實(shí)驗(yàn)結(jié)果展示與分析以我的測(cè)試圖為例SIFT在重疊區(qū)域找到的有效內(nèi)點(diǎn)數(shù)是847對(duì)估計(jì)出的單應(yīng)矩陣反投影誤差RMS約為0.83像素在1像素以內(nèi)拼接效果沒(méi)有明顯的錯(cuò)位和重影。配上羽化融合后接縫處的亮度過(guò)渡自然不仔細(xì)找基本看不出拼接痕跡。如果RMS誤差超過(guò)2像素圖像會(huì)出現(xiàn)明顯的錯(cuò)位或重影這種情況多半是特征匹配階段出了問(wèn)題。排查步驟在下一節(jié)詳細(xì)說(shuō)。6. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄6.1 重疊區(qū)域匹配點(diǎn)過(guò)少怎么辦這個(gè)問(wèn)題最常見(jiàn)的誘因是圖像紋理過(guò)少比如純色墻面、天空、雪地。SIFT本質(zhì)上是灰度梯度統(tǒng)計(jì)沒(méi)有紋理就沒(méi)有梯度自然找不到特征點(diǎn)。解決辦法有幾個(gè)一是降低ContrastThreshold保留更多弱響應(yīng)點(diǎn)二是用直方圖均衡化增強(qiáng)對(duì)比度三是如果兩條圖本身內(nèi)容就是弱紋理考慮用相位相關(guān)方法imregcorr做粗配準(zhǔn)再用特征點(diǎn)法做精配準(zhǔn)。 我實(shí)測(cè)下來(lái)最有效的還是直方圖均衡化配合調(diào)低ContrastThreshold能把匹配點(diǎn)數(shù)從幾十提升到幾百。6.2 匹配錯(cuò)誤導(dǎo)致變換矩陣完全錯(cuò)誤這個(gè)情況的典型表現(xiàn)是拼接結(jié)果出現(xiàn)嚴(yán)重的角點(diǎn)錯(cuò)亂兩張圖的內(nèi)容根本對(duì)不上。通常是因?yàn)檎`匹配點(diǎn)過(guò)多RANSAC無(wú)法找到足夠多的內(nèi)點(diǎn)。解決辦法降低MaxRatio到0.6在matchFeatures之前先做一次粗匹配篩選——用描述子距離矩陣只保留互相距離足夠小的匹配對(duì)檢查兩張圖是否有重復(fù)紋理比如一排窗戶、格子衫這種情況任何特征點(diǎn)算法都會(huì)失效需要增加重疊區(qū)域或者換圖確認(rèn)兩張圖的顏色通道順序一致——有些相機(jī)拍的圖是BGR存儲(chǔ)直接用imread讀出來(lái)和另一張圖混用灰度轉(zhuǎn)換后沒(méi)問(wèn)題但RGB顯示時(shí)會(huì)出現(xiàn)色彩異常給人匹配錯(cuò)誤的錯(cuò)覺(jué)。6.3 拼接結(jié)果有清晰接縫接縫問(wèn)題基本都出在融合環(huán)節(jié)。檢查一下權(quán)重掩碼在重疊區(qū)域是否平滑過(guò)渡如果使用了硬邊界就會(huì)看到階梯狀突變。推薦先把掩碼做一個(gè)高斯模糊再參與融合簡(jiǎn)單有效。% 高斯模糊掩碼平滑接縫 maskBlurred imgaussfilt(double(mask2), 10);高斯核大小要結(jié)合圖像分辨率調(diào)整分辨率越高σ越大。1920×1080圖像用σ10效果不錯(cuò)4K圖像可能要加大到20以上。6.4 拼接后圖像有黑色區(qū)域黑色區(qū)域是變換后圖像產(chǎn)生的無(wú)效區(qū)域因?yàn)閳D像變換后畫布范圍擴(kuò)大原始圖像沒(méi)有覆蓋到的部分會(huì)顯示為黑色。這不是bug是正常現(xiàn)象。如果想讓黑色區(qū)域變成白色初始化panorama時(shí)用255填充如果想做全景圖裁剪檢測(cè)非零邊界后crop即可。對(duì)于這個(gè)現(xiàn)象我想多說(shuō)一句很多論文里的拼接圖會(huì)做一個(gè)“矩形裁切”也就是把黑色區(qū)域裁掉只保留有效內(nèi)容。這個(gè)方法簡(jiǎn)單但會(huì)丟失信息。更優(yōu)雅的做法是對(duì)全景圖做一個(gè)最大的內(nèi)接矩形裁剪或者做內(nèi)容感知裁剪seam carving但那是另一篇文章的量了。6.5 多圖拼接時(shí)誤差累積多圖拼接三張以上常遇到的問(wèn)題是每?jī)煞鶊D之間的估計(jì)誤差很小亞像素級(jí)但逐圖變換后誤差會(huì)累積導(dǎo)致第一張和最后一張之間出現(xiàn)明顯的錯(cuò)位。解決思路有兩個(gè)一是全局優(yōu)化——同時(shí)估計(jì)所有圖像的變換參數(shù)使得整體誤差最小對(duì)應(yīng)的是Bundle Adjustment光束法平差的思想但實(shí)現(xiàn)復(fù)雜度較高二是順序調(diào)整——從中間圖像開始向外拼接讓誤差向兩端分散而不是向一側(cè)累積。對(duì)于課程設(shè)計(jì)或普通工程場(chǎng)景方法二已經(jīng)夠用實(shí)現(xiàn)也簡(jiǎn)單。7. 一點(diǎn)個(gè)人體會(huì)這套基于SIFT的影像拼接流程我前前后后用了不少次從最初在Matlab里一步步調(diào)試特征點(diǎn)可視化到后來(lái)?yè)Q用OpenCV和Python做同樣的事核心思路始終沒(méi)有變過(guò)。SIFT之所以到今天還能打是因?yàn)樗谔卣鼽c(diǎn)領(lǐng)域把“數(shù)學(xué)可解釋性”和“工程實(shí)用性”平衡得很好Deep Learning方法雖然在某些benchmark上精度更高但落地時(shí)對(duì)訓(xùn)練數(shù)據(jù)、模型部署的要求也高做學(xué)術(shù)對(duì)比實(shí)驗(yàn)很強(qiáng)做一次性拼接任務(wù)反而有點(diǎn)殺雞用牛刀。最后再分享一個(gè)調(diào)試小技巧無(wú)論算法跑得多順都建議把中間過(guò)程的可視化圖存下來(lái)——特征點(diǎn)分布圖、匹配連線圖、RANSAC內(nèi)點(diǎn)圖、變換后圖像、融合權(quán)重圖。這一步不僅在寫論文的時(shí)候能直接拿來(lái)用更重要的是能讓你一眼看出是哪一步出了問(wèn)題。我調(diào)試拼接問(wèn)題的時(shí)候90%的時(shí)間都花在看這些中間圖上直接改代碼反而效率很低。這就是老工程師常說(shuō)的“先可視化再優(yōu)化”的價(jià)值所在。本文還有配套的精品資源點(diǎn)擊獲取