能否让DCMTK的writeJson()函数输出DICOM标签名称?
如何让DCMTK生成带DICOM标签名称的JSON?
问题背景
我在程序中使用DCMTK库生成JSON,DcmDataset::writeJson()能一键导出整个DICOM头信息,但输出的JSON里标签仅用8位偏移量(比如00201041)标识,不会显示标签名称(比如SliceLocation)——这和命令行工具dcm2json的表现完全一致。而另一个DCMTK工具dcmdump则会在输出中显示标签名称:
$ dcmdump $dcmfile | grep SliceLocation (0020,1041) DS [-67.181462883113] # 16, 1 SliceLocation
目前我只能通过迂回方式关联标签偏移量和名称,比如通过值反查:
$ dcm2json $dcmfile | grep -n3 67.181462883113 1552- "00201041": { 1553- "vr": "DS", 1554- "Value": [ 1555: -67.181462883113 1556- ] 1557- }, 1558- "00280002": {
或者通过命令拼接获取对应偏移量:
$ dcm2json $dcmfile | grep -n3 $(dcmdump $dcmfile | grep SliceLocation | awk '{print $1}' | tr "()," " " | awk '{print $1$2}')
但这类方法过于繁琐,想知道有没有直接生成带标签名称的JSON的方法,或是把DcmDataset::writeJson()和dcmdump的功能结合起来?
解决方案
1. 命令行层面:用脚本转换dcmdump输出为带标签名的JSON
DCMTK原生没有让dcm2json直接输出标签名的参数,但可以通过脚本解析dcmdump的结构化输出,转成JSON格式。以下是一个awk脚本示例:
dcmdump --print-all $dcmfile | awk ' BEGIN { print "{"; first=1 } /^[(]/ { if (!first) print ","; first=0; split($1, tag, /[(),]/); tag_str=tag[2] tag[3]; name=$NF; vr=$2; if ($3 ~ /\[.*\]/) { val=substr($3, 2, length($3)-2); } else { val=$3; } printf " \"%s\": { \"vr\": \"%s\", \"Value\": [ %s ] }", name, vr, val } END { print "\n}" }'
这个脚本会将dcmdump输出的标签名称、VR类型、值转换为类似dcm2json结构的JSON,直接用标签名称作为键。
2. C++代码层面:扩展DcmDataset::writeJson()逻辑
如果要在代码中实现,可以结合DCMTK的字典查询功能,手动序列化带标签名的JSON:
#include <dcmtk/dcmdata/dcdict.h> #include <dcmtk/dcmdata/dcdatset.h> #include <dcmtk/json/json.h> void writeJsonWithTagName(DcmDataset& dataset, std::ostream& out) { Json::Value root; DcmElement* elem = nullptr; OFCondition status = dataset.nextObject(elem, OFTrue); while (status.good() && elem != nullptr) { DcmTag tag = elem->getTag(); // 从字典中获取标签名称 const DcmTagEntry* tagEntry = DcmDataDictionary::getInstance()->findTagEntry(tag); const char* tagName = tagEntry ? tagEntry->getTagName() : "UnknownTag"; Json::Value elemValue; // 添加VR信息 OFString vrStr; tag.getVR().getVRName(vrStr); elemValue["vr"] = vrStr.c_str(); // 添加值(简化处理,实际需适配多值、不同VR类型) OFString valueStr; if (elem->getOFStringArray(valueStr, 0).good()) { elemValue["Value"].append(valueStr.c_str()); } // 用标签名称作为JSON键 root[tagName] = elemValue; status = dataset.nextObject(elem, OFTrue); } Json::StyledWriter writer; out << writer.write(root); }
注意:这段代码是简化版本,实际使用时需要处理多值元素、数字类型(如DS/IS)的数值转换、序列类型(SQ)的嵌套序列化等场景,同时要确保DCMTK的标准字典已正确加载。
3. 折中方案:同时保留偏移量和标签名称
如果不想完全替换原有JSON结构,可以在每个元素中额外添加标签名称字段,兼容dcm2json的原有格式:
// 基于上述代码修改元素序列化逻辑 Json::Value elemValue; // 添加标签偏移量 elemValue["tag"] = tag.toString().c_str(); // 添加标签名称 elemValue["name"] = tagName; // 添加VR和值... // 仍用偏移量作为键,保持原有结构 root[tag.toString().c_str()] = elemValue;
这样生成的JSON既保留了dcm2json的兼容性,又能直接看到标签名称,方便查询和阅读。
内容的提问来源于stack exchange,提问作者alle_meije
相关产品推荐
相关产品推荐

