3. DICOM信息模型与数据集编码

DICOM 网络服务之所以能跨厂商、跨设备交换影像,根本原因在于它先定义了一套稳定的信息模型,再把模型编码成可解析的字节流。理解这条“模型 → 数据集 → 字节流”的链路,是排查关联失败、图像错位、中文乱码和像素显示异常的基础。

一、四层信息模型:从患者到实例

DICOM 把医学影像对象组织为四个层级,通常称为 Patient(患者)→ Study(研究)→ Series(序列)→ Instance(实例,即 SOP Instance)。每一层都有唯一标识符(UID),并通过层级引用关系向下挂接:一个患者可以有多次检查(Study),一次检查可包含多个序列(Series),一个序列包含若干实例(图像、报告、结构化对象等)。

关键标识符包括:Patient ID 标识患者;Study Instance UID 标识一次检查;Series Instance UID 标识一个序列;SOP Instance UID 标识单个实例;SOP Class UID 说明该实例属于哪类对象(如 CT 图像存储、MR 图像存储)。工程上要牢记:UID 是跨系统的主键,Patient ID 只是本地标识。同一患者在不同系统里 Patient ID 可能不同,但 Study/Series/SOP Instance UID 必须全局唯一且不可重复使用。

层级关系还决定了查询与检索的粒度。C-FIND 可以按患者、研究、序列、实例四个层级分别查询;C-MOVE/C-GET 则以 Study、Series 或 Instance 为检索单位。若把 Series 与 Study 混淆,就会出现“只取到一层图像”或“重复拉取整检查”的问题。

二、数据元素:DICOM 的最小语义单元

数据集(DataSet)由一系列数据元素(Data Element)组成。每个数据元素由三部分构成:标签(Tag)、值表示(VR)、值长度(Value Length)和值域(Value Field)。标签是 (组号, 元素号) 的十六进制对,例如 (0010,0010) 是患者姓名,(0008,0060) 是模态,(7FE0,0010) 是像素数据。

标签按奇偶性分为两类:组号为偶数的标准标签,组号为奇数的私有标签。私有标签必须配合私有创建者(Private Creator)元素使用,否则不同厂商的私有数据会互相冲突。数据元素按标签升序排列,这是 DICOM 编码的基本约定,解析时若顺序错乱通常意味着数据集被破坏或拼接错误。

三、VR:值表示决定如何解释字节

VR(Value Representation)规定值的类型和编码方式,常见的有:PN(患者姓名)、DA(日期)、TM(时间)、UI(UID)、CS(代码字符串)、IS(整数字符串)、DS(小数字符串)、US(无符号短整型)、OB(字节串)、SQ(序列)、UN(未知)。VR 分为显式与隐式两种表达:显式 VR 在标签后直接写出两个字符的 VR;隐式 VR 不写 VR,由字典查表得到。

VR 还决定值长度字段的字节数:OB、OW、OF、SQ、UT、UN 等使用 4 字节长度(长格式),其余多为 2 字节(短格式)。若把长格式当短格式解析,后续所有元素都会错位。像素数据 (7FE0,0010) 的 VR 通常是 OW 或 OB,其长度往往很大,且可能受封装影响。

四、传输语法:字节流的“方言”

传输语法(Transfer Syntax)规定字节序、VR 表达方式和像素数据是否压缩。常见的有:Implicit VR Little Endian(1.2.840.10008.1.2)、Explicit VR Little Endian(1.2.840.10008.1.2.1)、Explicit VR Big Endian(1.2.840.10008.1.2.2,已弃用)、JPEG Baseline(1.2.840.10008.1.2.4.50)、JPEG Lossless(…4.57/4.70)、RLE(…5)等。字节序决定多字节整数的高低字节顺序;显式/隐式决定是否写 VR;压缩语法决定像素数据是原始流还是封装帧。

关联协商时,双方各自提出可接受的传输语法列表,最终选定一个共同支持的语法。若发起方只支持显式小端,而接收方只支持隐式小端,关联就会失败。工程上建议在日志中明确记录协商结果,便于定位“能连上但读不出图像”的问题。

五、字节流解析:从文件头到像素

解析一个 DICOM 文件或网络数据集,通常按以下顺序进行:先读 128 字节前导码和 “DICM” 魔数;再读文件元信息组 (0002,xxxx),其中 (0002,0010) 给出传输语法 UID;然后按该传输语法解析主数据集。主数据集解析时,循环读取标签、VR(若显式)、长度和值;遇到 SQ 则递归解析子数据集;遇到像素数据则根据 Bits Allocated、Rows、Columns、Samples per Pixel 等计算帧大小。

下面这张图把“四层信息模型”与“数据集编码链路”放在同一视图中,便于对照理解:左侧是层级引用关系,右侧是从标签到字节流的解析路径。

DICOM 信息模型与数据集编码链路 ① 四层信息模型(层级引用) Patient 患者 Patient ID / Patient Name Study 研究 Study Instance UID / Study Date Series 序列 Series Instance UID / Modality Instance 实例 SOP Instance UID / SOP Class UID 层级向下引用:1 患者 → N 研究 → N 序列 → N 实例 UID 全局唯一,是跨系统检索主键 ② 数据集编码与字节流解析 数据元素 Data Element Tag (gggg,eeee) VR Length Value Field 传输语法 Transfer Syntax 字节序 Little / Big Endian VR 表达 Implicit / Explicit 像素编码 Native / JPEG / RLE ③ 字节流解析路径 128B 前导码 + "DICM" 文件元信息 (0002,0010) TS UID 主数据集 按 TS 循环解析 像素数据 (7FE0,0010) 像素解析关键参数 Rows / Columns:图像矩阵尺寸 Bits Allocated / Bits Stored / High Bit:位深与有效位 Samples per Pixel:1 灰度,3 彩色 Photometric Interpretation:MONOCHROME2 / RGB 等 常见错位原因 VR 长短格式误判 / 字节序不一致 SQ 未递归 / 私有标签冲突

六、工程实践中的判断依据

当出现“关联成功但图像异常”时,可按以下顺序排查:第一,确认协商的传输语法是否与数据集实际编码一致,尤其是显式/隐式 VR 和字节序;第二,检查 (0002,0010) 中的传输语法 UID 是否被正确读取;第三,核对像素相关参数是否与图像矩阵匹配,例如 Rows×Columns×Samples×Bits Allocated/8 是否等于像素数据长度;第四,若为压缩语法,确认封装帧的 Basic Offset Table 和 Fragment 是否正确解析。

对于中文患者姓名,PN 的编码受 (0008,0005) Specific Character Set 控制。若该元素缺失或值不匹配,就会出现乱码。常见取值包括 ISO_IR 100(Latin-1)、ISO_IR 192(UTF-8)、GB18030 等。发送方与接收方必须对该元素理解一致,否则即使字节流完整,姓名也无法正确显示。

建议在集成测试中固定一组最小数据集:患者姓名、Patient ID、Study/Series/SOP Instance UID、Modality、Study Date、Rows、Columns、Bits Allocated、Pixel Data。用这组数据分别以隐式小端和显式小端各发一次,观察接收端解析结果是否一致,可快速验证传输语法协商与解析逻辑。

总结来说,DICOM 的互操作性建立在“模型定义语义、数据集承载语义、传输语法规定编码”这三层之上。把四层信息模型与字节流解析路径对应起来,就能在遇到关联失败、图像错位或中文乱码时,迅速定位是模型层、编码层还是传输层的问题。