STFT在图像配准中的MATLAB实现

STFT(短时傅里叶变换)在图像配准中主要用于局部频率分析。以下是MATLAB实现的完整方案:

一、基本原理

图像配准中的STFT通常用于:

  1. 局部相位分析 - 通过相位相关性实现亚像素精度
  2. 局部特征提取 - 提取旋转/缩放不变特征
  3. 多尺度配准 - 不同窗口大小适应不同尺度变换

二、基于STFT的相位相关配准

2.1 主函数:STFT相位相关配准

matlab 复制代码
function [registered_image, tform, displacement_field] = stft_image_registration(ref_img, mov_img, varargin)
% STFT图像配准 - 基于局部相位相关
% 输入:
%   ref_img - 参考图像
%   mov_img - 待配准图像
%   varargin - 可选参数
% 输出:
%   registered_image - 配准后的图像
%   tform - 变换矩阵
%   displacement_field - 位移场

% 参数设置
p = inputParser;
addParameter(p, 'window_size', 64, @isnumeric);    % 窗口大小
addParameter(p, 'overlap', 0.75, @isnumeric);      % 重叠比例
addParameter(p, 'max_shift', 20, @isnumeric);      % 最大位移
addParameter(p, 'method', 'affine', @ischar);      % 变换类型
parse(p, varargin{:});
params = p.Results;

% 图像预处理
if size(ref_img, 3) > 1
    ref_img = rgb2gray(ref_img);
end
if size(mov_img, 3) > 1
    mov_img = rgb2gray(mov_img);
end

% 确保图像大小一致
[rows, cols] = size(ref_img);
mov_img = imresize(mov_img, [rows, cols]);

% 计算局部位移场
displacement_field = compute_local_displacement(ref_img, mov_img, params);

% 根据位移场估计全局变换
tform = estimate_global_transform(displacement_field, params.method);

% 应用变换
registered_image = imwarp(mov_img, tform, 'OutputView', imref2d(size(ref_img)));

% 可视化结果
if nargout == 0
    visualize_registration(ref_img, mov_img, registered_image, displacement_field);
end
end

2.2 计算局部位移场

matlab 复制代码
function displacement = compute_local_displacement(ref, mov, params)
% 基于STFT相位相关计算局部位移场

[rows, cols] = size(ref);
window_size = params.window_size;
step = round(window_size * (1 - params.overlap));
max_shift = params.max_shift;

% 初始化位移场
displacement = struct();
displacement.dx = zeros(floor(rows/step), floor(cols/step));
displacement.dy = zeros(floor(rows/step), floor(cols/step));
displacement.confidence = zeros(floor(rows/step), floor(cols/step));
displacement.x_pos = zeros(floor(rows/step), floor(cols/step));
displacement.y_pos = zeros(floor(rows/step), floor(cols/step));

% 创建窗口函数(二维汉宁窗)
window = hanning(window_size) * hanning(window_size)';

% 遍历图像块
idx = 1;
for y = 1:step:rows-window_size
    for x = 1:step:cols-window_size
        % 提取参考图像块
        ref_patch = ref(y:y+window_size-1, x:x+window_size-1);
        
        % 提取移动图像块(考虑可能的最大位移)
        y_start = max(1, y - max_shift);
        y_end = min(rows, y + window_size - 1 + max_shift);
        x_start = max(1, x - max_shift);
        x_end = min(cols, x + window_size - 1 + max_shift);
        
        mov_patch = mov(y_start:y_end, x_start:x_end);
        
        % 应用STFT相位相关
        [dy, dx, conf] = stft_phase_correlation(ref_patch, mov_patch, window, max_shift);
        
        % 存储结果
        i = floor(y/step) + 1;
        j = floor(x/step) + 1;
        displacement.dx(i, j) = dx;
        displacement.dy(i, j) = dy;
        displacement.confidence(i, j) = conf;
        displacement.x_pos(i, j) = x + window_size/2;
        displacement.y_pos(i, j) = y + window_size/2;
        
        idx = idx + 1;
    end
end
end

2.3 STFT相位相关核心算法

matlab 复制代码
function [dy, dx, confidence] = stft_phase_correlation(ref_patch, mov_patch, window, max_shift)
% STFT相位相关计算位移

% 确保窗口大小一致
window_size = size(window, 1);
[h1, w1] = size(ref_patch);
[h2, w2] = size(mov_patch);

if h1 ~= window_size || w1 ~= window_size
    error('参考图像块大小与窗口不匹配');
end

% 对参考图像块加窗并计算FFT
ref_windowed = ref_patch .* window;
F_ref = fft2(ref_windowed);

% 对移动图像块中心区域加窗并计算FFT
center_y = floor((h2 - window_size)/2) + 1;
center_x = floor((w2 - window_size)/2) + 1;
mov_center = mov_patch(center_y:center_y+window_size-1, center_x:center_x+window_size-1);
mov_windowed = mov_center .* window;
F_mov = fft2(mov_windowed);

% 计算互功率谱
R = F_ref .* conj(F_mov);
R = R ./ (abs(R) + eps);  % 归一化,避免除以0

% 逆FFT得到相位相关平面
corr_plane = real(ifft2(R));

% 零频移到中心
corr_plane = fftshift(corr_plane);

% 在允许的位移范围内寻找峰值
center = floor(window_size/2) + 1;
search_range = max_shift;

y_start = center - search_range;
y_end = center + search_range;
x_start = center - search_range;
x_end = center + search_range;

% 确保索引在范围内
y_start = max(1, y_start);
y_end = min(window_size, y_end);
x_start = max(1, x_start);
x_end = min(window_size, x_end);

% 提取搜索区域
search_region = corr_plane(y_start:y_end, x_start:x_end);

% 找到峰值位置
[max_val, max_idx] = max(search_region(:));
[peak_y, peak_x] = ind2sub(size(search_region), max_idx);

% 计算亚像素精度(通过二次拟合)
if peak_y > 1 && peak_y < size(search_region, 1) && ...
   peak_x > 1 && peak_x < size(search_region, 2)
    % y方向二次插值
    y_vals = search_region(peak_y-1:peak_y+1, peak_x);
    y_offset = quadratic_interpolation(y_vals);
    
    % x方向二次插值
    x_vals = search_region(peak_y, peak_x-1:peak_x+1);
    x_offset = quadratic_interpolation(x_vals');
    
    % 计算最终位移
    dy = (peak_y - 1 + y_offset) - search_range - 1;
    dx = (peak_x - 1 + x_offset) - search_range - 1;
else
    dy = peak_y - search_range - 1;
    dx = peak_x - search_range - 1;
end

% 置信度(峰值高度)
confidence = max_val;
end

function offset = quadratic_interpolation(vals)
% 二次插值求亚像素偏移
if vals(2) == 0
    offset = 0;
else
    offset = (vals(1) - vals(3)) / (2 * (vals(1) - 2*vals(2) + vals(3)));
end
end

2.4 估计全局变换

matlab 复制代码
function tform = estimate_global_transform(displacement, method)
% 从位移场估计全局变换

% 提取有效位移点(高置信度)
threshold = 0.5 * max(displacement.confidence(:));
valid_idx = displacement.confidence > threshold;

if sum(valid_idx(:)) < 4
    % 如果有效点太少,使用所有点
    valid_idx = displacement.confidence > 0;
end

% 获取对应点
x_src = displacement.x_pos(valid_idx);
y_src = displacement.y_pos(valid_idx);
x_dst = x_src + displacement.dx(valid_idx);
y_dst = y_src + displacement.dy(valid_idx);

% 根据方法选择变换类型
switch lower(method)
    case 'translation'
        % 计算平均平移
        mean_dx = mean(displacement.dx(valid_idx));
        mean_dy = mean(displacement.dy(valid_idx));
        
        tform = affine2d([1 0 0; 0 1 0; mean_dx mean_dy 1]);
        
    case 'affine'
        % 估计仿射变换
        [x_src, y_src] = prepare_points(x_src, y_src);
        [x_dst, y_dst] = prepare_points(x_dst, y_dst);
        
        % 使用最小二乘法
        A = zeros(2*length(x_src), 6);
        b = zeros(2*length(x_src), 1);
        
        for i = 1:length(x_src)
            A(2*i-1, :) = [x_src(i), y_src(i), 0, 0, 1, 0];
            A(2*i, :) = [0, 0, x_src(i), y_src(i), 0, 1];
            b(2*i-1) = x_dst(i);
            b(2*i) = y_dst(i);
        end
        
        % 求解参数
        params = A \ b;
        
        % 构建变换矩阵
        tform = affine2d([params(1) params(3) 0; params(2) params(4) 0; params(5) params(6) 1]);
        
    case 'projective'
        % 估计透视变换
        [x_src, y_src] = prepare_points(x_src, y_src);
        [x_dst, y_dst] = prepare_points(x_dst, y_dst);
        
        % 使用RANSAC估计
        tform = fitgeotrans([x_src, y_src], [x_dst, y_dst], 'projective');
        
    otherwise
        error('未知的变换类型');
end
end

function [x, y] = prepare_points(x, y)
% 准备点集,移除异常值
if length(x) > 100
    % 随机采样,避免计算量过大
    idx = randperm(length(x), min(100, length(x)));
    x = x(idx);
    y = y(idx);
end
end

2.5 可视化函数

matlab 复制代码
function visualize_registration(ref, mov, reg, displacement)
% 可视化配准结果

figure('Position', [100, 100, 1200, 800]);

% 原始图像对比
subplot(2, 3, 1);
imshowpair(ref, mov);
title('配准前(参考 vs 移动)');

% 配准后对比
subplot(2, 3, 2);
imshowpair(ref, reg);
title('配准后(参考 vs 配准)');

% 位移场
subplot(2, 3, 3);
quiver(displacement.x_pos(:), displacement.y_pos(:), ...
       displacement.dx(:), displacement.dy(:), 0);
axis ij; axis equal; axis tight;
title('局部位移场');

% 置信度图
subplot(2, 3, 4);
imagesc(displacement.confidence);
colorbar;
title('配准置信度');
xlabel('X位置'); ylabel('Y位置');

% 差分图像(配准前)
subplot(2, 3, 5);
diff_before = imabsdiff(ref, mov);
imshow(diff_before, []);
title(sprintf('配准前差分 (MSE=%.2f)', mean(diff_before(:).^2)));

% 差分图像(配准后)
subplot(2, 3, 6);
diff_after = imabsdiff(ref, reg);
imshow(diff_after, []);
title(sprintf('配准后差分 (MSE=%.2f)', mean(diff_after(:).^2)));

colormap('jet');
end

三、使用示例

3.1 基本使用

matlab 复制代码
% 示例1:平移配准
ref = imread('cameraman.tif');
mov = imtranslate(ref, [5.5, 3.2]); % 添加平移

% 使用STFT配准
[registered, tform, displacement] = stft_image_registration(...
    ref, mov, 'window_size', 64, 'overlap', 0.75, 'method', 'affine');

fprintf('估计的平移: dx=%.2f, dy=%.2f\n', ...
    tform.T(3,1), tform.T(3,2));

3.2 旋转和缩放配准

matlab 复制代码
% 示例2:旋转和缩放配准
ref = imread('pout.tif');
mov = imrotate(ref, 5, 'bilinear', 'crop'); % 旋转5度
mov = imresize(mov, 1.02); % 缩放2%

% 使用STFT配准(需要修改算法以处理旋转缩放)
[registered, tform, displacement] = stft_image_registration(...
    ref, mov, 'window_size', 128, 'overlap', 0.5, 'method', 'affine');

3.3 弹性配准

matlab 复制代码
% 示例3:局部形变配准
function demo_elastic_registration()
    % 创建测试图像
    ref = imread('coins.png');
    ref = imresize(ref, [256, 256]);
    
    % 创建非线性形变
    [X, Y] = meshgrid(1:256, 1:256);
    Xd = X + 10 * sin(2*pi*Y/128);
    Yd = Y + 10 * sin(2*pi*X/128);
    
    % 应用形变
    mov = interp2(double(ref), Xd, Yd, 'linear', 0);
    mov = uint8(mov);
    
    % STFT配准(局部位移)
    params.window_size = 32;
    params.overlap = 0.75;
    params.max_shift = 15;
    
    displacement = compute_local_displacement(ref, mov, params);
    
    % 可视化局部位移场
    figure;
    quiver(displacement.x_pos(:), displacement.y_pos(:), ...
           displacement.dx(:), displacement.dy(:), 0);
    axis ij; axis equal; axis tight;
    title('弹性形变位移场');
end

四、高级功能:旋转/缩放不变配准

matlab 复制代码
function [theta_est, scale_est] = estimate_rotation_scale(ref, mov)
% 使用傅里叶梅林变换估计旋转和缩放

% 转换为频域
F1 = fft2(double(ref));
F2 = fft2(double(mov));

% 幅度谱(移到中心)
M1 = fftshift(log(abs(F1) + 1));
M2 = fftshift(log(abs(F2) + 1));

% 转换为极坐标
[r1, theta1] = polar_transform(M1);
[r2, theta2] = polar_transform(M2);

% 使用相位相关估计旋转
[~, rotation] = phase_correlation(r1, r2);
theta_est = rotation;

% 使用相位相关估计缩放(通过对数径向坐标)
[~, scale] = phase_correlation(theta1, theta2);
scale_est = exp(scale);

% 应用估计的旋转和缩放进行补偿
mov_corrected = imrotate(mov, -theta_est, 'bilinear', 'crop');
mov_corrected = imresize(mov_corrected, 1/scale_est);
end

function [r, theta] = polar_transform(image)
% 将图像从笛卡尔坐标转换到极坐标
[M, N] = size(image);
center = [floor(N/2), floor(M/2)];
max_radius = min(center);

% 创建极坐标网格
rho = linspace(0, max_radius, M);
theta_angles = linspace(0, 2*pi, N);

[r, theta] = meshgrid(rho, theta_angles);

% 插值
X = center(1) + r .* cos(theta);
Y = center(2) + r .* sin(theta);

polar_image = interp2(image, X, Y, 'linear', 0);
r = polar_image;
end

五、性能优化建议

matlab 复制代码
% 1. 使用并行计算加速
function displacement = compute_local_displacement_parallel(ref, mov, params)
    % 开启并行池
    if isempty(gcp('nocreate'))
        parpool;
    end
    
    % 并行计算位移
    [rows, cols] = size(ref);
    window_size = params.window_size;
    step = round(window_size * (1 - params.overlap));
    
    % 预分配
    y_positions = 1:step:rows-window_size;
    x_positions = 1:step:cols-window_size;
    
    % 并行循环
    parfor idx = 1:length(y_positions)*length(x_positions)
        [i, j] = ind2sub([length(y_positions), length(x_positions)], idx);
        % ... 并行计算每个块的位移
    end
end

% 2. GPU加速
function displacement_gpu = compute_local_displacement_gpu(ref, mov, params)
    % 将数据传输到GPU
    ref_gpu = gpuArray(ref);
    mov_gpu = gpuArray(mov);
    
    % 在GPU上执行FFT和相关计算
    % ... GPU加速的相位相关代码
    
    % 将结果传回CPU
    displacement_gpu = gather(result_gpu);
end

参考代码 STFT算法,用于图像处理中的图像配准 www.3dddown.com/csa/96468.html

六、注意事项

  1. 窗口大小选择

    • 纹理丰富区域:小窗口(32×32)
    • 纹理稀疏区域:大窗口(64×64或更大)
  2. 重叠比例

    • 高重叠(0.75)提高精度但增加计算量
    • 低重叠(0.5)减少计算但可能错过细节
  3. 应用场景

    • 医学图像(超声、OCT)配准
    • 遥感图像对齐
    • 显微图像拼接
  4. 局限性

    • 大形变需要多尺度策略
    • 无纹理区域配准困难
    • 计算量相对较大
相关推荐
sa1002715 小时前
基于Python的京东评论爬虫
开发语言·爬虫·python
ii_best15 小时前
安卓/ios脚本开发辅助工具按键精灵横纵坐标转换教程
android·开发语言·ios·安卓
a31582380616 小时前
Android 大图显示策略优化显示(二)
android·java·开发语言·javascript·kotlin·glide·图片加载
月明长歌16 小时前
Java多线程线程池ThreadPoolExecutor理解总结:6 个核心参数 + 4 种拒绝策略(附完整示例)
java·开发语言
学编程的小鬼16 小时前
JVM 常见的问题
开发语言·jvm
故事不长丨16 小时前
C#File文件操作全解析:从基础用法到异常处理
服务器·开发语言·visualstudio·c#·文件操作·io流·file
lowhot16 小时前
C语言UI框架
c语言·开发语言·笔记·ui
gihigo199816 小时前
使用MATLAB绘制3D心形图和玫瑰花图案
开发语言·matlab·3d
柠檬叶子C16 小时前
【Python】解决 No module named ‘imp‘ 问题 | Python3 中废弃的 imp 模块
开发语言·python