简介这份资源面向图像修复与重构方向的研究人员和开发者聚焦Criminisi算法的改进实现。原始Criminisi算法基于概率反向传播预测缺失像素优先级而本包用P-Laplacian算子替代原数据项强化边缘保持与局部信息权重减少噪声传播使修复结果更自然、保真度更高。压缩包共5个文件以3个m脚本、1个c源码和1个dll动态库为主涵盖算法主流程、辅助函数与PSNR质量评估模块整体约6KB体积轻量便于快速部署调试。已有212人学习下载适合在Matlab环境下验证改进优先级计算、边界处理与修复效果并借助PSNR定量对比不同参数下的图像质量为图像去噪、去雾、拼接等场景提供可复用的实验基础。1. 从 p-laplace.rar 说起Criminisi 算法在 MATLAB 里到底能修什么图手里拿到一个叫p-laplace.rar的压缩包标题里还挂着 Criminisi、criminisi改进、matlab criminisi 这几个词大概率是两种情况之一要么你在做图像修复相关的课程设计或毕设要么你手上有一批老照片、扫描件、去字后的素材需要补洞搜到了 Criminisi 这条经典路线。Criminisi 算法本身解决的是「已知区域纹理丰富、待修复区域结构复杂」时的图像补全问题——它不像扩散类方法那样把洞抹成一片模糊而是按优先级一块一块地从源区域搬纹理过去所以对划痕、文字水印、物体移除这类场景特别对路。而 p-laplace 通常指的是各向异性扩散里的 p-Laplace 算子把它和 Criminisi 放一起多半是想在补纹理的同时把边缘和梯度结构保住也就是所谓 criminisi改进 的常见思路。这篇不聊空理论按「先跑通原版 → 再理解优先级 → 再上 p-laplace 改进 → 再避坑」的顺序把 MATLAB 里能复现的路径讲清楚新手能照着敲熟手能直接看参数边界。2. Criminisi 原版在 MATLAB 里跑通从掩膜到第一块补丁2.1 先把数据结构和主循环定下来Criminisi 的输入就三样原图I、掩膜mask待修复区为 1已知区为 0、补丁边长patchSize常见 9 或 11。核心循环是「算优先级 → 找最佳匹配块 → 拷贝像素 → 更新掩膜」直到掩膜全为 0。很多人第一次翻车不是算法错而是掩膜边界没做膨胀导致补丁窗口越界。下面这段是能直接跑的最小骨架注释里标了每个变量的含义。function I criminisi_basic(I, mask, patchSize) % I: uint8 三通道原图; mask: logical 同尺寸, true 为待修复 % patchSize: 奇数, 推荐 9 或 11 half floor(patchSize / 2); [H, W, ~] size(I); % 边界膨胀, 防止 fill 窗口越界 mask imdilate(mask, strel(square, 3)); while any(mask(:)) % 1) 找填充前沿: 待修复且四邻域有已知像素 front mask (imdilate(~mask, strel(square,3)) mask); [ys, xs] find(front); if isempty(ys), break; end bestP -inf; bestY 0; bestX 0; for k 1:numel(ys) y ys(k); x xs(k); % 2) 置信项 C: 已知像素占比 C computeConfidence(mask, y, x, half); % 3) 数据项 D: 等照度线强度 D computeDataTerm(I, mask, y, x); P C * D; if P bestP bestP P; bestY y; bestX x; end end % 4) 在源区域搜索最佳匹配块并拷贝 I fillPatch(I, mask, bestY, bestX, half); % 5) 更新掩膜 mask(max(1,bestY-half):min(H,bestYhalf), ... max(1,bestX-half):min(W,bestXhalf)) false; end end逻辑说明front是当前待修复区和已知区的交界只有交界上的点才参与优先级竞争这是 Criminisi 效率的关键。C越大说明周围已知信息越多D越大说明该点处在强边缘上两者相乘决定谁先补。参数上patchSize太小会碎、纹理接不上太大则计算量暴涨且容易把不相关纹理搬进来9 是多数场景的平衡点。imdilate那一步别省省了在图像边缘附近的洞会直接报索引越界。2.2 置信项和数据项怎么写才不跑偏computeConfidence本质是补丁窗口内已知像素数除以窗口总面积范围 0 到 1。computeDataTerm用的是等照度线的法向量和梯度旋转 90 度后的点积再归一化。新手最容易把D写成梯度模长那样边缘越强值越大方向却丢了补出来的结构会歪。正确做法是先算灰度梯度[gx, gy]法向量n [-gy, gx]归一化再和梯度方向做点积取绝对值。function C computeConfidence(mask, y, x, half) [H, W] size(mask); y1 max(1,y-half); y2 min(H,yhalf); x1 max(1,x-half); x2 min(W,xhalf); win mask(y1:y2, x1:x2); C sum(~win(:)) / numel(win); % 已知像素占比 end function D computeDataTerm(I, mask, y, x) gray rgb2gray(I); [gx, gy] imgradientxy(gray, central); g [gx(y,x), gy(y,x)]; if norm(g) 1e-6, D 0; return; end n [-g(2), g(1)] / norm(g); % 等照度线法向 D abs(dot(g / norm(g), n)); end参数说明imgradientxy用central差分比默认的sobel在细结构上更稳1e-6是防止平坦区除零。C和D都归一化到 0 到 1 后相乘量纲才一致否则D会单方面主导优先级补丁顺序全乱。跑通这一步你会看到补丁从强边缘处开始往里填这就是 Criminisi 和普通扩散修复最直观的区别。3. 把 p-laplace 接进来criminisi改进 到底改在哪3.1 p-Laplace 算子在修复里扮演什么角色原版 Criminisi 的置信项C只数已知像素个数不区分这些像素是平坦区还是边缘结果就是平坦区补得还行边缘附近容易糊。p-Laplace 算子来自各向异性扩散形式是div(|∇u|^(p-2) ∇u)p2退化成普通拉普拉斯各向同性边缘也糊p2时扩散在梯度大的地方被抑制边缘得以保留p2反过来增强弱梯度。criminisi改进 里最常见的接法有两种一是用 p-Laplace 平滑后的梯度去替换数据项D里的原始梯度让优先级对噪声更鲁棒二是把 p-Laplace 扩散结果作为匹配块搜索时的预筛选减少把噪声块当最佳匹配搬进去的概率。前者改动小、见效快推荐先做这个。3.2 用 p-laplace 重构数据项的 MATLAB 实现下面这段把computeDataTerm换成基于 p-Laplace 平滑梯度的版本。核心是先对灰度图做若干次 p-Laplace 迭代再在平滑结果上求梯度。迭代次数iter和指数p是两个必调参数。function D computeDataTerm_pLaplace(I, mask, y, x, p, iter, dt) % p: 扩散指数, 常用 1.5~3; iter: 迭代次数, 10~30; dt: 步长, 0.1~0.25 gray double(rgb2gray(I)); u gray; for t 1:iter [ux, uy] gradient(u); mag sqrt(ux.^2 uy.^2) 1e-8; % p-Laplace 扩散系数 c mag.^(p - 2); % 散度近似: div(c * grad u) [cx, cy] gradient(c); div cx .* ux c .* divergence(ux, uy) cy .* uy; u u dt * div; end [gx, gy] gradient(u); g [gx(y,x), gy(y,x)]; if norm(g) 1e-6, D 0; return; end n [-g(2), g(1)] / norm(g); D abs(dot(g / norm(g), n)); end function d divergence(fx, fy) [dfx, ~] gradient(fx); [~, dfy] gradient(fy); d dfx dfy; end逻辑说明c mag.^(p-2)是 p-Laplace 的关键p2时梯度大的位置c小扩散弱边缘保住p2时c恒为 1退化成热扩散。dt超过 0.25 会数值不稳定图像出现棋盘伪影这是血泪经验别贪快。iter太小等于没平滑太大则弱边缘被抹掉10 到 30 之间按图像噪声水平调。把这段替换进第 2 章的主循环后你会发现补丁在边缘处的走向明显更贴合原结构而不是横着切过去。3.3 改进前后怎么对比才算数别只看肉眼看不出差别就说改进无效。建议固定同一张图、同一个掩膜、同一patchSize只切换computeDataTerm和computeDataTerm_pLaplace然后算两个指标一是修复区与真值如果有的 PSNR二是修复区边缘处的梯度方向一致性。没有真值就用结构相似度 SSIM 在修复区邻域做局部对比。表格里给一组我常用的参数起点实际按图微调。参数原版推荐p-laplace 改进推荐作用patchSize99 或 11补丁边长奇数p无1.5 ~ 3.0扩散指数越大越保边iter无10 ~ 30平滑迭代次数dt无0.1 ~ 0.25扩散步长超 0.25 不稳掩膜膨胀3x33x3防越界注意p和iter是耦合的p大时iter可以小一点否则边缘被过度平滑反而丢结构。调参顺序建议先定patchSize再调p最后微调iter和dt。4. 避坑与排查Criminisi 在 MATLAB 里最容易翻车的 5 个点4.1 补丁越界报索引超范围现象运行到图像边缘附近的洞时MATLAB 报Index exceeds matrix dimensions。原因填充前沿可能落在距边界不足half的位置y-half或xhalf变成 0 或超过H/W。解决所有窗口索引统一用max(1, ...)和min(H, ...)夹住或者提前对掩膜做imdilate把洞推离边界。我一般两个都做双保险。4.2 优先级全为 0 导致死循环现象while any(mask(:))一直不退出front为空。原因掩膜更新时把整块补丁都置为已知但补丁之间可能有缝隙没被覆盖或者front计算条件写错。解决更新掩膜时确保覆盖bestY-half到bestYhalf的完整方形front用mask imdilate(~mask, strel(square,3))而不是手写四邻域避免边界漏判。加一个最大迭代次数兜底比如maxIter H*W超了就 break 并警告。4.3 补出来的纹理方向明显错乱现象修复区纹理和周围对不上像贴了块补丁。原因数据项D的梯度方向算错或者C和D没归一化导致优先级顺序乱。解决确认D用的是等照度线法向与梯度的点积不是梯度模长确认C在 0 到 1 之间。另外patchSize太大也会搬错纹理先降到 9 试。4.4 p-laplace 迭代后图像出现棋盘格现象平滑后的灰度图有规律性网格伪影梯度计算全乱。原因dt超过稳定性上限显式差分格式发散。解决dt压到 0.2 以下或者改用隐式格式计算量大但稳。多数场景dt0.15、iter20就够别为了省迭代次数把dt拉到 0.3。4.5 大图跑得慢到无法接受现象512x512 以上的图原版逐像素算优先级要跑几十分钟。原因每个前沿点都重新算整幅图的梯度重复计算。解决梯度图在循环外算一次循环内只索引front只遍历交界点而不是全图find(mask)匹配块搜索用normxcorr2或积分图加速。实测把梯度提到循环外能快 3 到 5 倍这是最划算的优化。5. 进阶技巧让 criminisi改进 在真实素材上稳住的三个习惯第一个习惯是掩膜先做形态学清理。真实素材的待修复区往往边缘毛糙直接拿去算前沿会得到一堆孤立点优先级竞争变成噪声竞争。我一般先imopen去掉小噪点再imclose把断裂的划痕连起来最后imdilate膨胀 2 到 3 像素。这一步不写进算法论文但决定了你跑出来能不能看。第二个习惯是分块修复而不是整图一把梭。大图直接跑 Criminisi内存和耗时都吃不消而且优先级在全局竞争时远处的强边缘会把近处的补丁顺序挤掉。做法是把图切成有重叠的块每块单独修复重叠区做加权融合。重叠宽度取patchSize的两倍融合权重用余弦窗接缝基本看不出来。第三个习惯是给 p-laplace 的p值做自适应。固定p在不同区域表现差异很大平坦区希望p接近 2 快点扩散边缘区希望p大一点保住结构。可以按局部梯度方差分档方差大的区域p取 2.5 到 3方差小的取 1.5 到 2。实现上就是算一个局部方差图归一化后映射到p的范围再传给computeDataTerm_pLaplace。function pMap adaptiveP(gray, pLow, pHigh) % 按局部梯度方差自适应生成 p 值图 win 7; meanG imfilter(gray, ones(win)/win^2, replicate); varG imfilter(gray.^2, ones(win)/win^2, replicate) - meanG.^2; varG mat2gray(varG); % 归一化到 0~1 pMap pLow (pHigh - pLow) * varG; end参数说明pLow建议 1.5pHigh建议 3.0win取 7 和patchSize同量级即可。这个pMap逐像素传给扩散系数计算比全局固定p在混合内容图上 PSNR 通常能再涨 0.5 到 1 dB。最后说个我自己的教训别一上来就堆改进先把原版 Criminisi 在一张图上跑通、看清补丁顺序再动 p-laplace否则你连问题是出在优先级还是出在扩散都分不清。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?