Skip to main content
Skip table of contents

Step 5 of 5: Command, Action, ACE Practice

Goal

In this step, you will configure a new Command, Action, ACE set to act on XNAT session data.

Make a new Command, Action, and ACE

In this step, we'll use the custom Python image we generated in Part 1 - Step 4 labeled xnat/dcmstack_python:v1. Recall that we loaded a base python image with several toolboxes and a python script, pydicom.py.

pydicom.py

PY
# /bin/env python
# Converts a directory of one or more DICOM files into the NIfTI format
# Primary use is to test the XNAT Docker service.
# Input directory is assumed to be /input
#   Input directory format is assumed to be /data/input/*.dcm
# Output directory is assumed to be /data/output
#   Output directory format will be generated as /data/output/data.nii.gz
# USAGE: python pyscript.py
import sys
import os
import dcmstack
import getopt
from glob import glob
def main(argv):
    input_dir = '/input'
    output_dir = '/output'
    dcm = glob(input_dir + os.path.sep + '*.dcm')
    nifit_file_name = output_dir + os.path.sep + 'scan' + '.nii.gz';
    dcm_to_nii(dcm, nifit_file_name)
def dcm_to_nii(dcm, nii_file_name):
    try:
        stacks = dcmstack.parse_and_stack(dcm)
        for stack in stacks.itervalues():
            nii = stack.to_nifti()
            nii.to_filename(nii_file_name)
            break
    except:
        print 'dcmstack DICOM to NIFTI failed.'
if __name__ == "__main__":
    main(sys.argv[1:]) 

When run within our xnat/dcmstack_python:v1 container, this script takes any .dcm files it finds in /input and converts them to NIfII format in the /output folder. The following setup will build a context for that script, providing XNAT image data at the expected location within our Docker container, and execute pydicom.py to process the provided data.

Register The Image With XNAT

Register the image with XNAT and get the id.

  1. Return to the XNAT Swagger page.
  2. Expand docker-images-rest-api, and POST /xapi/docker/images.
  3. Enter JSON in the dockerImageDto field: {"name":"xnat/dcmstack_python","image-id":"sha256:041fa8c8bacd2f1106f2b98fb41744c6cb98e303e2f61ce8f1958faed22e22fd"}.
  4. Press the "Try it out!" button.
  5. Note the id in the Response Body. We will use it in a moment.

Initialize A Command For This Image In XNAT

  1. Expand command-rest-api, and POST /xapi/commands.
  2. Enter the following JSON, using the Image id that you just got as the docker-image.id value.

    CODE
    {
        "name": "dicom-scan",
        "description": "run a script on a scan's dicom files from an input mount",
        "docker-image": {"id": 2},
        "mounts-in": [
            {
                "name": "DICOM",
                "path": "/input"
            }
        ],
        "mounts-out": [
            {
                "name": "NIFTI",
                "path": "/output"
            }
        ],
        "run-template": ["python", "/scripts/pydicom.py"],
        "type": "docker-image"
    }
  3. Press the "Try it out!" button.
  4. Note the id in the Response Body. We will use it in a moment.

    Command mounts

    Let us pause to study this Command. It has two new properties that we have not seen before: mounts-in and mounts-out. The former is where input files will be made available to your container, and the latter is where you can write output files for XNAT to read when your container execution finishes. The names we gave are, by default, the names of resources that XNAT will look for on whatever object we use to resolve the ACE. We will see more about this in a few moments when we define an Action and resolve an ACE from it.

Create An XNAT Action That Can Run The Command

  1. Expand action-rest-api , and POST /xapi/actions.
  2. Enter the following JSON in the actionDto field, using the Command id that you just got as the command-id value.

    CODE
    {
        "name":"dicom-scan",
        "command-id": 3,
        "root-xsi-type": "xnat:imageScanData"
    }

    Note that this command will run on a scan, which does not have a globally unique id. The refer to a scan, we will use an id which is <session id>:<scan id>.

  3. Press the "Try it out!" button.

Ensure That The Action Can Run In Your XNAT Context

  1. Expand ace-rest-api, and GET /xapi/aces.
  2. Enter XNAT_E00001:301 as the id, and xnat:imageScanData as the xsiType.
  3. Press the "Try it out!" button.
    Example response body:

    CODE
    [
      {
        "name": "dicom-scan",
        "description": null,
        "inputs": [],
        "action-id": 2,
        "command-id": 3,
        "project": "Day3Data",
        "root-id": "XNAT_E00001:301",
        "resources-staged": [
          {
            "path": "/data/xnat/archive/Day3Data/arc001/5Yp0E/SCANS/301/DICOM",
            "overwrite": false,
            "name": "DICOM",
            "mount": "DICOM"
          }
        ],
        "resources-created": [
          {
            "path": null,
            "overwrite": false,
            "name": "NIFTI",
            "mount": "NIFTI"
          }
        ]
      }
    ]
     

Run Your Action in XNAT (Which Performs The Command On Your Image)

  1. Copy the ACE object from the Response Body (do not include the surrounding square brackets  [] which denote a list).
  2. Expand POST /xapi/aces.
  3. Paste the ACE that you just copied into the aceDto field.

    CODE
    {
        "name": "dicom-scan",
        "description": null,
        "inputs": [],
        "action-id": 2,
        "command-id": 3,
        "project": "Day3Data",
        "root-id": "XNAT_E00001:301",
        "resources-staged": [
          {
            "path": "/data/xnat/archive/Day3Data/arc001/5Yp0E/SCANS/301/DICOM",
            "overwrite": false,
            "name": "DICOM",
            "mount": "DICOM"
          }
        ],
        "resources-created": [
          {
            "path": null,
            "overwrite": false,
            "name": "NIFTI",
            "mount": "NIFTI"
          }
        ]
      }
  4. Press the "Try it out!" button.
    Example response:
XML
{
  "name": "dicom-scan",
  "description": null,
  "inputs": [],
  "timestamp": 1465176871666,
  "enabled": true,
  "created": 1465176871434,
  "id": 2,
  "disabled": 0,
  "action-id": 2,
  "project": "Day3Data",
  "root-id": "XNAT_E00001:301",
  "resources-staged": [
    {
      "path": "/data/xnat/archive/Day3Data/arc001/5Yp0E/SCANS/301/DICOM",
      "overwrite": false,
      "name": "DICOM",
      "mount": "DICOM"
    }
  ],
  "resources-created": [
    {
      "path": null,
      "overwrite": false,
      "name": "NIFTI",
      "mount": "NIFTI"
    }
  ],
  "resolved-command": {
    "command-id": 3,
    "run": [
      "python",
      "/scripts/pydicom.py"
    ],
    "docker-image-id": "sha256:041fa8c8bacd2f1106f2b98fb41744c6cb98e303e2f61ce8f1958faed22e22fd",
    "env": {},
    "mounts-in": [
      {
        "name": "DICOM",
        "local-path": "/data/xnat/archive/Day3Data/arc001/5Yp0E/SCANS/301/DICOM",
        "remote-path": "/input",
        "read-only": true
      }
    ],
    "mounts-out": [
      {
        "name": "NIFTI",
        "local-path": "/data/xnat/build/6d18d6f6-3212-4e32-8801-895c952b35f3",
        "remote-path": "/output",
        "read-only": false
      }
    ]
  },
  "container-id": "56e2eba875c28121b8a2181e2897a04300ed5ea0b78b7452aa91c7293e1d1e05"
}

 

Let's inspect this output. You can see in resolved-command.mounts-out.local-path that a random path was created in XNAT's build space for this ACE execution to write its output data. XNAT will (eventually...) be able to upload any files created in that directory back to the root object as a new resource. But that doesn't happen just yet. For now, check that that directory for your newly generated NIfTI file.

 

 

Completed!

While the Action/Context Execution infrastructure is still in early stages of development,  we hope this gives you a flavor of XNAT functionality on the horizon.

Feel free to experiment with other interesting Docker images you've found or created.

Back to: Practical Session 3

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.