DICOM医学图像处理:利用fo-dicom发送C-Find查询Worklist

来源:互联网 发布:2010nba总决赛数据 编辑:程序博客网 时间:2024/04/20 19:20

背景:

        如上一篇专栏博文所描述,Worklist可以看做是PACS系统、MODALITY设备和RIS系统之间的信息交换。从RIS系统到MODALITY通过Worklist可以提供诸如患者个人信息(姓名、年龄、生日等)和其他管理数据,以及提供关于成像过程和产生图像相关的一个唯一UID等信息。基本的结构如下图:

image (具体来源不清楚了,非本人原创)

问题提出:

        上一次利用DCMTK开源库顺利的模拟了“发送C-Find请求,查询worklist信息”的整个过程,通过利用DCMTK开源库提供的wlmscpfs.exe和findscu.exe工具包,使得模拟过程简单明了。此次希望通过fo-dicom(C#版的DCMTK)库来模拟该过程。

解决方案:

1)前提条件:

        为了使得该模拟过程与上一篇博文的过程具有可比性,此次只利用fo-dicom库来构建C#版本的发送C-Find请求的过程,worklist服务端依然使用DCMTK提供的工具包wlmscpfs.exe。

2)利用fo-dicom发送C-Find请求:

        具体代码如下,

 

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Dicom;using Dicom.Network;using Dicom.Log;namespace FindSCU1{    class Program    {        static void Main(string[] args)        {            string id = "123456";            var cfind = DicomCFindRequest.CreateWorklistQuery(patientId: id);            cfind.OnResponseReceived = (DicomCFindRequest rq, DicomCFindResponse rp) =>            {                Console.WriteLine("********Patient Name is  {0}**********", rp.Dataset.Get<string>(DicomTag.PatientName));             };            var client = new DicomClient();            client.AddRequest(cfind);            client.Send("127.0.0.1", 104, false, "SCU-LargeV", "OFFIS");            Console.Read();        }    }}

3)实际测试:

        利用wlmscpfs.exe开启worklist服务,输入如下指令:

        >wlmscpfs.exe 104 –d –dfp d:\DcmWorklist\wlistdb 

        显示效果如下:

image

        表示worklist服务端已经顺利启动……

        找到步骤2)中生成的可执行程序FindSCU1.exe,双击直接运行,此时服务端和客户端的结果如下:

image

(客户端) image(服务端)

4)错误调试:

        只是简单的发送了一次以PatientID为目标的worklist查询服务,代码总共没有几行的,为什么会出现异常呢?根据上述客户端的异常提示,通过单步调试,定位到首次抛出异常的“事故点”:DicomDatasetReaderObserver.cs的OnElement函数中,该函数是从DicomReader.cs的ParseDataset函数中跳转过来的。截取OnElement函数的代码,

image

        发现该函数内部,由于无法识别VR类型为SQ的字段,因此而抛出了throw new DicomDataException("Unhandled VR in DICOM parser observer: {0}", vr.Code)异常。

仔细回想一下我们的代码在哪个位置会出现SQ类型的字段呢?只有在CreateWorklistQuery函数中可能添加过SQ类型的字段,进入到DicomCFindRequest.cs中的CreateWorklistQuery函数内部,发现的确有如下代码:

        dimse.Dataset.Add(new DicomSequence(DicomTag.ReferencedStudySequence));

        为了证实我们的猜测,此处直接将该行代码注释掉,然后在fo-dicom源码工程中编译DICOM工程,重新生成Dicom.dll程序集。重新编译运行我们的测试工程FinSCU1.exe。服务端和客户端能够顺利运行,

image

总结验证:

        修改fo-dicom库源码毕竟不是常规方法,在网络上搜索发现Github上有人遇到过类似的情形(https://github.com/rcd/fo-dicom/issues/62#issuecomment-46248073,如下图)最终也是修改fo-dicom源代码解决的。所以猜测可能是fo-dicom源代码中的部分逻辑还没有完善,还存在着些许漏洞。

b3539526-d4fb-11e3-9748-7be6e3b91c2f

d404e86a-d4fb-11e3-9ce7-a654843bc35f

        为了验证是否是由于dimse.Dataset.Add(new DicomSequence(DicomTag.ReferencedStudySequence));添加了SQ格式的字段而导致的服务端错误,我们利用上次创建wlistqry.wl查询文件的DCMTK工程,向其中写入SQ格式的(0008,1110)DCM_ReferencedStudySequence字段,代码如下:

        dataset->insertEmptyElement(DCM_ReferencedStudySequence);

        然后利用findscu.exe 来进行查询操作,查看worklist服务端程序wlmscpfs是否正常,验证结果图如下:

image        由此证明,根本原因并不是由于WorklistQuery中插入了SQ格式的字段所引起的,在此仅仅标记一下,等待后续的继续排查和验证。

 

(未完待续……)


 

作者:zssure@163.com

时间:2014-09-01

2 0
原创粉丝点击