新的一年开始,专栏会坚持下去,继续与大家相互交流学习。本篇博文再一次分析DCMTK自带的工具包dcmqrscp.exe(类似于一个单机版miniPACS),此次主要关注dcmqrscp.exe的数据库部分,通过使用dcmqridx.exe手动操作dcmqrscp.exe的数据库文件,直观了解数据库的记录内容;然后利用dcmqrti.exe查询dcmqrscp.exe的数据库文件,学习如何操作dcmqrscp.exe数据库。
单机版数据库就是只能运行在单机上,不提供网络功能的数据库。比如ACCESS、FORPRO等都是单机数据库(摘自百度百科“单机数据库”)其实单机数据库种类还有很多,年前分析过Orthanc的数据库——SQLite,和此次即将要分析的index.dat文件,此外甚至还有FireBird、Derby、HSql、PostgreSQL、JavaDB 、H2等。
之所以使用数据库(无论单机版还是网络版),目的是尽量减少数据的冗余、提高数据利用率、保持数据完整性和一致性,以及数据使用效率。无论哪一种数据库系统,其所建立的数据库文件都可以看做是具有想相同性质的记录的集合,更广义的说,我们常见的xml、json、ini等配置文件也是单机版的数据库。
原本以为index.dat可能是一种类似于xml、json等常见格式的标准文件,搜索了一下百度百科中的描述“在微软windows操作系统中,index.dat是一个由Internet Explorer和资源管理器创建的文件。这个文件的功能就像一个数据库,随系统启动。它的功能在于收集个人信息,就像网址,搜索字符串和最近打开的文件。它的职责就像数据库中的索引”。因此博文下面将index.dat看做是DCMTK中自定义的一种用于记录相关信息的索引数据库文件,主要用于dcmqrscp.exe、dcmqridx.exe、dcmqrti.exe等工具包中。
下面就会通过分析和实际使用dcmqrscp.exe、dcmqridx.exe和dcmqrti.exe工具包来分析index.dat数据库文件。
关于dcmqrscp.exe的相关介绍参照之前的博文DICOM医学图像处理:DCMTK的wiki资料学习之PACS调试。
之前博文对dcmqrscp.exe的介绍侧重于DIMSE服务,如C-ECHO、C-FIND、C-STORE、C-MOVE等,并未提及内部的数据库部分。既然dcmqrscp能够响应C-FIND请求,那么其内部自然实现了数据库功能,用于存储C-STORE上传的相关记录。
重新查看DCMTK的官方说明文档,也可以发现dcmqridx、dcmqrscp、dcmqrti三个工具同属于dcmqrdb模块,DCMTK文档称之为an image database server。
如果再仔细翻看dcmqrscp.exe工具包的源码会发现,在正式处理链接请求之前,是数据库相关操作,具体代码如下:
#ifdef WITH_SQL_DATABASE // use SQL database DcmQueryRetrieveSQLDatabaseHandleFactory factory; #else // use linear index database (index.dat) DcmQueryRetrieveIndexDatabaseHandleFactory factory(&config); #endif DcmQueryRetrieveSCP scp(config, options, factory); scp.setDatabaseFlags(opt_checkFindIdentifier, opt_checkMoveIdentifier); /* loop waiting for associations */ while (cond.good()) { cond = scp.waitForAssociation(options.net_); if (!options.singleProcess_) scp.cleanChildren(); /* clean up any child processes */ } cond = ASC_dropNetwork(&options.net_); if (cond.bad()) { OFLOG_FATAL(dcmqrscpLogger, "cannot drop network: " << DimseCondition::dump(temp_str, cond)); return 10; }
由于目前DCMTK还未实现DcmQueryRetrieveSQLDatabaseHandle相关类,因此windows系统中的dcmqrscp.exe工具包使用的是DcmQueryRetrieveDatabaseIndexDatabaseHandle,即index.dat对应的索引数据库。
查看DcmQueryRetrieveIndexDatabaseHandle类定义,其内部包含了数据库句柄,类型为DB_PrivateHandle,这是一个结构体,具体定义如下:
struct DB_Private_Handle { int pidx ; DB_ElementList *findRequestList ; DB_ElementList *findResponseList ; DB_LEVEL queryLevel ; char indexFilename[DBC_MAXSTRING+1] ; char storageArea[DBC_MAXSTRING+1] ; long maxBytesPerStudy ; long maxStudiesAllowed ; int idxCounter ; DB_CounterList *moveCounterList ; int NumberRemainOperations ; DB_QUERY_CLASS rootLevel ; DB_UidList *uidList ; DB_Private_Handle() : pidx(0) , findRequestList(NULL) , findResponseList(NULL) , queryLevel(STUDY_LEVEL) // , indexFilename() // , storageArea() , maxBytesPerStudy(0) , maxStudiesAllowed(0) , idxCounter(0) , moveCounterList(NULL) , NumberRemainOperations(0) , rootLevel(STUDY_ROOT) , uidList(NULL) { } };
从其构造函数可以判断出pidx记录的是index.dat文件的描述符,与文件句柄类似;indexFilename记录的是index.dat数据库文件的全路径;storageArea记录的是dcmqrscp.cfg配置文件中AETable部分中给出的与storagearea(在dcmqrcnf.txt文件中说明Application Entity Table部分中可针对不同的AE设置不同的storage area,因此启动dcmqrscp.exe后,可能会生成多个index.dat数据库文件,用于分别记录不同AE的操作)
大致了解了dcmqrscp.exe的数据操作后,让我们来实际测试一下,与dcmqrscp.exe工具包测试时公用同一个dcmqrscp.cfg配置文件,其路径为d:\DcmScuScp,
输入下面指令:
cd d:\DcmScuScp,此时可以注意到该路径下有一个曾经使用dcmqrscp.exe工具时生成的index.dat文件,这里为了更清楚的说明index.dat的记录操作,我们将其删除,确保当前目录下不存在index.dat文件。
dcmqridx.exe –d d:\DcmScuScp\ c:\test1.dcm,为了了解更多的信息,我们采用调试状态,添加-d参数。
从输出结果中我们可以大致猜测出,index.dat文件中记录的应该就是上图中罗列的各种信息,然我们打开D:\DcmScuScp目录,使用UltriEdit打开刚生成的index.dat文件,其内容如下:
将标尺拖动到文件后半部分,可以发现dcmqridx.exe调试状态输出的各种信息,例如StudyDate、StudyTime、SeriesNumber、InstanceNumber、Modality、SeriesInstanceUID、SOPInstanceUID等等,由此可以看出index.dat数据库文件就是按照统一的格式来记录每一个dcm文件的相关信息,包含了DICOM常见的关系型数据库中的四级结构所需的全部信息。当然index.dat并非是对每个dcm文件信息简单的在文件末尾进行追加填写,例如添加完test1.dcm文件都index.dat文件大小约为48k,而再添加test2.dcm文件索引后index.dat文件大小变为52k。
了解了index.dat的基本结构,以及如何手动向index.dat数据文件总添加记录,那么我们又该如何查看index.dat数据文件中的记录呢?dat文件并非是一种统一的标准格式,再未拿到具体协议之前我们无法精确解析index.dat文件,不过还好DCMTK已经为我们提供了一款工具,它就是dcmqrti.exe。
官网对dcmqrti.exe的描述如下:
The dcmqrti program (telnet initiator) is an interactive character based program intended to be used for examining the dcmqrscp image databases and sending images contained within these databases to Vendor nodes.
——dcmqrti是用于检测dcmqrscp图像数据库,即index.dat,的一种交互工具,还可以将index.dat中记录的图像发送到其他DICOM终端(该终端需要在dcmqrscp.cfg的Host Table中进行注册)。
下面我们进行实际测试:
输入dcmqrti.exe可以看到关于该工具包使用的简单介绍,如下图左:
dcmqrti工具必须的唯一参数就是在dcmqrscp.cfg配置文件Vendor Table中注册的vendor节点,博文DICOM医学图像处理:DCMTK的wiki资料学习之PACS调试配置文件中的vendor是acmeCTcompany,该vendor包含了Host Table中的所有节点,Host Table中的节点就是PACS系统中通常需要配置的各个客户端的节点信息,即AETitle、IP、Port。输入下面指令可看到上图右侧的结果
dcmqrti.exe acmeCTcompany
此刻命令提示符变为ACME_STORE->ACME1>,其中ACME_STORE是dcmqrscp.cfg配置文件中AETable部分设置的本地存储的Title,ACME1是Host Table中设置的某个AE Title(dcmqrt.exe工具默认选择Host Table中的第一个节点)。说明我们进入dcmqrscp数据库index.dat的控制状态。
此刻输入help,如下所示:
我们接下来逐个测试上面的指令,
输入:title
可以看到在dcmqrscp.cfg配置文件中Host Table部分的所有Host节点,其中带星号的是当前默认,也就是ACME1
输入:title 1
可以看到命令提示符变成ACME_STORE->ACME2>,说明当前host节点的AETitle变为ACME2
输入:database
可以看到dcmqrscp.cfg配置文件中AETable部分设置的本地存储的Title,由于此次配置文件中只指定了一个存储区域即ACME_STORE,存储路径为d:\DcmScuScp,因此就只生成了一个index.dat文件。
分别输入study、series、image指令可查看刚才通过dcmqridx.exe手动注册的dcm的相关信息,如下图所示:
此处为了方便,只是用send image来发送刚才上传的test1.dcm文件到指定的节点。
重新开启一个命令行程序,开启C-STORE SCP服务,输入:storescp.exe –d 11110 –aet ACME2
storescp此处的参数是依照dcmqrscp.cfg配置文件中Host Table部分来填写的,为了方便查看直接将dcmqrscp.cfg配置文件截图如下:
在dcmqrti.exe客户端输入:send image,具体结果如下图所示:
转到DcmData目录下,可以看到顺利接收到了dcm图像,如下图:
然后输入quit或exit顺利退出dcmqrti.exe控制状态。
至此对于DCMTK中的dcmqrscp.exe、dcmqridx.exe和dcmqrti.exe工具包的介绍就告一段落了,通过此次亲自测试大致了解了dcmqrscp工具中存储记录数据的方式,以及所采用的数据库文件index.dat,同时在上一篇博文的基础上,对dcmqrscp.cfg配置文件中的各项参数有了更进一步的认识,后续会再进一步详细研究,尝试替换dcmqrscp.exe工具中默认的索引数据库方式,改用sqlite或者mysql,敬请期待……
利用fo-dicom搭建简单的PACS Server服务端
dcmqrscp.exe工具包中的数据库的替换
时间:2015-01-11