骨折图像数据集构建全流程:从DICOM整理到模型训练
简介这是一份面向医学影像分析与深度学习方向的骨折图像标注数据集适用于骨折分类、定位与分割任务的研究和算法验证。数据源自孟加拉国三家主要医院的X射线扫描由两位放射科专家独立注释并经医疗官员审核标注质量较有保障。资源包共2000个文件以1998个JSON标注文件为主体辅以2个Markdown说明文档整体大小约320.98MB。JSON文件按图像逐张保存标注结果可便捷转换为COCO或VOC格式用于模型训练。目前已有226人学习下载对于从事医学图像智能诊断的研究者或数据竞赛玩家这套带专家先验的标注数据能有效支撑模型调优与学术探索。1. 骨折图像数据集从 PACS 存片到可训练标注集核心是受控管线把影像科积累的骨折病例整理成可用的数据集第一道坎通常不是图而是数据本身。DICOM 文件里躺着患者信息、设备型号、扫描参数诊断结论却写在放射报告的一段自然语言里同一患者骨折复诊拍了几次片子按图像随机切分时模型已经“见过”答案。名为“综合收集”的骨折数据集落到工程上是一条受控流水线去除隐私、统一图像规范、对齐标签口径、控制数据划分。它适用于建骨折筛查分类、目标检测或分型模型的算法团队也适用于想把存量 PACS 影像做二次研究的影像科与科研组。这个标题真正的信息量不在“收集”而在“综合”。2. 骨折图像数据集的设计结构图像形态、标注粒度和质量把关2.1 X光平片、CT 与 MRI三种影像的数据特点和标注成本骨折影像数据集的主力形态是 DR 平片。X光检查是骨科初诊和骨折复查的标准路径数据量大、检查费用低、流通性好公开竞赛中也常以腕、肘、手、踝等部位的平片为主。平片的缺点是二维投影下骨端重叠轻微裂纹或不完全骨折容易漏判这恰恰给分类模型留出可学的信息空间。CT 适合肋骨骨折、脊柱骨折、关节内骨折等复杂场景。CT 本身的各向同性分辨率让三维重建可以多平面观察但随之而来的是数据体积大、标注工作量大。一个胸部 CT 序列动辄几百张断层图像逐层标注显然不现实最常见做法是先用算法或医生标注定位到若干关键断层再以这些断层为中心扩展数据块控制正负样本比例。CT 的 DICOM 中保存像素值有两套体系原始 HU 值和按窗宽窗位渲染后的显示值整理时必须锁定其中一套否则同一个病例在不同读取软件里导出后灰度分布完全不同。MRI 在骨折数据集中占比最低主要用于骨挫伤、隐匿性骨折和韧带合并损伤的分析。MRI 序列种类多、参数敏感同一解剖部位在不同序列下视觉差异很大做数据增强时如果按自然图像的翻转、旋转策略盲目处理可能把左右结构语义弄乱。影像形态典型用途单例数据量标注复杂度收集难度DR 平片骨折筛查、四肢骨折定位15 张/例低低CT肋骨、脊柱、关节内骨折200800 张/例高中MRI隐匿性骨折、骨挫伤410 个序列/例很高高2.2 标注分层从“骨折/未见骨折”到区位分型骨折数据集的标注可以大致分成三个粒度不同粒度对应不同建模任务不能混用。第一层是图像级二分类。标签只有 positive 和 negative适合做快速筛查模型。这个层的难点在于负样本定义报告写“未见明确骨折”的算 negative但部分病例存在陈旧骨折影像表现和新鲜骨折不同是否计入 positive 需要提前规定口径。第二层是区域级定位标注。用包围框或关键点标出骨折位置。这类标注要求同时看到局部纹理和周围上下文成本明显高于二分类。RSNA 骨折检测竞赛采用的就是“图像级标签 骨折区域框”的混合标注方案实践证明这种方式可以有效训练出既能判断又大致定位的模型。第三层是分型标注。AO/OTA 骨折分型、Gustilo 开放骨折分型等专业体系常被用来做精细分类。但分型信息通常只存在于报告中且不同医生书写习惯差异大直接做文本映射成功率不高。我一般建议把分型当作辅助标签逐步积累先保证“有无骨折”和“骨折部位”两个基础维度可靠再向分型扩展。2.3 数据筛选三关去隐私、去废片、统一读片口径整理数据集第一关是隐私处理。DICOM 标签里的患者姓名、检查号、出生日期、设备序列号等字段必须清洗或置换。实际做法是在采集阶段就把需要的字段白名单化只保留患者 ID 的内部编码、检查日期、模态、体位、设备厂商和型号其余标签一律删除。处理后的文件导出为 PNG、JPEG 或 NIfTI 格式时也要检查像素内是否残留了不可见水印。第二关是废片剔除。摆位错误、体表异物遮挡、严重伪影、曝光过度或不足的图像混入训练集后模型会学习到虚假特征。废片判断建议由技师级别的人员先做一轮初筛再由阅片医生复核规则可以简化为目标部位是否居中和完整、对比度是否可读、有无体外遮挡。第三关是读片口径统一。同一张片子不同医生给出的判断很可能不一致尤其在不完全骨折、骨裂这些边界样本上。我见过的可靠做法是双人独立标注分歧样本进入争议集由高年资医生裁断争议集不作为训练集混入而是单独保留后续用于测试模型在模糊样本上的表现。3. 骨折图像数据集的构建管线从 DICOM 整理到标签结构化3.1 目录布局与元数据拆分让后续迭代不必动原始文件无论数据规模是几千例还是几十万例目录结构建议在第一天就固定下来。推荐按“原始文件不动、成品图单独存放、标注和划分文件独立管理”的三段式布局data/ ├── raw/ # 源文件DICOM 目录只读 ├── images/ # 预处理后的 PNG/JPG/NIfTI ├── labels/ │ ├── fractures.csv # 图像级标签和定位标签 │ ├── metadata.csv # 设备厂商、体位、窗宽窗位等 │ └── contested.csv # 标注争议样本 └── splits/ ├── train_patients.txt ├── val_patients.txt └── test_patients.txt这样的布局有几个直接好处raw 目录保证原始数据可回溯预处理脚本出问题时不至于污染源头images 目录里只放成品图训练时读取路径短且稳定splits 按患者 ID 而不是按图像路径管理避免后期发现数据泄漏要整体重切。labels 和 splits 用纯文本或者 CSV 保存比直接写进数据库更便于代码审查和版本管理。3.2 用 pydicom 完成 DICOM 读取、窗宽窗位归一化和灰度导出骨折图像数据集中 CT 和 DR 并存的场景最需要统一预处理。下面这段代码是基础但完整的一套转换流程既能读 CT也能处理 DR 平片import pydicom import numpy as np import cv2 from pathlib import Path def dicom_to_gray8(dcm_path, out_path, target_max_side1024): ds pydicom.dcmread(dcm_path) arr ds.pixel_array if ds.Modality CT: # CT 像素值是 HU按骨窗截断保留皮质骨信息 ww float(getattr(ds, WindowWidth, 2000)) wc float(getattr(ds, WindowCenter, 400)) vmin, vmax wc - ww / 2, wc ww / 2 else: # DR 平片没有统一的窗宽窗位取 2% 和 98% 分位 vmin, vmax np.percentile(arr, (2, 98)) # 截断并线性拉伸到 8bit arr np.clip(arr, vmin, vmax) arr ((arr - vmin) / (vmax - vmin) * 255).astype(np.uint8) # 限制最长边保持宽高比不直接拉伸成正方形 h, w arr.shape long_side max(h, w) if long_side target_max_side: scale target_max_side / long_side arr cv2.resize(arr, (int(w * scale), int(h * scale)), interpolationcv2.INTER_AREA) cv2.imwrite(str(out_path), arr)代码里值得注意的点有三个。第一CT 读取出的 pixel_array 是原始 HU 值不是渲染后的图像直接做 min-max 归一化会让软组织占据大部分灰度区间皮质骨反而被压缩所以必须做窗宽窗位截断。第二DR 平片不同设备的灰度曲线差异很大用 2% 和 98% 分位截断是常见做法对曝光偏暗或偏亮的片子都有一定容忍度。第三统一尺寸时用“最长边限制”而不是强制 resize 成正方形因为骨折检测更依赖长宽比保真的全局结构正方形压缩会让腕骨和桡骨远端相对位置发生畸变。批量处理时只要在外层遍历 DICOM 文件列表调用这个函数即可。3.3 把放射报告转成结构化标签先排除否定再确认阳性骨折数据集中最容易出错的环节是报告到标签的转换。报告文本里“未见明确骨折”“骨折不除外”“左桡骨远端骨折”这几句话的语义完全不同靠简单关键词匹配会制造大量脏标签。一个保守但可靠的文本规则如下import re POS_PATTERN re.compile(r(骨折|骨裂|粉碎性骨折|撕脱性骨折)) NEG_PATTERN re.compile(r(未见.{0,4}骨折|无明显骨折|排除骨折|未见明确骨折)) def label_from_report(report_text: str) - str: # 先查否定再查阳性因为否定句中通常也包含骨折一词 if NEG_PATTERN.search(report_text): return negative if POS_PATTERN.search(report_text): return positive return unknown这段规则的关键是顺序必须先做否定匹配再做阳性匹配。比如“未见明确骨折”同时包含“未见”和“骨折”若先做阳性匹配就会错误标成 positive。落入 unknown 的样本不要随意猜测我一般会把这类报告交给标注员人工复核并记录复核结果。至于“骨折不除外”这类留有余地的表述应视项目目标决定归入 negative 还是单独建一个 uncertain 类别但绝不能和 positive 混杂。3.4 元数据字段保留清单把“设备”和“体位”写进记录预处理阶段除了像素还要同步记录元数据。至少应保留 patient_id 的内部编号、检查日期、modality、body_part、view_position如 AP、PA、LAT、设备厂商和型号。设备厂商和型号这个字段经常被忽视但不同 DR 厂商的图像处理算法差异会导致灰度分布偏移CT 的骨算法和软组织算法重建结果也完全不同。把设备信息记入 metadata.csv 后后续做跨中心验证或灰度对齐时才有据可查。体位信息同理同一部位的正位、侧位、斜位图像混合在一起训练模型学到的可能不是骨折特征而是拍摄方位特征。4. 用骨折图像数据集建模正确切分、增强策略与评价指标4.1 按患者维度切分数据集防止同一病人的图像跨集合泄漏骨折图像数据几乎天然存在患者维度相关性。同一患者在一次检查中可能拍正位、侧位、斜位多张片复诊还会再次拍摄如果随机按图像切分同一患者的片子会同时出现在训练集和验证集中。模型在验证集上的表现会因为“见过此人同类图像”而虚高入院筛查场景下的真实能力无从评估。正确的做法是以 patient_id 为最小切分单位from sklearn.model_selection import train_test_split patients metadata_df[patient_id].unique() train_pts, val_pts train_test_split(patients, test_size0.15, random_state42) train_df metadata_df[metadata_df[patient_id].isin(train_pts)] val_df metadata_df[metadata_df[patient_id].isin(val_pts)]这里 test_size 取 0.15 是常见选择对骨折这类大类不平衡的数据来说验证集的阳性病例数比比例更重要建议切分后单独统计两端阳性占比如果验证集阳性例数少于 100就下调 test_size 或改用分层切分。test 集应在数据收集完成后一次性锁定不参加任何调参循环。4.2 骨折数据增强的参数范围旋转角度要小灰度扰动要足骨折识别对图像旋转有一定容忍度但和自然图像不同医学图像的解剖方位有实际临床意义。旋转角度建议控制在 ±15 度以内超过这个范围会让骨骼形态失真模型可能学到体位畸变而不是骨折征象。水平翻转在骨折任务中通常可以使用因为左右侧骨骼结构对称检测目标“是否存在骨折”一般不受侧别影响但如果模型需要输出左右侧定位翻转就不可用了。增强方式建议取值使用目的旋转±10°±15°模拟投照角度轻微变化缩放0.81.2 倍适配不同体型和摆位距离差异亮度/对比度乘性因子 0.71.3模拟不同 DR 设备的灰度输出差异高斯噪声sigma 0.0050.01模拟低剂量曝光和散射噪声弹性形变轻微程度模拟软组织牵拉导致的骨骼形貌变化慎用于骨折端灰度扰动在骨折数据集上的重要性远高于旋转。不同医院 DR 设备的灰度映射曲线不同CT 图像骨窗参数也各异模型对灰度分布敏感是最常见的跨院失效原因。在训练阶段加入对比度抖动和 gamma 调整相当于隐式增加了数据来源多样性。4.3 模型选型筛查分类、目标检测、分割各就各位别一上来就跑分割骨折任务的第一版模型我通常建议从分类开始。骨折筛查本质上是在大样本中找到可疑阳性DenseNet、EfficientNet 这类成熟分类网络在 1K 级数据量下就能得到有参考价值的基线结果。分类模型输入常压缩到 512 或 640保留长宽比做 padding避免暴力拉伸。当场景要求告诉医生“骨折在哪里”时再上目标检测。检测模型对数据量和标注质量的要求明显提高训练集中定位框的边界误差会直接反映在最终定位精度上。如果只有图像级标签可以先训练分类模型做特征提取再用类别激活热图生成伪定位辅助标注员快速打框。分割通常只留给“CT 三维重建 肋骨/脊柱定位”这类强空间任务。nnU-Net 这类自适应框架可以省去大量调参工作量但 3D 分割对显存和数据量的需求成倍增长需要先算清楚每个训练病例的体素裁块尺寸和批大小再规划 GPU 资源。4.4 评价指标以敏感度和 FROC 为主准确率只做参考骨折阳性率通常在总样本中占 5% 到 15%类别高度不平衡下准确率几乎没有参考价值——把所有样本预测为阴性就能达到 85% 以上的准确率。筛查场景的核心指标应该是敏感度对应漏诊率。模型若在一万人中漏掉一个真实骨折后果远比重报三个可疑病例严重。检测类任务推荐用 FROC 曲线横坐标是平均每张图像的假阳性个数纵坐标是敏感度。临床上常关注假阳性率在 0.5 到 1.0 个/图区间内的敏感度表现如果敏感度要达到 0.9 需要允许每张图出现 2 个以上假阳性这个模型就不适合直接进入报告流程。分类任务至少报告敏感度、特异度、F1 和 PR-AUC并同时给出按患者粒度的指标而不是只报图像粒度因为一张片子判错和一位患者被漏诊的临床代价完全不同。5. 骨折图像数据集建成后的进阶用法争议集与跨中心验证5.1 把标注分歧样本隔离成“争议集”用来探测模型的不确定性盲区标注阶段记录双人标注不一致的样本单独放入 contested.csv不参与训练。训练完成后用模型在这些争议样本上的表现做一次额外评估。如果模型对争议集的表现显著差于常规测试集说明当前特征学习无法处理边界骨折样本此时应回看争议集中占比最高的解剖部位和影像条件必要时为该部位补充训练样本。做法上可以统计每个争议样本是“双人一致 positive 但模型判 negative”还是“标注有争议但模型高置信度判 positive”。前者是典型漏诊风险需要调整阈值后者说明模型把边界样本学成了确定阳性需要检查是否学习了灰度伪影。这一步骤把标注阶段的争议记录转化成了模型迭代的定向反馈。5.2 用设备型号和部位维度做交叉验证提前暴露领域偏移数据集元数据里记录了设备厂商和型号就可以做一种低成本的分组验证按 device 字段把数据分成组用其中一组做验证集其余做训练集观察模型在“未见过设备”上的掉点幅度。掉点明显说明模型对设备相关灰度特征过拟合此时应回到预处理环节检查灰度归一化是否到位或加大对比度增强幅度。同样思路应用在体位维度上只用 AP 位训练用 LAT 位测试结果如果断崖式下降说明模型把体位当成了关键特征。这个验证过程不增加任何标注成本只需要在划分时多加一个分组条件却是评估骨折图像数据集能否真实外推的最有效手段。本文还有配套的精品资源点击获取