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 → 重采样 → 归一化 → 去标识化 → 送入推理。若某序列不是目标模态,应在元数据阶段直接丢弃,避免读像素。若内存紧张,可以按层流式处理,而不是一次性加载整个序列。
流水线落地时,建议把每一步都做成可观测的:记录输入 SOPClassUID、原始 Rows/Columns、PixelSpacing、窗参数、重采样后尺寸、归一化范围、去标识化命中标签数。这样当模型输出异常时,可以快速定位是窗宽窗位错了、spacing 没统一,还是去标识化把关键标签误删。对于 CT 序列,还要注意层间顺序:按 ImagePositionPatient 的 z 值排序,而不是按文件名或 InstanceNumber,否则重建方向会颠倒。
最后要强调一致性:训练时用的窗、spacing、归一化方式、通道顺序,推理端必须逐项对齐。边缘预处理不是“把图变好看”,而是把不同来源的 DICOM 变成同一语义空间下的张量。只有这一步稳定,后续的模型加速、量化和部署才有意义。