【问题标题】:How to invoke C-STORE when trying to query from SCP尝试从 SCP 查询时如何调用 C-STORE
【发布时间】:2018-06-01 19:09:29
【问题描述】:

我一直在使用来自 pynetdicom 库的以下代码在我的机器 (SCU) 上查询和存储来自远程服务器 SCP 的一些图像。

"""
Query/Retrieve SCU AE example.

This demonstrates a simple application entity that support the Patient
Root Find and Move SOP Classes as SCU. In order to receive retrieved
datasets, this application entity must support the CT Image Storage
SOP Class as SCP as well. For this example to work, there must be an
SCP listening on the specified host and port.

For help on usage,
python qrscu.py -h
"""

import argparse
from netdicom.applicationentity import AE
from netdicom.SOPclass import *
from dicom.dataset import Dataset, FileDataset
from dicom.UID import ExplicitVRLittleEndian, ImplicitVRLittleEndian, \
    ExplicitVRBigEndian
import netdicom
# netdicom.debug(True)
import tempfile

# parse commandline
parser = argparse.ArgumentParser(description='storage SCU example')
parser.add_argument('remotehost')
parser.add_argument('remoteport', type=int)
parser.add_argument('searchstring')
parser.add_argument('-p', help='local server port', type=int, default=9999)
parser.add_argument('-aet', help='calling AE title', default='PYNETDICOM')
parser.add_argument('-aec', help='called AE title', default='REMOTESCU')
parser.add_argument('-implicit', action='store_true',
                    help='negociate implicit transfer syntax only',
                    default=False)
parser.add_argument('-explicit', action='store_true',
                    help='negociate explicit transfer syntax only',
                    default=False)

args = parser.parse_args()

if args.implicit:
    ts = [ImplicitVRLittleEndian]
elif args.explicit:
    ts = [ExplicitVRLittleEndian]
else:
    ts = [
        ExplicitVRLittleEndian,
        ImplicitVRLittleEndian,
        ExplicitVRBigEndian
    ]

# call back


def OnAssociateResponse(association):
    print "Association response received"


def OnAssociateRequest(association):
    print "Association resquested"
    return True


def OnReceiveStore(SOPClass, DS):
    print("FINALLY ENTERED")
    print "Received C-STORE", DS.PatientName
    try:
        # do something with dataset. For instance, store it.
        file_meta = Dataset()
        file_meta.MediaStorageSOPClassUID = '1.2.840.10008.5.1.4.1.1.2'
        # !! Need valid UID here
        file_meta.MediaStorageSOPInstanceUID = "1.2.3"
        # !!! Need valid UIDs here
        file_meta.ImplementationClassUID = "1.2.3.4"
        filename = '%s/%s.dcm' % (tempfile.gettempdir(), DS.SOPInstanceUID)
        ds = FileDataset(filename, {},
                         file_meta=file_meta, preamble="\0" * 128)
        ds.update(DS)
        #ds.is_little_endian = True
        #ds.is_implicit_VR = True
        ds.save_as(filename)
        print "File %s written" % filename
    except:
        pass
    # must return appropriate status
    return SOPClass.Success


# create application entity
MyAE = AE(args.aet, args.p, [PatientRootFindSOPClass,
                             PatientRootMoveSOPClass,
                             VerificationSOPClass], [StorageSOPClass], ts)
MyAE.OnAssociateResponse = OnAssociateResponse
MyAE.OnAssociateRequest = OnAssociateRequest
MyAE.OnReceiveStore = OnReceiveStore
MyAE.start()


# remote application entity
RemoteAE = dict(Address=args.remotehost, Port=args.remoteport, AET=args.aec)

# create association with remote AE
print "Request association"
assoc = MyAE.RequestAssociation(RemoteAE)


# perform a DICOM ECHO
print "DICOM Echo ... ",
st = assoc.VerificationSOPClass.SCU(1)
print 'done with status "%s"' % st

print "DICOM FindSCU ... ",
d = Dataset()
d.PatientsName = args.searchstring
d.QueryRetrieveLevel = "PATIENT"
d.PatientID = "*"
st = assoc.PatientRootFindSOPClass.SCU(d, 1)
print 'done with status "%s"' % st

for ss in st:
    if not ss[1]:
        continue
    # print ss[1]
    try:
        d.PatientID = ss[1].PatientID
    except:
        continue
    print "Moving"
    print d
    assoc2 = MyAE.RequestAssociation(RemoteAE)
    gen = assoc2.PatientRootMoveSOPClass.SCU(d, 'SAMTEST', 1)
    for gg in gen:
        print
        print gg
    assoc2.Release(0)
    print "QWEQWE"

print "Release association"
assoc.Release(0)

# done
MyAE.Quit()

运行程序,我得到以下输出:

Request association
Association response received
DICOM Echo ...  done with status "Success "
DICOM FindSCU ...  done with status "<generator object SCU at 0x106014c30>"
Moving
(0008, 0052) Query/Retrieve Level                CS: 'PATIENT'
(0010, 0010) Patient's Name                      PN: 'P*'
(0010, 0020) Patient ID                          LO: 'Pat00001563'
Association response received
QWEQWE
Moving
(0008, 0052) Query/Retrieve Level                CS: 'PATIENT'
(0010, 0010) Patient's Name                      PN: 'P*'
(0010, 0020) Patient ID                          LO: 'Pat00002021'
Association response received
QWEQWE
Release association

Echo 工作,所以我知道我的关联正在工作,并且我能够按照输出的建议查询和查看服务器上的文件。但是,正如您所看到的,OnReceiveStore 似乎没有被调用。我对 DICOM 很陌生,我想知道可能是什么情况。如果我错了,请纠正我,但我认为gen = assoc2.PatientRootMoveSOPClass.SCU(d, 'SAMTEST', 1) 应该调用OnReceiveStore。如果没有,请了解如何调用 C-STORE。

【问题讨论】:

    标签: python dicom pydicom pynetdicom


    【解决方案1】:

    如果您对 DICOM 不是很熟悉,DICOM C-MOVE 是一个复杂的操作。

    您不是自己调用OnReceiveStore,它是在SCP 开始向您的应用程序发送实例时调用的。你用你自己的 AE 标题向 SCP 发出 C-MOVE 命令,你想在其中接收图像。在您的情况下 SAMTEST。由于这是 C-MOVE 命令的唯一参数,因此需要预先配置 SCP 以了解 SAMTEST AE 的 IP 和端口。你这样做了吗?

    我不知道,为什么代码没有从 SCP 输出对 C-MOVE 命令的响应。看起来应该。这些可以很好地表明正在发生的事情。您还可以查看 SCP 端的日志,看看发生了什么。

    另外,这里有一些quite good reading about C-MOVE operation

    【讨论】:

    • 嘿塔莫。我以前读过Roni 的博客,很有帮助。正如你所提到的,我已经配置了 SCP,“TESTFORSAM”,它接受来自任何设备的所有通信(我知道这不安全),以确保我不会遇到连接问题。我也可以将文件从 SCU 发送到 SCP,这确保了连接存在。既然你似乎比我更了解这一点,你是说 gen = assoc2.PatientRootMoveSOPClass.SCU(d, 'SAMTEST', 1) 让 SCP 开始一个 OnReceiveStore 吗?这是我最初的想法。如果我错了,请纠正我。
    • 基本上,您引用的行向 SCP 发送 DICOM C-MOVE 命令。 SCP 查看命令,如果它有效,它会打开一个从 SCP 到 SCU 的新的、单独的关联,并向 SCU 发送 C-STORE 命令,然后由您的代码中的 OnReceiveStore 方法处理。为此,SCP 需要知道您在 C-MOVE 中使用的 SAMTEST AE 的 IP 和端口。这是与仅允许 SCP 接受任何和所有传入连接不同的设置。查看您的软件文档,了解它应该如何配置。
    • 我正在使用 Clear Canvas 图像服务器,并且我的 SCU 确实在设备选项卡中为服务器所知。
    • 您检查过 ClearCanvas 端的日志吗?您是否知道如何在 pynetdicom 端输出 C-MOVE 命令的结果?如果一切都失败了,启动 WireShark 并查看 DICOM 流量正在移动,给你一个线索,正在发生(或没有发生)。
    • 问题出在 SCU 的端口侧,现在已修复并可以正常工作!感谢您提供帮助。
    猜你喜欢
    • 1970-01-01
    • 2013-03-25
    • 2021-04-08
    • 1970-01-01
    • 2014-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多