一、项目任务定义
任务目标:对肺部CT图像进行肺结节分割,即从三维CT影像中自动分割出结节区域。这是计算机辅助诊断(CAD)系统中的关键任务,可帮助放射科医师定量分析结节(如体积、形态),并为良恶性判别提供依据。
输入:肺部CT扫描(DICOM格式或NIfTI格式)。
输出:与输入CT相同空间的三维二值掩膜(mask),其中1表示结节,0表示背景。
模型选择:Swin UNETR
二、数据获取与索引构建
2.1 主要数据集:LIDC-IDRI
LIDC-IDRI(The Lung Image Database Consortium)是最权威的肺部CT公开数据集:
-
规模:1018例胸部CT扫描
-
标注:4位放射科专家对肺结节进行了精细标注
-
格式:DICOM格式图像 + XML格式标注文件
-
下载方式:通过TCIA(The Cancer Imaging Archive)获取
下载步骤:
-
点击"Download"按钮,需要安装NBIA Data Retriever工具
-
选择下载内容:Images(125GB)+ Radiologist Annotations/Segmentations(XML格式)
-
等待下载完成(建议使用批量下载,总大小约125GB)
下载后得到一系列以 LIDC-IDRI-xxxx 命名的文件夹,内部为嵌套的DICOM文件。
你需要将它们统一移动到你的工作目录下,例如 /data/LIDC-IDRI/。一个典型的患者文件夹结构如下:
text
/data/LIDC-IDRI/LIDC-IDRI-0001/
└── 1.3.6.1.4.1.14519.5.2.1.6279.6001.298806137288633454246975630960/ # 这是一次CT检查的UID
└── 1.3.6.1.4.1.14519.5.2.1.6279.6001.179049374636540457614693186292/ # 系列文件夹
└── *.dcm # 一系列的DICOM文件
我们后续的代码会递归地读取这个结构。
2.2 辅助工具:pylidc
处理LIDC-IDRI的XML标注需要专用工具。pylidc 是一个Python库,封装了读取DICOM系列和XML标注的复杂逻辑,可快速获取CT体积和结节共识掩膜。
安装:
bash
pip install pylidc # 若遇numpy兼容问题,可尝试: pip install pylidc-updated
配置索引:
pylidc需要一个配置文件来告诉它你的LIDC-IDRI数据集存放在哪里。如果不做这一步,pylidc就无法定位你的DICOM文件。
-
找到你的用户目录 (Home Directory)
-
Windows: 通常是
C:\Users\你的用户名 -
Linux / macOS: 通常是
/home/你的用户名或/Users/你的用户名
-
-
创建配置文件
在你找到的用户目录下,创建一个文本文件,文件名和扩展名取决于你的操作系统:-
Windows: 创建文件名为
pylidc.conf的文件。 -
Linux / macOS: 创建文件名为
.pylidcrc的文件 (注意文件名前有一个点)。
-
-
编辑配置文件
用记事本或其他文本编辑器打开这个文件,输入以下内容:ini
[dicom] path = /data/LIDC-IDRI/
请务必将
/data/LIDC-IDRI/替换为你电脑上存储LIDC-IDRI数据集的真实路径。例如,如果你的数据在D盘的Datasets文件夹下,路径就是D:/Datasets/LIDC-IDRI/。这个配置文件的格式非常标准,被许多开发者验证和使用过。它告诉
pylidc去哪里寻找以LIDC-IDRI-xxxx命名的患者文件夹。
构建pylidc数据库:
配置完成后,需要让pylidc真正地去读取你的数据集,并建立一个索引数据库,这样后续的查询才能瞬间完成。pylidc使用SQLAlchemy作为ORM(对象关系映射)工具,将文件信息存储在一个轻量级的SQLite数据库中,极大地提高了数据访问效率。
打开你的终端(确保环境是激活的),然后运行以下Python命令:
bash
python -c "import pylidc; pylidc.mark_scan('/data/LIDC-IDRI/')"
请务必将 /data/LIDC-IDRI/ 再次替换为你的数据集路径。
等待索引构建完成(约30分钟~2小时)。
测试安装与配置:
在终端中进入Python交互环境:
python
import pylidc as pl # 尝试查询第一个患者 scan = pl.query(pl.Scan).first() print(scan) # 如果配置正确,你会看到类似这样的输出,而不会报错: # <Scan(patient_id=LIDC-IDRI-0001, ...)>
如果能成功打印出扫描信息,那么现在咱们的数据获取与索引构建这一步就大功告成了。你现在已经可以随时通过几行简单的Python代码,快速访问任何一个患者的CT数据和所有医生的结节标注了。
2.3 辅助工具:3D Slicer
在完成模型训练和预测后,如何直观地评估分割效果、观察结节形态,并与原始CT影像进行对比验证,是项目中不可或缺的一环。3D Slicer 正是完成这一任务的强大工具。
什么是3D Slicer?
3D Slicer是一个免费、开源的软件平台,专门用于医学图像的可视化、处理、分割和分析。它就像一个功能强大的“医学图像Photoshop”,不仅支持从二维CT切片重建出逼真的三维模型,还提供了丰富的工具来测量、编辑和评估分割结果。它由哈佛大学布莱根妇女医院和麻省理工学院等机构联合开发,拥有一个非常活跃的全球社区和众多扩展模块。
下载与安装
第一步:访问官方网站
打开浏览器,访问 3D Slicer 的官方下载页面:http://download.slicer.org/ 。
第二步:选择对应版本
页面会自动检测你的操作系统(Windows、macOS、Linux),并提供相应的安装包。建议选择最新的稳定版本(Stable Release),因为它经过了充分测试,运行更稳定。
第三步:安装软件
-
Windows用户:下载
.exe安装程序,双击运行,按照提示完成安装即可。 -
macOS用户:下载
.dmg文件,打开后将“3D Slicer”图标拖入“Applications”文件夹。 -
Linux用户:下载对应的压缩包,解压后运行文件夹内的
./Slicer脚本。
关于如何使用3D Slicer导入数据、调整显示、生成3D模型以及进行定量测量,我们将在本文 第五章 中结合模型预测结果进行详细演示。现在,请先完成安装,后续我们将用它来验证分割效果。
2.4 辅助工具:MONAI
在构建肺结节分割模型的过程中,我们需要处理大量三维数据、进行复杂的预处理和数据增强,并高效地训练先进的深度学习模型。MONAI(Medical Open Network for AI) 正是为此而生的开源框架,它基于PyTorch,专门为医疗影像领域设计,能显著提升开发效率和模型性能。
什么是MONAI?
MONAI 是由 NVIDIA 和 Kings College London 等机构联合开发的医疗影像深度学习框架,现已成为该领域的事实标准。它提供了从数据加载、预处理、增强,到网络构建、损失函数、评估指标的全套工具,并与 PyTorch 生态无缝集成。MONAI 的核心优势包括:
-
医疗专用变换:内置了大量针对医疗影像的变换,如
Spacingd(重采样)、Orientationd(方向标准化)、CropForegroundd(裁剪前景)、RandCropByPosNegLabeld(根据正负样本随机裁剪)等,可直接处理三维医学图像。 -
灵活的数据集:
CacheDataset和PersistentDataset支持数据缓存,大幅减少IO开销,加速训练。 -
丰富的网络模型:实现了 Swin UNETR、UNETR、Attention UNet 等前沿模型,可直接调用。
-
优化的评估指标:提供 Dice、Hausdorff Distance、表面距离等多种指标,支持分布式计算。
-
与医学图像格式无缝对接:可直接加载 NIfTI、DICOM 等格式,无需额外转换。
安装MONAI
在你已配置好的 Python 环境中,通过 pip 即可安装:
bash
pip install monai
安装后,可通过以下命令验证:
python
import monai print(monai.__version__)
三、数据处理Pipeline
3.1 步骤一:生成原始结节掩膜(mask.py)
原始数据中,结节标注是XML格式的轮廓点集。我们需要将其转换为体素级别的三维掩膜,并融合多位医生的标注得到共识掩膜。
由于我使用的Python版本为3.13,而pylidc 内部使用了 Python 3.11 之后被移除的旧式 SafeConfigParser。所以在导入 pylidc 之前,手动为 configparser 添加 SafeConfigParser 别名:(同理修复了np.int的问题)
python
import configparser
# 为旧版本兼容性添加别名
if not hasattr(configparser, 'SafeConfigParser'):
configparser.SafeConfigParser = configparser.ConfigParser
# 然后再导入其他库
import os
import numpy as np
import nibabel as nib
import pylidc as pl
...
mask.py
python
import configparser
# 为旧版本兼容性添加别名(Python 3.13+ 修复)
if not hasattr(configparser, 'SafeConfigParser'):
configparser.SafeConfigParser = configparser.ConfigParser
import numpy as np
# 为旧版 pylidc 兼容性添加 np.int 别名(如果缺失)
if not hasattr(np, 'int'):
np.int = int # 将弃用的 np.int 映射到内置 int
import os
import numpy as np
import nibabel as nib
import pylidc as pl
from pylidc.utils import consensus
import warnings
warnings.filterwarnings("ignore")
# ==================== 配置参数 ====================
LIDC_ROOT = "/data/LIDC-IDRI/" # LIDC-IDRI根目录
OUTPUT_DIR = "./lidc_nodule_masks_raw/" # 原始mask输出目录
MIN_ANNOTATORS = 2 # 生成共识掩膜所需的最少医生数
CONFIDENCE_LEVEL = 0.5 # 共识阈值 (超过50%的医生同意)
PAD_WIDTH = [(20, 20), (20, 20), (0, 0)] # 裁剪结节时的padding,确保结节完整
# =================================================
os.makedirs(OUTPUT_DIR, exist_ok=True)
# 获取所有扫描
scans = pl.query(pl.Scan).all()
print(f"总共发现 {len(scans)} 个扫描")
for scan in scans:
pid = scan.patient_id
print(f"\n处理患者: {pid}")
try:
# 1. 加载原始CT图像 (返回3D numpy数组) —— 新版pylidc-updated只返回volume数组
vol = scan.to_volume(verbose=False) # vol shape: (Z, Y, X)
# 获取仿射矩阵(affine):优先从scan对象获取,否则手动构造
if hasattr(scan, 'affine'):
affine = scan.affine
else:
# 手动构造简单仿射(假设轴对齐,像素间距和层厚)

370

被折叠的 条评论
为什么被折叠?



