第 7 章 医学影像特征提取与分析
本章导读
分割回答了"病灶在哪里",但临床医生更关心的是"它有多大、是什么形状、内部纹理如何、恶性可能性多高"。本章完成从"图像"到"数字"的跨越:形态学分析(7.1)把分割掩码转化为体积、形状等几何量;纹理与影像组学分析(7.2)从像素灰度的空间排列中挖掘人眼无法感知的定量信息;计算机辅助诊断(7.3)则把这些特征组织成完整的决策系统。
本章是连接核心技术篇与应用实践篇的枢纽:前面章节的分割结果是本章的输入,本章提取的特征又将直接服务于第 9 章的项目实战与第 12 章的影像组学临床应用。特别地,影像组学(Radiomics) 已成为近十年医学影像研究增长最快的方向之一------它的核心命题是"医学图像不只是用来看的,更是用来算的"。
本章学习目标
-
能从二值掩模计算面积、周长、质心、等效直径等形态学特征;
-
理解形状描述子(如圆形度、长宽比、傅里叶描述子)在良恶性鉴别中的作用;
-
理解 Marching Cubes 算法从体素数据重建三维表面的原理;
-
掌握放射组学的基本流程:分割 → 特征提取 → 特征筛选 → 建模 → 临床关联;
-
理解 GLCM、LBP 两类纹理特征的原理与计算方式;
-
了解 CAD 系统的两类范式:基于规则与基于分类模型;
-
知道特征降维(PCA、LASSO)在放射组学建模中的必要性。
7.1 形态学分析
第 5 章分割的输出通常是一个二值掩模:1 表示目标、0 表示背景。形态学分析就是从这个分割掩码中提取几何特征。这些特征看似简单,却是临床报告的直接组成部分:肿瘤体积决定 T 分期,结节倍增时间决定随访策略,心室容积与射血分数决定心功能分级。
7.1.1 区域特征提取
对二维区域 R R R,最基础的特征包括:
1. 面积与周长
面积 = ∣ R ∣ ⋅ s x ⋅ s y ( 像素数 × 物理间距 ) \text{面积} = |R| \cdot s_x \cdot s_y \quad (\text{像素数} \times \text{物理间距}) 面积=∣R∣⋅sx⋅sy(像素数×物理间距)
周长的计算必须小心:直接数边界像素会系统性高估(锯齿状边界比对角线长),工程上常用 Freeman 链码加权或 Crofton 公式校正。
2. 质心与方向
质心(零阶矩归一化的一阶矩):
x ˉ = 1 ∣ R ∣ ∑ ( x , y ) ∈ R x , y ˉ = 1 ∣ R ∣ ∑ ( x , y ) ∈ R y \bar{x} = \frac{1}{|R|}\sum_{(x,y) \in R} x, \qquad \bar{y} = \frac{1}{|R|}\sum_{(x,y) \in R} y xˉ=∣R∣1(x,y)∈R∑x,yˉ=∣R∣1(x,y)∈R∑y
二阶中心矩构成协方差矩阵,其特征向量给出区域的主轴方向(呼应 3.1 节的特征值分解),特征值之比刻画区域的"细长程度":
μ p q = ∑ ( x , y ) ∈ R ( x − x ˉ ) p ( y − y ˉ ) q \mu_{pq} = \sum_{(x,y) \in R} (x - \bar{x})^p (y - \bar{y})^q μpq=(x,y)∈R∑(x−xˉ)p(y−yˉ)q
3. 形状描述子
| 描述子 | 公式 | 临床含义示例 |
|---|---|---|
| 圆形度(Circularity) | 4 π ⋅ 面积 周长 2 \frac{4\pi \cdot \text{面积}}{\text{周长}^2} 周长24π⋅面积 | 良性结节圆度高,恶性常有毛刺 |
| 紧致度(Compactness) | 周长 2 面积 \frac{\text{周长}^2}{\text{面积}} 面积周长2 | 浸润性生长使紧致度升高 |
| 长宽比 | 主轴长度 / 次轴长度 | 肿大淋巴结由长圆形变圆 |
| 实心度(Solidity) | 面积 / 凸包面积 | 凹陷程度(如分叶征) |
| 离心率(Eccentricity) | 椭圆拟合的离心率 | 腺体导管的形态评估 |
| 分叶度 | 边界曲率的符号变化次数 | 肿瘤边界规则性 |
python
"""
基于 scikit-image计算形态学特征
"""
import numpy as np
from skimage import measure, morphology
# 假设 tumor_mask 是分割得到的二值掩码(第 5 章的输出)
tumor_mask = np.zeros((256, 256), dtype=bool)
yy, xx = np.ogrid[:256, :256]
tumor_mask[(yy - 128)**2 / 40**2 + (xx - 120)**2 / 60**2 <= 1] = True # 椭圆病灶
# 连通域标记 + 区域属性提取
labeled = measure.label(tumor_mask)
regions = measure.regionprops(labeled, intensity_image=None)
for r in regions:
print(f"面积: {r.area} 像素")
print(f"质心: {r.centroid}")
print(f"周长: {r.perimeter:.1f} 像素")
print(f"圆形度: {4*np.pi*r.area / r.perimeter**2:.3f}")
print(f"长宽比: {r.major_axis_length / r.minor_axis_length:.2f}")
print(f"离心率: {r.eccentricity:.3f}")
print(f"实心度: {r.solidity:.3f}")
print(f"主轴方向: {np.degrees(r.orientation):.1f}°")
4. Hu 不变矩
Hu 矩(7 个由二阶/三阶中心矩组合的量)具有平移、旋转、缩放不变性,适合病灶形态的模板匹配与检索(如"在病例库中查找形态相似的结节")。但高阶矩对噪声敏感,实际临床量化中低阶形状描述子更常用。
7.1.2 3D 体素分析
三维形态分析的原理与二维一致,但有两个必须注意的工程细节:
1. 体积计算要乘体素物理体积
python
"""
读取影像,并计算肿瘤体积。
"""
import SimpleITK as sitk
import numpy as np
mask_img = sitk.ReadImage('tumor_mask.nii.gz')
mask = sitk.GetArrayFromImage(mask_img) # (Z, Y, X)
spacing = mask_img.GetSpacing() # (sx, sy, sz),单位 mm
voxel_volume = spacing[0] * spacing[1] * spacing[2] # mm³
tumor_volume_mm3 = mask.sum() * voxel_volume
tumor_volume_ml = tumor_volume_mm3 / 1000
print(f"肿瘤体积: {tumor_volume_ml:.2f} mL")
医学影像小贴士:体积测量是疗效评估的硬指标
RECIST 标准用单径测量,但越来越多证据表明体积测量对疗效变化的敏感性是单径的 3--5 倍(球形病灶直径增大 26% 对应体积翻倍)。肿瘤负荷、脑萎缩速率、心室容积等关键指标全部依赖准确的 3D 体积分析------前提是各向同性重采样(第 4 章)与准确分割(第 5 章)都已正确完成。
2. 表面积需要表面重建
直接数边界体素会严重高估表面积(阶梯效应),正确做法是先用 Marching Cubes 重建光滑三角网格,再求网格面积。
7.1.3 Marching Cubes 表面重建
Marching Cubes(Lorensen & Cline, 1987)是把体数据转换为三角网格的经典算法,也是 3D 可视化、3D 打印、手术规划的基础。

图 7-1 Marching Cubes:从体数据到三角网格
Marching Cubes 表面重建算法核心思想(以 2D 版本 Marching Squares 说明):
- 逐个遍历 2 × 2 × 2 2\times2\times2 2×2×2 的体素立方体(cube)
- 立方体 8 个顶点各有"在等值面内/外"两种状态 → 共 2 8 = 256 2^8 = 256 28=256 种组合
- 查表确定等值面穿过该立方体的三角形构型(利用对称性可归并为 15 种基本情形)
- 棱边上的交点用线性插值精确定位
- 拼接所有立方体的三角形 → 完整表面网格
python
"""
表面重建
"""
from skimage import measure
import numpy as np
# 从体数据提取等值面(例如 CT 中骨骼的 HU 阈值 300)
volume = ... # 3D numpy array (Z, Y, X)
verts, faces, normals, values = measure.marching_cubes(
volume,
level=300, # 等值面阈值(HU)
spacing=(2.0, 0.5, 0.5), # 体素间距 → 输出物理坐标 mm
step_size=1, # 采样步长(>1 可加速但损失精度)
)
print(f"顶点数: {len(verts)}, 三角面片数: {len(faces)}")
# 网格表面积(物理单位 mm²)
mesh_surface_area = measure.mesh_surface_area(verts, faces)
print(f"表面积: {mesh_surface_area:.1f} mm²")
# 导出 STL 用于 3D 打印 / 手术规划软件
import struct
def save_stl(verts, faces, path):
with open(path, 'wb') as f:
f.write(b'\0' * 80) # STL 头部
f.write(struct.pack('<I', len(faces)))
for face in faces:
v0, v1, v2 = verts[face]
normal = np.cross(v1 - v0, v2 - v0)
norm = np.linalg.norm(normal)
normal = normal / norm if norm > 0 else normal
f.write(struct.pack('<12fH', *normal, *v0, *v1, *v2, 0))
# save_stl(verts, faces, 'bone_model.stl')
应用链:CT 分割(第 5 章)→ Marching Cubes 重建 → 3D 打印手术导板 / 虚拟现实术前演练。骨科、颌面外科已常规使用这一流程。
注意:平滑是重建前的重要步骤
分割掩码直接做 Marching Cubes 会得到"阶梯状"表面。标准做法是先对掩码做高斯平滑 ( σ ≈ 0.5 \sigma \approx 0.5 σ≈0.5-- 1.0 1.0 1.0 体素)再提取等值面,或重建后用 Taubin/Laplacian 平滑网格。但平滑会轻微缩小体积------定量测量时应以体素计数为准,网格仅用于可视化与几何分析。
7.2 功能与纹理分析
形态学特征描述"外形",而组织内部的灰度空间排列------纹理------包含肉眼不可见的微观结构信息。这是影像组学的核心洞察。
7.2.1 放射组学(Radiomics)
1. 影像组学的定义与流程
影像组学:从医学影像中高通量提取大量定量特征,通过数据挖掘建立与临床结局(病理分级、基因表型、预后、治疗响应)的关联。

图 7-2 影像组学标准五步流程
2. IBSI 标准与特征类别
IBSI(Image Biomarker Standardisation Initiative) 是影像组学特征的国际计算标准,统一了不同软件的特征定义------此前同名特征(如"熵")在不同软件中计算结果可相差数倍,严重阻碍多中心研究。
放射组学有几个关键工程细节必须强调:
- 可重复性:不同扫描仪、不同重建核、不同窗宽窗位下,同一肿瘤的纹理特征可能漂移。因此临床级放射组学必须做多中心数据归一化(第 4 章)、特征 ICC(组内相关系数)筛选 ------ 只有跨采集条件仍稳定的特征才保留。
- 特征标准化:GLCM、LBP 这些特征的量级差异巨大(面积可能几百、纹理熵可能 5),建模前必须做 Z-score 或 Min-Max 归一化(4.2.1)。
- 小样本陷阱 :上百维特征、几十例病人是放射组学论文的常态,极易过拟合。LASSO 正则化(3.2.2 的 L1 稀疏)、交叉验证、独立外部验证是必备防线。Python 里常用 PyRadiomics 库一键提取上述全套特征,是事实标准工具。
标准特征分为四族:
| 特征族 | 数量级 | 代表特征 | 刻画的信息 |
|---|---|---|---|
| 一阶统计(First-order) | ~18 | 均值、方差、偏度、峰度、熵 | 灰度分布(不考虑空间) |
| 形状(Shape) | ~16 | 体积、表面积、球形度、最大径 | 几何形态 |
| 纹理(Texture) | ~75 | GLCM、GLRLM、GLSZM、NGTDM、GLDM | 灰度空间排列 |
| 滤波后特征(Filtered) | 数百 | 小波/LoG 变换后的上述特征 | 多频率成分的细节 |
一个 ROI 通常提取 100--1500 个特征------"高通量"由此而来。
3. PyRadiomics 实战
python
"""
PyRadiomics库
"""
import SimpleITK as sitk
from radiomics import featureextractor
# 1. 配置提取器
settings = {
'binWidth': 25, # 灰度离散化 bin 宽度(IBSI 推荐固定 binWidth)
'resampledPixelSpacing': [1, 1, 1],# 重采样到各向同性(第 4 章!)
'interpolator': 'sitkBSpline',
'normalize': False, # CT 有 HU 物理意义,不 normalize
}
extractor = featureextractor.RadiomicsFeatureExtractor(**settings)
extractor.enableAllFeatures()
# 2. 提取(image 与 mask 必须空间对齐------第 6 章配准的意义)
image = sitk.ReadImage('lung_ct.nii.gz')
mask = sitk.ReadImage('lung_nodule_mask.nii.gz')
features = extractor.execute(image, mask, label=1)
# 3. 整理输出
for name, value in features.items():
if not name.startswith('diagnostics'): # diagnostics 是元信息
print(f"{name}: {value}")
医学影像小贴士:影像组学的三大工程陷阱
- 离散化(discretization):纹理矩阵必须先做灰度量化,binWidth 的选择直接影响纹理特征值------CT 推荐固定 binWidth=25 HU,MRI 因无标准单位需先归一化再用固定 bin 数
- 重采样:体素间距不同会改变纹理的空间尺度,必须先重采样到统一 spacing
- 特征可重复性:同一病灶两次勾画的特征差异(观察者内/间变异)应通过 ICC(组内相关系数)筛选,只保留 ICC > 0.8 的稳健特征进入建模
4. 特征选择与建模
上千个特征对几十到几百个样本------典型的"小 n 大 p"问题,直接建模必然过拟合。标准应对:
- 可重复性筛选:ICC > 0.8
- 单变量筛选:Mann-Whitney U 检验 / 相关性初筛
- 降维:PCA 或相关性聚类(去除 |r| > 0.9 的冗余特征)
- 嵌入式选择:LASSO(L1 正则逻辑回归------第 3 章的稀疏先验再次登场!)
- 建模 :逻辑回归 / SVM / 随机森林 + 嵌套交叉验证
python
"""
特征选择
"""
from sklearn.linear_model import LassoCV, LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler
import numpy as np
# X: (n_patients, n_features) 影像组学特征矩阵
# y: (n_patients,) 临床结局(如 0=良性, 1=恶性)
X_scaled = StandardScaler().fit_transform(X)
# LASSO 特征选择(L1 正则 → 稀疏解,3.1 节的几何直觉在此兑现)
lasso = LassoCV(cv=5, random_state=42, max_iter=5000)
lasso.fit(X_scaled, y)
selected = np.where(np.abs(lasso.coef_) > 1e-5)[0]
print(f"LASSO 从 {X.shape[1]} 个特征中选出 {len(selected)} 个")
# 用选出的特征建模
clf = LogisticRegression(max_iter=1000)
scores = cross_val_score(clf, X_scaled[:, selected], y,
cv=5, scoring='roc_auc')
print(f"5 折交叉验证 AUC: {scores.mean():.3f} ± {scores.std():.3f}")
7.2.2 纹理分析:GLCM 与 LBP

图 7-3 GLCM 灰度共生矩阵计算示意
1. GLCM(灰度共生矩阵)
GLCM 统计相距固定方向和距离的像素对的灰度联合分布:
P ( i , j ∣ d , θ ) = # { ( p , q ) : I ( p ) = i , I ( q ) = j , q = p + ( d cos θ , d sin θ ) } P(i, j | d, \theta) = \#\{(p, q) : I(p) = i, \; I(q) = j, \; q = p + (d\cos\theta, d\sin\theta)\} P(i,j∣d,θ)=#{(p,q):I(p)=i,I(q)=j,q=p+(dcosθ,dsinθ)}
从矩阵中提取的 Haralick 特征:
| 特征 | 公式 | 物理含义 | 肿瘤应用 |
|---|---|---|---|
| 对比度(Contrast) | ∑ i , j ( i − j ) 2 P ( i , j ) \sum_{i,j} (i-j)^2 P(i,j) ∑i,j(i−j)2P(i,j) | 局部灰度变化 | 恶性肿瘤异质性高 → 对比度高 |
| 能量(Energy/ASM) | ∑ i , j P ( i , j ) 2 \sum_{i,j} P(i,j)^2 ∑i,jP(i,j)2 | 纹理规则性 | 良性组织纹理均匀 → 能量高 |
| 同质性(Homogeneity) | ∑ i , j P ( i , j ) 1 + ∣ i − j ∣ \sum_{i,j} \frac{P(i,j)}{1+|i-j|} ∑i,j1+∣i−j∣P(i,j) | 灰度相近程度 | 坏死区破坏同质性 |
| 相关性(Correlation) | ∑ i , j ( i − μ i ) ( j − μ j ) P ( i , j ) σ i σ j \sum_{i,j} \frac{(i-\mu_i)(j-\mu_j)P(i,j)}{\sigma_i\sigma_j} ∑i,jσiσj(i−μi)(j−μj)P(i,j) | 灰度线性依赖 | 结构方向性 |
| 熵(Entropy) | − ∑ i , j P ( i , j ) log P ( i , j ) -\sum_{i,j} P(i,j)\log P(i,j) −∑i,jP(i,j)logP(i,j) | 随机性/复杂度 | 肿瘤异质性的经典度量 |
python
"""
提取GLCM
"""
from skimage.feature import graycomatrix, graycoprops
import numpy as np
# ROI 灰度量化(纹理矩阵的前提,呼应上面的工程陷阱)
roi = ... # 病灶 ROI,uint8
roi_q = (roi / roi.max() * 63).astype(np.uint8) # 量化为 64 级
# 4 个方向、距离 1 的共生矩阵
glcm = graycomatrix(roi_q, distances=[1],
angles=[0, np.pi/4, np.pi/2, 3*np.pi/4],
levels=64, symmetric=True, normed=True)
for prop in ['contrast', 'energy', 'homogeneity', 'correlation']:
vals = graycoprops(glcm, prop)
print(f"{prop:12s}: {vals.mean():.3f} (4 方向均值)")
肿瘤异质性与预后 :大量研究表明,高熵/高对比度(高异质性)的肿瘤在肺癌、胶质瘤、头颈癌中与更差的预后显著相关------影像组学把"异质性"从医生的主观印象变成了可统计的定量指标。
2. LBP(局部二值模式)
LBP 把每个像素与 8 邻域比较,生成 8 位二进制编码:
L B P P , R ( x c ) = ∑ p = 0 P − 1 s ( g p − g c ) ⋅ 2 p , s ( x ) = { 1 x ≥ 0 0 x < 0 LBP_{P,R}(x_c) = \sum_{p=0}^{P-1} s(g_p - g_c) \cdot 2^p, \quad s(x) = \begin{cases} 1 & x \ge 0 \\ 0 & x < 0 \end{cases} LBPP,R(xc)=p=0∑P−1s(gp−gc)⋅2p,s(x)={10x≥0x<0
整幅图像的 LBP 直方图构成 256 维纹理特征。旋转不变 LBP 与 uniform LBP(把含至多两次 0/1 跳变的模式归为一类)是常用变体。
python
"""
scikit-image 一行调用LBP
"""
from skimage.feature import local_binary_pattern
radius, n_points = 3, 24
lbp = local_binary_pattern(roi, n_points, radius, method='uniform')
# uniform LBP 直方图特征
n_bins = n_points + 2
hist, _ = np.histogram(lbp.ravel(), bins=n_bins, range=(0, n_bins),
density=True)
print(f"LBP 特征维度: {len(hist)}")
GLCM vs LBP 的选择:
| 维度 | GLCM | LBP |
|---|---|---|
| 捕捉的信息 | 像素对的联合分布(二阶统计) | 局部微结构模式 |
| 对单调灰度变换 | 敏感 | 不变(只比较大小关系) |
| 计算量 | 中 | 小 |
| 医学典型场景 | 肿瘤异质性定量 | 肝纤维化分级、乳腺钼靶纹理 |
LBP 的单调不变性在 MRI 上特别有价值 :MRI 无标准灰度单位,不同设备灰度绝对值不同,但组织间的相对明暗关系是稳定的------LBP 恰好只编码这种相对关系,因此跨设备鲁棒性优于 GLCM。
7.3 计算机辅助诊断(CAD)
CAD 是把前面所有技术组装成临床可用决策系统的工程。临床上分为两类:
- CADe(Computer-Aided Detection,检测):标记可疑位置,"别漏掉"
- CADx(Computer-Aided Diagnosis,诊断):判断良恶性/分级,"帮我判断"
7.3.1 基于规则的诊断系统
最早的 CAD 是专家规则的程序化------把放射科医生的读片经验写成显式条件:
肺结节 CADe 规则链(简化示例):
1. 肺实质分割(HU 阈值 -500,第 5 章)
2. 候选检测:肺野内球形度 > 0.6 且 3mm < 直径 < 30mm 的连通域
3. 假阳性剔除:
- 若候选与胸膜距离 < 2mm 且扁平 → 胸膜结节,剔除
- 若候选呈管状连通(血管追踪) → 血管断面,剔除
- 若 HU 均值 > 200 → 钙化灶,降级提示
4. 按恶性风险特征评分:毛刺 +2、分叶 +1、胸膜牵拉 +1
规则系统的价值与边界:
| 优势 | 局限 |
|---|---|
| 完全可解释,医生信任 | 规则覆盖面有限,泛化差 |
| 无需训练数据 | 阈值对设备/协议敏感 |
| 失效模式可预测 | 复杂模式(磨玻璃结节)难以规则化 |
| 满足早期监管要求 | 维护成本高 |
规则系统至今仍是 CAD 产品中后处理与假阳性剔除的常见组件------深度学习给出候选,规则做临床逻辑过滤,二者互补。
7.3.2 基于机器学习的 CADx
传统 ML 的 CADx = 影像组学特征 + 分类器(正是 7.2 节的组合):
python
"""
经典 CADx 流水线:分割 → 特征 → 分类
"""
def cad_pipeline(ct_image, nodule_mask):
# 1. 形态学特征(7.1)
region = measure.regionprops(measure.label(nodule_mask))[0]
morph_feats = [region.area, 4*np.pi*region.area/region.perimeter**2,
region.eccentricity, region.solidity]
# 2. 纹理特征(7.2)
roi = ct_image[nodule_mask]
roi_q = (np.clip(roi, -1000, 400) + 1000) // 22 # 64 级量化
glcm = graycomatrix(roi_q.reshape(-1, 1), ...) # 示意
texture_feats = [...]
# 3. 分类
X = np.array(morph_feats + texture_feats).reshape(1, -1)
malignancy_prob = trained_classifier.predict_proba(X)[0, 1]
return malignancy_prob
7.3.3 基于深度学习的疾病检测:肺炎 CT 筛查
深度学习 CAD 跳过手工特征,端到端学习"图像 → 诊断"。以胸部 CT 肺炎筛查为例(第 9 章将展开为完整项目):
1. 任务设计的关键决策
| 决策点 | 选项 | 肺炎筛查的选择 |
|---|---|---|
| 输入粒度 | 2D 切片 / 2.5D / 3D | 2.5D(相邻 3 层作通道) |
| 输出形式 | 分类 / 分割 / 检测 | 切片分类 + Grad-CAM 定位 |
| 标签来源 | 影像报告 NLP / 人工标注 | 报告结构化提取 + 抽检 |
| 网络 | ResNet / DenseNet / EfficientNet | DenseNet-121(特征复用,小数据友好) |
2. MONAI 分类网络实现
python
"""
MONAI 分类网络实现
"""
import torch
from monai.networks.nets import DenseNet121
from monai.transforms import (
Compose, LoadImaged, EnsureChannelFirstd, ScaleIntensityd,
Resized, RandFlipd, RandRotated, ToTensord
)
# 数据流水线(第 4 章知识的应用)
train_transforms = Compose([
LoadImaged(keys=['image']),
EnsureChannelFirstd(keys=['image']),
ScaleIntensityd(keys=['image']),
Resized(keys=['image'], spatial_size=(224, 224)),
RandFlipd(keys=['image'], prob=0.5, spatial_axis=0),
RandRotated(keys=['image'], prob=0.3, range_x=0.1),
ToTensord(keys=['image', 'label']),
])
# 模型:3 通道输入(2.5D:相邻 3 层切片)
model = DenseNet121(spatial_dims=2, in_channels=3,
out_channels=2, dropout_prob=0.3)
# 类别不平衡处理(第 5 章损失函数思想)
class_weights = torch.tensor([1.0, 3.0]) # 肺炎样本少,加权
criterion = torch.nn.CrossEntropyLoss(weight=class_weights)
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4,
weight_decay=1e-5) # 3.2 节的优化器
3. 可解释性:Grad-CAM 定位依据
临床 CAD 必须回答"模型为什么这样判断"。Grad-CAM 用最后一层卷积特征图的梯度加权生成热图:
w k = 1 Z ∑ i , j ∂ y c ∂ A i j k , L G r a d C A M = R e L U ( ∑ k w k A k ) w_k = \frac{1}{Z}\sum_{i,j} \frac{\partial y^c}{\partial A_{ij}^k}, \qquad L_{GradCAM} = \mathrm{ReLU}\Big(\sum_k w_k A^k\Big) wk=Z1i,j∑∂Aijk∂yc,LGradCAM=ReLU(k∑wkAk)
python
"""
Grad-CAM 热图
"""
from pytorch_grad_cam import GradCAM
from pytorch_grad_cam.utils.image import show_cam_on_image
target_layers = [model.features.denseblock4] # 最后一个特征块
cam = GradCAM(model=model, target_layers=target_layers)
grayscale_cam = cam(input_tensor=img_tensor, targets=None)[0]
# 叠加显示:热图应落在肺野炎症区域------否则模型可能在"看图边框猜答案"
visualization = show_cam_on_image(img_display, grayscale_cam, use_rgb=True)
重要:CAD 的可解释性不是可选项
曾有多篇论文的"肺炎检测模型"被发现实际学习的是图像角落的医院标记、扫描体位差异等捷径特征(shortcut learning)。Grad-CAM 热图检查 + 外部数据集验证是排除此类问题的最低要求。这也是第 10 章伦理与安全将深入讨论的主题。
7.3.4 CAD 系统的性能评估
分类模型的评估与分割(5.4 节)有完全不同的指标体系:

图 7-4 ROC 曲线与临床工作点选择
1. ROC 曲线与 AUC
ROC 曲线 :以假阳性率(1 − 特异性)为横轴、敏感性为纵轴,扫描分类阈值得到的曲线。AUC(曲线下面积)= 随机正样本排在随机负样本之前的概率。
- AUC = 0.5:无判别力;AUC > 0.9:优秀
- 临床阈值的选择:筛查任务选高敏感性工作点(宁可误报);确诊任务选高特异性工作点
python
"""
绘制ROC曲线
"""
from sklearn.metrics import roc_curve, auc
import matplotlib.pyplot as plt
fpr, tpr, thresholds = roc_curve(y_true, y_score)
roc_auc = auc(fpr, tpr)
# 找 Youden 指数最大的工作点
youden = tpr - fpr
best_idx = np.argmax(youden)
print(f"最佳阈值: {thresholds[best_idx]:.3f}, "
f"敏感性: {tpr[best_idx]:.3f}, 特异性: {1-fpr[best_idx]:.3f}")
plt.plot(fpr, tpr, label=f'AUC = {roc_auc:.3f}')
plt.plot([0, 1], [0, 1], 'k--', label='随机猜测')
plt.xlabel('1 - 特异性 (FPR)'); plt.ylabel('敏感性 (TPR)')
plt.legend(); plt.title('肺炎筛查 ROC 曲线'); plt.show()
2. FROC:检测任务专用
CADe 系统评估用 FROC(Free-Response ROC) :横轴是每例图像的平均假阳性数,纵轴是敏感性。临床可用性的经验标准是"每图 ≤ 1 个假阳性时敏感性 > 90%"。
3. 置信区间与统计比较
医学 AI 论文的规范:报告 95% 置信区间 (bootstrap 1000 次重采样),模型间比较用 DeLong 检验(比较两条 ROC 的 AUC 差异是否显著)。
python
"""
DeLong 检验
"""
def bootstrap_auc(y_true, y_score, n_boot=1000, seed=42):
rng = np.random.RandomState(seed)
aucs = []
n = len(y_true)
for _ in range(n_boot):
idx = rng.randint(0, n, n)
if len(np.unique(y_true[idx])) < 2:
continue
fpr_b, tpr_b, _ = roc_curve(y_true[idx], y_score[idx])
aucs.append(auc(fpr_b, tpr_b))
return np.percentile(aucs, [2.5, 50, 97.5])
ci_low, median, ci_high = bootstrap_auc(y_true, y_score)
print(f"AUC = {median:.3f} (95% CI: {ci_low:.3f}--{ci_high:.3f})")
医学影像小贴士:CAD 评估的临床转化视角
一个 AUC 0.95 的模型未必有临床价值。评估 CAD 必须回答:
- 工作点:在哪个阈值运行?该阈值下的敏感性/特异性/PPV 是多少?
- 疾病流行率:PPV 强烈依赖患病率------筛查人群(患病率 1%)中,即使特异性 99%,阳性预测值也只有约 50%
- 增量价值 :模型辅助下医生的 AUC 是否显著高于医生单独诊断?(reader study)
- 工作流影响:节省了多少读片时间?增加了多少不必要召回?
本章小结
本章完成了从"分割结果"到"临床决策"的三级跨越:
-
形态学分析
- 2D 区域特征(面积、周长、圆形度、离心率)与 3D 体素分析(体积必须乘体素物理体积)
- Marching Cubes 表面重建:256 种构型查表 + 棱边线性插值,输出三角网格用于 3D 打印与表面积测量
- 工程要点:重建前高斯平滑消除阶梯效应,但定量测量以体素计数为准
-
功能与纹理分析
- 影像组学五步法:采集 → 分割 → 提取 → 选择 → 建模,IBSI 标准统一特征定义
- GLCM 捕捉二阶灰度统计(熵 = 肿瘤异质性的定量度量);LBP 编码局部微结构且单调不变(MRI 跨设备友好)
- 小 n 大 p 问题的标准应对:ICC 筛选 → LASSO(第 3 章 L1 稀疏先验的直接应用)→ 嵌套交叉验证
-
计算机辅助诊断
- CADe/CADx 分工;规则系统的可解释性价值与深度学习互补
- 深度学习 CAD 的四要素:任务设计、MONAI 分类网络、Grad-CAM 可解释性、shortcut learning 防范
- 评估体系:ROC/AUC + bootstrap CI + FROC + DeLong 检验,以及临床转化的四问(工作点、流行率、增量价值、工作流)
提示
需要警惕的是贯穿全章的一条暗线:特征数值的可信度取决于前置环节------ 分割不准、归一化不做、采集条件不统一,特征再花哨也是噪声。
至此,第二篇核心技术篇(预处理、分割、重建与配准、特征分析)全部完成。读者已具备完整的技术栈------第三篇将把这些技术组装成各模态的完整实战项目。
思考题
- 为什么直接用边界像素数估计周长会系统性高估?Marching Cubes 的线性插值交点定位解决了什么类似问题?
- Marching Cubes 算法的 "逐立方体查表" 思想是什么?它为什么能把体素数据变成连续三角表面?
- 某研究团队用 GLCM 特征在中心 A 的 MRI 数据上训练了胶质瘤分级模型,在中心 B 上性能大幅下降。请从 MRI 的灰度特性、LBP 的单调不变性、离散化参数三个角度分析原因,并给出改进方案。
- 放射组学为什么要做特征 ICC 筛选?不做会有什么后果?
- 影像组学中 LASSO 的特征选择对应第 3 章的哪个几何原理?为什么在特征高度相关时(如多个 GLCM 特征)LASSO 的选择结果不稳定,可以如何改进(提示:Elastic Net)?
- 一个肺炎筛查模型 AUC 0.96,但在患病率 0.5% 的体检人群中,特异性 95% 意味着每 1000 人会产生多少假阳性?阳性预测值是多少?这说明了什么筛查设计原则?
- Grad-CAM 显示肺炎模型的热图集中在图像边缘而非肺野,模型可能学到了什么?你会设计哪些实验来验证和修复?
参考文献
- Lorensen W E, Cline H E. Marching cubes: A high resolution 3D surface construction algorithm. ACM SIGGRAPH, 1987, 21(4): 163--169.
- Haralick R M, Shanmugam K, Dinstein I. Textural features for image classification. IEEE TSMC, 1973, 3(6): 610--621.(GLCM 的原始文献)
- Ojala T, Pietikäinen M, Mäenpää T. Multiresolution gray-scale and rotation invariant texture classification with local binary patterns. IEEE TPAMI, 2002, 24(7): 971--987.(LBP)
- Lambin P, Rios-Velazquez E, Leijenaar R, et al. Radiomics: extracting more information from medical images using advanced feature analysis. European Journal of Cancer, 2012, 48(4): 441--446.(影像组学奠基论文)
- Gillies R J, Kinahan P E, Hricak H. Radiomics: images are more than pictures, they are data. Radiology, 2016, 278(2): 563--577.
- Zwanenburg A, Vallières M, Abdalah M A, et al. The image biomarker standardization initiative: standardized quantitative radiomics for high-throughput image-based phenotyping. Radiology, 2020, 295(2): 328--338.(IBSI 标准)
- van Griethuysen J J M, Fedorov A, Parmar C, et al. Computational radiomics system to decode the radiographic phenotype. Cancer Research, 2017, 77(21): e104--e107.(PyRadiomics)
- Aerts H J W L, Velazquez E R, Leijenaar R T H, et al. Decoding tumour phenotype by noninvasive imaging using a quantitative radiomics approach. Nature Communications, 2014, 5: 4006.
- Selvaraju R R, Cogswell M, Das A, et al. Grad-CAM: Visual explanations from deep networks via gradient-based localization. ICCV, 2017: 618--626.
- DeLong E R, DeLong D M, Clarke-Pearson D L. Comparing the areas under two or more correlated receiver operating characteristic curves: a nonparametric approach. Biometrics, 1988, 44(3): 837--845.
- Geirhos R, Jacobsen J H, Michaelis C, et al. Shortcut learning in deep neural networks. Nature Machine Intelligence, 2020, 2(11): 665--673.
- Rajpurkar P, Irvin J, Zhu K, et al. CheXNet: Radiologist-level pneumonia detection on chest X-rays with deep learning. arXiv:1711.05225, 2017.
- Lambin P, Leijenaar R T H, Deist T M, et al. Radiomics: the bridge between medical imaging and personalized medicine. Nature Reviews Clinical Oncology, 2017, 14(12): 749--762.
- PyRadiomics 官方文档. https://pyradiomics.readthedocs.io
- IBSI 官方文档. https://theibsi.github.io