686. PhysioNet - Digitization of ECG Images | physionet-ecg-image-digitization
ECG 图像 → 信号掩码预测 → 后处理波形提取
核心思想是将信号提取与信号重建分离。通过学习在像素级别分割 ECG 轨迹,模型对现实世界的伪影(如网格失真、扫描噪声、纸张折叠、墨水褪色和遮挡)变得显著更 robust(鲁棒)。
为了捕捉全局 ECG 布局和细粒度波形细节,使用了两种互补的训练策略:
这两种策略都采用轻量级的 ResNet 编码器(ResNet-18 和 ResNet-34d)并共享一个共同的解码头。它们的预测在推理过程中结合,以提高鲁棒性和泛化能力。
来自 @hengck23 的早期校正版本存在一个微妙的边界问题,即预测的网格没有完全跨越图像范围,导致最后 1-2 列像素在 warp( warping)期间映射错误或边框填充。这个问题通过强制固定输出画布、使用 (W−1, H−1) 归一化网格点以及在 upsampling 变形场时启用角点对齐插值 (align_corners=True) 得以修复。结果是,密集网格现在覆盖了完整的图像宽度,消除了边缘像素丢失,并显著改善了校正图像与监督掩码之间的像素级对齐,特别是在波形端点处。
# 修剪不稳定的网格列
gridpoint_xy = gridpoint_xy[:, :56]
# 校正扫描仪边距的经验偏移量
offset_y = 7
offset_x = 34
# 移除右侧噪声区域
image = image[:, :2166]
# 参考输出大小
H, W = 1700 - offset_y, 2200 - offset_x
# 分配填充的输出画布
empty_image = np.zeros((H + offset_y, W, 3), np.uint8)
# 将网格点归一化到 [-1, 1]
H1, W1 = image.shape[:2]
sparse_map = gridpoint_xy / [[[W1 - 1, H1 - 1]]] * 2 - 1
sparse_map = torch.from_numpy(
np.ascontiguousarray(sparse_map.transpose(2, 0, 1))
).unsqueeze(0).float()
# 将稀疏网格插值为密集变形场
dense_map = F.interpolate(
sparse_map,
size=(H, W),
mode="bilinear",
align_corners=True
)
# 应用基于网格的 warp
distort = torch.from_numpy(
np.ascontiguousarray(image.transpose(2, 0, 1))
).unsqueeze(0).float()
rectified = F.grid_sample(
distort,
dense_map.permute(0, 2, 3, 1),
mode="bilinear",
padding_mode="border",
align_corners=True
)
# 转换回图像格式
rectified = rectified.data.cpu().numpy()
rectified = rectified[0].transpose(1, 2, 0).astype(np.uint8)
# 恢复垂直偏移以进行对齐
empty_image[offset_y:, :, :] = rectified
return empty_image
系列数量:4
输出掩码形状:(4, 1696, 4352)(高度 × 宽度对应于校正后的 ECG 图像)
| 系列 | 零毫伏 (Zero-MV) | 毫伏 --> 像素 (mV --> Pixel) |
|---|---|---|
| 0 | 707 | 78.0 |
| 1 | 991 | 79.5 |
| 2 | 1273 | 78.5 |
| 3 | 1533 | 78.0 |
为了平衡全局 ECG 布局理解与局部波形精度,采用了两种互补的训练策略:全裁剪训练和半裁剪训练。每种策略都解决了早期实验中观察到的不同失败模式。
在全裁剪训练中,模型在整个校正后的 ECG 图像上进行训练,保留所有导联的完整时间跨度和垂直对齐。
半裁剪训练使用随机水平裁剪,覆盖大约一半的图像宽度,同时保留完整的垂直分辨率。裁剪区域在训练前调整回原始尺寸。
为什么半裁剪很重要:
| 增强 | 参数 | 概率 |
|---|---|---|
| 仿射变换 (Affine transform) | 缩放 0.90–1.10, 旋转 ±8°, 平移 ≤4% | 0.60 |
| 透视变换 (Perspective transform) | 缩放 0.02–0.07 | 0.40 |
| 光学失真 (Optical distortion) | 失真 ≤0.03, 偏移 ≤0.02 | 0.15 |
| 弹性变换 (Elastic transform) | Alpha = 10, Sigma = 3 | 0.03 |
| 网格失真 (Grid distortion) | Steps = 3, 失真限制 = 0.03 | 0.05 |
| 仿射 (剪切) | 剪切 ±3° | 0.15 |
| 增强 | 参数 | 概率 |
|---|---|---|
| 亮度 / 对比度 | ±0.15 | 0.50 (OneOf) |
| CLAHE | Clip = 2.0, Grid = 8×8 | 0.30 (OneOf) |
| 随机 Gamma | 0.8–1.2 | 0.20 (OneOf) |
| 高斯噪声 | 方差 5–20 | 0.50 (OneOf) |
| ISO 噪声 | — | 0.30 (OneOf) |
| 乘法噪声 | 0.9–1.1 | 0.20 (OneOf) |
| 色相 / 饱和度 / 值 | H±2, S±5, V±5 | 0.15 |
| 增强 | 参数 | 概率 |
|---|---|---|
| 锐化 (Sharpen) | Alpha 0.05–0.15 | 0.20 |
| 高斯模糊 | 核大小 3–5 | 0.60 (OneOf) |
| 运动模糊 | 核大小 3–5 | 0.40 (OneOf) |
| 增强 | 目的 | 概率 |
|---|---|---|
| CoarseDropout (小) | 墨水断裂 / 污渍 | 0.25 |
| CoarseDropout (垂直) | 打印机 / 扫描垂直线 | 0.20 |
| Perlin 噪声 patches | 纸张污垢 / 老化伪影 | ~0.50 (自定义) |
在基于分割的信号提取之后,应用额外的时间细化和间隙填充以恢复生理上一致的 ECG 波形。此后处理侧重于处理缺失段、强制周期一致性以及稳定 QRS 形态。