使用SimpleITK复制元数据,修复Seg3D处理后分割图像与MRI的对齐问题
问题背景
我有一个分割图像(original_image),原本和它来源的MRI图像叠加时完全匹配(比如在3D Slicer中查看)。但在Seg3D中对该分割图像操作并保存后得到new_image,新图像和原MRI叠加时出现位移、旋转,无法对齐。我用SimpleITK写了个函数尝试复制原图像的所有元数据/头信息,但问题没解决,只有图像中心位置正确。
尝试的代码
def save_itk_keeping_header(new_image, original_image, filename): image_bad_header_itk=sitk.ReadImage(new_image) image_good_header=sitk.ReadImage(original_image) image_bad_header_itk.CopyInformation(image_good_header) image_bad_header_itk.SetDirection(image_good_header.GetDirection()) image_bad_header_itk.SetOrigin(image_good_header.GetOrigin()) [image_bad_header_itk.SetMetaData(key,image_good_header.GetMetaData(key)) for key in image_good_header.GetMetaDataKeys()] sitk.WriteImage(image_bad_header_itk, filename, True)
输出的新分割图像看起来需要旋转90度才能和MRI对齐,而MRI坐标系通常和CT的XYZ坐标系存在旋转差异。
问题分析
你的代码里CopyInformation()已经会自动复制Origin、Direction、Spacing这些核心空间信息,后面重复调用SetDirection()和SetOrigin()属于冗余操作,但这不是问题根源。
真正的问题是Seg3D保存时改变了图像数据的维度顺序/排列,导致空间头信息和实际像素数据的对应关系错位。MRI常用的坐标系和CT不同,Seg3D可能默认用了CT的轴序来保存,使得数据本身的排列和原MRI的空间方向不匹配,只复制头信息的话,相当于给错位的数据套了正确的空间标签,自然出现旋转/位移的错觉。
解决步骤
1. 先确认空间参数差异
先打印两幅图像的关键空间参数,明确问题所在:
new_image = sitk.ReadImage(new_image_path) original_image = sitk.ReadImage(original_image_path) print("原图像方向矩阵:", original_image.GetDirection()) print("新图像方向矩阵:", new_image.GetDirection()) print("原图像尺寸:", original_image.GetSize()) print("新图像尺寸:", new_image.GetSize())
如果尺寸一致但方向矩阵呈现旋转关系,说明数据维度顺序被改变了。
2. 调整图像数据的轴序
用SimpleITK的PermuteAxesImageFilter()调整数据的维度排列,匹配原图像的空间逻辑。比如如果需要交换Y轴和Z轴(对应90度旋转的常见情况),示例代码如下:
permuter = sitk.PermuteAxesImageFilter() permuter.SetOrder((0, 2, 1)) # 参数是轴的新顺序,根据实际差异修改 new_image = permuter.Execute(new_image)
轴序参数需要根据方向矩阵的对比结果来确定,比如原图像的Z轴对应新图像的Y轴,就需要对应调整顺序。
3. 精简代码,避免冗余操作
不需要复制所有元数据,部分元数据(如DICOM专属标签)可能和新图像不兼容,反而引发问题。只保留核心的空间信息复制即可。
修正后的完整代码
def save_itk_keeping_header(new_image_path, original_image_path, output_filename): # 读取图像 new_image = sitk.ReadImage(new_image_path) original_image = sitk.ReadImage(original_image_path) # 调整轴序:这里以交换Y和Z轴为例,请根据实际参数对比结果修改 permuter = sitk.PermuteAxesImageFilter() permuter.SetOrder((0, 2, 1)) new_image = permuter.Execute(new_image) # 复制原图像的空间信息(Origin、Direction、Spacing) new_image.CopyInformation(original_image) # 保存处理后的图像 sitk.WriteImage(new_image, output_filename, True)
内容的提问来源于stack exchange,提问作者Cristóbal Rodero Gómez

