最近在开发一个基于MFC对话框的DCM编辑器,最基础的功能是将DCM文件中的所有数据按列表的形式进行显示,这里涉及到对DCM文件数据元素进行遍历的操作
目前网上只找到一篇介绍遍历Tag的接口函数的博文
使用DCMTK遍历读取DICOM文件所有Tag的方法:https://blog.csdn.net/a36254094/article/details/7614428
这篇博文主要介绍了下面函数接口的调用方法:
DcmObject *DcmItem::nextInContainer(const DcmObject *obj)
下面给出一段代码示例:
DcmFileFormat dfile;
string dcmFileName = "E:\\test.dcm";
OFCondition result = dfile.loadFile(dcmFileName.c_str());
DcmDataset *data = dfile.getDataset();
DcmObject *next = data->nextInContainer(NULL);
//遍历Tag(0008——7FE0)
while (next != nullptr)
{
cout << " (" << hex << setw(4) << setfill('0') << next->getGTag();
cout << "," << setw(4) << setfill('0') << next->getETag() << ")" << endl;
next = data->nextInContainer(next);
}
然后给出运行的结果(标签比较多,这里只截取了首尾两部分的结果):
我们再用DCM浏览器工具来查看这个DCM文件(这里也只截取了部分Tag):
从上面几个图比较不难发现:
结论:按上述的方法无法读取文件元信息标签,以及嵌套的数据集合,只能读取顶层的数据元素
接下来我们就要解决这两个问题,首先是文件元信息标签
下面给出编程的实例:
DcmFileFormat dfile;
string dcmFileName = "E:\\test.dcm";
OFCondition result = dfile.loadFile(dcmFileName.c_str());
DcmMetaInfo *metaInfo = dfile.getMetaInfo();
DcmObject *next = metaInfo->nextInContainer(NULL);
while (next != nullptr)
{
cout << " (" << hex << setw(4) << setfill('0') << next->getGTag();
cout << "," << setw(4) << setfill('0') << next->getETag() << ")" << endl;
next = metaInfo->nextInContainer(next);
}
通过上面的方法可以读出文件元标签,本文章的代码稍微修改一下DCM文件的路径就可运行
我们从上面两段代码可以发现,其实都是调用了nextInContainer这个方法,不过调用的对象不同
1.第一段代码,只能打印0008~7FE0的顶层Tag,而这些Tag刚好是DCM数据集里的标签,我们先获取文件的数据集对象,再用这个数据集调用nextInContainer方法,得以读取DCM数据集的标签
DcmDataset *data = dfile.getDataset();
DcmObject *next = data->nextInContainer(NULL);
2.第二段代码,打印了0002的Tag,这些Tag恰好是DCM文件头的数据标签,这里则是获取文件的文件头对象,再让该文件头对象调用nextInContainer方法,得以读取DCM文件头的标签
DcmMetaInfo *metaInfo = dfile.getMetaInfo();
DcmObject *next = metaInfo ->nextInContainer(NULL);
接下来要解决是嵌套数据集的遍历,目前我只找出了遍历二级嵌套数据集的方法,而DICOM文件中最多有三级数据集的嵌套,这里只给出一段代码示例 ( 部分代码已省略 )
DcmItem *sq;
data->findAndGetSequenceItem(tag, sq);
DcmObject *obj = sq->nextInContainer(NULL);
while (obj != nullptr)
{
cout << " (" << hex << setw(4) << setfill('0') << next->getGTag();
cout << "," << setw(4) << setfill('0') << next->getETag() << ")" << endl;
obj = sq->nextInContainer(obj);
}
主要的思路:
对于第三级的嵌套数据集,原本打算用递归调用来遍历,发现不行。。。
本篇博文主要讲遍历Tag,我们已经可以读取相应数据元素的Tag,那么像标签描述(tagName)、数据类型(VR)、长度(Length)、数据域(VF)都可以用相应的方法取到
这里列出几个有用的函数接口,感兴趣的可以参考一下
具体的调用方法,可以参考,DCMTK Class Reference
欢迎评论区交流一下第三级嵌套数据集遍历的方法