信息速览
BTXRD 是一份把「骨肿瘤的 X 线平片」单独拎出来做成可用数据集的工作。它由广西三家医院的院内影像、Radiopaedia 的教学图与 MedPix 的公开病例合并而成,清洗后留下三千七百四十六张骨骼平片,其中正常骨一千八百七十九张、良性肿瘤一千五百二十五张、恶性肿瘤三百四十二张;每一张肿瘤图都配一份 LabelMe 格式的多边形掩膜与矩形边界框。
它的价值不在数量,而在填补的位置。骨肿瘤影像长期是一个尴尬的空白:发病率低,单个中心攒不出几百例;标注要靠有经验的骨放射科医师,成本高;公开图库里的病例零散且带教学修饰。结果是深度学习论文里但凡出现「骨肿瘤 X 线」,数据几乎都是私有的,别人无法复现。BTXRD 是目前少数把图像、标签、部位、年龄、性别与逐病灶几何标注一起放出来的公开集,而且下载不需要注册。
这份材料有三个必须先说清的边界:它只到图像级,没有患者编号;它只覆盖四肢与骨盆,中轴骨被整类排除;它的九个亚型里有两个是合并类,不能当骨肿瘤全谱使用。下面的叙述按「里面有什么、标签怎么长、怎么取用、边界在哪」展开,所有规模数字取自 figshare 记录页与 Scientific Data 论文正文,口径与核验日期统一写在附录。一屏速览见下表。
| 维度 | 内容 |
|---|---|
| 全称 | Bone Tumor X-Ray Radiograph Dataset(BTXRD) |
| 主论文 | Scientific Data 12:88(2025),2025-01-16 见刊 |
| 数据托管 | figshare,DOI 10.6084/m9.figshare.27865398,2024-11-20 首发 |
| 图像总数 | 3746 张(正常 1879 / 良性 1525 / 恶性 342) |
| 肿瘤图 | 1867 张,每张一份 JSON 标注 |
| 亚型 | 9 类:骨软骨瘤、多发性骨软骨瘤、单纯骨囊肿、骨巨细胞瘤、骨纤维瘤、滑膜骨软骨瘤、骨肉瘤、其他良性、其他恶性 |
| 解剖部位 | 15 个,仅上肢、下肢与骨盆 |
| 体位 | 正位、侧位、斜位三种,未标左右侧 |
| 标注形态 | 多边形分割掩膜 + 矩形边界框,LabelMe JSON |
| 人口学 | 年龄 1—88 岁,男 2098 / 女 1648 |
| 来源 | 广西三家医院(2938)+ Radiopaedia(549)+ MedPix(259) |
| 格式 | 8 位灰度 JPEG + JSON + CSV,压缩包 801 MB |
| 许可 | CC BY-NC-ND 4.0 |
| 患者编号 | 无 |
| 官方基线 | YOLOv8s 检测 mAP@0.5 0.707,分割 0.691,三分类准确率 0.904/0.899/0.965 |
§1 它到底是什么
§1.1 一句话定义与三个反常识
一句话:BTXRD 是把「一张骨肿瘤平片上有几个病灶、在哪、是什么亚型、良性还是恶性」这件事,拆成分类、检测、分割三个任务并给出统一标签的公开影像集。
第一个反常识是它的规模并不大。三千七百四十六张图放在胸部 X 线的量级里只是零头,VinDr-CXR 有一万八千张、CheXpert 二十余万张。骨肿瘤的流行病学决定了这个数字:原发性恶性骨肿瘤年发病率在百万分之几的量级,一个省级中心十年也只能攒出几千张可用片。所以评价 BTXRD 不能用「够不够大」,要用「在骨肿瘤这个稀缺池子里,它是不是把可得的部分都拿到了」。答案是:它把三家医院的连续病例与两个公开库的教学图都收了进来,并把一万零八十余张候选筛到三千七百余张,保留了约三成七。
第二个反常识是它的标签不是单一的类名,而是一行多热向量。同一张图可以同时是「股骨 = 1」「下肢 = 1」「肿瘤 = 1」「良性 = 1」「骨巨细胞瘤 = 1」「正位 = 1」,其余全为 0。这种宽表结构对做表型分析很方便,对直接喂给交叉熵损失很不方便——绝大多数分类代码默认标签是互斥的整数,第一次跑通时会把「良性」和「骨巨细胞瘤」当成两个互相竞争的类别。
第三个反常识是它没有患者编号。表里的主键是 image_id,不是 patient_id。这意味着同一个人的正位与侧位两张图在表里是两个独立样本,任何按行随机切分的训练/验证划分,都会把同一病灶的两张图分到两边,验证集指标因此系统性偏乐观。官方基线用的是随机八二划分,所以论文里的 0.707 与 0.691 应当读作「同分布随机划分下的上限估计」,而不是「新患者上的表现」。
§1.2 决策卡:你的处境决定你怎么用它
| 你的处境 | 它能帮你什么 | 它帮不了什么 |
|---|---|---|
| 要做一个骨肿瘤良恶性分类的原型,手里没有任何数据 | 一千八百六十七张肿瘤图 + 一千八百七十九张正常图,三类标签现成,一天能跑通基线 | 不能证明模型在真实门诊可用,因为恶性只有三百余例且只含原发瘤 |
| 要做病灶检测或分割的预训练,再迁到自己的 CT/MRI | 一千八百六十七份多边形掩膜可直接转 COCO 或 YOLO 格式,几何标注来自双人复核 | 掩膜是二维平片投影,不携带深度信息,迁到断层模态时形状先验不可直接搬 |
| 要研究「年龄—部位—形态」三元组在诊断中的作用 | 每张图都有年龄、性别、十五个部位与九类亚型的多热标签,正好做结构化先验 | 没有左右侧、没有病程、没有实验室值,做不了更细的临床推理 |
| 要做骨肿瘤的教学图库或住培题库 | 九类亚型覆盖了教科书上最常见的良性、交界性与恶性代表,图质经过筛选 | 病例数少,同一亚型的外观多样性有限,不能替代真实阅片量 |
| 要评估一个已上市模型在骨肿瘤上的表现 | 可以作为外部测试集的一角,尤其是良性亚型的误报率 | 不适合作为唯一外部集,因为来源集中在中国广西与两个英文教学库 |
| 要做预后、疗效或生存分析 | 无 | 没有任何随访、治疗与结局字段 |
这张表的用法是反过来看:如果你的目标落在右列,就不该在这个数据集上花时间。它的设计目标只有一个——让骨肿瘤的影像算法有一个能复现的起点。
§1.3 不适合谁
不适合把「骨肿瘤」理解成「所有骨头上长的东西」的人。这个集子明确排除了头、颈、胸、腹区域的原发骨肿瘤,只保留上肢、下肢与骨盆。脊柱、骨盆以外的中轴骨、颅面骨、肋骨全都不在。原因写在方法里:这些部位样本量少且伪影多。但对使用者来说,后果是模型的适用域被悄悄砍掉了一块,而这一块在成人骨肿瘤里恰恰是转移瘤与骨髓瘤的高发区。
不适合需要病理金标准的人。数据集的诊断来自两类证据:有组织学结果的按病理定,没有的由两名放射科专家经验判定。论文自己承认,缺少病理信息时存在误判可能。做标签噪声研究可以用它,做「金标准」引用不行。
不适合把图像当原始 DICOM 用的人。院内部分从 PACS 导出后统一转成 8 位灰度 JPEG,公开部分本来就是 JPEG。窗宽窗位、像素间距、曝光指数、设备型号全部丢失。任何以物理单位为基础的测量——骨破坏区直径多少毫米、皮质厚度多少毫米——在这份数据上都做不了。
§2 数据构成:三千七百四十六张怎么来的
§2.1 总量与三类构成
清洗后的总量是三千七百四十六张。按临床语义分三层:正常骨一千八百七十九张,占一半略多;良性肿瘤一千五百二十五张,占四成;恶性肿瘤三百四十二张,占不到一成。把后两者合并才是「肿瘤图」,共一千八百六十七张,与「每张肿瘤图一份标注」的口径对得上。
| 类别 | 图像数 | 占比 | 是否有几何标注 |
|---|---|---|---|
| 正常骨 | 1879 | 50.2% | 无 |
| 良性肿瘤 | 1525 | 40.7% | 有 |
| 恶性肿瘤 | 342 | 9.1% | 有 |
| 合计 | 3746 | 100% | 肿瘤侧 1867 份 |
这张表里最该被注意的是最后一行与第三行的比例。恶性只占全部图像的百分之九,占肿瘤图也只有百分之十八点三。一个在全体上训练的三分类模型,只要把所有图都猜成「正常」或「良性」,准确率就能到九成以上。所以任何只报整体准确率的结果都没有信息量,必须报宏平均与每类召回。
良性内部同样极不均衡。骨软骨瘤一类就占了七百五十四张,是肿瘤图的四成;骨肉瘤两百九十七张,不到两成;多发性骨软骨瘤两百六十三张;单纯骨囊肿两百零六张。这四类合起来一千五百二十张,剩下三百四十七张分摊到骨巨细胞瘤、骨纤维瘤、滑膜骨软骨瘤、其他良性、其他恶性五个标签上。论文只给出了前四类的确切病灶数,后五类没有逐一列数,这是使用时的第一个信息缺口。
§2.2 三源合并与各自的贡献
| 来源 | 图像数 | 正常 | 良性 | 恶性 | 采集方式 |
|---|---|---|---|---|---|
| 中心一:广西三家医院 | 2938 | 1593 | 1110 | 235 | PACS 导出 DICOM,转 8 位灰度 JPEG |
| 中心二:Radiopaedia.org | 549 | 259 | 214 | 76 | 站点原图 JPEG,2024-02 检索下载 |
| 中心三:MedPix(NLM) | 259 | 27 | 201 | 31 | 站点原图 JPEG,2024-02 检索下载 |
| 合计 | 3746 | 1879 | 1525 | 342 | — |
中心一包含广西医科大学第一附属医院、右江民族医学院附属医院与百色市人民医院,时间跨度从 2013 年 7 月到 2023 年 7 月,纳入标准是有组织学确认或两名放射科专家共同确认的原发性骨肿瘤。它贡献了全部图像的百分之七十八点四,也贡献了绝大部分正常对照——一千五百九十三张正常图只可能来自院内,因为公开教学库很少发布「正常骨」这种没有教学价值的片子。
中心二与中心三的性质完全不同。Radiopaedia 是放射科医师共建的病例库,MedPix 是美国国家医学图书馆维护的开放教学库,两站的图都是「精选过的典型病例」:诊断明确、征象典型、往往配有讲解。这类图对教学极好,对训练极坏——它们代表的是每个病的「教科书脸」,而不是门诊里那些不典型、被遮挡、拍歪了的片子。五百四十九加二百五十九,一共八百零八张,占两成出头,比例不算离谱,但它们的分布与院内图不同:MedPix 的二百五十九张里有两百零一张是良性,正常只有二十七张,说明这个来源几乎不提供对照。
§2.3 十五个解剖部位
部位字段是十五个 0/1 列,覆盖手、尺骨、桡骨、肱骨、足、胫骨、腓骨、股骨、髋骨、踝关节、膝关节、髋关节、腕关节、肘关节、肩关节。前十个是骨,后五个是关节;这种骨与关节混编的编码方式,意味着同一张膝关节图可能同时命中「股骨」「胫骨」「膝关节」三列。
| 部位 | 病灶数 | 归类 |
|---|---|---|
| 胫骨 | 630 | 下肢长骨 |
| 股骨 | 592 | 下肢长骨 |
| 腓骨 | 259 | 下肢长骨 |
| 肱骨 | 235 | 上肢长骨 |
| 其余十一个部位 | 未逐项公布 | 手足短骨、关节与髋骨 |
四个长骨合计一千七百一十六个病灶,占全部病灶的九成以上。这是骨肿瘤的解剖学现实:原发瘤偏好长骨干骺端,尤其是膝关节周围。也正因如此,任何在这份数据上训练的模型都会强烈依赖「膝关节周围的骨破坏」这一视觉模板,遇到骨盆、手足短骨或中轴骨时性能会掉。这不是模型的错,是分布决定的。
§2.4 年龄、性别与人群谱系
年龄范围一比八十八岁,均值三十七点五三岁,标准差十九点五八。性别男两千零九十八、女一千六百四十八,男女比约一点二七比一。年龄分布有两个峰:十到二十岁一个,五十到六十岁一个。这个双峰不是噪声,它正是骨肿瘤的年龄谱系:第一个峰对应骨肉瘤与骨软骨瘤的青少年高发,第二个峰对应成人期的软骨肉瘤、骨巨细胞瘤与转移瘤。
按来源拆开看,差异非常明显:中心一均值四十点三六岁,中心二二十二点三二岁,中心三二十二点五八岁。院内队列偏中年,两个公开库偏年轻。原因大概是教学库偏好「影像征象漂亮」的年轻病例,而院内连续病例包含了完整年龄谱。把三者混在一起训练时,年龄这个变量与来源中心高度相关,模型可能学到「年轻 + Radiopaedia 风格 = 某种亚型」这种伪相关。
§2.5 一条记录的逐行解剖
论文表三给出了 dataset.csv 的一行示例,是理解整个表结构最快的入口。这一行的文件名是 IMG0000265.jpeg,来源中心 1,年龄 65,性别 F,部位命中桡骨,类别命中肿瘤、良性、巨细胞瘤,区域命中上肢,体位命中正位,其余列全为 0。
| 字段 | 值 | 读法 |
|---|---|---|
| image_id | IMG0000265.jpeg | 主键,也是 JSON 文件名 |
| center | 1 | 院内来源 |
| age / gender | 65 / F | 仅有的两项人口学 |
| radius | 1 | 桡骨 |
| tumor / benign / malignant | 1 / 1 / 0 | 有瘤、良性、非恶性 |
| giant cell tumor | 1 | 亚型 |
| upper limb | 1 | 区域 |
| frontal | 1 | 体位 |
这一行值得停一下。六十五岁女性、桡骨、巨细胞瘤——骨巨细胞瘤的典型年龄是二十到四十岁、骺线闭合之后,好发于股骨远端与胫骨近端,桡骨远端属于第二位好发部位但年龄偏大并不典型。这不是说标签错了,而是说:真实数据里总有这类不典型的组合,而这类组合恰恰是模型最容易判错、也最有临床价值的部分。把「IMG0000265」当成全文的贯穿例子,后面讲标注、讲划分、讲坑点时会反复回到它。
§2.6 从一万零八十余张到三千七百余张
论文提到初始收集一万零八十余张,最终保留三千七百四十六张。被砍掉的部分有三类原因:部位不符(头颈胸腹整类排除)、质量不合格(不完整、模糊、分辨率过低)、重复(同一病灶的冗余图像)。保留率约百分之三十七,这个数字说明筛选是相当激进的。
| 环节 | 数量 | 说明 |
|---|---|---|
| 初始候选 | 10089 | 三源合计 |
| 部位筛选 | — | 剔除头颈胸腹原发瘤 |
| 质量筛选 | — | 剔除不完整、低清、低分辨率 |
| 去冗余 | — | 剔除同病灶重复图 |
| 最终保留 | 3746 | 保留率约 37.1% |
这种漏斗带来一个隐蔽后果:留下的图都是「拍得好、看得清」的。真实场景里最难的那些片子——体位不正、有石膏、有内固定、曝光过度——在数据集里几乎不存在。模型在这个集子上学到的决策边界,比它在急诊片子上要面对的现实干净得多。
§3 病例层:谁、哪里、什么体位
§3.1 为什么先看体位再看诊断
一份平片数据集的信息密度,很大程度由体位决定。正位给的是冠状面上的骨轮廓与皮质连续性,侧位给的是前后方向的骨膨胀与软组织肿块,斜位多用于手、足、关节的避开重叠。骨肿瘤的三大征象——骨破坏模式、移行带、骨膜反应——在正位上最容易读,在侧位上最容易漏。
BTXRD 的体位是三个 0/1 列:frontal、lateral、oblique。没有左右侧字段,没有投照角度,没有是否负重。这三个缺失直接限制了增强策略:水平翻转是最常用的增强手段,但在骨骼影像上,翻转会把「左桡骨远端」变成「右桡骨远端」,而标签里根本没有左右,模型学不到侧别不变性,翻转只会引入一个标签无法约束的变换。更麻烦的是,很多平片在拍摄时会把 L/R 铅字标记烧进图像角落,翻转后这个标记就反了——如果模型碰巧学到「铅字在左 = 某个部位」,翻转会毁掉这条捷径,也可能让模型学到更糟的东西。
§3.2 部位编码的粒度问题
十五个部位列里,骨与关节是并列的。一张膝关节正位图,如果病灶在股骨远端,通常股骨与膝关节同时为 1;如果病灶在胫骨近端,则胫骨与膝关节同时为 1。做多标签预测时,这意味着「膝关节」这一列不是一个独立的解剖类别,而是「股骨远端或胫骨近端或髌骨」的并集。直接把十五列当十五个互斥类做 softmax,会得到一个语义混乱的分类器。
正确的处理是把部位拆成两级:一级是区域(上肢、下肢、骨盆),二级是骨(十个),关节列只作为附加描述,不参与主要监督。数据表里恰好也有 upper limb、lower limb、pelvis 三个区域列,可以直接用。
§3.3 年龄双峰与两套疾病谱系
十到二十岁与五十到六十岁两个峰,对应两套几乎不重叠的鉴别诊断清单。青少年一侧:骨肉瘤、尤文肉瘤、骨软骨瘤、单纯骨囊肿、骨纤维结构不良、朗格汉斯细胞组织细胞增生症。成人一侧:软骨肉瘤、骨巨细胞瘤、骨髓瘤、转移瘤、骨旁骨肉瘤。
BTXRD 的九类标签只覆盖了这两套谱系的一部分。骨肉瘤、骨软骨瘤、单纯骨囊肿、骨巨细胞瘤、骨纤维瘤、滑膜骨软骨瘤属于有名有姓的;多发性骨软骨瘤是一种遗传性综合征(多发性骨软骨瘤病),不是单个病灶的诊断;其他良性与其他恶性是两个收纳筐。尤文肉瘤、软骨肉瘤、骨髓瘤、转移瘤都没有独立标签,它们如果出现,只能落在「其他恶性」里。
这是这份数据集最深的一处结构性限制:它不能用来做恶性骨肿瘤的亚型鉴别。想做「骨肉瘤 vs 尤文肉瘤 vs 软骨肉瘤」的三分类,这份数据给不了。它给的是「良性 vs 恶性 vs 正常」这一层,以及良性内部的几个常见亚型。
§3.4 病例层能回答与不能回答的问题
| 问题 | 能否回答 | 原因 |
|---|---|---|
| 这个病灶在哪个骨 | 能 | 十个骨列 |
| 这个病灶在正位还是侧位看到的 | 能 | 三个体位列 |
| 这个患者是男是女、多大 | 能 | age / gender |
| 同一个患者有几张图 | 不能 | 无患者编号 |
| 病灶在骨的左侧还是右侧 | 不能 | 无侧别字段 |
| 病灶发现多久、有没有痛 | 不能 | 无病史 |
| 病理分级是几级 | 不能 | 无分级字段 |
| 治疗后有没有复发 | 不能 | 无随访 |
这张表的后四行不是「暂时缺」,是「设计上就没有」。把 BTXRD 当作临床研究队列会产生系统性误判,把它当作算法基准则完全够用。
§4 标注层:几何、标签与它们的边界
§4.1 三种标注形态并存
BTXRD 的标注分三层,粒度由粗到细:
| 层级 | 载体 | 覆盖范围 | 用途 |
|---|---|---|---|
| 图像级多热标签 | dataset.csv 的 0/1 列 | 全部 3746 张 | 分类、表型统计 |
| 矩形边界框 | Annotations/*.json 的矩形 shape | 1867 张肿瘤图 | 检测、弱监督定位 |
| 多边形分割掩膜 | Annotations/*.json 的多边形 shape | 1867 张肿瘤图 | 语义分割、病灶定量 |
三层的关系是包含而非并列:有几何标注的一定有图像级标签,反之不成立(正常图只有标签没有 JSON)。这一点决定了任何按目录遍历的代码都必须先处理「标注文件缺失」的情况,否则会的到一千八百六十七份 JSON 而不是三千七百四十六份。
标注工具是 LabelMe,一个开源的图像标注工具,输出 JSON 里 shapes 是列表,每个元素有 label、points、shape_type 三个关键字段。矩形用两个对角点表示,多边形用任意多个顶点表示。同一张图上有多个病灶时,shapes 里会有多个元素,且它们的 label 可能相同(都是「tumor」)。
§4.2 多热标签向量的正确读法
以「IMG0000265」为例,它的标签向量可以写成这样一组互不排斥的断言:有肿瘤、良性、巨细胞瘤、桡骨、上肢、正位。六条断言里有三条属于不同维度——病理性质、亚型、解剖、体位。把六条压成一个整数类标是错的第一种形式;把它们全部当独立二分类是错的第二种形式(因为「良性」与「恶性」互斥,「骨肉瘤」与「骨软骨瘤」互斥)。
正确的做法是按维度切块:
| 维度 | 列 | 互斥性 | 建模方式 |
|---|---|---|---|
| 病理性质 | tumor / benign / malignant | tumor 与另两者是层级关系 | 先二分类「有无瘤」,再三分类「正常/良性/恶性」 |
| 亚型 | 九列 | 互斥(理论上) | 仅在肿瘤图上做九分类,正常图不参与 |
| 部位 | 十骨 + 五关节 + 三区域 | 骨内互斥、关节可叠加 | 多标签 sigmoid,或只监督骨列 |
| 体位 | frontal / lateral / oblique | 互斥 | 单标签,可作辅助任务 |
§4.3 标注一致性与复核流程
标注由一位十年经验的骨肿瘤专科医师用 LabelMe 完成,再由一位二十年经验的专家复核。为评估一致性,随机抽五十张图,一个月后重新分割与重画框,得到分割 Dice 零点九零(标准差零点零七)、边界框 IoU 零点九一(标准差零点零六)。
| 指标 | 数值 | 含义 |
|---|---|---|
| 分割 Dice | 0.90 ± 0.07 | 同一标注者隔月复标的自我一致性 |
| 边界框 IoU | 0.91 ± 0.06 | 同上,框级 |
这两个数字是标注者自身重测信度,不是两名标注者之间的一致性。它回答的是「同一个人隔一个月画得一样吗」,不回答「两个专家意见一致吗」。前者高说明标注协议稳定、边界定义清楚;后者才关系到标签的客观性。论文没有报告 inter-rater 一致性,这是标注层的一个信息缺口。
从临床角度看,骨肿瘤的边界本身就模糊:成骨型骨肉瘤的硬化边与正常骨皮质之间没有清晰过渡,软骨帽的厚度在平片上极难界定,骨巨细胞瘤的膨胀性边界常与骨皮质变薄区混在一起。掩膜在这里更像是「专家认定的病灶范围」,而不是「病理学边界」。做分割时把它当 ground truth 训练没问题,做「肿瘤体积精确测量」就要保留一份怀疑。
§4.4 标注层的三个盲点
第一个盲点是正常图没有几何标注。这不奇怪,但会带来一个工程后果:如果你做的是「检测 + 分类」的联合模型,负样本(正常图)没有框,只能当背景图用;如果你按「有框 = 阳性」来构造数据集,会得到一千八百六十七个阳性与零个阴性,检测模型直接退化成永远输出框。
第二个盲点是多病灶图的处理。论文说「每个肿瘤实例有独立的掩膜与边界框」,但没有说明多发病灶的图占多少。骨软骨瘤与多发性骨软骨瘤都可能在一张片子上有多个病灶,滑膜骨软骨瘤病更是以关节内多发游离体为特征。如果你的分割管线假设「一张图一个病灶」,这些图会被静默截断。
第三个盲点是合并类的语义。「其他良性」与「其他恶性」不是诊断,是收纳筐。做九分类时,模型会被要求区分「骨软骨瘤」与「其他良性」,而后者内部可能包含五六个互不相关的病。这种类别在统计上必然表现差,且差得没有解释价值。合理的做法是把这两类排除在亚型任务之外,只保留七个具名类,或者只做良恶性二层。
§4.5 数据结构:目录树与字段字典
解压后的结构极简,只有三个顶层目录:
BTXRD/
├── images/ # 3746 张 JPEG,命名 IMG000000.jpeg 起
│ ├── IMG000000.jpeg
│ ├── IMG0000265.jpeg # 论文表三的示例行
│ └── ...
├── Annotations/ # 1867 份 JSON,与肿瘤图同名
│ ├── IMG0000265.json
│ └── ...
└── dataset.csv # 3746 行 × 37 列
字段字典按 DAIMS 的八列口径整理,核心字段如下:
| 字段名 | 类型 | 说明 | 示例值 | AI 用途 | 观测误差 | 缺失编码 | 取值范围 |
|---|---|---|---|---|---|---|---|
| image_id | string | 主键,含扩展名 | IMG0000265.jpeg | 与文件、JSON 对齐 | 无 | 无 | IMG000000—IMG003745 |
| center | int | 来源中心 | 1 | 域偏移分层 | 院内三院合并为 1 | 无 | 1—3 |
| age | int | 年龄(岁) | 65 | 结构化先验、亚组分析 | 无出生日期,只有整岁 | 无 | 1—88 |
| gender | string | 性别 | F | 亚组公平性 | 二值,无其他 | 无 | M / F |
| tumor | 0/1 | 是否有肿瘤 | 1 | 一级任务 | 无病理时靠专家判定 | 0 兼作「否」 | 0 / 1 |
| benign / malignant | 0/1 | 性质 | 1 / 0 | 二级任务 | 同上 | 0 兼作「否」 | 0 / 1 |
| osteochondroma 等九列 | 0/1 | 亚型 | 骨软骨瘤=0 | 三级任务 | 合并类语义模糊 | 0 兼作「否」 | 0 / 1 |
| radius 等十列 | 0/1 | 骨部位 | 1 | 部位先验、分层 | 多骨受累只标主要 | 0 兼作「否」 | 0 / 1 |
| knee-joint 等五列 | 0/1 | 关节 | 0 | 辅助 | 与骨列重叠 | 0 兼作「否」 | 0 / 1 |
| frontal / lateral / oblique | 0/1 | 体位 | 正位=1 | 辅助任务、增强约束 | 无角度 | 0 兼作「否」 | 0 / 1 |
注意「缺失编码」一列全部是「0 兼作否」。这是宽表设计的通病:0 既表示「这个标签不成立」,也表示「这个字段没填」。在 BTXRD 里因为所有字段都是必填的 0/1,问题不大;但如果后续有人往表里加列,这种编码会立刻变成陷阱。
§5 取数层:从压缩包到张量
§5.1 获取与校验
官方入口是 figshare 的 DOI,压缩包八百零一兆,下载不需要注册、不需要填表、不需要申请。这一点在医学影像数据集里相当少见——多数需要签数据使用协议或走 PhysioNet 的培训认证。
#-- 下载并校验:整包 801 MB,解压后约 3 个顶层目录
mkdir -p data/btxrd && cd data/btxrd
curl -L -o btxrd.zip "https://ndownloader.figshare.com/files/50361144"
unzip -q btxrd.zip
#-- 三个计数必须同时对:图像数、标注数、CSV 行数
find . -name "*.jpeg" | wc -l # 期望 3746
find . -name "*.json" | wc -l # 期望 1867
python3 -c "import pandas as pd; d=pd.read_csv('dataset.csv'); print(len(d), d.shape[1])"
如果三个数字对不上,先查是不是解压到了嵌套目录(figshare 的 zip 有时多一层同名文件夹),再查是不是只下载了部分文件。八百零一兆这个体量,断点续传失败很常见。
§5.2 解析 LabelMe 标注
JSON 的结构是 LabelMe 标准格式,shapes 是列表,每个元素包含 label、points、shape_type,imageWidth 与 imageHeight 是原图尺寸。转掩膜时要注意:多边形的点是浮点像素坐标,先取整再填充;边界框要从同一批点里算包围盒,而不是另存一份。
#-- 把一份 LabelMe JSON 拆成 mask 与 boxes,返回 numpy,便于批量缓存
import json
import numpy as np
from PIL import Image, ImageDraw
def load_annotation(json_path):
with open(json_path, "r", encoding="utf-8") as f:
ann = json.load(f)
h, w = ann["imageHeight"], ann["imageWidth"]
mask = Image.new("L", (w, h), 0)
draw = ImageDraw.Draw(mask)
boxes = []
for shape in ann["shapes"]:
pts = [(float(x), float(y)) for x, y in shape["points"]]
xs = [p[0] for p in pts]
ys = [p[1] for p in pts]
boxes.append([min(xs), min(ys), max(xs), max(ys)])
if shape["shape_type"] == "polygon":
draw.polygon(pts, outline=1, fill=1)
else:
draw.rectangle([min(xs), min(ys), max(xs), max(ys)], outline=1, fill=1)
return np.array(mask, dtype=np.uint8), np.array(boxes, dtype=np.float32)
mask, boxes = load_annotation("Annotations/IMG0000265.json")
print(mask.shape, mask.sum(), boxes.shape)
这段代码有一个容易忽略的细节:矩形 shape 的 points 只有两个对角点,直接 draw.polygon 会画出一条线而不是一个矩形,所以必须分开处理。论文的标注里两种 shape 都存在,只处理 polygon 会丢掉框。
§5.3 读取多热宽表
CSV 的三十七列里,真正的元数据只有四列(image_id、center、age、gender),其余三十三列全是 0/1。读取时要做的第一件事是把它们按维度切开,而不是一股脑转成张量。
#-- 按语义维度切列:性质 / 亚型 / 骨部位 / 关节 / 区域 / 体位
import pandas as pd
df = pd.read_csv("dataset.csv")
subtypes = ["osteochondroma", "multiple osteochondromas", "simple bone cyst",
"giant cell tumor", "osteofibroma", "synovial osteochondroma",
"osteosarcoma", "other bt", "other mt"]
bones = ["hand", "ulna", "radius", "humerus", "foot", "tibia",
"fibula", "femur", "hip bone"]
joints = ["ankle-joint", "knee-joint", "hip-joint", "wrist-joint", "elbow-joint",
"shoulder-joint"]
views = ["frontal", "lateral", "oblique"]
regions = ["upper limb", "lower limb", "pelvis"]
#-- 一致性自检:亚型列之和应等于 tumor 列之和(每图只标一个亚型)
assert df[subtypes].sum(axis=1).max() <= 1, "同一图出现多个亚型,需人工核对"
print(df.groupby("tumor")[subtypes].sum().T)
那个 assert 不是摆设。如果某张图同时命中两个亚型列,说明标注时把两个诊断都打上了,这在合并类附近最容易发生(例如「骨软骨瘤」与「多发性骨软骨瘤」)。
§5.4 划分策略:在没有患者编号时怎么切
这是整份数据集最需要动脑的地方。没有 patient_id,就不能做真正的患者级划分。可用的替代方案有三档:
| 方案 | 做法 | 优点 | 风险 |
|---|---|---|---|
| 随机按行切 | 直接 train_test_split | 与官方基线一致,可比 | 同病灶多体位跨集,指标虚高 |
| 近似患者聚簇 | 按 (age, gender, center, 主要部位) 四元组聚簇,整簇分配 | 能拆开大部分同患者图 | 会误并不同患者的同岁同性别同部位图 |
| 时间或来源留出 | 按 center 留一,或用公开源做外部测试 | 最接近真实泛化 | 中心间风格差异大,掉点严重但真实 |
第二档的实现要点是聚簇后检查簇大小分布:如果出现一个几百张图的巨簇,说明四元组太粗,需要把亚型也加进去。
#-- 近似患者聚簇:同 (中心, 年龄, 性别, 主要骨) 视为同一患者,整簇分配
import pandas as pd
from sklearn.model_selection import GroupShuffleSplit
df = pd.read_csv("dataset.csv")
bone_cols = ["hand", "ulna", "radius", "humerus", "foot", "tibia",
"fibula", "femur", "hip bone"]
df["main_bone"] = df[bone_cols].idxmax(axis=1)
df["pseudo_pid"] = (df["center"].astype(str) + "_" + df["age"].astype(str)
+ "_" + df["gender"] + "_" + df["main_bone"])
gss = GroupShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
train_idx, val_idx = next(gss.split(df, groups=df["pseudo_pid"]))
print(len(train_idx), len(val_idx), df["pseudo_pid"].nunique())
这个划分不完美,但它把「同一患者的两张图落在两边」的概率压到了很低。任何在 BTXRD 上报指标的工作,都应该说明自己用的是哪一档,否则数字之间不可比。
§5.5 交付物与体积
| 交付物 | 内容 | 体积 | 备注 |
|---|---|---|---|
| images/ | 3746 张 JPEG | 约 780 MB | 8 位灰度,尺寸不一 |
| Annotations/ | 1867 份 JSON | 约 20 MB | LabelMe 格式 |
| dataset.csv | 3746 行 × 37 列 | 小于 1 MB | 多热宽表 |
| 整包 | zip | 801 MB | 免注册直下 |
尺寸不一是第三个工程细节。论文没有统一重采样,所以图像短边从几百到两千像素都有。训练时若要固定输入,必须自己写 resize;直接 torchvision.transforms.Resize 会改变长宽比,对骨长度这类比例特征有影响,建议用 letterbox 保持比例再补边。
§6 能做什么:任务谱与基线
§6.1 三类任务与各自的评价口径
| 任务 | 输入 | 输出 | 主指标 | 类别不平衡处理 |
|---|---|---|---|---|
| 三分类 | 整图 | 正常 / 良性 / 恶性 | 宏平均 F1、每类召回 | 类加权,重点看恶性召回 |
| 检测 | 整图 | 若干框 + 置信度 | mAP@0.5 | 只在肿瘤图上评,正常图当负样本 |
| 分割 | 整图 | 二值掩膜 | Dice、IoU | 小病灶用 Tversky 或边界损失 |
三个任务的难度差异很大。三分类在官方基线上已经到零点九以上,属于「快饱和」的任务;检测与分割的 mAP 在零点七上下,还有明显提升空间。如果你的目标只是发一篇应用论文,三分类的空间已经不大;如果要做方法贡献,分割的边界质量与跨部位泛化是更有价值的切口。
§6.2 官方基线到底跑了什么
论文用 YOLOv8 系列做了三组实验,输入六百像素,训练三百轮,八二随机划分。检测用 YOLOv8s,分割用 YOLOv8s-seg,分类用 YOLOv8s-cls。
| 任务 | 模型 | 指标 | 数值 |
|---|---|---|---|
| 检测 | YOLOv8s | mAP@0.5(全部) | 0.707 |
| 分割 | YOLOv8s-seg | Mask mAP@0.5(全部) | 0.691 |
| 分类 | YOLOv8s-cls | 正常准确率 | 0.904 |
| 分类 | YOLOv8s-cls | 良性准确率 | 0.899 |
| 分类 | YOLOv8s-cls | 恶性准确率 | 0.965 |
恶性准确率最高,这个结果需要解释,否则会被误读。原因不是恶性容易认,而是恶性样本最少、征象最典型:三百四十二张恶性图里绝大多数是骨肉瘤,骨肉瘤的成骨、骨膜反应、软组织肿块三件套在平片上极其醒目。相反,良性里的骨纤维瘤与骨囊肿边界温和、与正常骨重叠多,才是真正难的部分。一个模型在恶性上到零点九六、在良性上只有零点八九九,说明它学的是「典型恶性征象」,而不是「良性 vs 恶性」的边界。
§6.3 训练配方建议
基于这份数据的特性,一套稳妥的配方是:先做「正常 vs 肿瘤」二分类,用全部三千七百四十六张;再在肿瘤子集上做三分类与亚型分类;检测与分割用 YOLOv8-seg 或 Mask R-CNN 从头训,或用 COCO 预训练权重微调。
| 阶段 | 数据 | 损失 | 轮数 | 备注 |
|---|---|---|---|---|
| 一 | 全部 3746 张 | BCE | 30—50 | 学到骨轮廓与大体异常 |
| 二 | 肿瘤 1867 张 | CE + 类权重 | 50—80 | 三分类 |
| 三 | 肿瘤 1867 张 | CE(七具名类) | 50—80 | 亚型,剔除两个合并类 |
| 四 | 肿瘤 1867 张 | CIoU + Dice | 100—300 | 检测分割联合 |
关键不在超参,而在阶段二与阶段三的样本量。三百四十二张恶性图,一次五折交叉验证每折只有六十多张验证样本,指标的置信区间会非常宽。报结果时必须给置信区间或多次重复的均值方差,单次划分的一个小数点没有意义。
§6.4 评估协议
#-- 三分类评估:宏平均 F1 + 每类召回 + 恶性召回的 bootstrap 置信区间
import numpy as np
from sklearn.metrics import f1_score, recall_score, confusion_matrix
def report(y_true, y_pred, n_boot=1000, seed=42):
rng = np.random.default_rng(seed)
macro = f1_score(y_true, y_pred, average="macro")
rec = recall_score(y_true, y_pred, average=None, labels=[0, 1, 2])
boot = []
for _ in range(n_boot):
idx = rng.integers(0, len(y_true), len(y_true))
boot.append(f1_score(y_true[idx], y_pred[idx], average="macro"))
lo, hi = np.percentile(boot, [2.5, 97.5])
return {"macro_f1": round(macro, 4), "recall": rec.round(4).tolist(),
"ci95": (round(lo, 4), round(hi, 4)),
"cm": confusion_matrix(y_true, y_pred).tolist()}
报宏平均而不报准确率,报每类召回而不报总体,报置信区间而不报单点——这三条是这份数据的最低评估纪律。原因很直白:正常图占一半,恶性只占百分之九,总体准确率会被正常类主导。
§6.5 八个真实坑点
⚠️ 坑点 1:按目录遍历标注,只数出一千八百六十七份(分类:预处理陷阱)
问题:Annotations 目录只有肿瘤图的 JSON,正常图没有对应文件。用「一份 JSON 一个样本」的方式构造数据集,会把一半的正常图全部丢掉,模型永远学不到「正常骨长什么样」。
症状:训练集只有一千八百六十七个样本,验证集准确率虚高到零点九八,一上真实片子就把正常骨判成肿瘤。
解决:
- 简单方法:以 images 目录为准遍历,用
os.path.exists判断有无 JSON,无则掩膜全零、标签取 dataset.csv。- 进阶方法:把正常图显式当负样本,构造
(image, mask=None, label=0)三元组,检测任务里作为背景图参与,分割任务里用全零掩膜加一个has_lesion标志位区分「真负样本」与「未标注」。- SOTA 方法:用半监督或自监督预训练把正常图当无标注数据,先学骨轮廓表征,再在有标注子集上微调。
参考:论文 Data Records 段明确说明 images 含全部图像、Annotations 只含肿瘤图。
⚠️ 坑点 2:把多热标签当单标签做 softmax(分类:标签理解)
问题:dataset.csv 的三十三列是 0/1 多热,一行同时命中「肿瘤」「良性」「股骨」「下肢」「正位」「骨软骨瘤」。直接
argmax或CrossEntropyLoss会把「良性」与「骨软骨瘤」当成互斥类,梯度互相抵消。
症状:训练损失下降很慢,混淆矩阵出现「良性被判成骨软骨瘤」这类跨维度错误,验证准确率卡在零点六上下。
解决:
- 简单方法:先按维度切列,只取亚型九列做单标签,且只在 tumor=1 的行上训练。
- 进阶方法:多头结构,性质头(三分类)、亚型头(九分类)、部位头(多标签 sigmoid)、体位头(三分类),损失加权求和。
- SOTA 方法:用层级分类,先判有无瘤,再判良恶性,最后判亚型,每层只在上一层为正的样本上计算损失,避免正常图污染亚型头。
参考:论文表三示例行的字段说明。
⚠️ 坑点 3:没有患者编号,随机划分造成泄漏(分类:数据泄漏)
问题:主键是 image_id,同一患者的不同体位图在表里是独立行。官方基线用八二随机划分,同一病灶的正位图可能在训练集、侧位图在验证集。
症状:验证集指标比外部测试高十到二十个百分点,同一张片子换个角度就判错。
解决:
- 简单方法:至少把文件名相邻的图放在同一侧(
image_id是顺序编号,同批采集的图编号接近)。- 进阶方法:用 (center, age, gender, 主要骨) 四元组构造伪患者编号,GroupShuffleSplit 整簇分配。
- SOTA 方法:按来源中心留一交叉验证,把 Radiopaedia 与 MedPix 当外部测试集,中心一内部再做伪患者分组。
参考:论文未提供 patient_id;第三方研究在汇总公开骨影像集时把 BTXRD 归入「无患者标识」一类。
⚠️ 坑点 4:同一病灶多视角,图像级指标虚高(分类:评估误用)
问题:一张片子上可能有多个病灶实例,一个患者可能有多张不同体位的片子。按图像计指标时,同一病灶被重复计入,等于给容易识别的病例加权。
症状:报「恶性召回 0.96」很漂亮,但按病灶去重后掉到零点九以下。
解决:
- 简单方法:报指标时同时给图像级与伪患者级两套数字。
- 进阶方法:对预测做非极大值抑制后再统计,避免同一病灶多个框被算成多次命中。
- SOTA 方法:用 FROC 或每病灶灵敏度(lesion-level sensitivity)作为主指标,这是检测类临床评估的通行口径。
参考:论文说明「每个肿瘤实例」有独立掩膜与框,隐含一图多实例。
⚠️ 坑点 5:8 位 JPEG 没有标尺,别做毫米级测量(分类:预处理陷阱)
问题:院内 DICOM 转 JPEG 时丢了像素间距与投照参数,公开源本来就是网页图。图像上更没有放标尺。
症状:算出的「病灶长径 3.2 厘米」在不同图上系统性偏移,同一病灶在正位与侧位上算出的面积差三倍。
解决:
- 简单方法:只做相对量(病灶面积占骨面积的比例),不做绝对量。
- 进阶方法:用解剖标志(股骨髁宽度、椎体高度)做个体内标定,把像素换算成比例的骨单位。
- SOTA 方法:改用带像素间距的 DICOM 源数据做定量,把 BTXRD 只用于训练与验证分割算法,不用于测量学结论。
参考:论文 Methods 说明 DICOM 转 8 位灰度 JPEG。
⚠️ 坑点 6:体位与侧别缺失,水平翻转是危险增强(分类:预处理陷阱)
问题:表里只有正位、侧位、斜位三个标志,没有左右侧。水平翻转会把左桡骨变成右桡骨,标签无法约束这一变换;若图像角落烧有 L/R 铅字,翻转后语义直接反了。
症状:加了水平翻转后验证指标不升反降,或模型对同一病灶的左右镜像给出不同诊断。
解决:
- 简单方法:禁用水平翻转,改用旋转小角度、亮度对比度扰动、随机裁剪。
- 进阶方法:先做侧别检测(识别铅字或按解剖不对称性推断),只对侧别无关的任务开翻转。
- SOTA 方法:把侧别作为显式条件输入(condition),让模型学「同一病灶左右对称等价」而不是被强制等价。
参考:dataset.csv 列清单无 left/right 字段。
⚠️ 坑点 7:合并类拖垮宏平均(分类:标签理解)
问题:其他良性与其他恶性是收纳筐,内部病种互不相关,样本量又小。九分类的宏平均会被这两类拉低,且低得没有解释价值。
症状:七类具名亚型 F1 都在零点八以上,宏平均只有零点六五。
解决:
- 简单方法:亚型任务只用七类具名标签,两个合并类排除。
- 进阶方法:把合并类作为「其他」超类,做层级 softmax,允许模型在不确定时退回超类。
- SOTA 方法:用开集识别(open-set)框架,把合并类当已知未知,评估模型拒识能力。
参考:论文图五说明 other bt 与 other mt 是小样本合并。
⚠️ 坑点 8:三源混采的域偏移,一套归一化参数不够(分类:偏倚陷阱)
问题:院内 PACS 图与 Radiopaedia、MedPix 网页图的对比度、锐化、边框裁切都不同。统一用 ImageNet 均值方差归一,会让某一源的像素分布整体偏离。
症状:按中心拆分评估时,中心三的准确率比中心一低十个百分点以上;混淆矩阵里出现「按来源分组」的聚类结构。
解决:
- 简单方法:分中心统计像素均值方差,各源用各自参数,或统一做直方图均衡。
- 进阶方法:CLAHE 或 z-score 逐图归一,去掉全局亮度差异;训练时把 center 作为辅助任务,观察模型是否偷学来源。
- SOTA 方法:域泛化训练(如 CORAL、MixStyle),或把中心二、中心三整体留作外部测试。
参考:论文给出三中心各自的年龄均值与图像数,分布差异明显。
§6.6 增强的安全边界
| 增强 | 是否安全 | 理由 |
|---|---|---|
| 小角度旋转(±10°) | 安全 | 平片体位本身有轻微角度差异 |
| 亮度/对比度扰动 | 安全 | 模拟不同设备与后处理 |
| 随机裁剪 + 缩放 | 安全 | 但需保证病灶不被裁掉,用框做约束 |
| 高斯噪声/模糊 | 谨慎 | 过度模糊会抹掉骨膜反应这类细征象 |
| 水平翻转 | 危险 | 侧别语义丢失,铅字反转 |
| 垂直翻转 | 禁止 | 解剖上不成立 |
| 弹性形变 | 危险 | 会改变骨皮质连续性与病灶边界 |
| CutMix / MixUp | 谨慎 | 两张骨片叠加产生的「骨折线」是伪影,可能被学成征象 |
§7 质量与局限性
§7.0 阅读本节前需要知道的一件事
评价这份数据集时最容易发生的框架错位,是拿它和胸部 X 线大数据集比规模。CheXpert 有二十二万张、VinDr-CXR 有一万八千张,BTXRD 只有三千七百四十六张,看起来小得可怜。但这个比较没有意义:胸部平片是每年上亿次的常规检查,骨肿瘤是年发病率百万分之几的罕见病,两者的可得上限差四个数量级。
正确的参照系是「骨肿瘤领域的公开数据」。在这个池子里,BTXRD 是目前少数同时具备图像、亚型、部位、年龄性别与逐病灶几何标注的公开集,而且免注册。它的局限不是「不够大」,而是「不够深」——没有患者编号、没有病理分级、没有随访、恶性亚型覆盖不全。评价它应该问:在我需要的那个维度上,它是不是唯一的选项?
§7.1 已知偏倚
| 偏倚类型 | 描述 | 严重程度 | 缓解 |
|---|---|---|---|
| 来源偏倚 | 广西三家医院贡献七成八图像,人群与设备集中 | 高 | 按中心分层评估,报告各源指标 |
| 选择偏倚 | 一万余张筛到三千七百余张,保留率三成七 | 中高 | 意识到数据偏「拍得好」,勿宣称覆盖真实退化分布 |
| 构成偏倚 | 骨软骨瘤占肿瘤图四成,恶性仅一成八 | 高 | 类加权、分层抽样、宏平均 |
| 亚型覆盖偏倚 | 无软骨肉瘤、尤文肉瘤、骨髓瘤独立标签 | 高 | 只做良恶性二层,或明确声明覆盖范围 |
| 标注偏倚 | 部分病例无病理,靠两名专家经验判定 | 中 | 报告标注来源构成,做标签噪声敏感性分析 |
| 年龄-来源混杂 | 院内均值四十岁,公开源均值二十二岁 | 中 | 把年龄作为协变量而非直接特征 |
| 体位不均衡 | 正位为主,侧位斜位少 | 中 | 按体位分层报告,勿在少数体位上下强结论 |
| 时间偏倚 | 院内跨十年,设备与后处理有代际差 | 低中 | 无采集年份字段,只能按中心近似 |
§7.2 标注质量的三层判断
第一层是协议质量。双人复核(十年经验标注、二十年经验审核)、LabelMe 标准格式、掩膜与框同源,这套流程在公开影像集里属于中上水平。零点九零的自我重测 Dice 说明边界定义是可重复的,不是随手画的。
第二层是客观性。没有 inter-rater 一致性统计,没有病理金标准覆盖全部病例,合并类的语义边界未定义。这三点决定了标签的「真值」属性是软性的:它反映的是专家共识,不是组织学事实。
第三层是可用性。标注文件与图像同名、格式标准、字段齐全,工程上没有障碍。真正的问题在语义层——同一张图上「tumor」这个 label 是否包含了反应性水肿区、是否包含了骨膜反应、是否只标了溶骨中心,论文没有给出标注细则。这会影响分割模型的边界行为,也让不同工作之间的 Dice 不可直接比较。
§7.3 泛化性评估
| 目标场景 | 失效风险 | 依据 |
|---|---|---|
| 同分布随机划分 | 低 | 官方基线 mAP 0.707 |
| 同中心新患者 | 中高 | 无患者编号,泄漏难以完全排除 |
| 跨中心(院内到公开源) | 高 | 三源风格差异明显,年龄分布不同 |
| 跨人群(中国到欧美) | 高 | 单一国家为主,公开源为英文教学库 |
| 跨解剖部位(四肢到中轴骨) | 极高 | 中轴骨整类未收录 |
| 跨病种(原发瘤到转移瘤) | 极高 | 转移瘤不在标签体系内 |
| 跨模态(平片到 CT/MRI) | 极高 | 二维投影与断层成像的征象不可迁移 |
| 儿童到成人 | 中 | 年龄跨度大但各段样本量不均 |
这张表最该被记住的是最后三行。骨肿瘤的真实门诊里,成人最常见的骨病变是转移瘤,而转移瘤完全不在这份数据的标签体系里。一个在 BTXRD 上训练到零点九五的模型,遇到乳腺或前列腺转移的溶骨灶时,会输出「恶性」——从二分类角度看是对的,但它并没有学会区分原发与转移,而这个区分决定了治疗路径。
§7.4 伦理与合规
数据采集经广西大学医学院研究伦理委员会批准,批号 GULL240522,因回顾性设计且数据匿名化而豁免知情同意。公开来源部分声明遵守 MedPix 与 Radiopaedia 的图像使用条款。
| 合规要点 | 状态 | 说明 |
|---|---|---|
| 伦理批号 | 有 | GULL240522 |
| 知情同意 | 豁免 | 回顾性 + 匿名 |
| 去标识化 | 图像级 | 去姓名、住院号、检查号、机构标识 |
| 保留的人口学 | 年龄、性别 | 二者组合在小样本下仍有理论再识别风险 |
| 许可 | CC BY-NC-ND 4.0 | 禁商用、禁演绎 |
| 二次发布 | 受限 | ND 条款下不得发布修改版数据集 |
ND 条款这一条值得单独说。CC BY-NC-ND 禁止发布「改编材料」,而把一个数据集重新划分、转格式、加派生标签,在很多法域下都可能被认定为改编。这意味着你可以在论文里报告基于它的实验结果,但把「BTXRD 重划分版」再公开发布是有风险的。做衍生工作时,更稳的做法是发布代码与划分索引文件,让使用者自行复现,而不是发布重打包的图像。
§7.5 DAIMS 24 项评估
| # | 检查项 | 状态 | 说明 |
|---|---|---|---|
| 1 | 宽格式 | ✅ | dataset.csv 一行一图,标签横向展开 |
| 2 | 唯一标识 | ✅ | image_id 全局唯一,与文件名、JSON 名一致 |
| 3 | 特殊字符 | ✅ | 文件名纯 ASCII,无空格与中文 |
| 4 | 重复行 | ⚠️ | 无患者编号,同病灶多体位图无法判重 |
| 5 | 缺失编码 | ⚠️ | 0 兼作「否」与「未填」,加列即出问题 |
| 6 | 标签标识 | ✅ | 列名即语义,无编码表依赖 |
| 7 | 罕见类分组 | ✅ | 其他良性/其他恶性显式合并 |
| 8 | 偏倚评估 | ⚠️ | 论文给分布,未做偏倚量化 |
| 9 | 数据字典 | ⚠️ | 无独立字典文件,字段含义靠表头与图注 |
| 10 | 信息性缺失解释 | ❌ | 未说明正常图为何无几何标注 |
| 11 | 设备记录 | ❌ | 无厂商、型号、曝光参数 |
| 12 | 共线性 | ⚠️ | 部位与亚型强相关,年龄与来源强相关 |
| 13 | 编码映射 | ⚠️ | 无 ICD-11 / SNOMED CT 映射 |
| 14 | 时间戳处理 | ❌ | 无检查日期,仅中心级年份区间 |
| 15 | 划分建议 | ⚠️ | 官方仅给随机八二,未给患者级方案 |
| 16 | 泄漏讨论 | ❌ | 论文未讨论同患者跨集问题 |
| 17 | 标签分布 | ✅ | 亚型与部位计数公开 |
| 18 | 测量偏倚 | ⚠️ | 8 位 JPEG 无标尺,绝对测量不可行 |
| 19 | 外部验证建议 | ⚠️ | 未做跨中心留出验证 |
| 20 | 版本记录 | ✅ | figshare DOI 可解析,首发日期明确 |
| 21 | 预处理脚本 | ❌ | 无官方转换或加载脚本 |
| 22 | 合规要求 | ⚠️ | 有伦理批号,无 DUO 标签 |
| 23 | 多模态对齐 | ❌ | 单模态,无配对 CT/MRI/病理 |
| 24 | 去标识化 | ✅ | 去直接标识,仅留年龄性别 |
DAIMS 评分:12.5 / 24。二十四项里八项完全满足,九项部分满足,七项缺失。扣分集中在元数据深度(设备、时间、编码映射)与治理(泄漏讨论、预处理脚本、缺失解释)。
评分解读:这个分数在公开影像集里属于中等偏上。它的强项是「表结构干净」——唯一键、纯 ASCII、标签即语义、罕见类显式合并,这四项是很多大牌数据集都做不好的。它的弱项是「可追溯性」——没有设备、没有日期、没有 ICD 映射,意味着你无法做任何与时间、设备、编码体系相关的二次分析。十二点五分不是一个「差」的评价,而是一个「边界清楚」的评价:它把该给的给了,没给的也没假装给。
对你意味着什么:如果你的工作依赖设备参数或时间趋势,这份数据直接出局;如果你要做的是「有没有瘤、在哪、什么形状」,它够用而且省事;如果你要发论文,务必在 Methods 里写明「无患者标识,采用伪患者分组划分」,并报告按来源分层的指标——审稿人现在会查这一条。
§7.6 外部验证矩阵
| 外部场景 | 来源 | 任务 | 结果 | 关键发现 |
|---|---|---|---|---|
| 骨肿瘤基础模型评测 | 独立研究(2026,npj Digital Medicine 系) | 零样本/线性探针分类 | 被列为公开骨肿瘤平片基准之一 | 与 MURA、GRAZPEDWRI-DX、FracAtlas 同列,用于检验骨骼基础模型 |
| 官方自评 | 原论文 | 检测/分割/分类 | mAP 0.707 / 0.691,准确率 0.904—0.965 | 8:2 随机划分,无患者级拆分 |
外部独立验证目前很少。这不是数据集的错,是领域现状:骨肿瘤平片本身就缺统一评测协议,各家用的划分、类别、指标都不同。在这种情况下,任何跨论文的数字比较都要打折扣。
§8 生态位:一个明确的空白格
§8.1 骨肿瘤 X 线在库内的位置
站内骨骼方向此前是薄的。按关键词检索,与骨骼、脊柱、骨折、肉瘤、放射相关的词条一共十几条,但真正落在「骨肿瘤」上的只有一条骨肉瘤病理词条,而且那是组织病理切片,不是影像。其余分布在别的格子里:颈椎骨折是创伤,骨龄是生长发育,脊柱 X 线是退变与压缩,胸部 X 线是心肺。
| 站内词条 | 模态 | 病种 | 与骨肿瘤的关系 |
|---|---|---|---|
| osteosarcoma | 病理全切片 | 骨肉瘤 | 同一病种,不同模态;无影像 |
| soft-tissue-sarcoma | 多组学 + 病理 | 软组织肉瘤 | 间叶来源但非骨,需区分 |
| cervical-spine-fracture | X 线/CT | 颈椎创伤 | 同模态,非肿瘤 |
| rsna-bone-age | 手部 X 线 | 骨龄 | 同模态,非肿瘤 |
| spr-xray-age | 手部 X 线 | 骨龄 | 同模态,非肿瘤 |
| vindr-spinexr | 脊柱 X 线 | 退变 | 同模态,非肿瘤 |
| medpix-nlm | 多模态教学库 | 全病种 | 上游来源之一 |
| openi-iu-xray | 胸部 X 线 | 心肺 | 同模态,不同部位 |
| vinbigdata-cxr | 胸部 X 线 | 心肺 | 同模态,不同部位 |
这张表说明一件事:在「骨肿瘤 + 影像」这个交叉格上,此前是空的。BTXRD 填的正是这一格。它的不可替代性不在规模,而在于它是目前唯一一份把骨肿瘤平片做成「分类 + 检测 + 分割」三任务统一标注的公开集。
§8.2 与软组织肉瘤的分界
软组织肉瘤那一篇容易被误当成「同类」。两者的差别是解剖学层面的:软组织肉瘤起源于脂肪、肌肉、血管、神经鞘等间叶组织,影像上表现为软组织肿块,骨通常是被侵犯的一方而不是起源;骨肿瘤起源于骨与软骨,影像上以骨破坏、骨膜反应、基质矿化为核心征象。
这个差别决定了任务不同。软组织肉瘤的多组学数据用来做分子分型与预后,影像只是分期工具;骨肿瘤平片的核心任务就是「这张片子上的骨破坏是不是瘤、是哪种瘤」。前者是基因组学问题,后者是影像诊断问题,两者不能互相替代,也不构成竞争。
§8.3 上游来源的可追溯性
BTXRD 的八百零八张图来自 Radiopaedia 与 MedPix。这两个库本身是公开的,意味着理论上可以回溯到原始病例页面看讲解。这对教学很有用——你可以拿一张图对照它对应的放射学讨论,理解为什么标成这个亚型。
但也带来一个隐性的复现问题:教学库的病例会更新、会下架、会被编辑修改。今天下载的图,明年可能在源站已经找不到对应页面。数据集打包时冻结了图像,但没冻结来源链接,所以「这张图出自哪个病例」这件事在数据包内是不可查的。做审计或做教学引用时,这是一个无法补上的缺口。
§8.4 它为何能持续
公开数据集的生命周期通常取决于三件事:托管是否稳定、许可是否清晰、社区是否有持续的使用需求。BTXRD 在这三点上都不算差。
托管在 figshare,有 DOI,属于 Springer Nature 体系,长期可解析的概率高。许可明确写了 CC BY-NC-ND 4.0,虽然限制商用与演绎,但至少不是「许可不明」——后者才是数据集消亡的主因。需求侧更稳:骨肿瘤平片的公开数据稀缺是结构性的,只要这个领域还有人在做算法,这份数据就会被引用。
真正的风险在维护。论文没有承诺版本更新,figshare 记录首发于 2024 年 11 月,目前只有一个版本。如果未来要补中轴骨、补恶性亚型、补患者编号,需要重新走伦理与标注流程,成本不低。所以更现实的预期是:这份数据会长期以「v1 静态快照」的形态存在,靠引用而非更新维持价值。
§9 使用指引
§9.1 三种角色的最短路径
| 角色 | 第一步 | 第二步 | 第三步 |
|---|---|---|---|
| 算法工程师 | 下载 → 数三个数(图、JSON、CSV 行) | 跑通「正常 vs 肿瘤」二分类 | 加分割头,用伪患者划分复评 |
| 放射科医师 | 下载 → 按亚型翻图 | 对照教科书征象核对标签 | 挑出可疑标错,形成反馈清单 |
| 教学/住培 | 下载 → 按部位建索引 | 每类挑 5—10 张做题库 | 用掩膜做「指出病灶」练习 |
三类角色的共同前提是先把三个计数对齐。图、JSON、CSV 行数不对,后面所有工作都是在错的基础上叠加。
§9.2 最小实现:从零到第一个指标
#-- 最小闭环:读表 -> 取子集 -> 训练三分类 -> 报宏平均 F1
import pandas as pd
import torch
from torch.utils.data import Dataset, DataLoader
from PIL import Image
from torchvision import transforms
class BTXRDCls(Dataset):
def __init__(self, df, root, tf):
self.df, self.root, self.tf = df.reset_index(drop=True), root, tf
def __len__(self):
return len(self.df)
def __getitem__(self, i):
row = self.df.iloc[i]
img = Image.open(f"{self.root}/images/{row.image_id}").convert("L").convert("RGB")
#-- 三类:0 正常 / 1 良性 / 2 恶性,由两个 0-1 列合成
label = 0 if row.tumor == 0 else (1 if row.benign == 1 else 2)
return self.tf(img), torch.tensor(label, dtype=torch.long)
tf = transforms.Compose([
transforms.Resize((600, 600)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
])
df = pd.read_csv("data/btxrd/dataset.csv")
ds = BTXRDCls(df, "data/btxrd", tf)
dl = DataLoader(ds, batch_size=16, shuffle=True, num_workers=4)
batch_x, batch_y = next(iter(dl))
print(batch_x.shape, batch_y.bincount())
这段代码有三个刻意的选择:读图时先转灰度再转三通道,是为了复用 ImageNet 预训练权重;标签由 tumor 与 benign 两列合成而不是直接读 malignant,是为了让「正常」与「良性」的边界显式;批大小十六配上六百像素输入,在二十四吉显存的卡上刚好。
§9.3 它在 AI 流程中的位置
BTXRD 适合放在流程的「预训练 + 基准」两段,不适合放在「部署前验证」这一段。
预训练段的用法:用三千七百四十六张图做骨影像的自监督或监督预训练,学到一个懂骨轮廓、懂皮质连续性、懂病灶区域的encoder,再迁到自己的 CT 或 MRI 任务上。骨影像的纹理与对比度在平片与断层之间有共性,这一步的迁移通常有效。
基准段的用法:作为「骨肿瘤良恶性分类」这一任务的公开参照点。任何新方法要证明自己在骨肿瘤上有效,报一个 BTXRD 上的数字是低成本的取信方式。
不适合部署前验证,原因已经说过:来源集中、恶性亚型不全、无患者标识。部署前的验证必须用你目标医院自己的、带患者编号与病理金标准的留出集。
§10 AI 使用声明
| 项目 | 内容 |
|---|---|
| 性质 | 公开研究数据集,非医疗器械,非临床决策系统 |
| 模型训练用途 | 允许(非商业),需署名并引用 DOI |
| 商业用途 | 需另行取得授权(NC 条款) |
| 衍生数据发布 | 受限(ND 条款,禁发改编版数据) |
| 不建议用途 | 直接临床辅助诊断、患者级预后预测、以毫米为单位的测量学结论 |
| 伦理 | 原始采集经 GULL240522 批准,豁免知情同意;二次使用应遵守当地伦理要求 |
| 引用 | 引用 Scientific Data 论文与 figshare DOI 两处 |
| 版本 | figshare v1,2024-11-20 首发 |
| 页面状态 | published |
常见误读(避坑清单)
| 常见说法 | 实际情况 | 证据 |
|---|---|---|
| 「这是目前最大的骨肿瘤 X 线数据集」 | 它是目前少数公开的,不是最大的;私有队列常有上万张 | 论文自述公开数据缺失,未做规模排名 |
| 「九个亚型就是骨肿瘤的全谱」 | 九类里两类是合并类,软骨肉瘤、尤文肉瘤、骨髓瘤无独立标签 | 表三字段清单与图五 |
| 「有三千七百四十六个病例」 | 是三千七百四十六张图,患者数未公布且明显更少 | 主键为 image_id,无 patient_id |
| 「标注是三名医师投票的金标准」 | 一人标、一人复核,一致性是自我重测不是评分者间 | Methods 标注段 |
| 「图像是原始 DICOM」 | 院内 DICOM 已转 8 位灰度 JPEG,头信息全丢 | Data Records 段 |
| 「正常图也有分割掩膜」 | 只有一千八百六十七张肿瘤图有 JSON | 目录结构与计数 |
| 「可以直接商用」 | CC BY-NC-ND 4.0,禁商用禁演绎 | 论文 Rights and permissions |
| 「恶性准确率 0.965 说明模型很可靠」 | 恶性样本仅三百余张且以骨肉瘤为主,属典型征象易分 | 表四与亚型分布 |
| 「和软组织肉瘤数据集是同类」 | 一个是骨原发肿瘤平片,一个是软组织肉瘤多组学 | 解剖起源不同 |
| 「下载要申请」 | figshare 直下,免注册 | 论文 Data Records 段 |
| 「中轴骨肿瘤也在里面」 | 头颈胸腹整类排除,仅四肢与骨盆 | Methods 排除标准 |
| 「有左右侧字段」 | 只有正位、侧位、斜位,无侧别 | dataset.csv 列清单 |
附录 A 数据组织
| 层级 | 内容 | 数量 | 命名规则 |
|---|---|---|---|
| 顶层 | 压缩包 | 1 | 801 MB |
| 图像 | JPEG | 3746 | IMG + 六位零填充 + .jpeg |
| 标注 | JSON | 1867 | 与图像同名,仅肿瘤图有 |
| 表格 | CSV | 1 | dataset.csv,3746 行 37 列 |
| 字段组 | 元数据 4 + 标签 33 | 37 | 元数据为 id、center、age、gender |
三者的对齐关系是:CSV 的 image_id 去掉扩展名后,等于 images 下的文件名主干,也等于 Annotations 下的文件名主干(若存在)。任何一方缺失都说明数据不完整。
附录 B 肿瘤类别与编号
| 序 | 英文标签 | 中文 | 性质 | 病灶数 | 说明 |
|---|---|---|---|---|---|
| 1 | osteochondroma | 骨软骨瘤 | 良性 | 754 | 最常见,干骺端背向关节生长 |
| 2 | osteosarcoma | 骨肉瘤 | 恶性 | 297 | 青少年干骺端,成骨与骨膜反应 |
| 3 | multiple osteochondromas | 多发性骨软骨瘤 | 良性(综合征) | 263 | 遗传性多发病灶,非单病灶诊断 |
| 4 | simple bone cyst | 单纯骨囊肿 | 良性 | 206 | 儿童长骨中心性溶骨 |
| 5 | giant cell tumor | 骨巨细胞瘤 | 交界性 | 未单列 | 骺线闭合后偏心性溶骨 |
| 6 | osteofibroma | 骨纤维瘤 | 良性 | 未单列 | 与骨纤维结构不良非同一诊断 |
| 7 | synovial osteochondroma | 滑膜骨软骨瘤 | 良性(关节) | 未单列 | 关节滑膜来源,非骨原发 |
| 8 | other bt | 其他良性 | 合并类 | 未单列 | 小样本良性汇总 |
| 9 | other mt | 其他恶性 | 合并类 | 未单列 | 小样本恶性汇总 |
前四类合计一千五百二十个病灶,占肿瘤图约八成;后五类的合计约三百四十七个,未逐一公布。第 5 至第 7 类的性质归类需注意:骨巨细胞瘤在 WHO 分类中属交界性/局部侵袭性,滑膜骨软骨瘤起源于关节滑膜而非骨,二者被并入「骨肿瘤」标签体系是数据集的一处概念扩展。
附录 C 术语表
| 术语 | 解释 |
|---|---|
| 原发性骨肿瘤 | 起源于骨、软骨或骨附属组织的肿瘤,区别于转移瘤 |
| 溶骨性破坏 | 骨密度降低、骨结构被吸收的破坏形式 |
| 成骨性改变 | 新生骨形成导致的密度增高 |
| 移行带 | 病灶与正常骨之间的过渡区宽度,窄提示良性、宽提示恶性 |
| 骨膜反应 | 骨膜受刺激形成的新骨,Codman 三角、葱皮样、日光放射样各有提示 |
| 软骨帽 | 骨软骨瘤顶端的软骨覆盖层,厚度与恶变风险相关 |
| 地图样破坏 | 边界清晰、形态规则如地图的溶骨区,多见于良性 |
| 虫蚀样破坏 | 多发小孔状边缘模糊的破坏,提示侵袭性 |
| 渗透性破坏 | 边界完全不清的弥漫破坏,恶性度最高 |
| 基质矿化 | 肿瘤内部钙化或骨化,软骨类呈环弧状 |
| 多热编码 | 一行可同时命中多个 0/1 标签的编码方式 |
| 伪患者编号 | 用人口学与部位组合近似替代缺失的患者标识 |
| 宏平均 F1 | 各类 F1 的算术平均,不受类样本量影响 |
| 病灶级灵敏度 | 以病灶而非图像为单位统计的召回率 |
| Letterbox | 保持长宽比缩放后补边到固定尺寸的预处理 |
| 域偏移 | 训练与部署数据的分布差异,此处主要指来源中心差异 |
| 开集识别 | 允许模型对未知类别输出拒识的识别框架 |
| 合并类 | 把多个小样本类别并入一个标签的收纳式类别 |
附录 D 常见问题
| 问题 | 回答 |
|---|---|
| 一共多少张图、多少个患者 | 图三千七百四十六张;患者数未公布,且由于同一患者可有多张不同体位图,患者数明显少于图像数 |
| 有几个亚型 | 九个标签,其中两个是合并类;七个具名类里骨巨细胞瘤、骨纤维瘤、滑膜骨软骨瘤未公布单类计数 |
| 标注是框还是掩膜 | 两者都有,同一份 LabelMe JSON 内含多边形与矩形两种 shape |
| 图像是 DICOM 吗 | 不是,已转 8 位灰度 JPEG,无头信息 |
| 从哪里下载 | figshare,DOI 10.6084/m9.figshare.27865398,免注册 |
| 能商用吗 | 不能,CC BY-NC-ND 4.0 |
| 能自己重新划分后发布吗 | 不建议,ND 条款可能把重划分视为改编;发布划分索引文件更稳 |
| 为什么搜到 Mendeley 也有 | 那是目录检索层,文件托管与 DOI 解析都在 figshare |
| 能用来做骨肉瘤 vs 尤文肉瘤吗 | 不能,尤文肉瘤没有独立标签 |
| 能做预后分析吗 | 不能,无随访与结局 |
| 中文标签在哪 | 数据包内只有英文列名,中文对照见附录 B |
| 为什么正常图比肿瘤图多 | 正常对照易得,且院内可批量导出;肿瘤病例稀缺 |
附录 E 许可与引用
| 项目 | 内容 |
|---|---|
| 数据集 DOI | 10.6084/m9.figshare.27865398 |
| 论文 DOI | 10.1038/s41597-024-04311-y |
| 期刊 | Scientific Data,卷 12,文章号 88(2025) |
| 收稿 / 接收 / 见刊 | 2024-06-17 / 2024-12-17 / 2025-01-16 |
| figshare 首发 | 2024-11-20 |
| 许可 | CC BY-NC-ND 4.0 |
| 伦理批号 | GULL240522(广西大学医学院) |
| 引用格式 | Yao S, Huang Y, Wang X, et al. A Radiograph Dataset for the Classification, Localization, and Segmentation of Primary Bone Tumors. Sci Data 12, 88 (2025). |
@article{yao2025btxrd,
title = {A Radiograph Dataset for the Classification, Localization, and Segmentation of Primary Bone Tumors},
author = {Yao, Shunhan and Huang, Yuanxiang and Wang, Xiaoyu and Zhang, Yiwen and Paixao, Ian Costa and Wang, Zhikang and Chai, Charla Lu and Wang, Hongtao and Lu, Dinggui and Webb, Geoffrey I. and Li, ShanShan and Guo, Yuming and Chen, Qingfeng and Song, Jiangning},
journal = {Scientific Data},
volume = {12},
pages = {88},
year = {2025},
doi = {10.1038/s41597-024-04311-y}
}
编辑说明
本篇核验日期为 2026-10-29。规模数字取自 figshare 记录摘要与 Scientific Data 论文正文(Data Records、Methods、Technical Validation 三节),许可取自论文 Rights and permissions 段。未做全量下载与逐图统计,因此不写任何分布类的新数字;后五个亚型的确切计数、多病灶图的占比、患者实际例数三项在原文中未给出,正文按未公布处理而不做推算。figshare 元数据接口在核验时不可达,许可条款以论文声明为准,若后续 figshare 页面标注不同,以页面为准并同步修订附录 E。
相关数据集导航
以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:
- hecktor — 共享标签:医学影像 / X光影像 / 医学图像分割 / 肿瘤学
- fracatlas — 共享标签:医学影像 / X光影像 / 骨骼肌肉影像
- rsna-bone-age — 共享标签:医学影像 / X光影像 / 骨骼肌肉影像
- chexmask-cxr-segmentation-data — 共享标签:医学影像 / X光影像 / 医学图像分割
- chexmask-u — 共享标签:医学影像 / X光影像 / 医学图像分割
- lung-segment-mimic-cxr — 共享标签:医学影像 / X光影像 / 医学图像分割
- mimic-cxr-ext-ils — 共享标签:医学影像 / X光影像 / 医学图像分割
- ddsm — 共享标签:医学影像 / X光影像 / 医学图像分割
- mura — 共享标签:医学影像 / X光影像 / 骨骼肌肉影像
- osteosarcoma — 共享标签:医学影像 / 骨骼肌肉影像 / 肿瘤学
导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

