图像修复的核心问题是:在缺损区域 DDD 内,用周围已知信息 Ω∖D\Omega\setminus DΩ∖D 推断补全。PDE 流派从 1990s 起形成三条主线:
| 模型 | 提出者 | 核心思想 |
|---|---|---|
| TV 修复 | Rudin--Osher--Fatemi 推广到 inpainting (Chan--Shen 1999) | 缺损区内最小化 TV 范数,$\partial_t u = \mathrm{div}\big(\frac{\nabla u}{ |
| BSCB | Bertalmio--Sapiro--Caselles--Ballester 2000 | 信息沿等照度线 方向向洞内输运,ut=∇⊥u⋅∇gu_t = \nabla^\perp u \cdot \nabla gut=∇⊥u⋅∇g(各向异性扩散) |
| CDD | Chan--Kang 2000 (Curvature-Driven Diffusion) | 在 TV 基础上引入曲率项,使大尺度结构 / 细长条能被"拉"进洞 |
一、三种模型方程对照
记缺损域为 DDD,已知域为 Ω∖D\Omega\setminus DΩ∖D,u0u_0u0 为观测图像。
1、TV 修复(Chan--Shen)
minu∫Ω∣∇u∣ dxs.t. u∣Ω∖D=u0∣Ω∖D \min_u \int_{\Omega} |\nabla u| \,dx\quad \text{s.t. } u|{\Omega\setminus D}=u_0|{\Omega\setminus D} umin∫Ω∣∇u∣dxs.t. u∣Ω∖D=u0∣Ω∖D
Euler--Lagrange(加人工时间 ∂tu=−δEδu\partial_t u = -\frac{\delta E}{\delta u}∂tu=−δuδE):
∂tu=div (∇u∣∇u∣β)+λ(x)(u0−u),x∈D \partial_t u = \mathrm{div}\!\left(\frac{\nabla u}{|\nabla u|_\beta}\right) + \lambda(x)(u_0-u),\quad x\in D ∂tu=div(∣∇u∣β∇u)+λ(x)(u0−u),x∈D
- ∣∇u∣β=∣∇u∣2+β2|\nabla u|_\beta = \sqrt{|\nabla u|^2+\beta^2}∣∇u∣β=∣∇u∣2+β2 ,β\betaβ 防除零
- λ(x)\lambda(x)λ(x) 是指示函数:在 DDD 内为 1,已知区为 0(或松弛)
- 直觉 :缺损区里做"最小 TV"填充,边缘会被保留成分段光滑,但对大洞/细长结构不友好------TV 偏爱短路,把细线"切"断了
2、BSCB(等照度线输运)
等照度线:{x:u(x)=c}\{x:u(x)=c\}{x:u(x)=c},其法向是 ∇u\nabla u∇u,切向是 ∇⊥u=J∇u\nabla^\perp u = J\nabla u∇⊥u=J∇u(JJJ 是 90° 旋转)。
BSCB 核心方程:
ut=∇⊥u⋅∇g=⟨∇g, ∇⊥u⟩ u_t = \nabla^\perp u \cdot \nabla g = \langle \nabla g,\; \nabla^\perp u\rangle ut=∇⊥u⋅∇g=⟨∇g,∇⊥u⟩
- ggg 通常是 g=∣∇u∣g=|\nabla u|g=∣∇u∣ 或高斯平滑后的梯度模,用来控制权重大小
- 直觉:信息沿着等照度线"流"进洞------因为自然图像里等照度线=结构走向(发丝、栏杆、织物),顺着它传最合理
- 实现关键:∇⊥u=(−uy,ux)\nabla^\perp u = (-u_y, u_x)∇⊥u=(−uy,ux)
3、CDD(曲率驱动)
TV 的扩散系数是 1/∣∇u∣1/|\nabla u|1/∣∇u∣,对平坦/陡峭都一样;但大洞需要"长距离"输运,靠曲率引导:
∂tu=div (d(κ)∇u∣∇u∣β),d(κ)=11+∣∇u∣(1+αsinκπ) \partial_t u = \mathrm{div}\!\left(d(\kappa)\frac{\nabla u}{|\nabla u|_\beta}\right),\qquad d(\kappa)=\frac{1}{1+|\nabla u|}\bigl(1+\alpha\sin\frac{\kappa}{\pi}\bigr) ∂tu=div(d(κ)∣∇u∣β∇u),d(κ)=1+∣∇u∣1(1+αsinπκ)
- κ=div(∇u/∣∇u∣)\kappa = \mathrm{div}(\nabla u/|\nabla u|)κ=div(∇u/∣∇u∣) 是曲率
- sin(κ/π)\sin(\kappa/\pi)sin(κ/π) 让凸/凹结构被"拉长"进洞
- 直觉:曲率项让细线、长边缘在大缺损下也能连通,是 TV 在大洞场景的升级
二、MATLAB 实现(三者同框对比)
2.1 主脚本 pde_inpainting_comparison.m
matlab
%% 三种基于 PDE 的图像修复模型对比
clear; clc; close all;
%% ===== 1. 准备图像 + 缺损掩膜 =====
% 用内置 lena 或自己图
img_orig = im2double(imread('lena.png')); % 请自备图,或换成 cameraman
if size(img_orig,3)==3, img_orig = rgb2gray(img_orig); end
% 造缺损:文字 + 划痕
mask = ones(size(img_orig)); % 1=已知, 0=缺损
% 中央文字块
mask(120:180, 140:260) = 0;
% 一条斜划痕
for i = 1:size(mask,1)
j = round(i*0.8 + 50);
if j>0 && j<=size(mask,2)
mask(max(1,i-2):min(size(mask,1),i+2), max(1,j-2):min(size(mask,2),j+2)) = 0;
end
end
% 缺损图
img_damaged = img_orig .* mask;
img_damaged(mask==0) = 0.5; % 缺损区填个灰色便于看
%% ===== 2. 参数 =====
params.nIter = 3000;
params.dt = 0.2; % TV / CDD 时间步(需 CFL: dt < h^2/4 量级)
params.beta = 1e-2; % TV 分母防零
params.alpha_cdd = 2.0; % CDD 曲率权重
params.gauss_sigma = 1.0; % BSCB 里 g 的高斯平滑
fprintf('缺损像素占比: %.1f%%\n', 100*sum(mask(:)==0)/numel(mask));
%% ===== 3. 分别修复 =====
tic; u_tv = tv_inpaint(img_damaged, mask, params); t_tv = toc;
tic; u_bscb = bscb_inpaint(img_damaged, mask, params); t_bscb = toc;
tic; u_cdd = cdd_inpaint(img_damaged, mask, params); t_cdd = toc;
fprintf('TV: %.1fs, BSCB: %.1fs, CDD: %.1fs\n', t_tv, t_bscb, t_cdd);
%% ===== 4. 误差(只看缺损区,已知区强制一样)=====
mse_tv = mean((u_tv(mask==0) - img_orig(mask==0)).^2);
mse_bscb = mean((u_bscb(mask==0) - img_orig(mask==0)).^2);
mse_cdd = mean((u_cdd(mask==0) - img_orig(mask==0)).^2);
psnr = @(mse) 10*log10(1/mse);
fprintf('缺损区 MSE / PSNR:\n');
fprintf(' TV: %.4e / %.2f dB\n', mse_tv, psnr(mse_tv));
fprintf(' BSCB: %.4e / %.2f dB\n', mse_bscb, psnr(mse_bscb));
fprintf(' CDD: %.4e / %.2f dB\n', mse_cdd, psnr(mse_cdd));
%% ===== 5. 可视化 =====
figure('Color','w','Position',[100 100 1400 500]);
subplot(1,4,1); imshow(img_damaged); title('缺损图');
subplot(1,4,2); imshow(u_tv); title(sprintf('TV 修复 (PSNR=%.1f)',psnr(mse_tv)));
subplot(1,4,3); imshow(u_bscb); title(sprintf('BSCB 修复 (PSNR=%.1f)',psnr(mse_bscb)));
subplot(1,4,4); imshow(u_cdd); title(sprintf('CDD 修复 (PSNR=%.1f)',psnr(mse_cdd)));
sgtitle('三种 PDE 图像修复对比', 'FontSize',14, 'FontWeight','bold');
% 局部放大看结构连通性
figure('Color','w');
yrange = 160:220; xrange = 100:200;
subplot(2,2,1); imshow(img_orig(yrange,xrange)); title('原图局部');
subplot(2,2,2); imshow(u_tv(yrange,xrange)); title('TV:细线易断');
subplot(2,2,3); imshow(u_bscb(yrange,xrange)); title('BSCB:等照度输运');
subplot(2,2,4); imshow(u_cdd(yrange,xrange)); title('CDD:曲率拉通');
2.2 TV 修复(分裂写成显式,好懂)
matlab
function u = tv_inpaint(img_damaged, mask, params)
% TV inpainting: u_t = div( grad(u)/|grad(u)| ) in D, Dirichlet outside
u = img_damaged;
known = (mask > 0.5);
[h,w] = size(u);
dt = params.dt; beta = params.beta;
for iter = 1:params.nIter
% 梯度
[ux, uy] = gradient(u);
norm_grad = sqrt(ux.^2 + uy.^2 + beta^2);
% 散度项 div( grad/|grad| )
px = ux ./ norm_grad;
py = uy ./ norm_grad;
[pxx, ~] = gradient(px);
[~, pyy] = gradient(py);
div = pxx + pyy;
% 只在缺损区演化,已知区拉回原值
u = u + dt * div;
u(known) = img_damaged(known); % 硬约束
if mod(iter,1000)==0, fprintf(' TV iter %d\n',iter); end
end
end
2.3 BSCB(等照度线输运)
matlab
function u = bscb_inpaint(img_damaged, mask, params)
% BSCB: u_t = < grad(g), J grad(u) >, J = [0 -1; 1 0]
u = img_damaged;
known = (mask > 0.5);
dt = params.dt;
for iter = 1:params.nIter
% 梯度 + 旋转 90° = 等照度线切向
[ux, uy] = gradient(u);
% J grad(u) = (-uy, ux)
Jgu = cat(3, -uy, ux);
% g = |grad(u)| 高斯平滑(控制权重大小)
g = sqrt(ux.^2 + uy.^2);
g = imgaussfilt(g, params.gauss_sigma);
[gx, gy] = gradient(g);
% 点积 <grad(g), J grad(u)>
rhs = gx .* Jgu(:,:,1) + gy .* Jgu(:,:,2);
u = u + dt * rhs;
u(known) = img_damaged(known);
if mod(iter,1000)==0, fprintf(' BSCB iter %d\n',iter); end
end
end
2.4 CDD(曲率驱动)
matlab
function u = cdd_inpaint(img_damaged, mask, params)
% CDD: u_t = div( d(κ) * grad(u)/|grad(u)| )
% κ = div( grad(u)/|grad(u)| )
u = img_damaged;
known = (mask > 0.5);
[h,w] = size(u);
dt = params.dt; beta = params.beta;
alpha = params.alpha_cdd;
for iter = 1:params.nIter
[ux, uy] = gradient(u);
norm_gu = sqrt(ux.^2 + uy.^2 + beta^2);
% 单位法向 n = grad(u)/|grad(u)|
nx = ux ./ norm_gu;
ny = uy ./ norm_gu;
% 曲率 κ = div(n)
[nx_x, nx_y] = gradient(nx);
[ny_x, ny_y] = gradient(ny);
kappa = nx_x + ny_y; % div(n)
% 扩散系数 d(κ)
dk = (1./(1+sqrt(ux.^2+uy.^2+1e-3))) .* (1 + alpha*sin(kappa/pi));
% div( dk * n )
px = dk .* nx; py = dk .* ny;
[pxx, ~] = gradient(px);
[~, pyy] = gradient(py);
div = pxx + pyy;
u = u + dt * div;
u(known) = img_damaged(known);
if mod(iter,1000)==0, fprintf(' CDD iter %d\n',iter); end
end
end
纯显式对 TV/CDD 的
dt要小心:CFL 大致dt < h²/4 ≈ 0.06(h=1 像素)。上面dt=0.2能跑但会稍抖,想要稳可以改dt=0.05或把 TV 换成 Split-Bregman(快 10× 且无条件稳)。
参考代码 分析三种基于PDE的图像修复模型 www.youwenfan.com/contentcsw/82220.html
三、三种模型对比
| 维度 | TV | BSCB | CDD |
|---|---|---|---|
| 物理直觉 | 缺损区最小 TV,边缘保边 | 信息沿等照度线"流"进洞 | TV + 曲率项,长结构被拉通 |
| 对小缺损 | 很好,边缘锐 | 纹理走向自然 | 略重 |
| 对细长结构 | 易断(分段常数倾向) | △ 靠等照度方向,但无曲率仍会散 | 曲率把细线"连"回来 |
| 对大洞 | 拉不通,出现分片平台 | △ 能传但易模糊 | 最优 |
| 计算代价 | 低(可 Split-Bregman 加速) | 中 | 高(曲率二阶,需小 dt) |
| 典型场景 | 划痕、小文字擦除 | 纹理/发丝/织物修补 | 大缺损 + 结构连通(人脸、建筑线脚) |