学习笔记:基于3D分割实现自动判断脂肪肝和严重程度
核心技术: 3D医学图像分割 (PaddleSeg/MedicalSeg)、SimpleITK、Numpy
目标: 利用 AI 自动分割 CT 图像中的肝脏和脾脏,计算两者 CT 值比率,从而自动化诊断脂肪肝及其严重程度。
一、 项目背景与意义
1.1 临床问题:脂肪肝诊断
- 成因: 现代生活方式(高脂饮食、缺乏运动)导致甘油三酯在肝细胞内过度积累,形成脂肪肝。
- 诊断方法: 医学影像(B超、CT)是常用手段。CT 在检出率和特异性上优于 B超。
- CT诊断标准:
- 通过计算肝脏 CT 值与脾脏 CT 值的比率(肝脾比,L/S Ratio)来判断。
- 正常肝脏: L/S Ratio > 1.0
- 轻度脂肪肝: 0.7 ≤ L/S Ratio < 1.0
- 中度脂肪肝: 0.5 ≤ L/S Ratio < 0.7
- 重度脂肪肝: L/S Ratio < 0.5
- 当前痛点: 放射科医生需要手动在 CT 图像最大层面上选取肝脏和脾脏的感兴趣区域 (ROI),计算平均 CT 值,再计算比值。这个过程繁琐、耗时,且可能因 ROI 选择不同而引入主观误差。
1.2 AI 解决方案
- 利用深度学习中的语义分割技术,自动识别和勾画出 CT 扫描中完整的肝脏和脾脏区域。
- 基于分割结果,自动、客观地计算整个器官或代表性区域的平均 CT 值。
- 自动化计算肝脾比,并根据临床标准输出诊断结果(正常、轻/中/重度脂肪肝)。
- 目标: 提高诊断效率,减少医生重复性劳动,提升诊断的一致性和客观性。
二、 数据准备
- 数据来源: 整合自“医学图像十项全能挑战赛”(Medical Segmentation Decathlon) 中包含肝脏和脾脏的数据集。
- 数据量: 88 例训练/验证数据(带标注),4 例测试数据。
- 标注 (Mask):
- 背景: 0
- 肝脏: 1
- 脾脏: 2
- 格式: NIFTI (Neuroimaging Informatics Technology Initiative),文件扩展名为
.nii.gz
。这是一种医学影像领域常用的三维或四维数据格式。 - 可视化工具: ITK-SNAP 等医学影像查看软件。
三、 核心技术:MedicalSeg 3D 分割工具
- 框架: 基于 PaddlePaddle 的 PaddleSeg 分割套件。
- 组件: MedicalSeg 是 PaddleSeg 中专注于医疗 3D 图像分割的工具。
- 优势: 提供了针对医疗 3D 数据特点的预处理、模型、训练和评估流程。
- 参考: 项目作者提供了 MedicalSeg 的入门教程链接,方便快速上手。
四、 详细实现流程
4.1 环境与代码准备
- 克隆 PaddleSeg: 从 Gitee (或 GitHub) 克隆 PaddleSeg 仓库。
git clone https://gitee.com/PaddlePaddle/PaddleSeg.git
- 进入 MedicalSeg 目录:
cd PaddleSeg/contrib/MedicalSeg
- 安装依赖: 安装 MedicalSeg 所需的 Python 包。
pip install -r requirements.txt -i https://mirror.baidu.com/pypi/simple
4.2 数据解压与预处理
- 解压数据: 将
.nii.gz
文件解压到工作目录。unzip -o /home/aistudio/data/data194126/SpleenAndLiver.zip -d /home/aistudio/work
- 自定义预处理脚本: 将项目特定的预处理脚本 (
prepare_SpleenAndLiver.py
) 复制到 MedicalSeg 工具目录下。cp /home/aistudio/prepare_SpleenAndLiver.py /home/aistudio/PaddleSeg/contrib/MedicalSeg/tools/prepare_SpleenAndLiver.py
- 执行预处理:
- 运行该脚本,将 NIFTI 文件 (
.nii.gz
) 转换为模型训练所需的 NumPy (.npy
) 格式。 - 关键步骤 (推测
prepare_SpleenAndLiver.py
内包含):- 使用
SimpleITK
读取 NIFTI 文件。 - 重采样 (Resampling): 将不同来源、不同扫描参数的 CT 数据统一到固定的体素间距 (Spacing) 和尺寸 (Shape),例如项目中的
(128, 128, 128)
。这是为了让模型输入具有一致性。 - 窗宽窗位 (Windowing): 调整 CT 值的显示范围 (如
[-100, 300] HU
),突出肝脏和脾脏组织,抑制其他无关信息。 - 归一化 (Normalization): 将 CT 值缩放到 [0, 1] 或 [-1, 1] 范围,便于模型训练。
- 数据分割: 将数据集划分为训练集 (
train.txt
) 和验证集 (val.txt
)。 - 元数据保存: 生成包含数据参数(如原始尺寸、间距等)的 JSON 文件,供后续预测时恢复原始尺寸使用。
- 使用
python tools/prepare_SpleenAndLiver.py
- 运行该脚本,将 NIFTI 文件 (
4.3 模型训练
- 配置文件: 使用 YAML 文件 (
SpleenAndLiver.yml
) 定义训练参数,包括:- 模型结构 (例如 V-Net 或 UNet 变体)
- 数据集路径
- 学习率、优化器、损失函数 (如 Dice Loss)
- 训练轮次 (Epochs/Iterations)
- 数据增强策略
- 验证设置
- 开始训练: 运行
train.py
脚本。python3 train.py --config /home/aistudio/SpleenAndLiver.yml \ --save_dir "/home/aistudio/output/SpleenAndLiver_vent_128" \ --save_interval 70 --log_iters 20 \ --keep_checkpoint_max 4 \ --num_workers 1 --do_eval --use_vdl
--config
: 指定配置文件。--save_dir
: 指定模型和日志保存路径。--save_interval
: 每隔多少轮保存一次模型。--log_iters
: 每隔多少步打印一次日志。--keep_checkpoint_max
: 最多保存多少个检查点。--num_workers
: 数据加载使用的进程数。--do_eval
: 训练过程中进行验证。--use_vdl
: 使用 VisualDL 记录训练过程。
4.4 模型评估
- 验证集评估: 使用
val.py
脚本在验证集上评估最佳模型的性能。python3 val.py --config /home/aistudio/SpleenAndLiver.yml \ --model_path /home/aistudio/output/SpleenAndLiver_vent_128/best_model/model.pdparams \ --save_dir /home/aistudio/output/SpleenAndLiver_vent_128/best_model
- 评估指标: 主要使用 Dice Similarity Coefficient (Dice 系数),衡量预测分割结果与真实标签的重叠程度。范围 [0, 1],越接近 1 表示分割效果越好。
- 项目报告结果:整体 Dice: 0.9391, 肝脏 Dice: 0.9229, 脾脏 Dice: 0.8998。
4.5 模型导出
- 将训练好的模型参数 (
.pdparams
) 转换为推理部署所需的格式 (.pdmodel
,.pdiparams
)。python export.py --config /home/aistudio/SpleenAndLiver.yml \ --model_path /home/aistudio/output/SpleenAndLiver_vent_128/best_model/model.pdparams \ --save_dir /home/aistudio/export_model
五、 预测与后处理
目标:对新的 CT 数据进行分割,并将分割结果 (Mask) 转换回原始 CT 数据的空间,用于后续 CT 值计算。
5.1 预测流程
- 加载原始数据: 使用
SimpleITK
读取待预测的.nii.gz
文件。 - 数据预处理 (关键!):
- 获取原始图像的
Size
,Spacing
,Origin
,Direction
。 - 必须执行与训练时完全相同的预处理步骤:
- 重采样到模型输入尺寸 (e.g.,
(128, 128, 128)
) 和对应的new_spacing
。 - 应用相同的窗宽窗位 (
crop_wwwc
, e.g.,[-100, 300]
)。 - 转换为 NumPy 数组 (
float32
)。 - 归一化 (e.g.,
/ input_data.max()
)。 - 增加 Batch 和 Channel 维度 (
np.expand_dims
),符合模型输入要求 (e.g.,(1, 1, D, H, W)
或(1, 1, Z, Y, X)
)。
- 重采样到模型输入尺寸 (e.g.,
- 获取原始图像的
- 创建预测器: 使用 Paddle Inference API 加载导出的模型文件 (
.pdmodel
,.pdiparams
)。- 配置预测器(如启用 GPU、内存优化)。
- 执行预测: 将预处理后的 NumPy 数据输入预测器,得到输出的概率图或类别索引图 (NumPy 格式)。
- 输出形状: 预测结果通常是
(1, D, H, W)
或(1, Z, Y, X)
,表示每个体素属于哪个类别的概率或索引。
5.2 后处理与结果保存
- NumPy -> SimpleITK: 将预测得到的 NumPy Mask 转换回
SimpleITK.Image
对象。- 去除 Batch 维度 (
np.squeeze
)。 - 设置正确的
Spacing
(应为预处理时的new_spacing
)、Origin
和Direction
(应与重采样后的图像一致,或者直接从原始图像拷贝并调整)。 - 转换为合适的整数类型 (
sitk.sitkUInt8
)。
- 去除 Batch 维度 (
- 连通组件分析 (可选但推荐):
- 对每个预测类别 (肝脏=1, 脾脏=2) 分别进行处理。
- 阈值化: 提取单个类别的二值图像。
- 形态学开运算 (Optional):
sitk.BinaryMorphologicalOpeningImageFilter
,可以去除小的噪声点和细小连接。 - 最大连通域提取:
sitk.ConnectedComponent
+sitk.LabelIntensityStatisticsImageFilter
,保留体积最大的连通区域,去除可能存在的其他小分割区域(伪影或错误分割)。函数GetLargestConnectedCompont
实现了此功能。 - 将处理后的各类别结果合并回一个多类别的 Mask 数组。
- 结果重采样回原始空间 (关键!):
- 创建一个新的
SimpleITK.Image
对象,包含处理后的 Mask 数组。 - 必须将此 Mask 的
Spacing
,Origin
,Direction
设置为与原始 CT 图像一致。可以使用sitkMask.CopyInformation(mask_itk_new)
(如果mask_itk_new
已有正确信息) 或手动设置。 - 使用
sitk.ResampleImageFilter
将 Mask 重采样回原始 CT 图像的尺寸 (Size) 和间距 (Spacing)。 - 插值方法: 对于 Mask,应使用最近邻插值 (
sitk.sitkNearestNeighbor
),以保持清晰的边界和离散的标签值。 - 对齐: 确保最终 Mask 的元数据 (Size, Spacing, Origin, Direction) 与原始 CT
origin
完全一致。可以使用Mask.CopyInformation(origin)
。
- 创建一个新的
- 保存结果: 将最终处理好的、与原始 CT 对齐的 Mask 保存为
.nii.gz
文件。sitk.WriteImage(Mask, '/home/aistudio/pred_data.nii.gz')
- 可视化验证: 使用 ITK-SNAP 等工具加载原始 CT 和预测生成的 Mask,检查分割准确性和边界贴合度。
六、 自动计算肝脾比与诊断
有了与原始 CT 对齐的肝脏 (标签 1) 和脾脏 (标签 2) 的 Mask,可以进行 CT 值计算。
6.1 计算流程
- 加载数据: 读取原始 CT 图像 (
imgSitk
) 和预测生成的 Mask (maskSitk
)。转换为 NumPy 数组 (imgNp
,maskNp
)。 - ROI 采样策略: 为了获得稳健的 CT 均值,避免局部病变或伪影影响,采用随机采样多个小立方体 ROI 的方法。
- 目标: 在肝脏和脾脏内部各采样 N 个 (项目中 N=6,实际用了前5个) 10mm x 10mm x 10mm 的立方体。
- 体素尺寸计算: 根据 CT 图像的
Spacing
(x, y, z 方向上的物理间距,单位 mm/像素),计算 10mm 对应多少个体素 (lengthx
,lengthy
,lengthz
)。 - 循环处理每个器官 (肝脏/脾脏):
- 提取单个器官的二值 Mask (
temp
)。 - 确定采样范围: 使用
maskcroppingbox
函数找到该器官 Mask 的最小外接边界框,缩小随机采样的空间,提高效率。 - 随机中心点: 在边界框内随机生成一个坐标
(posZ, posY, posX)
作为立方体的起始点或中心点(代码中似乎是起始点)。 - 提取立方体 Mask: 从二值 Mask (
temp
) 中提取对应[sliceZ, sliceY, sliceX]
的小立方体。 - 有效性检查: 检查提取出的立方体 Mask 是否完全位于器官内部(即
np.sum(block) == lengthx*lengthy*lengthz
)。这是为了确保 ROI 完全在目标器官内,避免包含背景或其他组织。 - 计算 CT 总值: 如果立方体有效,则在原始 CT 图像 (
imgNp
) 的相同位置[sliceZ, sliceY, sliceX]
提取对应的 CT 值,并计算其总和 (np.sum(...)
)。存入label
字典对应器官的列表中。 - 重复采样,直到获取足够数量 (N=6) 的有效立方体 CT 总值。
- 提取单个器官的二值 Mask (
- 计算肝脾比:
- 组合配对: 使用
itertools.product
生成所有肝脏 ROI CT 总值和脾脏 ROI CT 总值的组合对(liver_sum, spleen_sum)
。项目中采样了 6 个,但实际计算时可能只用了 5 个有效值?(需要确认代码逻辑,输出显示采样了 6 个,但配对数量可能是 5x5=25 或 6x6=36)。 - 计算单个比值: 对每一对
(liver_sum, spleen_sum)
,计算比值liver_sum / spleen_sum
。(注意:这里是用 CT 总值相除,假设立方体体积相同,等效于平均 CT 值相除)。 - 计算平均比值: 计算所有配对比值的平均值 (
np.mean(cts)
),作为最终的肝脾比。
- 组合配对: 使用
- 诊断分级:
- 根据计算出的
mean_ct
和临床标准,判断脂肪肝类型。 - 输出诊断结果(“非脂肪肝”, “轻度脂肪肝”, “中度脂肪肝”, “重度脂肪肝”)。
- 根据计算出的
6.2 示例结果
- 肝脏 CT 总值列表 (6个):
[205964.0, 224356.0, 212064.0, 209330.0, 202258.0, 209558.0]
- 脾脏 CT 总值列表 (6个):
[203052.0, 209845.0, 221099.0, 221029.0, 223527.0, 206339.0]
- 计算得到的平均 CT 比值:
0.984765...
- 诊断结果: 轻度脂肪肝 (因为 0.7 ≤ 0.9847 < 1.0)
七、 总结与讨论
- 价值: 该项目成功演示了如何利用 3D 图像分割技术自动化处理一项重复性的临床诊断任务,展示了 AI 在医学影像辅助诊断方面的潜力。方法流程清晰,结合了分割模型和具体的临床计算逻辑。
- 局限性:
- 分割精度: 报告的 Dice 分数(肝 0.92, 脾 0.90)虽然不错,但在细节和边界处可能仍有改进空间,这会影响后续 CT 值计算的准确性。
- 数据量: 88 个训练样本对于深度学习模型来说可能偏少,尤其是在面对不同扫描设备、不同病患群体的差异时,模型的泛化能力可能有限。
- ROI 采样策略: 随机小立方体采样是一种方法,但其代表性和稳定性可能有待商榷。例如,是否应避开大血管区域?是否需要考虑器官形态?
- 验证: 项目主要在分割层面进行了验证,对于最终诊断结果的准确性(与医生手动诊断对比)缺乏量化评估。
八、 潜在改进方向
- 数据增强:
- 更多数据: 收集更多样化的、带有准确标注的 CT 数据。
- 数据扩增 (Data Augmentation): 应用更丰富的 3D 数据增强技术(如旋转、缩放、弹性变形、亮度/对比度调整、噪声添加等)来提升模型的鲁棒性。
- 模型优化:
- 尝试更先进的模型: 探索如 UNETR, SwinUNETR, nnU-Net 等在医学图像分割领域表现更优异的模型架构。
- 超参数调优: 对学习率、优化器、损失函数(如结合 Dice Loss 和 Cross-Entropy Loss)等进行更细致的调整。
- 迁移学习: 如果有更大规模的相关数据集(如其他腹部器官分割),可以考虑使用预训练模型进行迁移学习。
- 预处理/后处理优化:
- 预处理: 探索不同的窗宽窗位设置或自适应窗宽技术。研究更优的归一化方法。
- 后处理: 优化连通组件分析逻辑,可能结合形态学操作(腐蚀、膨胀)进一步平滑边界或去除伪影。考虑基于概率图进行阈值优化。
- 肝脾比计算改进:
- ROI 策略:
- 排除边缘/血管: 在采样 ROI 时,可以先对 Mask 进行腐蚀操作,确保采样区域位于器官内部较远位置,避开边界和主要血管。
- 采样密度: 根据器官大小调整采样数量或密度。
- 确定性采样: 采用非随机的、覆盖整个器官的网格采样或基于解剖区域的采样方法。
- 计算方法: 比较“先计算每个 ROI 的平均 CT 值再求比值”与“先计算整个器官(或多个 ROI)的平均 CT 值再求比值”的差异。研究更鲁棒的统计方法(如中位数比值、去除离群值等)。
- ROI 策略:
- 端到端验证:
- 临床对比: 将模型自动诊断结果与多位经验丰富的放射科医生的手动诊断结果进行盲法比较,评估准确率、敏感性、特异性、Kappa 一致性等指标。
- 性能测试: 对模型在不同硬件(CPU/GPU)上的推理速度进行测试。
- 用户界面/集成: 开发一个简单的图形用户界面 (GUI),方便医生上传 CT 数据、查看分割结果和自动诊断报告。
九、 关键学习点
- 理解了利用 CT 肝脾比诊断脂肪肝的临床原理和手动流程的痛点。
- 掌握了使用 PaddleSeg/MedicalSeg 进行 3D 医学图像分割的基本流程:数据准备、预处理、训练、评估、导出。
- 认识到 NIFTI 数据格式以及 SimpleITK 在读取、处理和写入医学影像中的重要作用。
- 理解了预处理一致性的重要性:训练和预测时必须采用完全相同的重采样、窗宽窗位、归一化等步骤。
- 理解了后处理的必要性:将模型输出的 Mask 转换回原始图像空间(尺寸、间距、方向)对于后续基于原始数据的计算至关重要,需要用到重采样和元数据拷贝。最近邻插值适用于 Mask 重采样。
- 学习了一种基于分割结果进行 ROI 采样并计算临床指标(肝脾比)的方法。
- 了解了常用的分割评估指标 Dice 系数。
- 认识到模型改进需要从数据、模型、处理流程等多个维度进行考虑。