锥束CT(CBCT)三维重构算法:FDK算法详解与实现

锥束CT(Cone Beam Computed Tomography)是一种广泛应用于医学影像和工业检测的三维成像技术。FDK(Feldkamp-Davis-Kress)算法是锥束CT重建中最经典的滤波反投影算法,由Feldkamp、Davis和Kress于1984年提出。

FDK算法原理

FDK算法是对传统二维CT中滤波反投影(FBP)算法的扩展,用于处理锥形束投影几何。其核心思想是:

  1. 加权投影数据:根据几何关系对投影数据进行加权
  2. 滤波处理:对加权后的投影数据进行斜坡滤波
  3. 三维反投影:将滤波后的数据反投影到三维空间

数学表达

重建图像f(x,y,z)f(x,y,z)f(x,y,z)可表示为:
f(x,y,z)=12∫02πD2(D+s)2∫−∞∞DD2+u′2+v′2Pβ(u′,v′)h(u−u′)du′dβf(x,y,z) = \frac{1}{2} \int_0^{2\pi} \frac{D^2}{(D + s)^2} \int_{-\infty}^{\infty} \frac{D}{\sqrt{D^2 + u'^2 + v'^2}} P_\beta(u',v') h(u - u') du' d\betaf(x,y,z)=21∫02π(D+s)2D2∫−∞∞D2+u′2+v′2 DPβ(u′,v′)h(u−u′)du′dβ

其中:

  • DDD:源到旋转中心的距离
  • sss:体素点到源的距离在探测器平面上的投影
  • Pβ(u′,v′)P_\beta(u',v')Pβ(u′,v′):角度β\betaβ处的投影数据
  • h(u)h(u)h(u):斜坡滤波器

MATLAB代码

matlab 复制代码
function volume = fdk_reconstruction(projections, angles, DSD, DDR, vol_size, voxel_size)
% FDK锥束CT三维重建算法
% 输入:
%   projections: 投影数据 [探测器行数, 探测器列数, 投影角度数]
%   angles: 投影角度数组 (弧度)
%   DSD: 源到探测器的距离 (mm)
%   DDR: 源到旋转中心的距离 (mm)
%   vol_size: 重建体积尺寸 [x, y, z]
%   voxel_size: 体素尺寸 [dx, dy, dz] (mm)
% 输出:
%   volume: 重建后的三维体积数据

% 参数设置
[num_rows, num_cols, num_angles] = size(projections);
vol_x = vol_size(1); vol_y = vol_size(2); vol_z = vol_size(3);
dx = voxel_size(1); dy = voxel_size(2); dz = voxel_size(3);

% 创建滤波器(斜坡滤波器加Hamming窗)
filter = design_filter(num_cols);

% 初始化重建体积
volume = zeros(vol_x, vol_y, vol_z, 'single');

% 计算探测器参数
du = (2 * DDR * tan(0.5 * atan(num_cols * 0.5 / DSD))) / num_cols;
dv = du; % 假设正方形像素
u_center = (num_cols + 1) / 2;
v_center = (num_rows + 1) / 2;

% 创建网格坐标
[x, y, z] = meshgrid(...
    ((0:vol_x-1) - (vol_x-1)/2) * dx, ...
    ((0:vol_y-1) - (vol_y-1)/2) * dy, ...
    ((0:vol_z-1) - (vol_z-1)/2) * dz);

% 主重建循环
for angle_idx = 1:num_angles
    beta = angles(angle_idx);
    fprintf('处理角度 %d/%d (%.1f°)\n', angle_idx, num_angles, rad2deg(beta));
    
    % 获取当前角度投影
    proj = projections(:, :, angle_idx);
    
    % 1. 加权投影
    [U, V] = meshgrid(((1:num_cols) - u_center) * du, ((1:num_rows) - v_center) * dv);
    weight_factor = DSD ./ sqrt(DSD^2 + U.^2 + V.^2);
    weighted_proj = proj .* weight_factor;
    
    % 2. 滤波处理
    filtered_proj = filter_projections(weighted_proj, filter);
    
    % 3. 三维反投影
    % 计算旋转矩阵
    R = [cos(beta)  sin(beta) 0; 
         -sin(beta) cos(beta) 0;
         0          0         1];
    
    % 坐标旋转
    coords = [x(:)'; y(:)'; z(:)'];
    rotated_coords = R * coords;
    xr = reshape(rotated_coords(1,:), size(x));
    yr = reshape(rotated_coords(2,:), size(y));
    zr = reshape(rotated_coords(3,:), size(z));
    
    % 计算投影坐标
    u_proj = (DSD * yr) ./ (DDR - xr) / du + u_center;
    v_proj = (DSD * zr) ./ (DDR - xr) / dv + v_center;
    
    % 反投影权重
    weight = DSD^2 ./ (DSD - xr).^2;
    
    % 插值获取投影值
    valid_idx = (u_proj >= 1) & (u_proj <= num_cols) & ...
                (v_proj >= 1) & (v_proj <= num_rows);
    
    proj_vals = zeros(size(x), 'single');
    proj_vals(valid_idx) = interp2(filtered_proj, u_proj(valid_idx), v_proj(valid_idx), 'linear', 0);
    
    % 累加到体积
    volume = volume + proj_vals .* weight;
end

% 角度积分归一化
volume = volume * (2 * pi / num_angles);
end

%% 设计滤波器
function filter = design_filter(length)
% 设计斜坡滤波器(加Hamming窗)
    n = 0:(length-1);
    filter = zeros(1, length);
    
    % 斜坡滤波器
    filter(1) = 1 / (4); % 中心点
    even = mod(length, 2) == 0;
    
    if even
        filter(2:end) = -1./(pi^2 * (n(2:end) - 0.5).^2);
    else
        filter(2:end) = -1./(pi^2 * n(2:end).^2);
    end
    
    % 加窗(Hamming窗)
    window = hamming(length)';
    filter = filter .* window;
    
    % 归一化
    filter = filter / sum(abs(filter));
end

%% 投影滤波
function filtered_proj = filter_projections(proj, filter)
% 对投影数据进行滤波
    [num_rows, num_cols] = size(proj);
    filtered_proj = zeros(num_rows, num_cols, 'single');
    
    % 扩展投影数据(避免边界效应)
    padded_proj = zeros(num_rows, 2 * num_cols);
    padded_proj(:, 1:num_cols) = proj;
    
    % 频域滤波
    for i = 1:num_rows
        row = padded_proj(i, :);
        freq_row = fft(row);
        filtered_freq = freq_row .* fftshift(filter);
        filtered_row = real(ifft(filtered_freq));
        filtered_proj(i, :) = filtered_row(1:num_cols);
    end
end

%% 示例使用
function run_fdk_example()
% FDK重建示例

% 生成合成投影数据(Shepp-Logan 3D体模)
vol_size = [128, 128, 128]; % 体积尺寸
voxel_size = [0.5, 0.5, 0.5]; % 体素大小 (mm)
num_angles = 360; % 投影角度数
angles = linspace(0, 2*pi, num_angles); % 投影角度
DSD = 1000; % 源到探测器距离 (mm)
DDR = 500; % 源到旋转中心距离 (mm)

% 创建Shepp-Logan 3D体模
phantom_vol = phantom3d(vol_size(1));

% 生成投影数据
projections = simulate_projections(phantom_vol, angles, DSD, DDR, vol_size, voxel_size);

% 执行FDK重建
recon_vol = fdk_reconstruction(projections, angles, DSD, DDR, vol_size, voxel_size);

% 显示结果
figure;
subplot(1,3,1);
imshow(squeeze(phantom_vol(:,:,round(vol_size(3)/2))), []);
title('原始体模(中心切片)');
subplot(1,3,2);
imshow(squeeze(recon_vol(:,:,round(vol_size(3)/2))), []);
title('重建结果(中心切片)');
subplot(1,3,3);
imshow(projections(:,:,1), []);
title('投影数据示例');

% 显示三维重建结果
figure;
show_volume(recon_vol);
title('三维重建结果');
end

%% 辅助函数:三维体模生成
function vol = phantom3d(n)
% 生成3D Shepp-Logan体模
    vol = zeros(n, n, n);
    [x, y, z] = meshgrid(linspace(-1,1,n), linspace(-1,1,n), linspace(-1,1,n));
    
    % 定义椭球参数 [A, a, b, c, x0, y0, z0, phi, theta, psi]
    ellipsoids = [
        2.0  0.69  0.92  0.90  0.0  0.0  0.0  0  0  0
        -0.8 0.6624 0.874 0.88  0.0  0.0  0.0  0  0  0
        -0.2 0.1100 0.310 0.22  0.22 0.0  0.0  -18 0  10
        -0.2 0.1600 0.410 0.28  -0.22 0.0  0.0  18  0  10
        0.1  0.2100 0.250 0.41  0.0  0.35 0.0  0  0  0
        0.1  0.0460 0.046 0.05  0.0  0.1  0.0  0  0  0
        0.1  0.0460 0.046 0.05  0.0  -0.1 0.0  0  0  0
        0.1  0.0460 0.023 0.05  -0.08 -0.65 0.0  0  0  0
        0.1  0.0230 0.023 0.02  0.0  -0.65 0.0  0  0  0
        0.1  0.0230 0.046 0.02  0.06 -0.65 0.0  0  0  0
    ];
    
    for i = 1:size(ellipsoids, 1)
        A = ellipsoids(i,1);
        a = ellipsoids(i,2);
        b = ellipsoids(i,3);
        c = ellipsoids(i,4);
        x0 = ellipsoids(i,5);
        y0 = ellipsoids(i,6);
        z0 = ellipsoids(i,7);
        phi = deg2rad(ellipsoids(i,8));
        theta = deg2rad(ellipsoids(i,9));
        psi = deg2rad(ellipsoids(i,10));
        
        % 旋转矩阵
        Rz = [cos(psi) -sin(psi) 0; sin(psi) cos(psi) 0; 0 0 1];
        Ry = [cos(theta) 0 sin(theta); 0 1 0; -sin(theta) 0 cos(theta)];
        Rx = [1 0 0; 0 cos(phi) -sin(phi); 0 sin(phi) cos(phi)];
        R = Rz * Ry * Rx;
        
        % 坐标变换
        coords = [x(:)-x0, y(:)-y0, z(:)-z0] * R';
        X = reshape(coords(:,1), size(x));
        Y = reshape(coords(:,2), size(y));
        Z = reshape(coords(:,3), size(z));
        
        % 椭球方程
        idx = (X/a).^2 + (Y/b).^2 + (Z/c).^2 <= 1;
        vol(idx) = vol(idx) + A;
    end
end

%% 辅助函数:投影模拟
function projections = simulate_projections(vol, angles, DSD, DDR, vol_size, voxel_size)
% 模拟锥束CT投影
    [n, m, p] = size(vol);
    num_angles = length(angles);
    projections = zeros(m, p, num_angles, 'single');
    
    % 计算探测器尺寸
    max_dim = max(vol_size .* voxel_size);
    detector_size = ceil(2 * max_dim * DSD / DDR);
    
    % 创建探测器网格
    [u, v] = meshgrid(linspace(-1,1,p), linspace(-1,1,m));
    u = u * detector_size/2;
    v = v * detector_size/2;
    
    % 生成投影
    for i = 1:num_angles
        beta = angles(i);
        R = [cos(beta)  sin(beta) 0; 
             -sin(beta) cos(beta) 0;
             0          0         1];
        
        proj = zeros(m, p);
        
        % 计算投影矩阵
        for j = 1:m
            for k = 1:p
                % 计算射线方向
                source = [0; -DDR; 0]; % 源位置
                detector_point = [0; DDR; 0] + [u(j,k); 0; v(j,k)];
                
                % 旋转坐标系
                ray_dir = R * (detector_point - source);
                ray_dir = ray_dir / norm(ray_dir);
                
                % 计算射线与体模的交点
                % (这里简化处理,实际应用中应使用Siddon算法等)
                t_min = -max_dim;
                t_max = max_dim;
                
                % 步进累加
                num_steps = 200;
                step_size = (t_max - t_min) / num_steps;
                value = 0;
                
                for t = t_min:step_size:t_max
                    point = source + t * ray_dir;
                    % 转换为体素坐标
                    idx_x = round((point(1) + max_dim/2) / voxel_size(1));
                    idx_y = round((point(2) + max_dim/2) / voxel_size(2));
                    idx_z = round((point(3) + max_dim/2) / voxel_size(3));
                    
                    if idx_x >= 1 && idx_x <= n && ...
                       idx_y >= 1 && idx_y <= m && ...
                       idx_z >= 1 && idx_z <= p
                        value = value + vol(idx_x, idx_y, idx_z) * step_size;
                    end
                end
                
                proj(j,k) = value;
            end
        end
        
        projections(:,:,i) = proj;
    end
end

%% 辅助函数:三维数据显示
function show_volume(vol)
% 显示三维体积
    % 创建等值面
    p = patch(isosurface(vol, 0.5));
    isonormals(vol, p);
    p.FaceColor = 'red';
    p.EdgeColor = 'none';
    
    % 设置视图
    daspect([1 1 1]);
    view(3);
    axis tight;
    camlight;
    lighting gouraud;
end

FDK算法关键步骤详解

1. 投影数据加权

在锥束几何中,由于X射线路径长度不同,需要根据几何关系对投影数据进行加权:

matlab 复制代码
weight_factor = DSD ./ sqrt(DSD^2 + U.^2 + V.^2);
weighted_proj = proj .* weight_factor;

其中:

  • DSD:源到探测器的距离
  • U, V:探测器上的坐标

2. 滤波处理

FDK算法使用斜坡滤波器(Ram-Lak滤波器)进行滤波处理,通常加窗(如Hamming窗)以减少噪声:

matlab 复制代码
function filter = design_filter(length)
    % 斜坡滤波器核心
    filter(1) = 1 / (4);
    filter(2:end) = -1./(pi^2 * n(2:end).^2);
    
    % 加Hamming窗
    window = hamming(length)';
    filter = filter .* window;
end

3. 三维反投影

反投影过程将滤波后的投影数据映射回三维空间:

matlab 复制代码
% 计算投影坐标
u_proj = (DSD * yr) ./ (DDR - xr) / du + u_center;
v_proj = (DSD * zr) ./ (DDR - xr) / dv + v_center;

% 反投影权重
weight = DSD^2 ./ (DSD - xr).^2;

% 插值获取投影值
proj_vals(valid_idx) = interp2(filtered_proj, u_proj(valid_idx), v_proj(valid_idx), 'linear', 0);

% 累加到体积
volume = volume + proj_vals .* weight;

参考 锥束CT(CBCT)的三维重构算法(FDK)www.youwenfan.com/contentcso/65715.html

算法性能优化

  1. 并行计算:

    matlab 复制代码
    parfor angle_idx = 1:num_angles
        % 处理每个角度的投影
    end
  2. GPU加速:

    matlab 复制代码
    % 将数据转移到GPU
    projections_gpu = gpuArray(projections);
    volume_gpu = gpuArray(zeros(vol_size, 'single'));
    
    % 在GPU上执行计算
    % ...
    
    % 将结果传回CPU
    volume = gather(volume_gpu);
  3. 插值优化:

    • 使用最近邻插值加速(牺牲精度)
    • 使用三次样条插值提高精度(增加计算量)

总结

FDK算法作为锥束CT三维重建的基石算法,具有实现简单、计算效率高的优点。尽管存在锥束伪影等局限性,通过合理的优化和改进,仍然是实际应用中广泛使用的重建方法。随着计算能力的提升和新型算法的出现,锥束CT重建技术将继续向更高精度、更低剂量、更快速度的方向发展。

本实现提供了FDK算法的完整MATLAB实现,包括投影模拟、滤波处理、三维反投影等关键步骤,以及结果可视化功能,可作为锥束CT研究和开发的基础框架。

相关推荐
启观川13 分钟前
数据结构与算法-第 3 章 常用算法-贪心算法
数据结构·笔记·python·算法·贪心算法
对空六课24 分钟前
指标口径生效时间的版本查询实现
大数据·服务器·前端·算法·数据分析
对空六课29 分钟前
RFM分层边界变化的回溯计算
大数据·服务器·前端·数据库·人工智能·算法·数据分析
一勺思维36 分钟前
我为什么把 Agent 的核心逻辑从 LangChain 里搬出来手写
算法
碧海银沙音频科技研究院1 小时前
基于炬芯ATS308X的LE aduio LC3编解码算法功能实现
算法
小蒋观天下1 小时前
厂区人员徘徊游荡判别——基于时序轨迹速度的逗留行为分级算法落地
大数据·人工智能·深度学习·算法·机器学习·ai大模型
程序员清风1 小时前
堆与优先队列:从 Top K 到任务调度
java·数据结构·算法
shaibdoio1 小时前
瞬维AI技术拆解:AI获客智能体的双层漏斗算法原理
大数据·人工智能·算法
suhan1 小时前
【数据结构】四、串:串string、模式匹配BF\KMP、广义表
数据结构·后端·算法
hetao17338371 小时前
联盟场-提高组-R7 & ZYZSC-S-Round 11
c++·算法