如何使用Python裁剪mhd格式MR三维影像并保存为新mhd文件
非正方形画幅MR mhd影像裁剪落地方案
核心逻辑:mhd格式为「头文件(.mhd)+裸数据(.raw)」的配对存储结构,裁剪操作不需要依赖原始DICOM文件,仅需完成体数据截取、空间几何参数校正、元数据映射三个核心步骤,最后重新生成配对的mhd/raw文件即可。
实现步骤
- 环境准备:安装SimpleITK、numpy、json三个依赖库,所有操作直接在本地完成,不需要上传数据。
- 原始数据读取:调用SimpleITK的
ReadImage()接口直接读入原始.mhd文件,接口会自动关联同目录下同名.raw文件,读入后可直接获取原始体数据、像素间距(Spacing)、影像原点(Origin)、方向矩阵(Direction)四类核心空间参数,读入时不要做任何重采样操作,保持原始非正方形画幅的像素精度。注意:调用
GetArrayFromImage()转numpy数组时,维度顺序为[z轴(层方向), y轴, x轴],和mhd头文件中记录的x/y/z顺序相反,后续裁剪操作不要写反索引。 - 裁剪范围确定与体数据截取:明确三个维度的保留区间,x/y为画幅所在平面维度,z为层扫维度,按像素索引直接截取numpy数组对应区间即可,全程不要做插值操作,避免改变原始MR信号值。记录裁剪后三个维度的像素总数,后续更新头文件使用。
- 空间参数校正:裁剪操作不会改变像素间距、方向矩阵,这两个参数直接沿用原始值即可;原点坐标需要根据裁剪起始索引重新计算,避免保存后影像空间位置错位:
新原点x值 = 原始原点x值 + x轴裁剪起始索引 * x轴像素间距
新原点y值 = 原始原点y值 + y轴裁剪起始索引 * y轴像素间距
新原点z值 = 原始原点z值 + z轴裁剪起始索引 * z轴像素间距 - DICOM元数据映射:加载存储了全量原始DICOM头信息的json文件,将患者信息、扫描参数(TR/TE/层厚等)、序列信息等字段,直接作为元数据键值对写入新的影像对象;注意跳过
DimSize/Origin/Spacing/ElementDataFile这类和裁剪后参数强相关的字段,避免旧值覆盖新计算的参数。 - 结果保存:将裁剪后的数组、校正后的空间参数、映射完成的元数据绑定到影像对象,调用
WriteImage()接口指定输出后缀为.mhd,接口会自动生成配对的.raw文件。
参考实现代码
import SimpleITK as sitk import numpy as np import json # 读入原始mhd数据 raw_img = sitk.ReadImage("original_mr.mhd") raw_array = sitk.GetArrayFromImage(raw_img) depth, height, width = raw_array.shape # 对应z,y,x维度 # 按需修改裁剪范围 示例为x轴左右各裁20像素,y轴上下各裁30像素,z轴全保留 x_start, x_end = 20, width - 20 y_start, y_end = 30, height - 30 z_start, z_end = 0, depth # 执行数组裁剪 cropped_array = raw_array[z_start:z_end, y_start:y_end, x_start:x_end] # 构建新影像对象 写入空间参数 cropped_img = sitk.GetImageFromArray(cropped_array) cropped_img.SetSpacing(raw_img.GetSpacing()) new_origin = ( raw_img.GetOrigin()[0] + x_start * raw_img.GetSpacing()[0], raw_img.GetOrigin()[1] + y_start * raw_img.GetSpacing()[1], raw_img.GetOrigin()[2] + z_start * raw_img.GetSpacing()[2] ) cropped_img.SetOrigin(new_origin) cropped_img.SetDirection(raw_img.GetDirection()) # 写入json存储的DICOM元数据 with open("dicom_header.json", "r", encoding="utf-8") as f: dicom_meta = json.load(f) skip_keys = {"DimSize", "Origin", "Spacing", "Direction", "ElementDataFile", "ElementNumberOfChannels"} for meta_key, meta_val in dicom_meta.items(): if meta_key not in skip_keys: cropped_img.SetMetaData(meta_key, str(meta_val)) # 保存结果 sitk.WriteImage(cropped_img, "cropped_mr.mhd")
结果校验要点
- 重新读入保存后的mhd文件,检查三个维度的像素数是否和裁剪目标一致,非正方形画幅是否符合预期
- 选取3个以上固定解剖标记点,对比原始影像和裁剪后影像的空间坐标,确认无位置偏移
- 抽查TR、TE、患者ID、序列名这类核心元数据,确认和json中存储的原始DICOM信息一致
内容的提问来源于stack exchange,提问作者Magi
相关产品推荐
相关产品推荐

