-1

我一直在使用以下代码,该代码来自 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。

4

1 回答 1

0

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

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

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

此外,这里有一些关于 C-MOVE 操作的非常好的阅读材料

于 2018-06-02T19:56:04.893 回答