尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Lung-PET-CT-Dx数据集下载与预处理:从TCIA到YOLO目标检测

Lung-PET-CT-Dx数据集下载与预处理:从TCIA到YOLO目标检测 最近在做医学影像相关的目标检测数据源这块绕不过去的一个公开数据集就是Lung-PET-CT-Dx托管在TCIAThe Cancer Imaging Archive上。这个数据集对肺肿瘤、胸腹部器官检测来说很经典尤其做PET/CT多模态目标检测的人基本都碰过它。但很多第一次接触TCIA的同学会被它的下载方式劝退点进去不是zip直链而是一堆DICOM、RTSTRUCT和manifest文件怎么把数据完整拿到手、怎么整理成目标检测能用的格式里面有不少门道。这篇文章我就从零开始讲清楚Lung-PET-CT-Dx到底是什么、怎么从TCIA把它批量下载下来以及下载之后要做哪些预处理才能喂给YOLO这类目标检测模型。适合刚入门医学影像AI、手里有显卡但还没找到合适数据集的同学也适合那些已经在用CT数据、但想转PET/CT双模态检测的工程人员。1. 先弄明白Lung-PET-CT-Dx到底是个什么样的数据集1.1 不是普通自然图像数据集而是完整的PET/CT影像集合Lung-PET-CT-Dx是TCIA上的一个Collection集合主要包含非小细胞肺癌患者的FDG-PET/CT扫描。它的核心价值在于同一个患者同时有CT和PET两种模态的图像而且已经由医生在解剖图像上做了精细标注标注内容包括肺部、心脏、肝脏、脾脏、肾脏等主要器官以及肿瘤区域。这类数据对目标检测来说等于同时给了你“图像”和“真实框来源”不用自己从头画标注。这和KITTI、COCO这类自然图像数据集完全不同。KITTI给你的是jpg图片和txt标注框解压就能训练Lung-PET-CT-Dx给你的是DICOM格式的医学影像序列每个序列有几十到几百张2D切片标注则可能是RTSTRUCT轮廓或分割掩膜。如果你脑子里想的是“下载下来直接丢进YOLOv8就能跑”那在这里会碰壁中间至少要经过一层格式转换。我最初接触这个数据集时以为跟下载普通数据集一样浏览器点个按钮就能拿到全部PNG图片后来发现TCIA的主导思想是保存最原始的影像数据所有后处理都得自己做。这个设计虽然增加了上手成本但也保证了数据没有经过“二次加工”组织病理信息、像素原始值都保留完整训练出来的模型更可靠。1.2 对目标检测来说原始数据离“可直接训练”还差几步从TCIA下载下来的Lung-PET-CT-Dx目录里通常是一堆DICOM文件和一个包含分割标注的文件。直接拿这些做目标检测至少存在三方面问题。第一DICOM不是常规图片格式它不只是一个图像文件而是“图像像素大量头信息”的组合。一个CT序列里的每一张2D切片都是一个独立DICOM文件你需要用pydicom或SimpleITK这类库把它们读成numpy数组再按需要转成PNG或JPG。第二标注信息很可能是分割掩膜而不是目标检测用的矩形框。如果要做目标检测你要么把分割掩膜转成包围框要么用带分割头的模型。多数人做目标检测场景下会选择前者。第三医学影像的显示参数很讲究CT有窗宽窗位PET有SUV值映射关系如果直接按默认方式转成8位图可能导致肿瘤区域对比度很差目标框倒是有了但图像里看不清目标模型照样学不好。这也解释了为什么网上提到Lung-PET-CT-Dx时总有一堆人讨论“如何转换格式”“如何提取掩膜”而不是直接贴训练效果。数据获取只是第一步真正耗时间的是把它整理成适合目标检测管线的状态。1.3 为什么很多人拿它做肺肿瘤检测实验这个数据集的定位是“多模态肿瘤影像”正好踩中了当前目标检测的几个热点小目标检测、多模态融合、半监督学习。肺肿瘤在CT上往往表现为小范围高密度区域在PET上则表现为高摄取值区域天然适合做双模态特征融合实验。加上TCIA公开数据允许研究使用论文复现也有据可循所以不少医学影像顶会上能看到基于Lung-PET-CT-Dx的工作。对做目标检测算法创新的人来说它还有一个好处数据分布比自然图像更复杂同类器官在不同患者身上的形态差异大肿瘤尺寸变化也大直接拿YOLO跑一遍能暴露很多泛化问题。换句话说这个数据集不仅是“数据集”还是检验目标检测算法鲁棒性的试金石。2. 下载前的准备工作注册、看懂TCIA的结构2.1 注册TCIA账号这一步绕不开很多人一开始在TCIA上找不到下载按钮是因为没登录。TCIA的公开数据虽然不需要付费但平台要求你先注册账号登录后才能生成下载清单、调用API。注册流程很简单填邮箱、设置密码、收验证邮件几分钟搞定。需要留意的是TCIA的账号体系跟其他平台是独立的别跟什么Cancer Imaging Archive的其他子服务账号搞混。注册完成后个人中心里能看到自己的用户名和角色信息。后续如果要用REST API批量下载通常需要配置API密钥这个密钥也在个人设置里生成。虽然网页端手动下载不一定非要密钥但为了后面写脚本建议注册完就把密钥准备好。2.2 Collections、Subjects、SeriesTCIA的三层结构TCIA的数据组织方式是三级结构Collection集合对应一个研究项目或数据集比如Lung-PET-CT-DxSubject/Patient对应一个参与者或患者编号Series对应一次CT或PET扫描里面包含一组DICOM文件。这个结构和自然图像数据集的“类别-图片”差异很大刚开始容易迷糊。举个例子Lung-PET-CT-Dx这个Collection下可能有几百个Patient每个Patient有多次扫描比如CT一次、PET一次还可能存在随访数据。每一次扫描是一个Series每个Series由多个DICOM文件组成。如果你只想下载“所有患者的CT序列”那不能简单勾选整个Collection而是要在筛选器里按 modalityCT 过滤后再导出清单。理解这层结构非常重要因为TCIA的下载单元是Series而不是Patient。你生成download manifest时里面逐行列出的都是SeriesInstanceUID。后续用Python脚本下载时也是以这个UID为单位去拼接URL。2.3 选对下载方式网页导出Manifest还是APITCIA有两种主流下载方式。第一种是网页端浏览数据集用左侧筛选器选择Collection、Modality等条件然后点击Export生成一个.tcia清单文件再用官方工具NBIA Data Retriever批量下载。第二种是直接调用TCIA REST API在脚本里请求Series信息、下载DICOM文件。两种方式各有适用场景。我第一次用网页端的时候直接全选了Collection结果下载下来几百GB磁盘差点爆掉。后来学乖了先看该数据集整体说明确认什么Modality需要、什么不需要再生成清单。如果你只是做目标检测实验一般CT序列和对应的分割掩膜是必须的PET序列按需选择。如果只写离线脚本不想开桌面软件那API方式会更顺手后面我专门写了一节讲怎么用Python调TCIA接口。3. 从TCIA获取Lung-PET-CT-Dx的完整实操流程3.1 找到数据集并生成下载清单先打开TCIA官网在Collections列表里搜“Lung-PET-CT-Dx”点进详情页。详情页会显示这个Collection的描述、相关论文、引文信息以及包含的Modality类型。确认这是你要的数据集后点击页面里的“View Related Images”或类似入口进入数据浏览界面。在浏览页面左侧有筛选条件包括Collection、Body Part、Modality等。建议先按Modality过滤比如勾选CT把CT序列找出来。如果你需要分割掩膜还要注意哪些Series附带分割标注通常可以通过Data Type或者Series Description区分。确认勾选范围后页面右上角会出现下载选项点击后生成.tcia文件。这个文件本身不包含图像数据只包含一组DICOM文件的唯一标识符类似一个“下载清单”。真正下载前我会先检查一下清单文件的体积和条目数量。用文本编辑器打开.tcia文件可以看到每一行是一个SeriesInstanceUID。如果这里的数据量跟预期不符最好返回上一步调整筛选条件别急着下载。比如我只想要CT和掩膜如果清单里混入一堆PET动态序列后期处理会很烦。3.2 用NBIA Data Retriever批量下载TCIA官方推荐的下载工具是NBIA Data Retriever一个Java桌面程序支持读取.tcia清单并批量下载。下载并安装后直接打开工具把.tcia文件拖进窗口工具会弹出一个目录选择框让你选择保存位置。确定后它就开始逐一拉取Series并在界面里显示下载进度。这里有两个细节值得注意。第一下载目录里不要带中文路径或特殊字符NBIA Data Retriever在某些环境下对非英文字符支持不太好容易出现路径解析错误。第二工具默认会把每个Series放到一个以SeriesInstanceUID命名的文件夹里。下载完成后目录结构可能长这样根目录下是一堆以“1.2.840...”开头的文件夹每个文件夹内部是一个完整序列的DICOM文件。乍看很乱但这是医学影像平台的通用习惯。如果下载中断工具的“Resume”功能可以重新尝试续传但最好在网络稳定的环境里跑。我通常会在下载前把电脑休眠策略改掉避免夜里下载到一半系统休眠导致任务中断。3.3 下载完成后的目录结构长什么样下载完之后你大概率会看到两种主要文件DICOM系列的文件夹和可能存在的分割掩膜文件。DICOM文件用普通图片查看器打不开需要用专用工具比如RadiAnt、Slicer或者Python里用pydicom读取。掩膜文件如果提供的是NIfTI或NRRD格式用SimpleITK可以直接读成三维数组如果提供的是RTSTRUCT格式读取就稍微麻烦一些需要解析结构集轮廓点。我会强烈建议下载完先别急着跑训练而是做一个数据完整性检查。写个脚本遍历所有Series文件夹统计每个Sequence的DICOM文件数量看看有没有空目录、文件数异常少的序列。医学影像数据在某些环节容易丢文件如果某个序列的CT切片少了十几张后期重建出来的volume会错位目标框也随之偏移这种问题最难排查所以前置检查非常必要。4. 实际下载中容易踩的坑与排查经验4.1 下载速度慢、中途断掉怎么办TCIA的服务器在海外国内下载速度经常会让人抓狂。我在下载Lung-PET-CT-Dx时试过几个时间段发现白天高峰期很容易断流反而是凌晨速度快一些。如果你急着用最好不要把鸡蛋放在一个篮子里可以用NBIA Data Retriever同时开几个下载任务或者并行跑多个下载进程。但注意磁盘读写瓶颈目标文件夹分散在不同盘会更稳。中途断线后NBIA Data Retriever通常会在重试时跳过已经下载完的文件。如果发现同一份DICOM反复重复下载问题多半出在清单文件与服务器返回的文件名不匹配。此时可以清空当前输出目录重新生成一次.tcia清单再从头下载。别觉得可惜重复文件整理起来比重新下载更痛苦。还有个小技巧先下载一个Patient的Series做测试确认整条链路跑通后再全量下载。别一口气把几十GB数据都拉下来最后发现目录结构跟自己预想的不一样那就太浪费时间了。4.2 文件重复、命名混乱怎么办TCIA下载下来的文件夹命名主要是SeriesInstanceUID在人类可读性方面几乎为零。你想一眼看出哪个文件夹是CT、哪个是PET光看名字不行必须读取DICOM头信息里的Modality字段。我写了一个小脚本批量遍历每个Series文件夹读取序列里第一个DICOM的Modality、SeriesDescription然后重命名文件夹为“PatientID_Modality_SeriesDescription”的形式。这里要特别小心不要只按文件后缀判断文件内容。有的系统会把同一个Series内的DICOM文件分散到多个子文件夹但文件实际属于同一个序列。遇到这种情况脚本里应按完整文件路径读取而不是假设所有文件都在同一个平级目录。重命名文件夹后我还会生成一个CSV索引文件记录每个Series的PatientID、Modality、切片数、体素间距。这一步对后续的目标检测划分数据集很重要因为训练集/验证集的划分一定要在患者级别做如果不知道哪些文件属于同一个Patient很容易造成数据泄漏。4.3 只用Python批量下载的替代路线如果你不想安装桌面工具想完全用脚本自动化TCIA也提供了REST API接口。可以在Python里用requests库直接请求数据信息然后逐个下载DICOM文件。核心思路是先通过API查询Collection下的Patient和Series列表再对每个Series里的文件拼接下载URL。需要留意的是TCIA API的基地址和查询参数在文档里有明确说明。一个常见的查询方式是先请求指定Collection下的Patient列表再根据PatientID获取Series信息最后获取Series里的DICOM文件列表。拿到文件列表后可以用多线程或多进程并发下载速度比NBIA Data Retriever更可控。缺点是需要自己维护下载状态和重试逻辑一旦网络不稳代码复杂度会明显上升。我自己的选择是小规模试验用NBIA Data Retriever正式大批量下载用自建Python脚本。后者可以方便地集成断点续传、失败重试和格式检查不会出现“下载到一半工具崩溃”的尴尬。当然前提是TCIA API文档要读仔细避免请求频率太高被限流。5. 把下载好的数据整理成目标检测可用的格式5.1 从分割掩膜生成目标框终于到了跟目标检测最相关的环节。Lung-PET-CT-Dx这类医学数据集的标注通常以分割掩膜的形式提供也就是每个像素属于哪个器官或肿瘤。要做目标检测最简单的办法是把掩膜区域转成矩形框生成YOLO或VOC格式的标注文件。如果掩膜是3D的比如整个CT volume对应一个mask volume那就需要在每个2D切片上做连通域分析。先用measure.label找出同一标签的所有连通域再对每个连通域取最小外接矩形这样同一个标签在单张切片里如果出现多个分离目标也能得到多个框。不能直接把该切片整个标签范围当成一个框否则肿瘤分叶多灶时会合并成一个过大的框影响检测精度。下面这段代码是我常用的一种转换逻辑输入是某个标签的二维掩膜切片输出是YOLO格式的标注文本import numpy as np from skimage import measure def mask_to_yolo_lines(mask_slice, label_id, img_w, img_h): mask_slice: 二维数组0表示背景非0表示目标区域 label_id: 在YOLO标签里使用的类别编号 blobs measure.label(mask_slice 0) lines [] for region in measure.regionprops(blobs): minr, minc, maxr, maxc region.bbox if maxr - minr 1 or maxc - minc 1: continue x_center ((minc maxc) / 2) / img_w y_center ((minr maxr) / 2) / img_h w (maxc - minc) / img_w h (maxr - minr) / img_h x_center max(0.0, min(1.0, x_center)) y_center max(0.0, min(1.0, y_center)) w max(0.0, min(1.0, w)) h max(0.0, min(1.0, h)) lines.append(f{label_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) return lines这段逻辑里对每个连通域单独求框是为了处理器官或肿瘤在切片上不连续的情况。比如肺部在靠近横膈膜下方时可能分成两部分如果只取掩膜整体范围框会扩到背景区域这会让模型学到错误的边界。生成框之后我建议再用可视化工具把框画在对应CT图像上检查一遍别直接拿去做训练。5.2 图像导出与预处理DICOM转常规图片也不是直接另存为那么简单。CT图像每个像素的灰度值实际是“CT值”单位是HU数值范围动辄-1024到3000以上。如果直接线性映射到0-255肺部这类低密度区域会变成全黑目标细节全丢。所以导出图像前必须先设置窗宽窗位。对肺部和纵隔区域我常用的参数组合是窗位-600、窗宽1500这样能同时保留肺实质和软组织的信息。如果想更关注肿瘤和气管也可以试窗位40、窗宽400的纵隔窗。这个选择没有绝对标准最好先读取几个病例的DICOM用工具看一下窗宽窗位对目标可见度的影响再定一套统一参数。目标检测里模型对图像的“长什么样”非常敏感不同窗宽窗位几乎等价于换了数据集。PET图像的话一般转成SUV值或者先做归一化。如果只是做双模态目标检测的输入可以把PET图像归一化到某个固定范围比如0到1然后作为第二通道和CT图像堆叠起来。很多论文会做这种双通道输入。需要注意的是CT和PET的图像分辨率、像素间距往往不同使用前必须做重采样对齐否则在像素级别拼接通道没有任何意义。5.3 按患者划分训练集/验证集/测试集最后一步是划分数据集。医学影像数据有一个非常容易踩的坑同一个患者的CT序列里相邻切片高度相似如果直接随机划分图像训练集和验证集里会出现同一个患者的图像模型验证时相当于开卷考试指标虚高。正确做法是按PatientID划分。具体操作是先读所有Series的PatientID把患者列表随机打乱按7:2:1或者8:1:1的比例分成三组再根据每个患者的切片区分配入相应集合。这样保证同一个患者的所有图像只出现在一个集合里。除此之外肿瘤检测还要关注类别平衡。如果数据集中含肿瘤的切片远少于不含肿瘤的切片纯目标检测模型会对肿瘤类别的召回率偏低这时候可以考虑在采样时对含肿瘤切片做加权。划分完之后我会把训练集、验证集、测试集的图像路径和标注文件统一整理成一个简单清单文件比如train.txt、val.txt、test.txt。这样后续用YOLOv5、YOLOv8或者mmdetection训练时只需要把数据集配置指向这三个文件就行整个过程非常线性。这里再分享一个我自己的习惯每拿到一批医学影像数据我都会先写一个data_inspection.py脚本统计每个病例的切片数量、掩膜面积、目标框尺寸分布把结果存成CSV。训练模型之前先看一遍统计结果能发现不少问题比如某几个病例的掩膜明显偏小、某几个序列的窗宽窗位异常等等。这些发现比事后分析训练曲线要高效得多。从TCIA下载Lung-PET-CT-Dx的完整流程总结下来就是注册账号、理解TCIA三层结构、生成manifest、用工具或API下载、然后做格式转换和数据划分。这一套流程走下来数据获取环节就不再是瓶颈。后面真正花时间的是在多模态融合、小肿瘤检测这些点上去调模型。我后续还会继续写怎么基于这份数据集做目标检测训练和评估先把数据跑通了后面的事才有意义。
返回列表