2. 医学影像数据特性与边缘预处理

医学影像进入边缘设备时,并不是一张普通的 PNG 或 JPEG,而是一份带有患者信息、采集参数、像素矩阵和灰度映射语义的 DICOM 对象。边缘预处理的目标,是在算力、内存和网络都受限的条件下,把原始 DICOM 转换成模型可稳定消费的张量,同时不破坏诊断相关的灰度关系,并满足隐私合规要求。这一节围绕“从 DICOM 到模型输入”的完整链路展开,重点说明每一步在边缘端应该怎么做、参数如何取、结果如何判断。

一、DICOM 解析:先读元数据,再读像素

DICOM 文件由文件元信息、数据集和像素数据组成。边缘端解析时,第一步不是急着取像素,而是先读取关键标签,判断这份数据能不能进入后续流水线。常用标签包括:SOPClassUID(判断模态,如 CT/MR/CR)、Rows/Columns(矩阵尺寸)、BitsAllocated/BitsStored/PixelRepresentation(像素位深与有无符号)、RescaleSlope/RescaleIntercept(CT 的 HU 映射)、WindowCenter/WindowWidth(默认窗)、PhotometricInterpretation(MONOCHROME1/2,决定是否反相)、PixelSpacing(物理像素间距)、SliceThickness/SpacingBetweenSlices(层厚与层间距)。

解析时要注意传输语法:隐式 VR 小端、显式 VR 小端、显式 VR 大端以及 JPEG 系列压缩语法。边缘端若只做推理,建议优先支持未压缩的 Explicit VR Little Endian,压缩数据先解压再进入后续步骤。像素读取后,CT 需要按 HU = pixel × RescaleSlope + RescaleIntercept 转成亨斯菲尔德单位;MR 和 CR 通常不做该映射,直接保留原始灰度。若 PhotometricInterpretation 为 MONOCHROME1,还需做一次反相,否则窗宽窗位方向会整体颠倒。

二、窗宽窗位调整:把诊断窗口映射到 0–255

窗宽窗位是医学影像最核心的显示语义。窗宽 WW 决定灰度范围,窗位 WL 决定中心。对 CT 而言,常用肺窗 WL=-600、WW=1500,纵隔窗 WL=40、WW=400,骨窗 WL=400、WW=1800。映射公式为:

lower = WL - WW/2
upper = WL + WW/2
if HU <= lower: out = 0
elif HU >= upper: out = 255
else: out = (HU - lower) / WW * 255

边缘端实现时,建议把该映射做成查表:对 12 位或 16 位输入,先建立 65536 项的 LUT,再对整幅图做一次索引,速度远快于逐像素浮点运算。若模型训练时使用的是固定窗,推理端必须使用同一组 WL/WW;若训练时使用了多窗融合,则需要在通道维度上分别生成肺窗、纵隔窗、骨窗三路,再拼接为三通道输入。判断窗宽窗位是否正确,可以观察目标结构是否落在 0–255 的中段:若肺实质全黑、骨皮质全白,说明窗宽过窄或窗位偏移。

三、重采样:统一物理尺度,而不是统一像素尺寸

不同设备的 PixelSpacing 不同,直接缩放到 512×512 会破坏解剖比例。正确做法是按物理间距重采样到目标 spacing,例如把 0.7 mm×0.7 mm 重采样到 1.0 mm×1.0 mm,使 1 像素对应 1 mm。层间方向同理,用 SpacingBetweenSlices 把层间距统一到 1 mm 或 2 mm。插值方式上,灰度图常用双线性或三线性;若后续要做分割,建议对 mask 使用最近邻,避免引入不存在的类别。重采样后要重新计算新的 PixelSpacing 并写回元数据,否则后续测量会失真。

四、归一化与去标识化

归一化分两种:一种是把 0–255 线性映射到 [0,1] 或 [-1,1];另一种是按数据集统计做 z-score。边缘端若无法获得全局均值方差,建议使用固定窗后的 [0,1] 归一化,并在模型侧固化该约定。去标识化必须在数据离开设备前完成,至少清除 PatientName、PatientID、PatientBirthDate、AccessionNumber、InstitutionName 等标签,或替换为哈希值。像素中若烧录了姓名、日期,还需做 OCR 检测并遮盖。去标识化后应保留 StudyInstanceUID 的哈希映射,以便回溯而不泄露身份。

五、边缘端数据流水线设计

把上述步骤串成流水线时,关键不是“顺序执行”,而是“按需执行、尽早丢弃、内存可控”。典型设计是:接收 DICOM → 解析元数据 → 判断模态与序列 → 读取像素 → HU 映射 → 窗宽窗位 LUT → 重采样 → 归一化 → 去标识化 → 送入推理。若某序列不是目标模态,应在元数据阶段直接丢弃,避免读像素。若内存紧张,可以按层流式处理,而不是一次性加载整个序列。

医学影像边缘预处理流水线:从 DICOM 到模型输入 ① DICOM 解析 读元数据 / 传输语法 SOPClass / PixelSpacing ② HU 映射 HU = px×Slope+Intercept MONOCHROME1 反相 ③ 窗宽窗位 LUT 肺窗 -600/1500 纵隔 40/400 · 骨 400/1800 ④ 重采样 按 PixelSpacing 统一 双线性 / 三线性 ⑤ 归一化 [0,1] 或 z-score 固定窗约定 ⑥ 去标识化(隐私闸门) 清除 PatientName / ID / BirthDate 像素烧录文字遮盖 · UID 哈希映射 ⑦ 张量输出 → 推理 NCHW / NHWC · 固定尺寸 多窗三通道拼接(可选) 边缘端关键约束 • 内存:按层流式,避免整序列加载 • 算力:LUT 替代逐像素浮点 • 网络:去标识化后再出设备 • 一致性:训练/推理同窗同 spacing • 可回溯:UID 哈希保留映射 • 早丢弃:非目标模态在元数据阶段过滤 • 校验:窗后目标结构应落在中段灰度 • 插值:mask 用最近邻,灰度用线性 常见异常与判断 • 全黑/全白:窗宽过窄或窗位偏移 • 解剖变形:未按 spacing 重采样 • 灰度反转:MONOCHROME1 未反相 • HU 异常:Slope/Intercept 未应用 • 隐私泄露:像素烧录文字未遮盖 • 尺寸漂移:重采样后未更新元数据 • 通道错位:多窗拼接顺序与训练不一致 • 内存溢出:未做流式或未及时释放

流水线落地时,建议把每一步都做成可观测的:记录输入 SOPClassUID、原始 Rows/Columns、PixelSpacing、窗参数、重采样后尺寸、归一化范围、去标识化命中标签数。这样当模型输出异常时,可以快速定位是窗宽窗位错了、spacing 没统一,还是去标识化把关键标签误删。对于 CT 序列,还要注意层间顺序:按 ImagePositionPatient 的 z 值排序,而不是按文件名或 InstanceNumber,否则重建方向会颠倒。

教学示例参数:假设一台边缘设备接收 512×512、层厚 1.25 mm、PixelSpacing 0.7 mm 的胸部 CT,目标输入为 1.0 mm×1.0 mm、256×256、三通道(肺窗/纵隔窗/骨窗)。则重采样后每层约 358×358,再中心裁剪或缩放到 256×256;三通道分别做 LUT 后归一化到 [0,1],最终张量形状为 1×3×256×256。该示例仅用于说明参数关系,不代表真实设备实测结果。

最后要强调一致性:训练时用的窗、spacing、归一化方式、通道顺序,推理端必须逐项对齐。边缘预处理不是“把图变好看”,而是把不同来源的 DICOM 变成同一语义空间下的张量。只有这一步稳定,后续的模型加速、量化和部署才有意义。