You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何保留原点裁剪NIFTI图像?代码实现后位置偏移问题求助

NIfTI图像裁剪后中心对齐异常的解决方法

问题描述

我拥有一个尺寸为512x512x460的NIFTI图像,希望将其裁剪为512x216x460的尺寸,同时保留图像原点信息。

尝试的代码如下:

import nibabel as nib
import numpy as np

def cropNifti(img_path, out_path, crop_width=256, crop_height=512):
        
    # Load the NIfTI file
    img = nib.load(img_path)

    # Get the image data
    data = img.get_fdata()

    # Calculate the dimensions for the central crop
    original_shape = data.shape
    central_x = original_shape[0] // 2
    central_y = original_shape[1] // 2
    start_x = max(0, central_x - crop_width // 2)
    end_x = min(original_shape[0], central_x + crop_width // 2)
    start_y = max(0, central_y - crop_height // 2)
    end_y = min(original_shape[1], central_y + crop_height // 2)

    # Calculate the centering offsets
    offset_x = (crop_width - (end_x - start_x)) // 2
    offset_y = (crop_height - (end_y - start_y)) // 2

    # Crop each slice to the central region and center it
    cropped_data = np.zeros((crop_height, crop_width, original_shape[2]), dtype=data.dtype)
    for i in range(original_shape[2]):
        cropped_data[offset_y:(end_y - start_y + offset_y), offset_x:(end_x - start_x + offset_x), i] = data[start_y:end_y, start_x:end_x, i]

    # Save the cropped and centered image
    cropped_img = nib.Nifti1Image(cropped_data, img.affine, img.header)
    nib.save(cropped_img, out_path)    

img_path = r"some\path"
out_path = r"some\other\path"

cropNifti(img_path, out_path)

实际结果:裁剪后的图像未与原图像中心重叠,而是裁剪图左边缘与原图中心对齐。保留img.affine和img.header参数也未解决问题。用SimpleITK裁剪能居中,但体素大小被缩放,无法用于深度学习流程。


问题原因

  1. 轴顺序混淆:Nibabel中NIfTI数据的形状是(x, y, z),但代码中创建cropped_data时用了(crop_height, crop_width, original_shape[2]),颠倒了x和y轴顺序,导致裁剪区域计算错误。
  2. Affine矩阵未更新:直接复用原affine矩阵会导致物理原点偏移错误——裁剪后图像的物理位置需要对应调整,才能保证中心对齐。

修正后的代码

import nibabel as nib
import numpy as np

def crop_nifti(img_path, out_path, target_shape=(512, 216, 460)):
    # 加载NIfTI图像
    img = nib.load(img_path)
    data = img.get_fdata()
    original_shape = data.shape
    affine = img.affine.copy()
    header = img.header.copy()

    # 验证目标尺寸的合理性(仅裁剪y轴,x、z轴保持原尺寸)
    assert target_shape[0] == original_shape[0], "x轴尺寸需与原图一致"
    assert target_shape[2] == original_shape[2], "z轴尺寸需与原图一致"
    
    # 计算y轴中心裁剪的起始/结束索引
    y_center = original_shape[1] // 2
    y_crop_size = target_shape[1]
    start_y = y_center - y_crop_size // 2
    end_y = start_y + y_crop_size

    # 直接裁剪数据(无需零填充)
    cropped_data = data[:, start_y:end_y, :]

    # 更新Affine矩阵:调整y轴物理原点
    y_voxel_size = affine[1, 1]
    y_physical_offset = start_y * y_voxel_size
    affine[1, 3] += y_physical_offset

    # 更新Header中的图像尺寸信息
    header['dim'][1:4] = target_shape

    # 保存裁剪后的图像
    cropped_img = nib.Nifti1Image(cropped_data, affine, header)
    nib.save(cropped_img, out_path)

# 调用示例
img_path = r"some\path"
out_path = r"some\other\path"
crop_nifti(img_path, out_path)

关键修正说明

  • 轴顺序对齐:保持data[:, start_y:end_y, :]的索引顺序与原图像一致,避免轴混淆。
  • Affine矩阵调整:根据y轴裁剪的起始索引计算物理偏移量,更新affine矩阵的y轴原点坐标,确保裁剪后图像的物理中心与原图像完全重叠。
  • Header同步更新:修改header中的尺寸元数据,保证NIfTI文件的元数据与实际数据匹配。
  • 简化逻辑:仅裁剪y轴,无需额外填充,直接切片即可,符合深度学习流程对数据简洁性的要求。

SimpleITK问题补充

如果使用SimpleITK时出现体素缩放,是因为未保留原图像的Spacing参数。裁剪时需手动设置输出图像的Spacing与原图一致,避免自动调整。但Nibabel的修正方案更直接,更适配深度学习场景。

内容的提问来源于stack exchange,提问作者Rico

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 18:25:26