Package: pypx
Table of Contents1. Overview1.1 CompleteClientSide1.1.1 Quick PACS Primer1.1.2 Configuring a PACS1.1.3 Configuringpypx1.2 Components1.2.1 Environment1.2.2 Tools2. Installation2.1 Prerequisites2.2 Using docker2.3 PyPI3. Configuring the containerized version4 Usage4.1PACS_QR.shandworkflow.sh4.2PACS_QR.shquick-n-dirty5. Development and debugging7. Additional support (incomplete)7. Credits1. Overviewpypxis acompleteclient-side PACS (Picture Archive and Communications System) Query/Retrieve/Storage solution that operates in stand-alone script mode in addition to providing a set of python modules for use in other packages. The modules/API provide a simple mechanism for a python program to interact with an appropriately configured remote PACS, while the stand alone scripts offer a convenient ability to directly Query/Retrieve/Store images from the command line.pypxwas mostly developed for use in the ChRIS system as part of thepfdcmmicroservice; however the CLI scripts ofpypxand the provided docker image offer a quick and powerful means of accessing a PACS without any additional overhead.1.1 CompleteClientSideThis solution isclient-side and cannot operate fully independently of an appropriately configured PACS. Unfortunately, simply downloading this repo/tools and pointing the scripts at some PACS is insufficient. The PACS itself (which is NOT part of this repo) needs to be configured to service communications and requests from these tools. See below for more information.1.1.1 Quick PACS PrimerA PACS exists as a separate service on a network, andpypxcommunicates with a pre-configured PACS when asking for Query data and when Retrieving images. Importantly, from the client perspective, data isPUSHEDfrom the PACS, and notPULLEDfrom the client. This means that client software in essence “asks” the PACS for images and the PACS obliges by transmitting the images over the network to a pre-configured location.Communications with a PACS are for the most insecure and reflected a circa 1990s view/model of internetworking. When a client communicates with a PACS, it sends along with every request string identifiers unique to the client and configured in the PACS. Typical identifiers are theAETitleand sometimes additionally theCalledAETitle. The PACS examines these strings on receipt to identify/authenticate the client and also to identify a destination networkIP:portto which data can be transmitted.1.1.2 Configuring a PACSIn order to be fully complete, a destination PACS with whichpypxmodules wish to communicate needs to be configured with appropriateAETitle,CalledAETitle, as well as the network address IP and port of thepypxhosting machine. Configuring a PACS is obviously outside of the scope of this documentation. Consult your PACS for information on this configuration.As a brief note, if the opensourceorthancPACS server is being used, theorthanc.jsoncan be edited to include{"DicomAet":"CHRISV3T"}and{"CHRIS":["CHRIS","10.72.76.39",10402],"CHRISLOCAL":["CHRISLOCAL","192.168.1.189",11113]}whereCHRISLOCALfor example defines a DICOMstorescpservice on the host192.168.1.189and port11113whileCHRISdefines another destinationstorescpservice .1.1.3 ConfiguringpypxLocally, however, some configuration is required and conveniently located in the scriptPACS_QR.sh. In thefunctioninstitution_set{...}simply add another block reflecting the variables appropriate to your remote PACS service.1.2 Components1.2.1 Environmentpypxcan be thought of as a bridge connecting a PACS to a ChRIS instance. In between these services is a filesystem. Aretrieveoperation will request files from a PACS which arrive over the network and a separately configured listening service repacks these files in a specially configured location called theBASEMOUNT. Once these files are received, they can bepush-ed to special ChRIS friendly storage called swift, and once there they can beregister-ed to ChRIS/CUBE. Each of these services (swift and CUBE) have network locations and login details which are stored in theBASEMOUNTin<BASEMOUNT>/services/[swift,cube].json. Many different swift and CUBE configurations can in theory exist in these json files. Each configuration is identified by a key – theSWIFTKEYfor the swift service and theCUBEKEYfor the CUBE service. Using these keys makes for a convenient way to push and register files without very verbose CLI.SeePACS_QR.sh-xfor some in-line help on setting these keys.1.2.2 ToolsInternally, the code wraps around DCMTK utilies as well as the PyDicom module. The following modules/scripts are provided:pfstorage: Query / put files/objects into swift storage.px-do: Perform various downstream utility functions once apx-findhas completed.px-echo: Ping the PACS to make sure it is online (echoscu).px-find: Find (Query) a PACS in a variety of ways. The start point of almost all other workflows which are constructed asfind_then_do.px-listen: Deprecated listening service wrapper.px-move: Move data from the PACS (movescu).px-push: Push DICOM data to a remote node (either a PACS or a ChRIS swift object storage container).px-register: A companion topx-pushthat registers files in ChRIS swift storage to the ChRIS CUBE backend.px-repack: Read and repack DICOM files, organizing the destination in a human-friendly tree based layout.px-report: Consume the JSON outputs of many of the tools (esp thepx-findand generate various console-based reports).px-status: Report on the status of query results in theBASEMOUNT.px-smdb: A simple file-system based database that provides tracking and query for processed DICOM files.2. Installation2.1 PrerequisitesFor all installation solutions, make sure that the machine receiving images from a PACS has approporate listening and repacking services and that the PACS itself has been configured to recognize this machine. While out of scope of this document, the simplest way to set this up is to use thepfdcmservice (provided separately).2.2 Using dockerUsing the dockerized container is the recommended installation vector as the image contains all tools (dcmtk) that can interact both with a PACS as well as swift storage and CUBE without any additional software on the host system.dockerpullfnndsc/pypxAlternatively, you can build a local image with# If behing a proxyPROXY=http://some.proxy.comexportUID=$(id-u)DOCKER_BUILDKIT=1dockerbuild--build-arghttp_proxy=${PROXY}--build-argUID=$UID-tlocal/pypx.# otherwise...exportUID=$(id-u)DOCKER_BUILDKIT=1dockerbuild--build-argUID=$UID-tlocal/pypx.2.3 PyPIFor convenience, a PyPI installation is also available. This assumes additional non-python requirements such asdcmtkhave been installed. This is recommended only for advanced users.apt-getupdate\&&apt-getinstall-ydcmtk\&&apt-getinstall-ypython3-pippython3-dev\&&pip3install--upgradepip\&&pipinstallpypx3. Configuring the containerized versionIf using the container tool images directly, take care to assure that the machine receiving PACS transmissions is available and has a listener service accessible on an exposed port. This port should be accessible to the remote PACS. Our strong recommendation is to use the companionpfdcmcontainer/repo to receive PACS data. Note thatpfdcmitself containspypxand will handle the reception and repacking of DICOM files using the correctpypxtools.4 Usage4.1PACS_QR.shandworkflow.shFor the most complete example, please consult theworkflow.shscript in the source repository. This provides a Jupyter-notebook-shell-eque overview of most if not all the possible methods to call and use these tools.For the most convenient example, use thePACS_QR.shscript – consult its internal help withPACS_QR.sh-x4.2PACS_QR.shquick-n-dirtyThePACS_QR.shhas several implicit assumptions and values that can/should be set by approprate CLI. The entire scope is beyond this simple README, however,assumingthese values are set (either by using the defaults or an appropriate/custominstitution_setfunction), the workflow is rather simple. Assuming an MRN of say7654321,# QueryPACS_QR.sh--"--PatientID 7654321"# More "low level" -- in fact `PACS_QR.sh` is mostly a convenience wrapper
# around these low level functions. For completeness sake the low level
# `Query` is shown here. Note that passing `PACS_QR.sh -v 1 ...` will
# instruct `PACS_QR.sh` to show the actual commands it uses.px-find\--aecCHRIS\--aetCHRISV3\--serverIP134.174.12.21\--serverPort104\--db/home/dicom/log\--verbosity1\--PatientID7654321# A similar call using the
#    --then report --withFeedBack
# (note if --then <something> is specified, then a --withFeedBack needs to be added
# for console ouput)
# Also, this report shows the SeriesInstanceUIDs in the report bodypx-find\--aecCHRIS\--aetCHRISV3\--serverIP134.174.12.21\--serverPort104\--db/home/dicom/log\--verbosity1\--PatientID7654321--thenreport--withFeedBack# For the most flexibility in reporting, set find results to be JSON
# and pipe the json into the `px-report` app.px-find\--aecCHRIS\--aetCHRISV3\--serverIP134.174.12.21\--serverPort104\--db/home/dicom/log\--verbosity1--json\--PatientID7654321|\px-report\--colorizedark\--printReporttabular# RetrievePACS_QR.sh--doretrieve--"--PatientID 7654321"# StatusPACS_QR.sh--dostatus--"--PatientID 7654321"# Push to CUBE swift storagePACS_QR.sh--dopush--"--PatientID 7654321"# Register to CUBE internal DBPACS_QR.sh--doregister--"--PatientID 7654321"Note carefully the syntax of the abovePACS_QR.shcommands! A--string separates script<key>/<value>pairs from a string defining the search parameters. Note that most valid DICOM tags can be used for this string. More tags can also make a search more specific, for instance"--PatientID 7654321 --StudyDate 19990909"will limit returns only to hits performed on givenStudyDate.5. Development and debuggingThe recommended development/debug approach is to mount source directories into
the container and thus debug the containerized code from the host. Assuming you
are in the source code repo root, and assuming you want to debugpx-push:# Make sure that all env variables below are set appropriately!dockerrun--rm-ti-v$PWD/pypx:/usr/local/lib/python3.8/dist-packages/pypx\-v$PWD/bin/px-push:/usr/local/bin/px-push\-v$LOCALDICOMDIR:$LOCALDICOMDIR-v$BASEMOUNT:$BASEMOUNT$PYPX\--px-push\--swiftIP$SWIFTHOST\--swiftPort$SWIFTPORT\--swiftLogin$SWIFTLOGIN\--swiftServicesPACS$SWIFTSERVICEPACS\--db$DB\--swiftPackEachDICOM\--xcrdir$LOCALDICOMDIR\--parseAllFilesWithSubStrdcm\--verbosity1\--json7. Additional support (incomplete)Please see the relevant wiki pages for usage instructions (some are still under construction):pfstoragepx-dopx-echopx-findpx-movepx-pushpx-registerpx-repackpx-reportpx-statuspx-smdb7. CreditsPyDicomAuthor(s):darcymasonDCMTKAuthor(s): Dicom @ OFFIS Team