DCMTK遍历DICOM文件Tag

DCMTK遍历DICOM文件数据

最近在开发一个基于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);
    }

然后给出运行的结果(标签比较多,这里只截取了首尾两部分的结果):

  DCMTK遍历DICOM文件Tag_第1张图片        DCMTK遍历DICOM文件Tag_第2张图片

我们再用DCM浏览器工具来查看这个DCM文件(这里也只截取了部分Tag):

   DCMTK遍历DICOM文件Tag_第3张图片                    DCMTK遍历DICOM文件Tag_第4张图片

从上面几个图比较不难发现:

  1. 用nextInContainer读取到的Tag只有从0008开始的,而最前面的0002全都没有读取到(组号为0002的标签属于文件元信息标签);
  2. 再看运行结果中的标签(0008,1111)紧接着的标签号为(0009,0010),而从DCM浏览器中看到标签(0008,1111)后有一个嵌套的数据集,没有被遍历到。

结论:按上述的方法无法读取文件元信息标签,以及嵌套的数据集合,只能读取顶层的数据元素

接下来我们就要解决这两个问题,首先是文件元信息标签

下面给出编程的实例:

	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);
	}

主要的思路:

  • 根据getVRName()获取标签的数据类型是否为“SQ”,即序列数据项;              
  • 若为“SQ”时调用findAndGetSequenceItem方法,获取该项;
  • 利用该项调用nextInContainer方法来遍历二级的嵌套数据集;   

对于第三级的嵌套数据集,原本打算用递归调用来遍历,发现不行。。。

本篇博文主要讲遍历Tag,我们已经可以读取相应数据元素的Tag,那么像标签描述(tagName)、数据类型(VR)、长度(Length)、数据域(VF)都可以用相应的方法取到

这里列出几个有用的函数接口,感兴趣的可以参考一下

  • getTag
  • getGTag
  • getETag
  • getTagName
  • getVRName
  • getLength
  • findAndGetOFString

具体的调用方法,可以参考,DCMTK Class Reference

欢迎评论区交流一下第三级嵌套数据集遍历的方法

 

你可能感兴趣的:(DICOM,DICOM文件,DCM文件,遍历Tag,标签)