基于光流场的 Demons 算法

基于光流场的 Demons 算法,一种经典的非刚性图像配准方法,它借鉴了光流的概念,通过迭代优化使浮动图像与参考图像对齐。

算法核心原理

基本思想:将图像配准视为一个"扩散"过程。每个像素点被视为一个"Demon",根据局部强度差异(光流约束)和相邻像素的变形(正则化约束)来施加"力",使浮动图像逐渐变形以匹配参考图像。

数学模型

  1. 光流方程 (亮度恒定假设):
    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)` 是待求的位移场(光流场)。
  2. 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

改进方向
  1. 自适应步长 :根据迭代误差自动调整 step_size
  2. 局部相关系数:用局部相关性代替强度差异,对非线性光照变化更鲁棒
  3. 双向对称配准:同时优化正向和反向形变场,提高拓扑保持性
  4. 结合特征点:用 SIFT 等特征点提供初始形变估计

使用建议

  1. 预处理很重要:对图像进行直方图匹配或强度归一化,可显著提升性能
  2. 参数调试:先用小图像(下采样)快速调试参数,再应用到全分辨率
  3. 初始化:对于大形变,可先用仿射变换进行粗配准,再用 Demons 做非刚性精配
  4. 评估指标:除了 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 加速
相关推荐
哈哈不让取名字2 小时前
C++代码冗余消除
开发语言·c++·算法
棱镜Coding2 小时前
LeetCode-Hot100 27.合并两个有序链表
算法·leetcode·链表
2301_765703142 小时前
C++中的策略模式应用
开发语言·c++·算法
TGITCIC2 小时前
RAG不是魔法,是工程:从知识库到企业部署的硬核实践
人工智能·算法·机器学习·rag·ai agent·ai开发·rag增强检索
求梦8202 小时前
【力扣hot100题】两两交换链表中的节点(25)
算法·leetcode·链表
passxgx2 小时前
12.1 均值、方差与概率
算法·均值算法·概率论
血小板要健康2 小时前
189.轮转数组,力扣
数据结构·算法·leetcode
项目申报小狂人2 小时前
CEC2024获胜算法mLSHADE-RL:具有重新启动和本地搜索机制的多操作员集成LSHADE
算法
Faker66363aaa2 小时前
YOLOv26人脸检测算法实现与优化_2
算法·yolo