基于光流场的 Demons 算法,一种经典的非刚性图像配准方法,它借鉴了光流的概念,通过迭代优化使浮动图像与参考图像对齐。
算法核心原理
基本思想:将图像配准视为一个"扩散"过程。每个像素点被视为一个"Demon",根据局部强度差异(光流约束)和相邻像素的变形(正则化约束)来施加"力",使浮动图像逐渐变形以匹配参考图像。
数学模型:
- 光流方程 (亮度恒定假设):
I f ( x ) − I m ( T ( x ) ) ≈ ∇ I m ⋅ u ( x ) I_f(x) - I_m(T(x)) ≈ ∇I_m · u(x) If(x)−Im(T(x))≈∇Im⋅u(x)其中,u(x)` 是待求的位移场(光流场)。 - Demons 迭代更新公式 (基于 Thirion 的原始形式):
u n e w = u + ( I f − I m ∘ T ) ∗ ( ∇ I m / ( ∣ ∇ I m ∣ 2 + α ( I f − I m ∘ T ) 2 ) ) u_{new} = u + (I_f - I_m ∘ T) * (∇I_m / (|∇I_m|^2 + α(I_f - I_m ∘ T)^2)) unew=u+(If−Im∘T)∗(∇Im/(∣∇Im∣2+α(If−Im∘T)2))
并用高斯滤波器对u进行平滑(正则化)。
完整 MATLAB 实现
matlab
%% 基于光流场的 Demons 非刚性图像配准算法
clear; close all; clc;
%% 1. 准备测试图像(示例:合成变形)
% 生成参考图像(矩形 + 椭圆)
reference = zeros(128, 128);
reference(30:90, 30:90) = 1; % 矩形
[X, Y] = meshgrid(1:128, 1:128);
reference((X-70).^2/400 + (Y-70).^2/900 <= 1) = 0.7; % 椭圆
% 生成浮动图像(对参考图像施加非线性形变)
[xx, yy] = meshgrid(1:128, 1:128);
dx = 10*sin(2*pi*xx/64) .* cos(2*pi*yy/64); % 合成位移场
dy = 8*cos(2*pi*xx/80) .* sin(2*yy/128);
floating = interp2(double(reference), xx+dx, yy+dy, 'linear', 0);
% 显示初始图像
figure('Position', [100, 100, 1200, 400]);
subplot(1, 3, 1); imshow(reference, []); title('参考图像 (Reference)');
subplot(1, 3, 2); imshow(floating, []); title('浮动图像 (Floating)');
subplot(1, 3, 3); imshowpair(reference, floating);
title('配准前叠加(红色:参考,绿色:浮动)');
%% 2. Demons 算法参数
num_iter = 200; % 迭代次数
sigma_fluid = 2.0; % 位移场平滑的高斯核标准差("流体"正则化)
sigma_diffusion = 2.0; % 更新场平滑的高斯核标准差("扩散"正则化)
alpha = 2.0; % 强度差异调节因子(控制更新步长)
step_size = 1.0; % 步长控制因子
% 初始化位移场(u: 水平方向, v: 垂直方向)
u = zeros(size(reference)); % x方向位移
v = zeros(size(reference)); % y方向位移
%% 3. 多分辨率策略(金字塔,加速收敛并避免局部极小值)
pyramid_levels = 3; % 金字塔层数
for level = pyramid_levels:-1:1
scale = 1 / 2^(level-1);
% 对当前层的图像进行下采样
if level < pyramid_levels
ref_resized = imresize(reference, scale, 'bicubic');
flo_resized = imresize(floating, scale, 'bicubic');
u = imresize(u * scale, size(ref_resized), 'bicubic');
v = imresize(v * scale, size(ref_resized), 'bicubic');
else
ref_resized = reference;
flo_resized = floating;
end
fprintf('=== 第 %d 层 (尺寸: %dx%d) ===\n', ...
level, size(ref_resized, 1), size(ref_resized, 2));
% 当前层迭代
for iter = 1:num_iter
% 3.1 根据当前位移场变形浮动图像
[x, y] = meshgrid(1:size(ref_resized, 2), 1:size(ref_resized, 1));
x_deformed = x + u;
y_deformed = y + v;
flo_deformed = interp2(flo_resized, x_deformed, y_deformed, ...
'linear', 0);
% 3.2 计算强度差异和梯度
diff = ref_resized - flo_deformed; % 差异图像
% 计算浮动图像的梯度(在变形后的位置上)
[grad_x, grad_y] = gradient(flo_deformed);
grad_mag_sq = grad_x.^2 + grad_y.^2 + eps; % 避免除零
% 3.3 计算Demons力(更新场)
denominator = grad_mag_sq + alpha * diff.^2;
update_u = step_size * diff .* grad_x ./ denominator;
update_v = step_size * diff .* grad_y ./ denominator;
% 3.4 平滑更新场(扩散正则化)
update_u = imgaussfilt(update_u, sigma_diffusion);
update_v = imgaussfilt(update_v, sigma_diffusion);
% 3.5 更新位移场
u = u + update_u;
v = v + update_v;
% 3.6 平滑位移场(流体正则化)
u = imgaussfilt(u, sigma_fluid);
v = imgaussfilt(v, sigma_fluid);
% 显示中间结果(每50次迭代)
if mod(iter, 50) == 0
mse = mean(diff(:).^2);
fprintf('迭代 %3d: MSE = %.6f\n', iter, mse);
end
end
end
%% 4. 应用最终位移场,得到配准后的图像
[x, y] = meshgrid(1:size(reference, 2), 1:size(reference, 1));
registered = interp2(floating, x+u, y+v, 'linear', 0);
%% 5. 可视化结果
figure('Position', [100, 100, 1400, 500]);
% 5.1 配准前后对比
subplot(2, 4, 1); imshow(reference, []); title('参考图像');
subplot(2, 4, 2); imshow(floating, []); title('原始浮动图像');
subplot(2, 4, 3); imshow(registered, []); title('配准后的图像');
subplot(2, 4, 4); imshowpair(reference, registered);
title('配准后叠加(对齐程度)');
% 5.2 位移场可视化
subplot(2, 4, 5);
imagesc(sqrt(u.^2 + v.^2)); colorbar; axis image;
title('位移场幅度'); xlabel('像素'); ylabel('像素');
subplot(2, 4, 6);
quiver(x(1:4:end, 1:4:end), y(1:4:end, 1:4:end), ...
u(1:4:end, 1:4:end), v(1:4:end, 1:4:end), 2, 'b');
axis image; title('位移场向量(下采样显示)');
% 5.3 差异图像对比
subplot(2, 4, 7);
imagesc(abs(reference - floating)); colorbar; axis image;
title('配准前差异');
subplot(2, 4, 8);
imagesc(abs(reference - registered)); colorbar; axis image;
title('配准后差异');
%% 6. 定量评估
mse_before = mean((reference(:) - floating(:)).^2);
mse_after = mean((reference(:) - registered(:)).^2);
ssim_before = ssim(floating, reference);
ssim_after = ssim(registered, reference);
fprintf('\n=== 配准性能评估 ===\n');
fprintf('配准前 MSE: %.6f\n', mse_before);
fprintf('配准后 MSE: %.6f\n', mse_after);
fprintf('MSE 改善: %.2f%%\n', (1 - mse_after/mse_before)*100);
fprintf('配准前 SSIM: %.4f\n', ssim_before);
fprintf('配准后 SSIM: %.4f\n', ssim_after);
关键参数说明
| 参数 | 典型值 | 作用 | 调整建议 |
|---|---|---|---|
num_iter |
100-300 | 迭代次数 | 图像复杂则需更多迭代 |
sigma_fluid |
1.0-3.0 | 位移场平滑强度 | 值越大形变越平滑,但可能丢失细节 |
sigma_diffusion |
1.0-3.0 | 更新场平滑强度 | 控制局部形变的连续性 |
alpha |
0.5-2.0 | 强度差异调节 | 噪声大时增大可增加稳定性 |
step_size |
1.0-2.0 | 更新步长 | 太大易振荡,太小收敛慢 |
pyramid_levels |
3-4 | 金字塔层数 | 加速收敛,避免局部极小值 |
实际应用扩展
示例:医学图像配准
matlab
% 加载医学图像(例如 MRI 或 CT)
reference_medical = imread('patient_before.jpg');
floating_medical = imread('patient_after.jpg');
% 转换为灰度并归一化
if size(reference_medical, 3) == 3
reference_medical = rgb2gray(reference_medical);
floating_medical = rgb2gray(floating_medical);
end
reference_medical = double(reference_medical) / 255;
floating_medical = double(floating_medical) / 255;
% 应用 Demons 配准(参数需根据图像特性调整)
% [将上述主程序中的 reference 和 floating 替换即可]
参考代码 基于光流场的demon,matlab程序 www.3dddown.com/csa/96179.html
改进方向
- 自适应步长 :根据迭代误差自动调整
step_size - 局部相关系数:用局部相关性代替强度差异,对非线性光照变化更鲁棒
- 双向对称配准:同时优化正向和反向形变场,提高拓扑保持性
- 结合特征点:用 SIFT 等特征点提供初始形变估计
使用建议
- 预处理很重要:对图像进行直方图匹配或强度归一化,可显著提升性能
- 参数调试:先用小图像(下采样)快速调试参数,再应用到全分辨率
- 初始化:对于大形变,可先用仿射变换进行粗配准,再用 Demons 做非刚性精配
- 评估指标:除了 MSE、SSIM,还可计算目标分割区域的重叠度(Dice系数)
进阶:加速与优化
matlab
% 使用 GPU 加速(如有 Parallel Computing Toolbox)
if gpuDeviceCount > 0
reference_gpu = gpuArray(reference);
floating_gpu = gpuArray(floating);
% ... 在GPU上执行计算,速度可提升5-10倍
end
% 多线程优化
options = optimset('UseParallel', true);
% 在迭代循环中利用 parfor 加速