dicom 文件转nii (坐标系转换)

Python3.8

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

1. NIfTI 坐标系与 DICOM 坐标系的差异

DICOM 坐标系:
  • 使用 左手系
    • X 轴:从患者左侧到右侧(L → R)。
    • Y 轴:从患者背部到前部(P → A)。
    • Z 轴:从患者脚部到头部(F → H)。
NIfTI 坐标系:
  • 使用 右手系
    • X 轴:从左到右。
    • Y 轴:从后到前。
    • Z 轴:从下到上。

由于这两个坐标系的手性不同,在从 DICOM 转换到 NIfTI 时,方向可能会发生翻转。这会影响 image_position_patient 的计算和显示。

如果不进行坐标系转换,代码如下

def dicom_to_nifti(dicom_path, output_nii_path):
    # 获取所有 DICOM 文件路径
    dicom_files = [os.path.join(dicom_path, f) for f in os.listdir(dicom_path) if f.endswith('.dcm')]

    # 加载 DICOM 数据并按 InstanceNumber 排序
    dicom_data = [pydicom.dcmread(f) for f in dicom_files]
    dicom_data.sort(key=lambda x: float(x.ImagePositionPatient[2]))  # 按 Z 轴排序

    # 提取像素数据并堆叠为 3D 数组
    pixel_data = [d.pixel_array for d in dicom_data]

    # 提取元信息
    rows, cols = dicom_data[0].Rows, dicom_data[0].Columns
    pixel_spacing = dicom_data[0].PixelSpacing  # (row_spacing, col_spacing)
    slice_thickness = float(dicom_data[0].SliceThickness)
    image_orientation_patient = np.array(dicom_data[0].ImageOrientationPatient)  # 6 个值
    image_position_patient = np.array(dicom_data[0].ImagePositionPatient)  # 3 个值

    # 计算仿射矩阵
    affine = np.eye(4)

    # X 方向
    affine[:3, 0] = image_orientation_patient[:3] * pixel_spacing[1]  # 列方向

    # Y 方向
    affine[:3, 1] = image_orientation_patient[3:] * pixel_spacing[0]  # 行方向

    # Z 方向
    z_direction = np.cross(image_orientation_patient[:3], image_orientation_patient[3:])
    affine[:3, 2] = z_direction * slice_thickness  # 切片方向

    # 源点坐标
    affine[:3, 3] = [image_position_patient[0], image_position_patient[1], image_position_patient[2]]

    pixel_data = np.transpose(pixel_data, (0, 1, 2))  # 不修改坐标
    # 打印仿射矩阵
    print("Adjusted Affine Matrix:\n", affine)
 
    # 创建 NIfTI 图像
    nifti_image = nib.Nifti1Image(pixel_data, affine)
    nib.save(nifti_image, output_nii_path)

图像的原点

结果如下,发现原点坐标是(89.06,-63.56,-1073.60)

修改代码:

pixel_data = np.transpose(pixel_data, (2, 1, 0))  # 假设需要从 ZYX 转换为 XYZ
pixel_data = np.flip(pixel_data, axis=1)

结果发现 原点坐标 (-249.56,-63.56,-887.60)

但是发现右下角坐标是(197.56,383.56,-887.60),是原点的相反数

修改代码:

# 计算仿射矩阵
    affine = np.eye(4)

    # X 方向的反方向
    affine[:3, 0] = -image_orientation_patient[:3] * pixel_spacing[1]  # 列方向

    # Y 方向的反方向
    affine[:3, 1] = -image_orientation_patient[3:] * pixel_spacing[0]  # 行方向

    # Z 方向
    z_direction = np.cross(image_orientation_patient[:3], image_orientation_patient[3:])
    affine[:3, 2] = z_direction * slice_thickness  # 切片方向

    # 源点坐标取相反数
    affine[:3, 3] = [-image_position_patient[0], -image_position_patient[1],   image_position_patient[2]]

注释上下翻转

#pixel_data = np.flip(pixel_data, axis=1)

最后结果:原点坐标(-197.56,-383.56,-887.6)

最后完整代码

def dicom_to_nifti(dicom_path, output_nii_path):
    # 获取所有 DICOM 文件路径
    dicom_files = [os.path.join(dicom_path, f) for f in os.listdir(dicom_path) if f.endswith('.dcm')]

    # 加载 DICOM 数据并按 InstanceNumber 排序
    dicom_data = [pydicom.dcmread(f) for f in dicom_files]
    dicom_data.sort(key=lambda x: float(x.ImagePositionPatient[2]))  # 按 Z 轴排序

    # 提取像素数据并堆叠为 3D 数组
    pixel_data = [d.pixel_array for d in dicom_data]

    # 提取元信息
    rows, cols = dicom_data[0].Rows, dicom_data[0].Columns
    pixel_spacing = dicom_data[0].PixelSpacing  # (row_spacing, col_spacing)
    slice_thickness = float(dicom_data[0].SliceThickness)
    image_orientation_patient = np.array(dicom_data[0].ImageOrientationPatient)  # 6 个值
    image_position_patient = np.array(dicom_data[0].ImagePositionPatient)  # 3 个值

    # 计算仿射矩阵
    affine = np.eye(4)

    # X 方向的反方向
    affine[:3, 0] = -image_orientation_patient[:3] * pixel_spacing[1]  # 列方向

    # Y 方向的反方向
    affine[:3, 1] = -image_orientation_patient[3:] * pixel_spacing[0]  # 行方向

    # Z 方向
    z_direction = np.cross(image_orientation_patient[:3], image_orientation_patient[3:])
    affine[:3, 2] = z_direction * slice_thickness  # 切片方向

    # 源点坐标取相反数
    affine[:3, 3] = [-image_position_patient[0], -image_position_patient[1], image_position_patient[2]]

    # 打印仿射矩阵
    print("Adjusted Affine Matrix:\n", affine)

    pixel_data = np.transpose(pixel_data, (2, 1, 0))  # 假设需要从 ZYX 转换为 XYZ
    #pixel_data = np.flip(pixel_data, axis=1)
    
    # 创建 NIfTI 图像
    nifti_image = nib.Nifti1Image(pixel_data, affine)
    nib.save(nifti_image, output_nii_path)
    print(f"NIfTI 文件已保存到: {output_nii_path}")

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值