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

背景:

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

DICOM医学图像处理:利用fo-dicom发送C-Find查询Worklist_第1张图片 (具体来源不清楚了,非本人原创)

问题提出:

        上一次利用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,双击直接运行,此时服务端和客户端的结果如下:

DICOM医学图像处理:利用fo-dicom发送C-Find查询Worklist_第2张图片

(客户端) DICOM医学图像处理:利用fo-dicom发送C-Find查询Worklist_第3张图片(服务端)

4)错误调试:

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

DICOM医学图像处理:利用fo-dicom发送C-Find查询Worklist_第4张图片

        发现该函数内部,由于无法识别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。服务端和客户端能够顺利运行,

DICOM医学图像处理:利用fo-dicom发送C-Find查询Worklist_第5张图片

总结验证:

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

DICOM医学图像处理:利用fo-dicom发送C-Find查询Worklist_第6张图片

DICOM医学图像处理:利用fo-dicom发送C-Find查询Worklist_第7张图片

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

        dataset->insertEmptyElement(DCM_ReferencedStudySequence);

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

DICOM医学图像处理:利用fo-dicom发送C-Find查询Worklist_第8张图片        由此证明,根本原因并不是由于WorklistQuery中插入了SQ格式的字段所引起的,在此仅仅标记一下,等待后续的继续排查和验证。

 

(未完待续……)


 

作者:[email protected]

时间:2014-09-01

你可能感兴趣的:(DICOM,DCMTK,worklist,fo-dicom)