TCIA下载Lung-PET-CT-Dx:从DICOM到目标检测数据全流程
2026/9/16 5:18:04 网站建设 项目流程

搞肺癌目标检测的人,多半都体会过找数据的痛苦。CT、PET这种多模态影像不像自然图像数据集,光“能下载”就不容易,再加上标注聊胜于无,普通人想复现一篇论文比登天还难。我这几年反复折腾过LIDC-IDRI、LUNA16、Lung-PET-CT-Dx,也包括一部分自家医院脱敏的数据,最后发现论“拿来主义”的性价比,TCIA上的Lung-PET-CT-Dx算是比较能打的一个:公开、带标注、有完整的PET和CT序列,还能直接支撑目标检测任务。所以这一期先从数据源讲起,手把手把TCIA上下载Lung-PET-CT-Dx的流程、工具、坑点全部过一遍,适合刚入场医学影像AI、以及想复现论文但苦于数据格式不熟的读者。

1. 为什么选Lung-PET-CT-Dx:肺癌目标检测的数据需求

1.1 医学影像目标检测的“数据荒”

普通目标检测有COCO、VOC、OpenImages,想训练直接拉下来就行。但医学影像领域没有这种条件,绝大多数公开数据集都有“三个不”的问题:要么不让下载,要么格式杂,要么只有图像没有标注。即便像LIDC-IDRI这种元老级数据集,结节标注也是XML形式,做检测还得自己转格式,做完才发现原始CT层厚、重建参数五花八门,预处理工作比训练模型还累。PET-CT类的数据更少,因为多模态扫描成本高、涉及核医学设备,普通机构很难大批量采集,公开的更是稀缺。

所以在选数据集之前,我给自己列了几个硬指标:第一,影像必须带可用的标注,且标注物理意义明确,肿瘤轮廓或矩形框都行;第二,要有PET和CT双序列,不能只有单一模态;第三,病例量要够,至少支撑训练、验证、测试三分;第四,授权许可宽松,能公开使用。这样筛下来,剩下的候选就不多了,Lung-PET-CT-Dx是其中最符合的一个。

1.2 Lung-PET-CT-Dx的数据内容

这个数据集最初由托马斯·杰斐逊大学团队放出,后来托管在TCIA上。它收集的是经病理确诊的非小细胞肺癌(NSCLC)患者的诊断性PET/CT扫描,集中了一批带有可见原发肿瘤和淋巴结转移的中晚期病例,并且由医学专家在PET/CT图像上勾画了肿瘤区域作为标注。除了图像,每个病例还附带了年龄、性别、组织学类型、AJCC分期等临床信息,这对做跨模态目标检测和预后分析都很有价值。

从目录上看,每个病例通常包含诊断性CT序列、PET序列,部分还带CT融合序列或RTSTRUCT、Segmentation标注。你如果只是做目标检测,通常主线是:用CT或PET图像作为输入,把肿瘤的包围盒作为输出;如果想做得更细,还可以用分割标注辅助训练或者做弱监督。需要提醒的是,TCIA上这个集合的文件组织比较“原生”,它不是打包好的npz或TFRecord,而是纯DICOM目录加标注对象,所以拿到手之后至少还需要做一次质检和转换才能喂给YOLOv8、mmdetection这类框架,这一点后面会详细展开。

2. 开始之前:TCIA平台、账号与下载工具

2.1 TCIA是什么,为什么数据“藏”在里面

TCIA(The Cancer Imaging Archive)是美国国家癌症研究所支持的医学影像开放数据库,收录了大量经过脱敏的影像学数据,每个Collection相当于一个课题项目的打包结果。它是目前医学影像AI领域的主要数据源之一,除了Lung-PET-CT-Dx之外,还有很多知名集合,比如LIDC-IDRI、QIN-GENIE、NSCLC-Radiomics也都在上面。

TCIA的数据访问方式比较特殊:它提供网页预览、REST API、NBIA Data Retriever三种主要途径。网页预览只能看缩略图和元数据,真正要批量下载影像必须使用NBIA Data Retriever客户端,或者直接对接它的API。我第一次用的时候也觉得很绕,但用顺之后会发现这套机制的好处:患者级、检查级、序列级三级颗粒度都能控制,想要哪个序列拉哪个序列,而不是一上来就把几十GB全糊给你。

2.2 注册账号与访问准备

访问TCIA的数据需要注册一个免费账号,入口在官网右上角,走邮箱验证就行。有些单位的网络出口对境外学术站点的访问策略很严格,尤其是需要长时段下载的场景,建议提前在运维那边报备域名白名单,否则下载到一半被掐断,整晚流量白跑。登录后,你能看到一个可以搜索Collection和检查项的页面,搜索“Lung-PET-CT-Dx”就能进入这个集合的详情页。

详情页会列出数据用途、引用文献、数据许可协议、总病例数和下载入口。建议先翻一下License条款,这个集合一般使用CC-BY类协议,意味着你可以自由使用,但要注明来源,不能歪曲数据用途。如果以后想发布开源模型或数据集,这个条款一定要留着,后面很多论文审稿人都会要求你交代数据来源和许可。

2.3 下载工具怎么选

我现在常用的下载方式有三种,按场景选:

  • 图形界面场景:NBIA Data Retriever。适合在Windows、Mac、Linux桌面上操作,对网络中断恢复和断点续传支持不错,我日常最常用。
  • 服务器批量场景:TCIA命令行下载工具或通过manifest文件写脚本。适合在无图形界面的计算集群上跑,也方便做自动化。
  • 精确筛选场景:TCIA REST API加上自己写脚本。适合只下载特定模态或特定患者,比较灵活但上手难度高一些。

如果只是想复现实验,我建议第一次使用NBIA Data Retriever,直观也不容易出错。下文的主要流程也会基于它来走,但命令行方法我会单开一节,毕竟不少人手里的训练机根本没有显示器。

3. 从TCIA获取Lung-PET-CT-Dx的完整实操流程

3.1 第一步:生成manifest文件

在Lung-PET-CT-Dx详情页,找到Download按钮,点击后会生成一个.tcia文件。这个文件本质上是个JSON清单,里面列出所有需要下载的Series UID,并不包含影像本身,可以把它理解成超市购物清单。这个文件不要直接双击,导入NBIA Data Retriever之后才会真正开始传输。

这里有个很常见的坑:浏览器下载manifest文件时,可能因为服务端或代理原因被截断,表现为文件体积只有几KB甚至0字节。判断方法很简单,用文本编辑器打开,里面应该能看到大段的SeriesInstanceUID和链接信息;如果打开是空的或格式乱掉,重新生成一次就可以了。我习惯把这个文件放到和下载输出目录同一个磁盘分区,避免跨盘复制时丢失。

3.2 第二步:用NBIA Data Retriever下载全部影像

打开NBIA Data Retriever,它会要求你选择一个输出目录,然后把manifest文件拖到窗口里。客户端会自动连上TCIA的存储服务,逐个队列下载。下载过程中可以看到当前患者、当前序列、剩余大小、传输速度等状态,个人体感比网页下载稳很多,断了也能续传。

这里面有几个选项值得注意:

  • Download type:分为Modality、CT、PET等按模态细分的选项。如果只做目标检测,通常先全下,免得后面想用某个模态时还要重新拉一遍。
  • Number of parallel downloads:并发下载数。我一般设4到6,太快容易触发服务端限速,太慢又浪费时间。
  • Retry/failed download:个别DICOM文件可能因为网络波动失败,客户端会标记出来,可以在结束后单独重试。

整个Lung-PET-CT-Dx全量体积在几十GB到上百GB这个量级,具体取决于是否包含原始PET原始计数和部分重建序列。首选下载速度固然重要,但更关键的是下载完成后做完整性校验,不要急着清理源文件。

3.3 第三步:命令行批量下载(适合服务器场景)

如果你手里只有一台没有图形界面的服务器,可以用TCIA官方提供的NBIA Data Retriever的命令行模式。大致流程是:先下载manifest文件,然后在服务器上执行类似这样的命令:

# 使用NBIA Data Retriever的命令行模式 java -jar NBIA-Data-Retriever.jar \ -mf Lung-PET-CT-Dx.tcia \ -d /data/tcia/lung-pet-ct-dx \ -c 4

参数大致含义是:-mf指定manifest文件,-d指定输出目录,-c指定并发数。不同版本参数可能有变化,建议先用-help确认一遍。命令行方式的好处是一次执行完不用盯屏幕,日志清晰,适合夜里挂机下载。也可以把这个命令包进shell脚本,循环处理多个manifest文件,实现多数据集批量拉取。

如果你是Python生态的重度用户,也可以直接调用TCIA的REST API按SeriesInstanceUID下载:先用manifest里的信息构造请求头,再逐个文件拉流。这样自由度更高,但需要自己处理认证、重试和断点续传,工程成本不低,不太建议首次使用就上手。

3.4 第四步:下载完的目录结构与完整性检查

下载完成后,目录结构一般是:

/data/tcia/lung-pet-ct-dx/ Patient-ID-1/ Study-UID-1/ Series-UID-CT/ 000001.dcm 000002.dcm Series-UID-PET/ 000001.dcm Series-UID-RTSTRUCT/ 1-1.dcm Patient-ID-2/ ...

每个.dcm就是一张DICOM图像,它既包含图像像素,也包含Header元数据。这时候不要急着进入训练,先用pydicom或者DICOM工具抽查一下文件能不能正常读取,再用dcmtk的dcmdump看看SeriesDescription、Modality等字段是否和预期一致。

我习惯写一个简单的统计脚本,把所有病例、序列的Modality和SeriesNumber列出来,生成一张表。这一步特别重要,因为TCIA上的数据虽然是公开的,但采集自不同机构不同设备,偶尔会有序列缺失或重复扫描,提前摸清分布能省下后面清理的麻烦。比如有些病例有两次CT扫描,不做人工审核的话目标检测训练集里就会出现同一患者不同位置的重复影像,直接干扰验证集评估。

4. 数据集结构拆解:从DICOM到目标检测标注

4.1 一个病例里到底有哪些东西

打开某一个病例的目录,你大概率会看到这么几类:

  • CT图像序列:诊断性CT,通常是像素间距0.97mm左右、层厚2~3mm的体数据。
  • PET图像序列:PET经过衰减校正重建,与CT层面基本对齐,但spacing和图像尺寸可能不同。
  • 融合图像序列:CT和PET融合后的图,DICOM里可能以伪彩色或参数化形式存在,目标检测一般不直接拿来做输入。
  • RTSTRUCT或Segmentation:专家勾画的肿瘤区域,这是转监督标注的核心。
  • 伴随文档或JSON:可能包含临床元数据,比如年龄、性别、AJCC stage等。

我的建议是把RTSTRUCT和Segmentation都保留下来。有些病例只给了其中一种,两种都留可以互相校验,也方便后期从目标检测扩展到分割任务。如果你在意肿瘤代谢活性,PET图像里的SUV值也是提取影像组学特征的重要基础,别在预处理时提前丢了。

4.2 RTSTRUCT标注到底是什么格式

RTSTRUCT是放射治疗领域早已广泛使用的标准格式。它不是一个体素掩膜,而是以“轮廓点集合”的方式存储感兴趣区域:每个ROI在每一层上记录一组点坐标,这些点是落在DICOM坐标系下的物理坐标,单位是毫米。所以直接当成mask读是读不出来的,必须先拿到CT/PET的Image Position Patient、Pixel Spacing、Slice Thickness等信息,把轮廓点重采样回体素坐标,才能得到3D掩膜。

如果不想自己写这套转换,可以借助Highdicom或dcmrtstruct2nii这类开源库,一步把RTSTRUCT转成NIfTI标签文件。我自己更常用dcmrtstruct2nii,因为它可以直接输出nii.gz,和SimpleITK、MONAI都能无缝衔接。不过这个库的更新频率不算高,转之前最好在少数病例上做可视化核对,避免出现ROI名称错位,比如把淋巴结勾画当成原发肿瘤。

4.3 从分割掩膜生成目标检测框

有了3D掩膜之后,目标检测的标注制作就简单了。如果你的框架是2D目标检测,需要逐层生成2D bbox:先找到有掩膜的Z轴层,再在这层上取掩膜外接矩形。如果目标是3D检测,则直接过一遍体素坐标求最小外接立方体,或者用mmdetection3d风格的中心点加尺寸表示。

下面给一段简单的2D bbox生成代码,假设你已经把RTSTRUCT转成了NIfTI,并用SimpleITK读进来了:

import SimpleITK as sitk import numpy as np seg = sitk.ReadImage("gtvt_1.nii.gz") arr = sitk.GetArrayFromImage(seg) # (Z, Y, X) for z in range(arr.shape[0]): mask = arr[z] > 0 if not mask.any(): continue ys, xs = np.where(mask) x_min, x_max = xs.min(), xs.max() y_min, y_max = ys.min(), ys.max() # 输出为YOLO风格归一化坐标:cx, cy, w, h h, w = mask.shape cx = ((x_min + x_max) / 2) / w cy = ((y_min + y_max) / 2) / h box_w = (x_max - x_min) / w box_h = (y_max - y_min) / h print(z, f"{cx:.6f} {cy:.6f} {box_w:.6f} {box_h:.6f}")

这段代码只是个起点。实际使用时要特别注意三点:一,DICOM里Z轴方向可能与numpy数组的第一个维度相反,需要用Origin和Direction做一次映射;二,同一层可能不止一个肿瘤区域,要做连通域拆分或者按ROI名称区分;三,如果有多个ROI,比如GTV和淋巴结,不要把不同类别混成同一个类别,训练时类别标签会打架。

4.4 影像处理:从DICOM序列到训练用numpy/TFRecord

目标检测框架一般吃的是PNG/JPEG或numpy数组,不是DICOM。所以还需要把CT和PET序列做一次统一预处理。常见做法是:用SimpleITK读取DICOM序列为3D体数据,做spacing重采样到统一分辨率,然后裁取出包含ROI的局部patch,再按层导出为2D图像,同时把对应的bbox标注保存成txt文件。

CT图像的HU值范围大约是-1024到3071,直接输入网络会损失信息,通常要做一个窗宽窗位裁剪,比如肿瘤病灶观察常用纵隔窗,窗位40、窗宽400,归一化到0~1后存成PNG或npy。PET图像则通常转为SUV单位,再做截断或对数变换。这些细节都不复杂,但不提前统一的话,模型会在测量层面学出一些奇怪的捷径,换一批数据立刻现形。

我更推荐把预处理做成流程化脚本,而不是每次手动调参数。全流程串起来以后,从原始DICOM到训练txt只需要一条命令,后续不管你是换模型还是加新数据,都不需要重新折腾一遍图像和标注对齐。这里有一个耗时点:spacing重采样在几百个病例上是比较吃CPU的,尤其是3D体积的线性插值,建议用多进程并行,每个病例一个worker,能明显缩短等待时间。

5. 常见问题与坑点实录

5.1 下载到一半失败,流量白跑

最典型的场景是:下班前挂上NBIA Data Retriever,第二天发现中途断了,部分文件failed,整晚白等。最有效的解法是不要把所有鸡蛋放一个篮子里,先下载一部分做通流程验证,再大批量执行;另外把并发数调低一点,4并发比8并发在长时间任务里稳定性高很多。下载结束后记得点Failed Download列表逐个重试,不要直接开下一阶段。

如果下载的是超大manifest,我建议先拆成几个小manifest分别下载。TCIA的manifest文件在网页端可以按Series粒度勾选,我到后面都是按“全部病例的CT+PET+RTSTRUCT”拆成三个清单分开拉,哪块断了就单独补哪块,比整体重试灵活。

5.2 DICOM读取时弹出一堆烦人警告

用pydicom读某些文件会看到类似“Unknown tag”或者“Invalid value”的警告,这通常是私有Tag或者非标准字符集导致的,不一定影响使用。但我建议不要在warning里淹没主要信息,可以先设置读取参数忽略部分错误,再单独校验图像像素能不能转成numpy数组。这里的关键不是消灭所有警告,而是确保你关心的字段Modality、Rows、Columns、PixelData准确无误。

私有Tag有时候会保存重要的设备参数,但绝大多数目标检测流程用不到。真需要排查时,可以用dcmdump把某个DICOM的所有Tag导出来放到文本里,再配合厂商文档比对,别在读取阶段被几百条warning干扰注意力。

5.3 影像方向、spacing不一致,直接喂网络必翻车

不同医院、不同机型扫描出来的图像,Patient Position、Image Orientation、Slice Spacing都可能不同。如果你不做处理直接按0、1、2维顺序去截,切片出来的2D图可能要么是反的,要么各层间距不一样,网络会在这些无谓的差异上浪费大量Capacity。我的做法是先统一resample到各向同性1mm或2mm分辨率,再用固定的方向约定输出,最后做一次随机抽层可视化,确认ROI确实落在图像里而不是被截掉。

这里有个操作细节:重采样后一定要同步更新bbox坐标。因为重采样改变了体素到物理空间的映射关系,旧坐标直接套在新图上,框就悬空或偏了。最安全的做法是先重采样,再在同一个物理坐标系下做标注映射,最后输出训练txt,顺序不要搞反。

5.4 目标检测类别不平衡:肿瘤和淋巴结数量完全不在一个量级

在Lung-PET-CT-Dx这类NSCLC数据里,原发肿瘤基本上每个病例都有,但转移性淋巴结只出现在部分病例里,而且大小差异巨大。我处理这类不平衡的常用策略是:先用大learning rate训几个epoch,看看两类别在验证集上的AP分别多少;如果差距过大,就对稀有类别做Patch采样,或者对类别损失加权,再不行就把淋巴结单独拆出来做一次难例挖掘。数据层面能做的还有Mosaic增强和Copy-Paste增强,虽然医学影像上用起来要小心伪影,但局部粘贴ROI到同序列其他区域,在实际训练里确实有效。

5.5 授权、引用和版权合规问题

医学影像数据的合规红线比普通数据高得多。TCIA上的Lung-PET-CT-Dx虽然可以公开使用,但你发表的论文或开源仓库中必须标注数据来源,引用TCIA以及原始文献,同时不能把病例的个人标识信息重新展示出来。如果在自己的业务系统里使用,建议再和所在机构的伦理审查委员会确认一遍,别看到License宽松就直接进生产环境。

6. 后续方向与建议

6.1 从目标检测到分割、生存分析

这个数据集的价值不仅仅是“做一个检测框”。由于带分割标注,你可以很自然地从目标检测扩展到分割任务;同时它附带临床分期和随访信息,又能支撑影像组学甚至多模态预后预测。我自己的时间线是先做检测,再补分割,最后尝试把临床变量引入模型,查看对肿瘤病灶判别的增益。每一步都复用同一套数据,只是标注格式和训练目标不同。

如果你对轻量化模型感兴趣,基于这个数据集蒸馏一个小模型也是不错的玩法。PET-CT输入通道多、分辨率高,先用大模型做Teacher,再用蒸馏方式压缩到几MB级别,在边缘设备上做辅助诊断会更现实。当然这是后话,前提仍然是先把数据链路跑通。

6.2 数据划分与实验管理

医学影像数据通常具有患者内相关性,同一个患者的多个slice不能既出现在训练集又出现在验证集,否则会严重高估模型表现。我建议按患者维度划分训练/验证/测试集,保证一个患者的全部数据只在其中一个集合里。划分完成后,把划分结果存成一份固定的CSV文件,所有实验都基于它加载,这样复现起来也方便。

同时建议把原始数据、中间产物和标注文件分开目录存放。原始DICOM只读不可变,中间产物可以随时删掉重新生成,标注文件和代码一起走版本管理。这个习惯能帮你减少很多“数据莫名其妙变了”的排查时间。

6.3 可以尝试的检测框架

框架方面,小病灶检测推荐YOLOv8、YOLOv5这类训练成本低的2D检测器,直接把resample后的切片喂进去就能跑;如果要做3D检测,mmdetection3d、MONAI的检测模块也都能用。不过这些框架大多针对自然图像或体数据做了适配,医学影像里小目标和低对比度问题仍然需要自己调anchor和使用更强的数据增强。建议先跑通一个最小可复现的baseline,再逐步加trick。

写到这里,整个从TCIA获取Lung-PET-CT-Dx并整理成目标检测可用格式的流程基本就串完了。我个人在实际操作中的体会是,数据获取阶段最耗时间的不是下载本身,而是“把DICOM变成模型能吃的格式”这个过程;所以第一次做的时候,一定不要急着全量下载,先拿两三个病例跑通从manifest到RTSTRUCT转mask、再到bbox生成的完整链路,确认每个环节输出都正常,再放开全量。这套流程跑顺之后,后面换其他TCIA数据集,基本只是换一个manifest文件和检查新的标注结构而已,效率会高很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询