如何保留原点裁剪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裁剪能居中,但体素大小被缩放,无法用于深度学习流程。
问题原因
- 轴顺序混淆:Nibabel中NIfTI数据的形状是
(x, y, z),但代码中创建cropped_data时用了(crop_height, crop_width, original_shape[2]),颠倒了x和y轴顺序,导致裁剪区域计算错误。 - 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
相关产品推荐
相关产品推荐

