首页 / 文章 / 医学影像在模型看到它之前和之后会发生什么
← 返回
IT技术

医学影像在模型看到它之前和之后会发生什么

✍️ zhirenhun 📅 2026/8/27 👁 151 阅读 ⏱ 27 分钟
医学影像在模型看到它之前和之后会发生什么

医学影像论文充斥着熟悉的术语:归一化、标签、验证、标注和预处理。

如果你来自通用机器学习领域,你可能认为你已经知道这些词的意思。有时你确实知道。

但医学影像领域有一些特殊之处。有些术语含义不同,有些术语根据上下文会有多种用法。

本文将跟随一张胸部 X 光片从获取的那一刻,到模型做出预测的全过程。在此过程中,我们将审视医学影像论文中常见的术语及其实际含义。

一个伴随的 笔记本 让你可以亲自运行这些步骤中的大部分,而不仅仅是阅读它们。

我们将涵盖的内容:

你将学到什么

从图像到数据集

1. 获取

获取是指图像的创建过程。它包括成像设备、其设置以及患者的定位方式。

同一患者的两张胸部 X 光片如果使用不同的设备拍摄,可能会呈现不同的外观。制造商、探测器、曝光设置以及图像处理软件都可能影响最终图像。

患者的体位也很重要。例如,站姿的 PA(后前位) 胸部 X 光片可能与患者躺在床上时拍摄的便携式 AP(前后位) X 光片截然不同。

一个重要的区别是心脏的视在大小。这可能会影响模型学习的内容。

这些信息中的大部分存储在 DICOM 文件中。

DICOM(医学数字成像与通信)是存储和传输医学图像的标准格式。DICOM 文件不仅包含像素,还可以包含患者、扫描仪、研究、图像方向、像素间距以及其他细节的信息。

本教程中使用的图像最初是以 JPEG 形式到达的,因此原始的临床 DICOM 元数据不可用。为了演示,笔记本将图像包装在一个新的 DICOM 文件中,并添加了一些有用的字段。

ds = pydicom.dcmread("synthetic_cxr.dcm")

for tag in ["Modality", "BodyPartExamined", "ViewPosition",
            "Manufacturer", "ManufacturerModelName", "KVP", "PixelSpacing"]:
    print(f"{tag:24s} {ds[tag].value}")

值得关注的一个字段是 PixelSpacing。它表示每个像素所代表的物理尺寸,通常以毫米为单位。两张图片都可以是 512 × 512 像素,但覆盖的物理区域不同。

因此,如果你想以毫米为单位测量某物,不能仅仅计算像素。你还需要知道像素间距。

2. 匿名化、去标识化和假名化

这三个术语经常被互换使用,但它们的含义不同。

去标识化

去标识化会删除或修改可能用来识别个人的信息。

例如:

Patient name
Medical record number
Date of birth
Phone numbers
Other identifying information

目标是降低数据被追溯到个人的可能性。

假名化

假名化用代码替换标识符。

例如:

Jane Doe → SUBJ_0041

重要的区别在于,即使有独立的密钥,仍然可以将 SUBJ_0041 关联回 Jane Doe。

医院可能需要这样做,因为他们有时需要再次找到原始患者。

匿名化

匿名化的目标是使重新识别在合理范围内不可能实现。

与假名化不同,匿名化没有保留的密钥可用于将数据重新关联到个人。

一个简单的问题可以帮助:

此数据是否仍能通过额外信息关联回个人?

如果答案是肯定的,因为存在一个独立的密钥,那么通常您面对的是假名化而非真正的匿名化。

确切的法律含义取决于国家和法规,因此研究者在使用这些术语时应格外谨慎。

像素也可能包含标识符

从 DICOM 头部删除信息仅是工作的一部分。

有时文本实际上会被绘制到图像中。

例如:

Patient name
Date
Hospital name
R
PORTABLE

这被称为烧录注释。

删除 DICOM 元数据对这段文字没有任何影响。你必须在像素中找到文字并将其删除。

这比听起来要难。像“在图像顶部附近寻找亮像素”这样的简单规则会找到不仅仅是文字的内容。锁骨和肋骨等骨骼也很亮。

胸部 X 光片显示识别文本和解剖结构,说明为什么仅删除 DICOM 元数据无法去除烧录注释。

这意味着一个真正的去标识化管道通常会结合几种技术:

Text detection
OCR
Image-region rules
DICOM metadata removal
Validation

目标不仅仅是移除文字,而是要证明文字确实已被移除。

例如:

IDENTIFIERS = [
    "PatientName",
    "PatientID",
    "PatientBirthDate",
    "PatientSex",
    "InstitutionName",
    "ReferringPhysicianName",
    "StudyDate",
    "StudyTime",
    "AccessionNumber"
]

for tag in IDENTIFIERS:
    if tag in ds:
        ds[tag].value = ""

# Records that an identity-removal process was performed.
# This field alone does not make the dataset de-identified.
ds.PatientIdentityRemoved = "YES"

像素级部分是简单演示与真实生产流水线之间差异最大的地方。

3. 安全港和专家认定

如果您处理美国医疗数据,经常会看到两个 HIPAA 术语:安全港专家认定

它们是根据 HIPAA 判断受保护健康信息是否已去标识的两种方法。

安全港

安全港是一份清单。它要求删除 18 类标识符,包括以下内容:

Names
Geographic information smaller than a state
Certain dates
Phone numbers
Medical record numbers
Device identifiers
Full-face photographs

它相当直接,因为你可以按照明确的列表操作。

专家确定

专家确定采用不同的方法。合格的专家评估再识别的风险,并记录剩余风险非常小的原因。这可以让研究人员保留安全港要求删除的信息。

例如,精确的日期在研究疾病随时间的变化时非常有用。

因此存在权衡:

安全港更简单且更具限制性

专家确定更具灵活性,但需要有文档记录的风险评估

这些是美国 HIPAA 的概念。其他国家有不同的隐私法律和定义。

例如,欧盟的 GDPR 和印度的 DPDP 法案对匿名和假名数据有各自的处理方式。

从数据集到模型输入

4. 预处理

预处理是指在将图像输入模型之前对图像进行的操作。

常见的预处理步骤包括:

胸部 X 光片在预处理前后的对比,展示了调整大小、窗口化和方向更改等变化。

调整大小

模型通常期望输入固定尺寸的图像。医学图像可能有多种不同的尺寸,因此经常需要调整大小。

但调整大小会改变像素与物理空间之间的关系。

例如,如果将图像从 1024 × 1024 调整到 512 × 512,每个像素现在代表不同的物理面积。

因此,如果需要毫米级的物理测量(如距离或面积),则需要考虑原始或重采样后的像素间距。

窗口化

窗口化选择一组强度值的范围,并将该范围映射到显示范围。超出范围的值会被裁剪。

放射科医生在观察 CT 图像时常使用不同的窗口设置,因为不同组织在不同窗口下更易于观察。

窗口化改变了图像的表示或显示方式。这并不意味着原始图像数据已被更改。

笔记本使用第 2 和第 98 百分位数演示了窗口化:

lo, hi = np.percentile(img, [2, 98])
windowed = np.clip(
    (img.astype(float) - lo) / (hi - lo),
    0,
    1
)

方向

医学图像也包含方向信息。如果弄错了,左右会被互换,对胸部 X 光片而言,这是一个严重的错误。

5. 归一化

这是第一个具有双重含义的词。

在机器学习中,归一化通常指将数值转换为更一致的尺度或分布,以使训练行为更具可预测性。常见的两种方式:

显示不同像素值归一化方法的胸部 X 光片,对比原始图像以及经过最小-最大和 Z 评分归一化后的版本。
f = img.astype(np.float32)

minmax = (f - f.min()) / (f.max() - f.min())

最小-最大归一化有一个弱点:它直接依赖于最小值和最大值。一个非常亮的像素(例如由设备或噪声引起的像素)会改变范围,导致图像的大部分被压缩到尺度的较小部分。

Z-score 归一化对最小值和最大值的依赖较小,尽管极端值仍可能影响均值和标准差。

在医学影像中,归一化也可以在图像或数据集之间保持一致地应用,但使不同扫描仪或机构的图像可比较则更具体地称为 协调化。当你需要处理多个站点时,这一区别变得尤为重要,如第 10 节所述。

6. 注释和标签

两者都描述与图像相关的信息,但它们所代表的信息内容不同。

胸部 X 光片,展示了图像级标签与空间注释之间的区别,图像中标记了肺部区域。

标签通常用于描述整个图像。

例如:

Image → Pneumonia

一个 注释 通常会告诉你图像中某个物体的位置。

它可以是:

例如:

Image → Lung mask

关键区别在于位置

标签告诉你什么存在,而注释既能告诉你什么存在,还能告诉你在哪里

创建注释也需要付出更多的努力。

一个大型数据集可能从放射科报告中提取出数百万个图像级标签,但只有其中的一小部分可能拥有临床医生创建的详细掩码。

这种捷径有代价。报告可能会说“肺炎”,但这并不一定能告诉你确切是哪些像素显示肺炎。这可能导致噪声标签

7. 数据集划分

在医学影像研究中,最重要的决定之一就是如何划分数据

划分通常应在患者层面进行,而不是图像层面。

假设一位患者有五张胸部X光片。如果将三张图像放入训练集,两张放入测试集,那么模型在训练过程中已经看到该患者的图像。患者特有的特征可能同时出现在两个集合中。这属于数据泄漏

同样的原则也适用于以下情况:

目标很简单:测试集应包含模型在训练过程中未见过的患者。

因此,不应这样做:

先划分图像再分配患者

应这样做:

先划分患者再分配其图像

这是一个细节,其对结果的影响可能甚至超过更改模型架构。

从模型到预测

8. 分类、检测与分割

使用同一张胸部X光片,提出三个不同的问题。

胸部X光片展示了三种模型输出:图像级分类标签、用于检测的边界框以及像素级分割掩码。

分类

是否存在肺炎?

模型返回一个标签或概率。

Pneumonia: 0.92

它告诉你什么在图像中。它不会告诉你位置。

检测

异常在哪里?模型返回一个边界框。

[x, y, width, height]

它大致告诉你发现的位置,但不会描述其确切的形状。

分割

哪些像素属于异常?

模型返回像素级掩码。这能给出发现的形状和位置。

一个简单的记忆方法:

分类 = 什么?

检测 = 在哪里?

分割 = 哪些像素?

从分类到检测再到分割,标注工作量通常会增加。

因此,选择能回答你问题的最简单任务。如果你只需要知道扫描是否异常,可能不需要分割。

9. 数据增强

数据增强通过转换现有图像来创建新的训练样本。

常见的转换包括:

当医学数据集较小时,这可能很有用。

胸部X光片展示了图像增强的例子,包括旋转和水平翻转,演示了转换如何改变解剖方向。

但医学图像有一个重要的限制:转换后的图像仍应看起来像可能真实发生在患者身上的东西。

例如,水平翻转在自然图像机器学习中很常见。

翻转一张猫的照片,你仍然得到一只猫。

但翻转胸部X光片后,心脏会移到另一侧。你可能刚刚创建了一张看起来像dextrocardia的图像,其中心脏位于右侧。

同样的问题也会出现在标记上。右侧的标记可能突然出现在左侧。字母本身也会被镜像。模型不会自动理解这在解剖学上是错误的。

其他增强方式也可能引起问题。大的亮度变化可能掩盖重要发现。激进的裁剪可能会切除部分肺部。

因此,在使用增强之前,请自问:此图像是否可能真实来自真实的扫描仪和患者?

如果不是,则不要使用它。

# Reasonable: small rotation
M = cv2.getRotationMatrix2D((cx, cy), 7, 1.0)
rotated = cv2.warpAffine(
    img,
    M,
    (w, h),
    borderMode=cv2.BORDER_REPLICATE
)

# Potentially problematic for a chest X-ray:
flipped = img[:, ::-1]

10. Postprocessing

后处理在模型产生输出之后进行。

分割模型通常会为每个像素输出一个概率。在应用阈值后,掩码可能包含一些小的不需要的区域或空洞。

肺部分割掩码在后处理前后的对比,展示了小的连通区域的移除和空洞的填充。

例如,笔记本的原始掩码包含:

一种常见的清理步骤是仅保留最大的连通分量。

由于我们预期有两个肺,我们可以保留两个最大的区域。我们也可以填充小的空洞。

labelled, n = ndimage.label(mask > 0)

sizes = ndimage.sum(
    mask > 0,
    labelled,
    range(1, n + 1)
)

keep = np.isin(
    labelled,
    np.argsort(sizes)[-2:] + 1
)

clean = ndimage.binary_fill_holes(keep)

在这个例子中,清理操作将连通分量的数量从 16 减少到 2,同时改变的像素不到 5%。

那说明了评估中的重要点:像素重叠指标可能几乎没有变化,尽管预测的结构已经发生了显著变化。

对于某些应用,连通区域的数量和形状比像素重叠的微小变化更重要。因此,选择与你实际关心的错误相匹配的指标。

此外,要小心后处理。如果你的模型在结果看起来好之前需要大量的清理,那么清理可能掩盖了模型中的问题。

也要始终查看原始输出。

从一家医院到真实世界

11. 调和

想象两家医院使用不同的扫描仪。

图像可能具有以下不同:

在医院 A 上主要训练的模型可能学习到这些差异中的一些,而不是学习与疾病相关的特征。它在医院 A 上可能表现良好,但在医院 B 上可能失败。

这就是调和可以提供帮助的地方。

来自不同成像来源的胸部 X 光片,在调和前后展示了各站点之间亮度和对比度的差异。

调和尝试在保留重要信息的同时,使不同来源的数据更具可比性。

一个简单的例子是直方图匹配

它调整一幅图像的像素值分布,使其看起来更像参考图像。

from skimage.exposure import match_histograms

harmonized = match_histograms(
    image_from_hospital_b,
    reference_from_hospital_a
)

这有助于解决亮度和对比度的差异,但它不能解决所有问题。

如果两台扫描仪在分辨率、噪声特性或图像处理流程上有所不同,仅靠直方图匹配是不够的。

并且如果在图像获取或裁剪过程中信息丢失,协调也无法神奇地恢复它。

一个实用的经验法则是:

归一化使数值更一致。

协调解决了数据来源之间的系统性差异。

12. 回顾性和前瞻性验证

本节讨论研究设计。

回顾性

回顾性研究使用已经存在的数据。

例如:

我们从医院档案中收集了4000张胸部X光片,并在它们上测试了我们的模型。

在医疗AI中这很常见,因为它相对快速且成本低廉。

但它也会带来偏倚的机会。研究者可能会决定包括哪些患者,排除哪些扫描,使用哪家医院,以及选择哪个阈值。

这些决定可能会无意中使结果看起来更好。

前瞻性

在前瞻性研究中,你首先定义研究计划,然后向前收集数据。

例如:

我们在收集图像之前定义患者人群、评估标准和成功指标。

这可以减少一些偏倚来源,因为重要决策是在看到结果之前做出的。

外部验证

您还会看到术语 外部验证

这意味着在与开发模型所使用的数据独立的数据上测试模型。

例如:

Hospital A → Training
Hospital A → Internal test
Hospital B → External validation

一个更强的测试可能是:

Hospital A + B → Development
Hospital C → External validation

在本院数据上表现良好,但在另一家医院表现不佳的模型,可能学到了特定于该站点的模式,而不是普遍的疾病特征。

因此,外部验证往往比仅在同一数据集上再做一次随机划分更具信息量。

把它们放在一起

现在假设一篇医学影像论文中有这句话:

研究者从两家机构回顾性收集了 4,120 份去标识的前景胸部 X 光片。图像被重采样至 512 × 512,进行强度归一化,并通过直方图匹配在各站点之间进行协调。两位放射科医生手动标注了肺野;分割输出经过最大连通分量选择进行后处理。该模型在第三站点的 890 份研究上进行了外部验证。

这段文字信息量很大,但现在你可以解读它:

  1. 回顾性收集:研究者使用了已存在的图像。

  2. 去标识:移除或更改了身份信息。

  3. 两家机构:数据集来自多个来源。

  4. 重采样至 512 × 512:图像被转换为统一的尺寸。

  5. 强度归一化:像素值被转换为更一致的数值范围。

  6. 协调:研究者试图减少两个站点之间的系统性差异。

  7. 两位放射科医生手动标注:专家创建了显示肺野位置的空间信息。

  8. 后处理:模型的原始分割输出被清理。

  9. 外部验证:模型在另一站点的独立数据上进行了测试。

这一点尤为重要。仅在开发数据上表现良好的模型,无法充分反映其在真实世界中的表现。

结论

一篇医学影像论文可以用几句话描述完整的数据流程。

掌握这些术语后,你就能以不同的方式阅读这些句子。

与其仅关注模型及其准确率,不如提出以下问题:

模型是否经过外部验证?

  • 测试数据是否真正独立?

  • 预测后,模型的输出发生了什么?

  • 模型只是医学影像流水线的一部分。更重要的是,许多关键问题往往在 模型看到图像之前 就已经出现。

    ——

    🧑‍💻

    zhirenhun

    一个热爱技术的程序员,喜欢分享前沿AI知识和开发经验。

    ← 上一篇
    停止相信仅文本代理排行榜:来自 Cua-Bench 和 Factorio 的教训
    下一篇 →
    无服务器推理中的冷启动延迟:那些几秒钟到底发生了什么

    📌 相关推荐

    GraphRAG 是推理问题,而非数据库问题
    2026/8/30
    构建市场时光机:使用 Python 和 WebSocket 重放交易会话
    2026/8/30
    如何自行基准测试LLM推理:值得信赖的数字设计标准
    2026/8/30
    ← 返回文章列表