在医学影像系统中,DICOM格式不仅承载图像,还包含大量病人身份数据。使用C++解析这类文件时,必须理解其二进制结构,才能准确提取并脱敏隐私信息。脱敏的核心目标是移除或替换能识别个人的标签,同时保留临床与科研需要的其他属性。

一、DICOM文件基础结构
DICOM文件以128字节的前导符开头,接着是4字节的“DICM”魔法字。之后进入数据集部分,由一系列数据元素(Data Element)组成。每个数据元素包含标签(Tag)、值表示(VR)、长度(Length)和值(Value)。标签是一个8位十六进制数对,例如(0010,0010)表示病人姓名。
在C++中解析时,我们通常以二进制流方式打开文件,跳过前导部分,再循环读取数据元素。需要注意的是,显式VR和隐式VR两种编码方式会影响读取逻辑。显式VR在标签后直接给出两个字母的类型标识,而隐式VR需依赖字典推断。实际项目中建议优先支持显式VR,以降低复杂度。
二、病人身份相关标签清单
脱敏处理首先要明确哪些标签属于病人身份范畴。常用的包括(0010,0010)患者姓名、(0010,0020)患者ID、(0010,0030)出生日期、(0010,0040)性别,以及(0010,1000)其他患者ID等。此外,(0008,0090)推荐医师、(0008,1050)执行医师也可能暴露真实人员。
下面给出一个常见身份标签的对照表,方便在代码中建立映射:
| 标签 | 名称 | 脱敏建议 |
|---|---|---|
| (0010,0010) | PatientName | 替换为匿名编码 |
| (0010,0020) | PatientID | 哈希后截断存储 |
| (0010,0030) | PatientBirthDate | 置为空或仅留年份 |
| (0010,1000) | OtherPatientIDs | 直接清空 |
建立这样的表格后,程序在遍历数据元素时即可判断是否命中敏感标签,从而执行对应策略。注意有些标签虽不直接写姓名,但组合后可推断身份,因此脱敏范围应结合业务合规要求适当扩大。
三、C++解析与脱敏代码实现
下面示例展示如何用C++读取DICOM并脱敏患者姓名与ID。代码以简化显式VR为例,仅演示核心思路,真实项目需补充异常与完整性校验。
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
struct DataElement {
unsigned short group;
unsigned short element;
std::string vr;
std::string value;
};
// 简单解析显式VR的DICOM数据元素
std::vector<DataElement> parseDICOM(const std::string& path) {
std::ifstream file(path, std::ios::binary);
file.seekg(128); // 跳过前导
char magic[4];
file.read(magic, 4); // 读取DICM
std::vector<DataElement> elements;
while (file.good()) {
DataElement de;
file.read(reinterpret_cast<char*>(&de.group), 2);
file.read(reinterpret_cast<char*>(&de.element), 2);
char vr[2];
file.read(vr, 2);
de.vr = std::string(vr, 2);
unsigned int len = 0;
file.read(reinterpret_cast<char*>(&len), 4);
if (len > 0 && len < 10000) {
de.value.resize(len);
file.read(&de.value[0], len);
}
if (file.gcount() == 0) break;
elements.push_back(de);
}
return elements;
}
// 脱敏处理函数
void deidentify(std::vector<DataElement>& els) {
for (auto& e : els) {
if (e.group == 0x0010 && e.element == 0x0010) {
e.value = "ANON_NAME"; // 患者姓名替换
}
if (e.group == 0x0010 && e.element == 0x0020) {
e.value = "HASH_ID_001"; // 患者ID替换
}
}
}
int main() {
auto data = parseDICOM("test.dcm");
deidentify(data);
std::cout << "脱敏完成,元素数量:" << data.size() << std::endl;
return 0;
}
上述代码将文件流定位到数据集区,逐个读入标签与值。脱敏函数针对特定组号与元素号进行字符串替换。在工程化时,应把标签判断抽象为配置表,避免硬编码。
对于不可逆脱敏,可采用MD5或SHA对原始ID加盐后存储,既避免重识别,又能在同一批数据中保持映射一致。相比直接置空,哈希方式更利于多中心研究时关联同一匿名患者。
四、脱敏策略对比与注意点
直接清空标签实现简单,但会造成某些依赖患者ID的后续流程失效。哈希替换保留了唯一性,却要求盐值安全管理。另一种做法是生成完全虚构但格式合法的随机值,适合演示系统。
需要警惕的是,像素数据中的烧录文字(如超声图像角落的姓名)无法通过标签脱敏消除,必须借助图像处理方法。此外,私有标签(组号奇数)可能由设备厂商自定义身份字段,解析时应结合DICOM字典或设备文档补充处理规则。
五、总结
用C++解析DICOM并完成病人身份脱敏,关键在于准确读取数据元素、建立敏感标签清单并选择恰当的替换逻辑。开发者应在合规前提下,平衡隐私保护与数据可用性,才能构建可信的医学影像处理工具。
C++DICOMpatient_deidentification修改时间:2026-08-05 18:24:39