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

锥束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) = \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\beta \]

其中:

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

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射线路径长度不同,需要根据几何关系对投影数据进行加权:

weight_factor = DSD ./ sqrt(DSD^2 + U.^2 + V.^2);
weighted_proj = proj .* weight_factor;

其中:

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

2. 滤波处理

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

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. 三维反投影

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

% 计算投影坐标
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)youwenfan.com/contentcna/65715.html

算法性能优化

  1. 并行计算

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

    % 将数据转移到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研究和开发的基础框架。

posted @ 2025-07-22 13:41  yijg9998  阅读(1141)  评论(0)    收藏  举报