what would be the recommended way to realize DICOM network access via python script? We would need to load all CT scans of a patient (defined by patient ID) of a certain time period into Slicers DICOM database, then process data later. DICOM networking via GUI works well here.
I’m guessing you mean traditional dicom networking (a.k.a. “DIMSE”) since that is the very common standard, compared to the newer DICOMweb standard (if your PACS or VNA supports DICOMweb that’s cleaner).
For DIMSE, Slicer uses a combination of C++ and python. The CFIND, CMOVE type transactions are in CTK C++ but should all be exposed and usable in python. For the listener (CSTORE SCP) we use the dcmtk command line executable in a separate process in python.
If your PACS supports CGET, you are probably best to use getscu into a temp directory and then load into the database. Let us know if you need more pointers.
Right, if you can’t use CGET then you need to be running the Slicer listener and then do the CFIND to get the list of instances and CMOVE to tell them to be transferred to Slicer’s listener. This can be done using dcmtk command line tools but that might not be cleanest.
It’s been been about a decade since we did all that code, but I’m pretty sure everything you need is exposed in python if you use the ctkDICOMQuery and ctkDICOMRetrieve classes. These are what the GUI uses under the hood and it looks like all the methods are exposed. The ctk doxygen is down, but if you look in the header files you’ll find what you need.
And you can see how they are used by the widget code - it should just be a matter of using the same API from python. Hope that helps!
During the implementation of @lassoan 's script example I face the following problem:
The script works well with the public DICOM server, but does not work within the hospital setting. It returns a “failed” move operation upon retrieving the images.
The query itself seems to work fine and finds three CT series for a specific patient ID (which is correct)
All parameters are set exactly as I would do in the DICOM networking widget.
Is it possible that the function
is not exposed yet?
I also tried
dicomRetrieve.moveDestinationAETitle = “XXXXX”
with no luck.
I need to set the retriever (“XXXXX”, the computer which makes the DICOM retrieve call) in the widget form field “Storage AETitle”, otherwise, the widget networking call would not work.
I normally use it from the widget with CGET unchecked, but from the widget, it also works with CGET checked.
Debugging DIMSE networking is always a challenge. Both sides need to be configured just right, but it sounds like you are close.
Hmm, these appear be exposed correctly and that should match what’s happening in the GUI implementation.
In this case then you could try using the bool ctkDICOMRetrieve::getStudy(const QString& studyInstanceUID) or bool getSeries( const QString& studyInstanceUID, const QString& seriesInstanceUID ) methods? If the PACS side supports it then this is less tricky to configure.
The observation with the widget is: Takes quite a long time interval until the popup “Got a move request” is displayed (20 s), then it is again quite slow but realiable to retieve the data.
With the script, the query takes place almost instantly, the failed retrieval requests print messages are within 3 s.
I suspect a timing problem … if I could I would check logs on the server side, but I have no access myself and it is extremely difficult to get hold of the PACS guy