Coder Social home page Coder Social logo

pydicom / pynetdicom Goto Github PK

View Code? Open in Web Editor NEW
484.0 34.0 171.0 55.25 MB

A Python implementation of the DICOM networking protocol

Home Page: https://pydicom.github.io/pynetdicom

License: MIT License

Python 99.82% Shell 0.18%
dicom networking python pydicom

pynetdicom's People

Contributors

alcir avatar amosonn avatar cancan101 avatar catetrai avatar chsasank avatar dependabot[bot] avatar dimitripapadopoulos avatar edmcdonagh avatar eschivo avatar kosh-jp avatar martink84 avatar moloney avatar mrbean-bremen avatar mself avatar musicinmybrain avatar olieidel avatar or150 avatar patmun avatar pipitone avatar quantifiedcode-bot avatar r1b avatar rongcong avatar scaramallion avatar simonbiggs avatar sjswerdloff avatar sloria avatar tirkarthi avatar vsaase avatar woonchancho avatar yasushi-saito avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pynetdicom's Issues

pydicom.uid.InvalidUID Exception when sending C-STORE to public dicom server

Public Dicom Address = http://www.dicomserver.co.uk/
website: link

I am using the following code

from pynetdicom3 import AE, StorageSOPClassList
from pydicom import read_file
from pydicom.uid import UID
import os
# The Verification SOP Class has a UID of 1.2.840.10008.1.1
#   we can use the UID string directly

ae = AE(scu_sop_class=['1.2.840.10008.1.1'] + StorageSOPClassList)

addr='213.165.94.158'
port = 11112
dir_name = "/Users/shashankkumar/Downloads/54879843/DICOM/Doe^Pierre [54879843]/20060101 000000 [ - CRANE POLYGONE]/Series 002 [CT - Crane SPC]"
# Associate with a peer DICOM AE
assoc = ae.associate(addr, port)

if assoc.is_established:
    # Send a DIMSE C-ECHO request to the peer
    assoc.send_c_echo()
    print('echo sent')
    for file in os.listdir(dir_name):
        if file.endswith(".dcm"):
            print(file)
            dataset = read_file(os.path.join(dir_name, file))
            assoc.send_c_store(dataset)
    # Release the association
    assoc.release()`

Gives the following error:

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/site-packages/pynetdicom3-0.1.0-py3.5.egg/pynetdicom3/utils.py", line 226, in add_transfer_syntax
    transfer_syntax.is_valid()
  File "/usr/local/lib/python3.5/site-packages/pydicom-1.0.0a1-py3.5.egg/pydicom/uid.py", line 137, in is_valid
    raise InvalidUID('UID is not a valid format: %s' % self)
pydicom.uid.InvalidUID: 'UID is not a valid format: '

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/Cellar/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/threading.py", line 914, in _bootstrap_inner
    self.run()
  File "/usr/local/lib/python3.5/site-packages/pynetdicom3-0.1.0-py3.5.egg/pynetdicom3/dul.py", line 242, in run
    if self._is_transport_event() and self._idle_timer is not None:
  File "/usr/local/lib/python3.5/site-packages/pynetdicom3-0.1.0-py3.5.egg/pynetdicom3/dul.py", line 463, in _is_transport_event
    self._check_incoming_pdu()
  File "/usr/local/lib/python3.5/site-packages/pynetdicom3-0.1.0-py3.5.egg/pynetdicom3/dul.py", line 366, in _check_incoming_pdu
    self.primitive = self.pdu.ToParams()
  File "/usr/local/lib/python3.5/site-packages/pynetdicom3-0.1.0-py3.5.egg/pynetdicom3/pdu.py", line 779, in ToParams
    primitive.presentation_context_definition_results_list.append(ii.ToParams())
  File "/usr/local/lib/python3.5/site-packages/pynetdicom3-0.1.0-py3.5.egg/pynetdicom3/pdu.py", line 2367, in ToParams
    primitive.add_transfer_syntax(self.transfer_syntax_sub_item.ToParams())
  File "/usr/local/lib/python3.5/site-packages/pynetdicom3-0.1.0-py3.5.egg/pynetdicom3/utils.py", line 228, in add_transfer_syntax
    raise ValueError('Presentation Context attempted to add a '
ValueError: Presentation Context attempted to add a invalid UID

When user identity is requested, terminate association if identity incorrect

Plus test coverage for same.

There should be an option to require user identity, however I think it should be defaulted to ignoring UI requests.

User Identity Negotiation should be left to the end user (ae.on_user_identity_negotiation perhaps?). In the included apps, any UIN requests should be ignored and the Association accepted by default (unless there are other reasons to reject, of course)

Bytes differences for Find vs Echo SCP

hey @scaramallion ! I'm fairly new to this space, so apologies in advance if this is common knowledge. I noticed for the Find Service Class Provider and Echo Service Class Provider the default pdu_max (in bytes) is just slightly different:

# This is for Echo
   net_opts.add_argument("-pdu", "--max-pdu", metavar='[n]umber of bytes',
                          help="set max receive pdu to n bytes (4096..131072)",
                          type=int,
                          default=16382)

# and this is for Find
    net_opts.add_argument("-pdu", "--max-pdu", metavar='[n]umber of bytes',
                          help="set max receive pdu to n bytes",
                          type=int,
                          default=16384)

is it trivial and not meaningful, or is there something important about those two bytes? Thanks for your wisdom!

DIMSE-C Statuses not fully supported

From my reading of the DICOM standard, some of the Status values weren't supported by pynetdicom, nor were the associated optional command set elements. Unfortunately, supporting them properly will require that the user ae.on_c_* methods return a pydicom.dataset with a Status element instead of an int which is a fairly annoying (though not particular difficult to convert) change.

This will also mean that the current service_class status attributes will need to be removed (it wasn't particularly maintainable anyway as the same service class might have different status return values for the same nominal status depending on which of the DIMSE services it used).

I'm still thinking about the replacement, but it will need to be more adaptable.

Genericise PDU class methods

The PDU items should inherit generic encode, decode, to_primitive, from_primitive methods from the base class. The PDU items themselves should only be used to define the attributes/property getters and setters.

Improve end user documentation

It should follow the pydicom documentation, using sphinx with numpydoc to build and the output going to pydicom.github.io/pynetdicom3 and read the docs. Using circle to automate things would be nice

  • Configure Circle CI to build using sphinx/numpydoc and output to Github Pages

Also need to update/expand the user documentation:

  • Add examples for the various SCU/SCP services
  • Add examples for how to write DICOM files when acting as an SCP
  • Add examples for handling the file meta when writing to DICOM file format
  • Check that included examples all work

Move transport connection code deeper and consolidate it

By my count there are about three different locations where the sockets are opened for connecting and at least another three locations where the sockets are being closed. These all need to be consolidated and modified to follow the state machine more closely.

It's also a bit strange for the AE to be directly handling low level network issues.

Get the senders IP address.

Hi,

is there a way to find out the senders IP address? I made a little DICOM receiver application and I need to get the address of the peer.

Improve handling of elements with ambiguous VRs

When transferring datasets via C-STORE using Association.send_c_store, elements with ambiguous VR (such as 'US or SS') aren't encodable by pydicom (a ValueError gets raised in pydicom.filewriter).

Current status is that most elements with ambiguous VR are corrected, however there are some that I haven't been able to locate any information on how to handle them. See below.

Handling of ambiguous VR elements has been passed off to pydicom instead (pydicom/pydicom@2443a4c)

Moving from dcmtk to pynetdicom3

Hi,

thanks for porting pynetdicom to python3. I am currently using dcmtk (called from python) but would love to use pynetdicom3.

What I am not sure is how I would translate the following dcmtk findscu command to pynetdicom3 equivalent

findscu -v -S -k 0008,0052=SERIES -aec <AEC> <IP> -aet <AE_TITLE> -k PatientName -k PatientBirthDate -k PatientID -k PatientSex -k StudyID -k StudyDate -k Modality -k AccessionNumber -k BodyPartExamined -k StudyDescription -k SeriesDescription -k SeriesNumber -k InstanceNumber -k ReferringPhysicianName -k InstitutionName -k StudyInstanceUID -k SeriesInstanceUID -k StudyDate=20160101 -k SeriesDate=20160101 -k SeriesTime=000000-075959

So it does a Series level query and retrieves those attributes (all -k ones). The filter is set on a specific time. The basic example from (here)[https://github.com/scaramallion/pynetdicom3/blob/master/docs/scu_examples.rst] is running.

Thanks a lot for your time. If there are some easy fixes (documentation, code) I can try to contribute.

AE association related callbacks not all implemented?

The five association related callbacks (requested, accepted, rejected, released, aborted) all need verification that they're being called correctly. Probably a good idea to do this through the unit testing.

The on_association_aborted callback parameters also need sorting out.

pynetdicom3 vs. pynetdicom

hey @scaramallion! I'm a software engineer at Stanford, and I'm looking to implement a dicom receiver for some applications in python (we are using the old MRCTP and it's time for an update!) I found your repo as a fork off of the base https://github.com/patmun/pynetdicom and they seem to be moving in separate directions. Is the difference that this repo has python 3 support? Is there plans to integrate back into pynetdicom, or something else? I'm looking to see which I'd start with for our work (and will likely contribute to its development) so I want to understand how the projects are related. Thanks!

C-MOVE SCU/SCP not possible?

  • Due to the way the program structure works, its not possible to run a C-MOVE operation with the SCU as the move destination due to a C-MOVE invoking a separate Association request from the SCP for the C-STORE request (unlike C-GET which uses the same Association to receive the C-STORE request).
  • I'm not actually sure if this is a bug or if this is the desired behaviour. Why use a C-MOVE to fetch to the running AE instead of a C-GET?

Dicoms transferring slower than pynetdicom(0.8.1)

I have written a dicom server. When association accomplished and start to transferring dicom files. I found that pynetdicom3 much slower than pynetdicom0.8.1, I don't know why.

pynetdicom3 storage server code:

    scp = StorageSCP(ae_title=ae_title, port=port, on_c_store=my_on_c_store)
    scp.ae.maximum_associations = 10
    scp.start()

pynetdicom0.8.1 storage server code:

    ae = AE(ae_title, port, [PatientRootFindSOPClass,
                             PatientRootMoveSOPClass,
                             VerificationSOPClass],
            [StorageSOPClass, CTImageStorageSOPClass, RTImageStorageSOPClass,
             MRImageStorageSOPClass], )
    ae.OnReceiveStore = my_on_c_store

Intermittent ValueError during association release

Traceback (most recent call last):
  File "/opt/python/3.5.2/lib/python3.5/threading.py", line 914, in _bootstrap_inner
    self.run()
  File "/home/travis/build/scaramallion/pynetdicom3/pynetdicom3/DULprovider.py", line 484, in run
    if self.CheckNetwork():
  File "/home/travis/build/scaramallion/pynetdicom3/pynetdicom3/DULprovider.py", line 383, in CheckNetwork
    return self.is_transport_connection_event()
  File "/home/travis/build/scaramallion/pynetdicom3/pynetdicom3/DULprovider.py", line 450, in is_transport_connection_event
    read_list, _, _ = select.select([self.scu_socket], [], [], 0)
ValueError: file descriptor cannot be a negative integer (-1)

I think the cause is the thread being killed before the socket has time to close properly, possibly due to a race condition between the Assoc and DUL threads.

Occurs during/after association release.

The Association thread calls assoc.release(), which causes the peer to send a release confirmation then disconnect. In addition, assoc.release() is used to stop the DUL run loop. The DUL thread, on the other hand, is checking for network connection roughly every 0.001 s, so occasionally what happens is that the signal to kill the DUL happens after the peer disconnects but before the run loop is stopped. As a result, the DUL checks the socket, which returns -1 as its been closed by the peer, which in turn raises a ValueError.

Version 1.0.0 Release

The following should be completed before the v1.0.0 release:

Tasks

  • Update the DIMSE Status to use pydicom.dataset.Dataset objects and determine a more flexible approach for the Service Class DIMSE Statuses (and make sure all the Statuses are supported).
  • Implement support for extended negotiation items.
    • SCP/SCU Role Selection (#229)
    • Implement AE callback for User Identity (#233)
    • Asynchronous Window (only use of extended negotiation supported, not actual async operations) (#236)
    • SOP Class Extended (#236)
    • SOP Class Common Extended (needs ACSE update first) (#249)
  • Update the end user documentation and add it to github pages (complementary with pydicom).
  • Replace the PresentationContextManager, because it sucks (#229).
  • Update pdu module (#165)
  • Update ACSE methods to use PEP8 naming, and to have better control over association. (#238)
  • As per @patmun, change package name to pynetdicom (thanks!) (#250)
  • Add context and info parameters to the on_c_* callbacks (#167)
  • Implement DIMSE-N services (SCU only) #216, #219, #225, #226

Release related

  • Get a pypi account and fix the setup/install config as it requires.
  • Wait for pydicom 1.2 release and use it as the supported version.

Intermittent AttributeError after DUL start but before Association attempted

Traceback (most recent call last):
  File "/opt/python/3.3.5/lib/python3.3/threading.py", line 901, in _bootstrap_inner
    self.run()
  File "./pynetdicom3/DULprovider.py", line 487, in run
    if self.CheckNetwork():
  File "./pynetdicom3/DULprovider.py", line 387, in CheckNetwork
    return self.is_transport_connection_event()
  File "./pynetdicom3/DULprovider.py", line 456, in is_transport_connection_event
    self.CheckIncomingPDU()
  File "./pynetdicom3/DULprovider.py", line 329, in CheckIncomingPDU
    self.pdu = Socket2PDU(bytestream, self)
  File "./pynetdicom3/DULprovider.py", line 582, in Socket2PDU
    acse = dul.association.acse
AttributeError: 'Association' object has no attribute 'acse'

I've only seen it during Travis builds, weirdly.

Intermittent OSError during association abort

Traceback (most recent call last):
  File "/opt/python/3.4.2/lib/python3.4/threading.py", line 921, in _bootstrap_inner
    self.run()
  File "/home/travis/build/scaramallion/pynetdicom3/test/test_ae.py", line 95, in run
    self.ae.start()
  File "/home/travis/build/scaramallion/pynetdicom3/pynetdicom3/applicationentity.py", line 284, in start
    self._bind_socket()
  File "/home/travis/build/scaramallion/pynetdicom3/pynetdicom3/applicationentity.py", line 320, in _bind_socket
    self.local_socket.bind(('', self.port))
OSError: [Errno 98] Address already in use

Due to the next unit test run trying to set an SCP on the same port of a previous unit test that failed to close it properly, which in this case is the assoc.abort() test.

ae.start() method works on full load (100% CPU)

Either when I run my own code to create an scp or when running the scp tools located in app directory the CPU load of the application is 100%

I suppose start() uses a while(true) which is not so efficient?

Req: StoreScp example

Hi,

I am trying to set up a storescp to receive Dicom images.
This is what the code looks like now

def on_c_store(dataset):
    pydicom.write_file(filename='sample.dcm', dataset=dataset)
    return StorageServiceClass.Success

# Or we can use the inbuilt Verification SOP Class
ae = AE(ae_title="local", port=11112, scp_sop_class=['1.2.840.10008.5.1.4.1.1.2', VerificationSOPClass],
        transfer_syntax=[ExplicitVRLittleEndian, ImplicitVRLittleEndian, ExplicitVRBigEndian, JpegLossLess])
ae.on_c_store=on_c_store
# Start the SCP
ae.start()

So when i send a dicom image i get the following error

File "C:/Users/Adarsh/PycharmProjects/Insight/storescp.py", line 20, in on_c_store
pydicom.write_file(filename='sample.dcm', dataset=dataset)
File "C:\Python\Python35\lib\site-packages\pydicom-1.0.0a1-py3.5.egg\pydicom_init_.py", line 47, in write_file
return write_file(*args, **kwargs)
File "C:\Python\Python35\lib\site-packages\pydicom-1.0.0a1-py3.5.egg\pydicom\filewriter.py", line 556, in write_file
file_meta = dataset.file_meta
File "C:\Python\Python35\lib\site-packages\pydicom-1.0.0a1-py3.5.egg\pydicom\dataset.py", line 322, in getattr
"'{0:s}'.".format(name))
AttributeError: Dataset does not have attribute 'file_meta'.

The storescp example on your project is empty.
Can you guide me as to what i am doing wrong here? The dicom file i am sending has the file meta tag in it.

REQ: UUID as an ENUM?

This is great, but could these be ENUM or something similar so that the user doesn't have to remember or lookup the UUIDs?

ae = AE(scu_sop_class=['1.2.840.10008.1.1']) --> ae = AE(scu_sop_class=[AE.VerificationSOPClass])

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.