的MATLAB實現(xiàn)與調(diào)參指南)
簡介這份資源圍繞Criminisi圖像修復(fù)算法的改進實現(xiàn)展開面向圖像處理、圖像修復(fù)方向的研究人員與開發(fā)者尤其適合需要在Matlab環(huán)境下驗證算法效果、評估修復(fù)質(zhì)量的學(xué)習(xí)者。其核心思路是以P-Laplacian算子替代原始算法中的數(shù)據(jù)項從而提升優(yōu)先級計算的精確度增強邊緣保持能力并減少噪聲傳播。壓縮包共5個文件包含3個m腳本、1個c源碼與1個dll動態(tài)庫整體約6KB其中m文件承擔(dān)主流程與PSNR計算c與dll文件支撐底層輔助邏輯。資源提供了可直接運行的修復(fù)流程與PSNR定量評估功能便于讀者對比改進前后的修復(fù)效果理解優(yōu)先級計算、邊界處理與性能優(yōu)化等關(guān)鍵環(huán)節(jié)。目前已有212人學(xué)習(xí)下載適合作為圖像修復(fù)算法入門與改進實驗的參考素材。1. 拆開 p-laplace.rar一份把 Criminisi 數(shù)據(jù)項換成 P-Laplacian 的 MATLAB 修復(fù)包圖像修復(fù)里有個繞不開的經(jīng)典Criminisi 算法。2004 年那篇論文把「先補哪塊、從哪塊抄」拆成優(yōu)先級排序加樣本塊匹配兩步成了后來一大票修復(fù)方法的基線。但基線歸基線真拿它去補一條穿過紋理區(qū)域的劃痕邊緣經(jīng)常糊成一團噪聲還會順著補丁往里爬。p-laplace.rar 這份資源干的事就是把原算法里算優(yōu)先級的那個數(shù)據(jù)項從普通梯度換成 P-Laplacian 算子讓邊緣和細節(jié)在填充過程中被更狠地保住。包里是 MATLAB 實現(xiàn)核心文件是 Demo_inpaint.m、inpaint.m、bestexemplarhelper.c 及其編譯產(chǎn)物 bestexemplarhelper.dll外加一個 PSNR.m 用來量化修復(fù)質(zhì)量。適合正在做圖像修復(fù)、去劃痕、老照片修補或者拿 Criminisi 當(dāng)對比基線的人——你不需要從零復(fù)現(xiàn)論文但得知道它改了哪、怎么跑、哪里會翻車。2. Criminisi 的優(yōu)先級機制與 P-Laplacian 到底改了什么2.1 原版 Criminisi 的優(yōu)先級公式拆解Criminisi 的核心是給破損區(qū)域邊界上每個待補像素算一個優(yōu)先級 P(p)挑最高的先補。公式是 P(p) C(p) · D(p)其中 C(p) 是置信度項衡量這個像素周圍有多少已知信息D(p) 是數(shù)據(jù)項衡量等照度線isophote在邊界上的強度說白了就是「這個位置有沒有明顯的邊緣方向」。數(shù)據(jù)項 D(p) 的原始定義是D(p) |?I⊥(p) · n(p)| / α?I⊥(p) 是 p 點梯度的正交方向等照度線方向n(p) 是邊界法向量α 是歸一化因子灰度圖取 255。這個式子的物理含義是如果等照度線方向和邊界法向越接近垂直說明這里有強邊緣穿過應(yīng)該優(yōu)先補這樣紋理和結(jié)構(gòu)才能延續(xù)進去。問題出在 ?I 上。原版用的是普通梯度對噪聲敏感而且在線性結(jié)構(gòu)交叉或者光照不均的區(qū)域梯度方向容易算歪。一旦 D(p) 算錯優(yōu)先級排序就亂補丁順序跟著錯最后修復(fù)結(jié)果要么邊緣斷裂要么紋理錯位。2.2 P-Laplacian 算子為什么能頂替梯度P-Laplacian 算子的定義是Δ_p u div(|?u|^(p-2) ?u)當(dāng) p2 時退化成普通 Laplacianp2 時對梯度大的區(qū)域邊緣懲罰更重p2 時對梯度小的區(qū)域平滑區(qū)更敏感。在圖像修復(fù)場景里通常取 p 在 1 到 2 之間目的是讓算子在平坦區(qū)域做各向同性擴散在邊緣附近做各向異性擴散——也就是沿著邊緣方向擴散、垂直邊緣方向抑制。把它塞進 Criminisi 的數(shù)據(jù)項本質(zhì)是用 P-Laplacian 的擴散通量替代原始梯度方向讓優(yōu)先級計算對邊緣的判定更穩(wěn)。具體來說改進后的數(shù)據(jù)項不再直接取 ?I⊥而是用 P-Laplacian 在局部窗口內(nèi)的響應(yīng)來加權(quán)鄰域信息。這樣做的直接好處是噪聲引起的偽梯度被壓制真實邊緣的響應(yīng)被放大優(yōu)先級排序更貼近人眼期望的「先補結(jié)構(gòu)、再補紋理」。2.3 包里文件的分工與調(diào)用關(guān)系拿到壓縮包先別急著跑把文件角色理清楚文件類型作用Demo_inpaint.m腳本入口讀圖、設(shè)掩膜、調(diào) inpaint、算 PSNRinpaint.m函數(shù)Criminisi 主循環(huán)含優(yōu)先級計算和樣本塊搜索bestexemplarhelper.cC 源碼樣本塊匹配的加速實現(xiàn)bestexemplarhelper.dll編譯產(chǎn)物Windows 下供 MATLAB 調(diào)用的 MEX 文件PSNR.m函數(shù)計算修復(fù)前后峰值信噪比調(diào)用鏈?zhǔn)?Demo_inpaint → inpaint → bestexemplarhelper通過 MEX 接口。如果你在非 Windows 平臺dll 用不了得自己用 mex 重新編譯 bestexemplarhelper.c這一步后面避坑章節(jié)會細說。2.4 優(yōu)先級計算里 P-Laplacian 的接入點在 inpaint.m 里找優(yōu)先級計算那段通常會看到一個循環(huán)遍歷破損邊界上的像素。原版代碼大概長這樣% 原版數(shù)據(jù)項計算示意 [Ix, Iy] gradient(img); grad_perp [-Iy, Ix]; % 梯度正交方向 normal compute_normal(mask, p); D abs(sum(grad_perp .* normal)) / 255;改進版會把 gradient 那步換成 P-Laplacian 響應(yīng)% P-Laplacian 加權(quán)后的數(shù)據(jù)項示意 p 1.5; % P-Laplacian 階數(shù)常用 1.2~1.8 [Ix, Iy] gradient(img); grad_mag sqrt(Ix.^2 Iy.^2) eps; weight grad_mag.^(p - 2); % P-Laplacian 非線性權(quán)重 Ix_w weight .* Ix; Iy_w weight .* Iy; grad_perp [-Iy_w, Ix_w]; normal compute_normal(mask, p); D abs(sum(grad_perp .* normal)) / 255;邏輯說明weight 這一項就是 P-Laplacian 的核心。當(dāng) p2 時grad_mag 越小平坦區(qū)weight 越大擴散越強grad_mag 越大邊緣weight 越小擴散被抑制。這樣算出來的 grad_perp 在邊緣處更干凈不會被噪聲帶偏。參數(shù) p 是唯一需要調(diào)的默認(rèn) 1.5 是個穩(wěn)妥起點紋理密集的圖可以往 1.2 壓結(jié)構(gòu)為主的圖可以往 1.8 提。3. 跑通 Demo從掩膜制作到 PSNR 輸出3.1 環(huán)境準(zhǔn)備與 MEX 編譯MATLAB 版本沒有硬性要求但 bestexemplarhelper.dll 是預(yù)編譯的位數(shù)必須和你的 MATLAB 一致。64 位 MATLAB 配 64 位 dll32 位配 32 位混了直接報「invalid MEX-file」。如果你在 Windows 上且 dll 能用跳過編譯否則在 MATLAB 命令行執(zhí)行% 編譯 MEX 文件需提前配置好 C 編譯器 mex -O bestexemplarhelper.c-O 開優(yōu)化編譯完會生成 bestexemplarhelper.mexw64Windows或 .mexa64Linux。如果報「No supported compiler」去 MATLAB 的附加功能里裝一個 MinGW-w64 編譯器這是常見做法裝完再跑一次 mex -setup 選它。3.2 制作掩膜決定修復(fù)范圍的關(guān)鍵輸入Criminisi 需要一個二值掩膜白色1表示待修復(fù)區(qū)域黑色0表示已知區(qū)域。掩膜質(zhì)量直接決定修復(fù)效果別拿畫圖工具隨手涂。常見做法是用閾值分割加形態(tài)學(xué)處理% 從原圖生成掩膜示例假設(shè)修復(fù)區(qū)域是亮色劃痕 img imread(damaged.png); gray rgb2gray(img); mask gray 200; % 閾值提取亮色劃痕 mask imdilate(mask, strel(disk, 2)); % 膨脹 2 像素留余量 imwrite(mask, mask.png);參數(shù)說明閾值 200 是經(jīng)驗值具體看劃痕亮度和背景對比度可以用 imtool 交互看灰度直方圖定。膨脹半徑 2 是防止掩膜邊緣剛好壓在真實邊緣上導(dǎo)致修復(fù)時把好像素也覆蓋掉。掩膜寧可稍微大一點也別漏掉破損邊緣。3.3 調(diào)用 inpaint 主函數(shù)Demo_inpaint.m 里通常已經(jīng)寫好了調(diào)用模板核心就幾行% 主修復(fù)調(diào)用 img imread(damaged.png); mask imread(mask.png); mask logical(mask); patch_size 9; % 樣本塊大小奇數(shù) result inpaint(img, mask, patch_size); imwrite(result, restored.png); psnr_val PSNR(img, result, mask); fprintf(PSNR %.2f dB\n, psnr_val);邏輯說明patch_size 是樣本塊邊長9 是 Criminisi 論文里的推薦值。塊太小紋理匹配容易碎塊太大結(jié)構(gòu)延續(xù)會拖沓。inpaint 內(nèi)部會先算優(yōu)先級、再搜最佳樣本塊、然后拷貝像素并更新置信度循環(huán)直到掩膜區(qū)域填滿。PSNR 計算時注意第三個參數(shù) mask——只算修復(fù)區(qū)域的 PSNR 才有意義全圖算會被未修改區(qū)域拉高。3.4 PSNR 評估的正確用法PSNR.m 的調(diào)用簽名一般是 PSNR(original, restored, mask)。如果你手上沒有無損原圖PSNR 就沒法算這時候只能靠目視評估。有原圖的情況下修復(fù)區(qū)域的 PSNR 能到 30 dB 以上算不錯28 以下基本能看出明顯瑕疵。但別迷信 PSNR它和主觀質(zhì)量的相關(guān)性有限邊緣糊沒糊、紋理斷沒斷還是得放大看。提示跑 Demo 前先把 MATLAB 當(dāng)前目錄切到解壓后的文件夾否則 inpaint 找不到 bestexemplarhelper會報 undefined function。4. 避坑與排查dll 報錯、掩膜越界、優(yōu)先級反轉(zhuǎn)4.1 MEX 文件加載失敗現(xiàn)象運行 inpaint 時報「Invalid MEX-file bestexemplarhelper.mexw64: 找不到指定的模塊」或「不是有效的 Win32 應(yīng)用程序」。原因dll 位數(shù)和 MATLAB 不匹配或者缺少運行時依賴庫。預(yù)編譯的 dll 可能鏈接了特定版本的 MSVCRT。解決先確認(rèn) MATLAB 位數(shù)computer(arch)然后自己用 mex 重新編譯 bestexemplarhelper.c。編譯前裝好 MinGW-w64mex -setup 選它。如果還報缺庫用 Dependency Walker 查 dll 依賴補上對應(yīng)運行庫。4.2 掩膜全白或全黑導(dǎo)致死循環(huán)現(xiàn)象程序卡住不結(jié)束或者瞬間跑完但結(jié)果沒變化。原因掩膜全白意味著所有像素都待修復(fù)沒有已知信息可用優(yōu)先級計算里置信度全為零樣本塊搜索找不到有效源掩膜全黑則循環(huán)條件直接不成立。解決跑之前用 sum(mask(:)) 檢查掩膜像素數(shù)確保既不為 0 也不等于圖像總像素數(shù)。正常掩膜占比在 5% 到 30% 之間比較合理超過 50% 修復(fù)質(zhì)量會急劇下降這不是算法問題是信息量不夠。4.3 優(yōu)先級反轉(zhuǎn)導(dǎo)致結(jié)構(gòu)斷裂現(xiàn)象修復(fù)結(jié)果里長邊緣補到一半突然拐彎或者紋理方向錯亂。原因P-Laplacian 的 p 參數(shù)設(shè)得不對。p 太大接近 2退化成普通 Laplacian邊緣保持效果消失p 太小接近 1擴散過強平坦區(qū)被過度平滑優(yōu)先級排序被噪聲主導(dǎo)。解決p 從 1.5 開始試每次調(diào) 0.1觀察邊緣連續(xù)性。另外檢查 inpaint.m 里 P-Laplacian 權(quán)重那行有沒有加 eps沒加的話 grad_mag 為零時會出現(xiàn) Inf 或 NaN直接污染整個優(yōu)先級矩陣。4.4 PSNR 計算出負值或異常大現(xiàn)象PSNR 輸出 -Inf 或者 100 以上。原因-Inf 通常是修復(fù)結(jié)果和原圖在掩膜區(qū)域完全一致MSE0或者數(shù)據(jù)類型不匹配導(dǎo)致減法溢出。異常大則是掩膜區(qū)域選錯了比如把未修復(fù)區(qū)域也算進去。解決確認(rèn) PSNR.m 里先把圖像轉(zhuǎn)成 double 再算 MSEuint8 相減會截斷。檢查掩膜是不是 logical 類型double 類型的掩膜在索引時會被當(dāng)成數(shù)值而不是邏輯導(dǎo)致區(qū)域選錯。4.5 大圖跑不動或內(nèi)存爆掉現(xiàn)象處理 1024×1024 以上的圖時 MATLAB 卡死或報 Out of Memory。原因Criminisi 的樣本塊搜索是暴力匹配復(fù)雜度隨圖像尺寸和掩膜面積平方增長加上 P-Laplacian 權(quán)重計算額外開銷內(nèi)存占用比原版高。解決先把圖降采樣到 512 寬跑通流程確認(rèn)參數(shù)后再上原圖?;蛘甙蜒谀し殖扇舾蛇B通區(qū)域逐塊修復(fù)再合并。bestexemplarhelper.c 本身就是加速用的確保它被正確調(diào)用別退回到純 MATLAB 的慢速搜索。5. 進階調(diào)參與驗證把 P-Laplacian 階數(shù)當(dāng)成旋鈕來擰跑通 Demo 只是起點這份資源真正的價值在于 P-Laplacian 階數(shù) p 給了你一個連續(xù)可調(diào)的邊緣保持旋鈕。我一般會做一組對比實驗固定掩膜和 patch_size讓 p 從 1.1 到 1.9 步進 0.2每個值跑一遍把修復(fù)區(qū)域的 PSNR 和目視效果都記下來。% p 參數(shù)掃描腳本 p_list 1.1:0.2:1.9; psnr_results zeros(size(p_list)); for i 1:length(p_list) result inpaint(img, mask, 9, p, p_list(i)); psnr_results(i) PSNR(img, result, mask); imwrite(result, sprintf(restored_p%.1f.png, p_list(i))); end plot(p_list, psnr_results, -o); xlabel(P-Laplacian order p); ylabel(PSNR (dB));這段腳本假設(shè) inpaint 支持名值對參數(shù)傳 p如果你的版本里 p 是硬編碼的就去 inpaint.m 里把它提成函數(shù)參數(shù)。跑完看曲線通常會看到一個先升后降的趨勢峰值對應(yīng)的 p 就是這張圖的最優(yōu)值。紋理密集的圖峰值偏左p 小結(jié)構(gòu)為主的圖峰值偏右p 大。驗證環(huán)節(jié)別只看 PSNR。把修復(fù)結(jié)果和原圖在掩膜區(qū)域做差分放大看邊緣過渡帶有沒有振鈴或模糊。P-Laplacian 的強項是保邊如果差分圖里邊緣處出現(xiàn)明顯亮暗條紋說明 p 太小、擴散過強如果邊緣處出現(xiàn)階梯狀偽影說明 p 太大、退化成線性擴散了。還有一個容易忽略的點bestexemplarhelper.c 里的搜索窗口大小。默認(rèn)可能是全圖搜索大圖上極慢。常見做法是限制搜索半徑比如只在待補塊周圍 50 像素范圍內(nèi)找最佳樣本速度能快一個數(shù)量級質(zhì)量損失通常可接受。改完 C 源碼記得重新 mex 編譯。從那以后我每次拿到一個新的修復(fù)算法包都強制先跑一遍參數(shù)掃描再下結(jié)論絕不拿默認(rèn)參數(shù)的結(jié)果去對比別人的最優(yōu)結(jié)果。希望這份拆解幫到你少走點我當(dāng)年踩過的彎路。本文還有配套的精品資源點擊獲取