医院的放射科里,藏着数万张“身体内部的黑白照片”——CT 和 MRI 扫描仪把人体切成一片片薄如硬币的断面。医生的日常工作之一,是在这些灰色照片上描出肝脏、肿瘤的精确轮廓。以前这活儿靠手工,一例肝脏分割要画三四十分钟;如今大家请来一位叫 U-Net 的“AI 描图学徒”,让它学习专家手绘的线稿,练成自动描边的本事。这篇教程从认识片子的“密度刻度”讲起,带你看 U-Net 工作室的三件法宝(编码器、解码器、跳跃连接),再聊聊专家标注规范、小样本下的四招急救术、Dice 这把“评分卡尺”,最后把成品送回医院的 PACS 影像档案室,帮院长算清这笔账。学完,你就掌握了医疗影像 AI 从论文到病床前的最小完整闭环。
对 AI 从业者:掌握 CT/MRI 分割是进入医疗 AI 的入场券。理解 U-Net、标注规范与 PACS 集成,能帮你把模型从论文变成医院里真正可用的产品,而非停留在 demo 阶段。
可视化演示
演示U-Net影像分割、器官与病灶掩码提取及Dice评估,理解有限标注条件下医学影像分割的实现方法。
本节配有交互动效(进入视口后自动加载,约 3KB)。
影像分割:掩码提取 器官轮廓 病灶核心 Seg: Ω→{0,1} 像素级分离解剖结构
分割任务概述
教小 U 描边前,得先让它“看懂照片”。CT 片就像用 X 光给身体拍的黑白密度写真:骨头最亮(近乎白色),空气最黑(近乎黑色),肝脏、肾脏挤在大片灰阶里。MRI 片则是另一种画风——软组织层次更细腻,肌肉、脂肪、脑组织分得清清楚楚,但没有统一的“灰度刻度”。
医生看片靠眼睛和几十年经验;AI 看片靠把每个像素归类。分割任务的定义就是:给输入图片的每一个像素,贴上“肝脏”“病灶”“背景”这样的类别标签。这和“这张图有没有肿瘤”的图像分类是两码事——分类只回答一句话,分割要画出一整张地图。
为了让灰度可统一比较,CT 使用霍斯菲尔德单位(HU):规定水的值为 0,空气为 -1000,致密骨可到 +1000 以上。医生通过调节“窗宽窗位”查看不同组织——看肺用一个窗,看软组织用另一个窗。部署模型时,通常要把 HU 裁剪到目标组织范围并归一化;而 MRI 没有物理刻度,不同序列(T1/T2)灰度含义不同,预处理要单独设计。临床上,分割的用处很直接:肿瘤体积测量、放化疗疗效评估、术前规划、放疗靶区勾画——这些场景正是后面 ROI 讨论的落点。
- 组织挡光系数 μ每种组织对 X 光的衰减能力不同,是 HU 的原料。
- 与水的相对差用组织的衰减减去水的衰减,消除扫描仪自身差异。
- 放大 1000 倍把差值放大成易读刻度:水 0、空气 -1000、骨骼约 +1000。
U-Net架构
小 U 的工作室叫 U-Net,名字取自它的外形——一个大写的 U。左边一列逐渐变窄的矩形是“缩图台”(编码器),右边一列逐渐变宽的矩形是“放图台”(解码器),中间横着一条条虚线是“传送带”(跳跃连接)。
编码器像画家先“眯眼看全局”:图像一层层下采样,从像素级细节中提炼出“这团影子是什么、在腹部哪个位置”的整体理解,最底部的“瓶颈”是最浓缩的全局认知。这一步很像人看画先看构图,再盯笔触。
解码器负责“落笔描细节”:把全局理解一层层上采样放大回原尺寸,在每个位置判断像素类别。但缩图必然丢毛边,所以跳跃连接把编码器每层保留的细节图直接拼到解码器对应层,让描边“既懂全局、又不丢毫米级边界”。由于整个网络只用卷积、不接全连接层,输入任意尺寸都能处理,故称全卷积网络。
- Up 上采样把上一层缩小的特征图放大到当前层尺寸,像把草稿投到投影仪放大。
- 通道拼接中括号表示把两路特征按通道叠起来,让语义与细节合流。
- 卷积融合Conv 用可学习的卷积核重新混合拼接后的特征,决定哪些细节该突出。
变体模型
学会了素描,还有水彩和油画。U-Net 家族里有四位最常见的“画家”。
3D U-Net 把几十张连续切片叠成一个数据块直接输入,一次看清病灶前后方向的完整形态,适合肝脏、脑等三维器官。V-Net 在 3D 卷积上直接优化 Dice 损失,专门对付前景太小的病灶。Attention U-Net 在解码器装上“注意力门控”,自动忽略无关区域,把精力集中在器官边界。nnU-Net 则像一位“自动搭画室”的监理:拿到数据自动决定预处理、网络深度、训练策略,是医学分割竞赛的常胜将军。
选型直觉:器官类(肝、肾、脑)优先 3D 与 nnU-Net;病灶小而稀疏时用 Dice 类损失;算力受限或切片间距大时退回 2D U-Net。
- C 通道数多个 MRI 序列或 CT 窗位组合成的输入“图层”。
- D×H×W 尺寸深度(切片张数)、高度、宽度三个维度。
- fθ 分割函数3D 卷积网络把每个体素逐个分类,输出体积级掩膜。
数据标注规范
师傅画样例,徒弟学手艺。AI 分割的“样例”就是医生在 CT/MRI 片上手工勾画的掩膜。这一环通常是项目里最贵、最慢的。
动手标注前,先写“标注指南”:病灶边界画到哪?血管算不算器官一部分?坏死区怎么处理?不同医生习惯不同,指南不统一,模型学到的是互相矛盾的标准,输出边界必然模糊。实际操作常用 ITK-SNAP、3D Slicer 等开源工具逐层勾画,支持半自动轮廓插值,把工作量摊薄。
质量怎么把关?常用 Cohen's Kappa 衡量两位医生标注的一致性:1 表示完全一致,0 表示和随机差不多。分割标注通常要求 kappa ≥ 0.8,否则需要返工或请第三人仲裁。成本上,一例肝脏+肿瘤标注约 30-90 分钟,100 例高质量标注可能需要数周——这正是小样本方法重要性的由来。
- p_o 实际一致率两位医生逐像素标注一致的比例。
- p_e 随机一致率两人瞎画也可能碰巧一致的比例,必须扣除。
- kappa 打分分子扣随机、分母归一,结果最大为 1。
小样本策略
只给五张带教线稿,学徒能出师吗?有经验的师傅有四招。
第一招数据增强:把样例翻转、旋转、缩放、加噪声,五张变五十张,让模型学会“病灶不管长在哪边都认得”。第二招迁移学习:先在别的医院大数据上练熟“看肝”的手感,再到本院少量数据上微调。第三招半监督伪标签:大量片子没有标注,让当前模型打“伪标签”,只挑高置信度的混进训练集,相当于自学。第四招预训练模型:直接加载开源权重做起点,少走弯路。
注意增强要“尊重解剖常识”:肝脏不会长到图像右上角,CT 不会左右颠倒扫描。过度随机的增强反而破坏位置先验。把这几招组合起来,几十例标注也能训出可用的分割模型。
- 变换 T_a翻转、旋转、缩放等保持语义的几何变换,按分布随机采样。
- 增强样本对图像与掩膜同变换,标签与内容始终对齐。
- 伪标签门槛 τ置信度高于 τ 的未标样本才被采纳,防止噪声入队。
评估与调优
画得准不准,不能靠感觉。医生的第一把卡尺叫 Dice 系数:把模型画的红圈和标准答案红圈叠在一起,看重叠度。
Dice 取值 0 到 1,1 是完美重合。漏画和多画都被分母惩罚。另一个常用指标 IoU(交并比)分母更大,更严格。训练时常用 Dice Loss = 1 − Dice,或 Dice 与交叉熵的加权和,专门解决病灶只占全图 1% 像素、普通损失被背景淹没的问题。
调优还要注意:三维体素 Dice 通常高于二维切片 Dice;小病灶的 Dice 波动大,常配合体积误差、95% 豪斯多夫距离一起看,避免“平均分好看、单个病例翻车”。
- TP 真阳性预测和标准答案都判定为病灶的像素数。
- FP 与 FN多画与漏画的像素,都在分母里拉低分数。
- 双倍重叠重叠区放大两倍,保证结果落在 [0, 1] 区间。
PACS集成
医生日常阅片的地方,是医院的“中央影像档案室”——PACS(影像归档与通信系统)。所有 CT/MRI 都按 DICOM 标准存档,病人信息、扫描参数和像素数据打包在一起。
AI 分割要“住进”档案室,标准管线是:PACS 推送 DICOM → 解析像素与元数据 → 预处理 → GPU 推理得到掩膜 → 把掩膜编码成 DICOM 覆盖层或 RT-STRUCT 放疗勾画格式 → 回传 PACS,医生在原阅片界面直接叠加查看。
工程要点:推理服务容器化部署在院内 GPU 服务器,数据不出院;接口对接遵循 DICOMweb / HL7;低置信度结果打“待复核”标记而不是直接发布;并持续监控整条链路的端到端时延。
- T传输DICOM 文件拉取、解析、预处理的耗时。
- T推理模型在 GPU 上预测整套序列的耗时。
- T回传掩膜编码并写回 PACS、通知阅片端的耗时。
项目落地ROI
作品挂进了画廊,最后轮到院长翻账本:这套 AI 流水线到底划不划算?
成本大头在标注(人力最贵)、GPU 与院内部署、合规注册(三类医疗器械需临床验证)、以及持续运维。收益主要是医生勾画时间从 30-60 分钟压到 5-10 分钟,以及漏诊率下降带来的医疗质量提升。选高频、刚需、勾画费时的场景(肝脏肿瘤分割、脑卒中快速评估)最容易算正账。商业模式上可按“按例计费”或“平台年费”向医院收费,前提是 ROI 为正。
ROI 模型很简单:每个病例省下的医生分钟数 × 年病例量,是年度总节省;减去年度总成本,再除以年度总成本。分母越大,项目越需要“量大”来摊薄。
- Δt 单例节省手工勾画与 AI 辅助的耗时差,按分钟计。
- Ncases 年病例量该检查类型的年数量,决定节省能否放大。
- Ctotal 年总成本标注、算力、合规、运维的年摊成本。
AI 应用场景
肝脏肿瘤体积评估与手术规划
阶段:模型部署 → 医学图像分割 → 临床辅助决策
解决的问题:术前医生手动逐层勾画肝脏和肿瘤边界,单例耗时 30-90 分钟,且不同医生画法差异大。AI 自动分割 2 分钟内出结果,为外科医生提供肿瘤体积、与血管距离等量化参数,就像给“填色线稿”配了一把电子卡尺。
具体案例:某三甲医院肝胆外科接入 U-Net 分割服务,CT 序列到达 PACS 后自动触发推理,肝脏与肿瘤掩膜回传阅片端,医生一键确认后生成体积报告,术前规划时间缩短约 70%。
放疗靶区勾画自动化
阶段:小样本适配 → 分割模型微调 → 工作流嵌入
解决的问题:放疗科医生需在 MRI/CT 上逐层勾画靶器官与危及器官,勾画质量直接影响放疗剂量。AI 用迁移学习把小样本做“放大”,先自动勾画高危器官,医生只做重点审核与局部修改。
具体案例:某放疗中心用迁移学习把开源前列腺分割模型适配到本院 MRI 序列,仅标注 20 例即达到 Dice 0.85,靶区勾画时间从 40 分钟降至 8 分钟,模型结果以 RT-STRUCT 格式回传 PACS。
Python 演示
"""CT病灶分割小样本演示: 数据增强 + 多视角投票 + Dice评估"""import numpy as np np.random.seed(42) def make_slice(size=64): """合成一张类CT切片: 灰色背景 + 暗色'肝脏' + 亮色'病灶'""" yy, xx = np.ogrid[:size, :size] img = np.full((size, size), 0.1) liver = ((xx - 30) / 18) ** 2 + ((yy - 32) / 22) ** 2 <= 1 img[liver] = 0.5 lesion = ((xx - 38) / 6) ** 2 + ((yy - 40) / 5) ** 2 <= 1 img[lesion] = 0.95 mask = (img > 0.9).astype(np.uint8) return img, mask def augment(img, mask): """数据增强: 随机翻转 + 随机旋转90度""" if np.random.rand() < 0.5: img, mask = img[:, ::-1], mask[:, ::-1] k = np.random.randint(0, 4) return np.rot90(img, k), np.rot90(mask, k) def dice(pred, true): """Dice系数: 1为完美重合, 0为完全无重叠""" eps = 1e-6 inter = 2 * np.sum(pred * true) return inter / (np.sum(pred) + np.sum(true) + eps) def threshold_seg(img, th=0.85): """极简分割模型: 高密度阈值, 模拟小样本下不稳定的预测""" pred = (img > th).astype(np.float32) noise = np.random.rand(*img.shape) pred[noise > 0.97] = 1 - pred[noise > 0.97] # 3%随机翻转 return (pred > 0.5).astype(np.uint8) def un_aug(mask, k, flip): """撤销增强, 用于把投票结果拼回原图坐标系""" mask = np.rot90(mask, -k) if flip: mask = mask[:, ::-1] return mask def tta_seg(img, views=8): """测试时增强: 8个视角各预测一次, 过半投票合并""" votes = np.zeros_like(img, dtype=np.float32) for k in range(4): for flip in (False, True): aug_img = np.rot90(img[:, ::-1] if flip else img, k) votes += un_aug(threshold_seg(aug_img), k, flip) return (votes >= views // 2).astype(np.uint8) def main(): labeled = [make_slice() for _ in range(5)] # 小样本: 仅5例标注 pool = [] for img, mask in labeled: for _ in range(8): pool.append(augment(img, mask)) # 5例 -> 40例 print('数据增强: 5例标注 -> %d个训练样本' % len(pool)) test = [make_slice() for _ in range(40)] # 40例测试切片 d1 = np.mean([dice(threshold_seg(x), m) for x, m in test]) d2 = np.mean([dice(tta_seg(x), m) for x, m in test]) print('基础分割 Dice: %.3f -> 增强投票 Dice: %.3f' % (d1, d2)) print('提升: +%.3f (多视角投票抵消随机误差)' % (d2 - d1)) if __name__ == '__main__': main()
mask = (img > 0.9).astype(np.uint8)由生成规则产出“医生标注”的标准答案,模拟真实标注掩膜。pool.append(augment(img, mask))数据增强:5 例标注扩成 40 个训练样本,对应正文“翻转旋转缩放”策略。def dice(pred, true)原样实现正文 Dice 公式,返回 0~1 的重叠度。pred[noise > 0.97] = 1 - pred[noise > 0.97]给阈值模型注入 3% 随机翻转,模拟小样本下预测的不稳定性。votes += un_aug(threshold_seg(aug_img), k, flip)8 个视角各预测一次,再撤销到原坐标,完成测试时增强。(votes >= views // 2).astype(np.uint8)过半投票决定最终分割,把随机误差平均掉。
常见误区
误区我一直以为分割和分类差不多,模型输出一个“有肿瘤 / 没肿瘤”的标签就够了,顶多多几个类别。
正解分割输出的是和原图同尺寸的“逐像素标签图”,每个像素都要回答“我是什么组织”。就像填色书要求给每个色块描出边界,而不是只写一句“这页有猫”。分类回答一句话,分割画出一整张地图。
为何常见:图像分类是多数入门教程第一个讲的模型,任务边界容易串味。
误区只要多标几百例,医生之间画得不一样没关系,反正数据量大模型自己能学会。
正解标注标准不一致会让模型学到噪声。两位医生 kappa 低于 0.8 的边界,模型只能学到“平均值”,输出边界发虚。先定指南再标注,比单纯堆数量更有效。
为何常见:大家习惯把数据标注当成流水线体力活,忽略了标准制定才是质量的源头。
误区样本少就使劲翻转旋转,增强数量越多效果一定越好。
正解过度增强会破坏医学图像的解剖先验——肝脏不会长到图像右上角,CT 不会左右颠倒扫描。要选与临床一致的真实变换,同时配合迁移学习、预训练和伪标签,而不是单靠增强堆量。
为何常见:数据增强是公开课第一个教的小样本技巧,容易默认它万能。
误区模型 Dice 刷到 0.9 就万事大吉,可以全自动发布了。
正解Dice 对边界的小偏移不敏感,而临床更关心体积误差、漏诊/误诊比例,以及“医生还要不要再花 10 分钟改”。要同时看 95% 豪斯多夫距离和医生编辑距离,并区分三维体素 Dice 与二维切片 Dice。
为何常见:论文都用 Dice 当主指标,团队就习惯拿论文指标直接当产品验收标准。
误区既然模型自动出了掩膜,就应该直接写进诊断报告,这样最省事。
正解当前监管与临床习惯都要求 AI 作为“辅助”而非“决策者”。低置信度结果要打“待复核”标记并退回人工,PACS 集成时也要保留医生的确认环节,守住医疗责任边界。
为何常见:demo 里“自动出图”的效果很酷,容易让团队忽略医疗场景的责任与合规约束。
面试题
Q1. CT 图像中,水的霍斯菲尔德单位(HU)值约为?
- A.负1000
- B.正好为0← 正确答案
- C.正1000
- D.正500
答案:B。HU 以水为 0、空气为 -1000、致密骨约 +1000,是 CT 阅片和预处理的统一“灰度标尺”。选 1000 或 500 都是把刻度和骨密度记混了。
Q2. U-Net 中“跳跃连接”的主要作用是什么?
- A.加快训练收敛速度
- B.保留下采样的细节← 正确答案
- C.减少网络参数量
- D.放大输出到原尺寸
答案:B。编码器下采样会丢毛边,跳跃连接把同层细节图直接拼给解码器,让描边“既看全局又保细节”。加速收敛、减少参数都不是它的核心作用。
Q3. 下列哪些属于改善小样本分割的策略?
- A.随机翻转旋转增强← 正确答案
- B.迁移学习预训练微调← 正确答案
- C.提高CT扫描辐射剂量
- D.半监督伪标签扩增← 正确答案
答案:ABD。增强、迁移、伪标签是正文讲的三板斧;提高辐射剂量是临床安全问题,与算法无关且有害,绝不能选。
Q4. nnU-Net 相比普通 U-Net 的最大特点是什么?
- A.使用更强的GPU硬件
- B.自动配置训练细节← 正确答案
- C.只支持MRI影像数据
- D.不需要任何标注数据
答案:B。nnU-Net 像“自动搭画室的监理”,拿到数据自动决定预处理、网络深度与训练策略。它不挑硬件、不限定模态,更不可能脱离标注数据。
Q5. 两位医生标注结果的 Cohen's Kappa = 0.6,最合理的处理是?
- A.两人结果完全一致
- B.一致性差需检查指南← 正确答案
- C.一致性良好可直接使用
- D.与随机标注没有差异
答案:B。分割标注的合格线通常要求 kappa ≥ 0.8,0.6 属于中等一致,说明两人对边界的理解有分歧。这时候要回头检查标注指南,而不是急着拿去训练。
Q6. Dice Loss 在医学分割中常被用来解决什么问题?
- A.病灶像素占比太小← 正确答案
- B.标注数据量不足
- C.模型训练速度慢
- D.图片分辨率太低
答案:A。病灶常只占全图 1% 像素,普通交叉熵会被背景淹没。Dice Loss 直接以重叠度为损失,天然缓解类别不均衡,但它不负责数据量、速度或分辨率。
Q7. 计算 ROI 时,公式中的"Δt × N"表示什么?
- A.一年节省的医生总工时← 正确答案
- B.模型推理的总时延
- C.数据标注的总成本
- D.单张GPU显卡采购价
答案:A。Δt 是单例节省的医生分钟数,N 是年病例量,两者相乘就是年度总节省工时;其余选项都属于成本端,不是节流来源。
Q8. 小样本分割中,“伪标签”技术属于哪类方法?
- A.数据增强策略
- B.半监督学习方法← 正确答案
- C.模型压缩技术
- D.图像配准算法
答案:B。伪标签是先用模型给未标注数据打标,再挑高置信度的样本加入训练,本质是让模型“自学”,属于半监督学习,不依赖额外人工标注。
Q9. 关于 3D U-Net,下列描述正确的是?
- A.输入是立体数据块← 正确答案
- B.使用三维卷积操作← 正确答案
- C.一次看多张连续切片← 正确答案
- D.无法处理三维数据
答案:ABC。3D U-Net 的输入是 C×D×H×W 立体数据块,用三维卷积一次看多张连续切片,在体积连贯的器官上更稳。D 选项恰好说反。
Q10. 关于 PACS 集成,哪种做法最符合医疗合规?
- A.上传公有云处理
- B.院内GPU服务器部署← 正确答案
- C.个人电脑离线推理
- D.邮件传图给外包方
答案:B。医疗数据合规第一条是“不出院”,院内 GPU 服务器部署既能满足性能又守住隐私。公有云、个人电脑、邮件传图都可能触碰数据安全红线。