.. _tutorial_pylinac_api:
Image Analysis Using pylinac and the QATrack+ API
=================================================
As of version 0.3.0, QATrack+ includes `pylinac
`__ which for image and log file
analysis. This tutorial will cover setting up a **Picket Fence** imaging test
and then performing the test both via the web interface and the QATrack+ API.
Setting up the Test List
------------------------
Log into QATrack+ and :ref:`navigate to the admin section `.
Create the following tests (if you haven't created a Test List before, go
through the :ref:`step-by-step test list tutorial `
before attempting this tutorial):
#. Name:
Picket Fence upload & analysis
Macro name:
pf_upload_analysis
Category:
Choose existing Category or :ref:`create an Image Analysis category `.
Type:
File Upload
Display image:
Ensure this field is checked off
Calculation procedure:
.. code-block:: python
import io
import pylinac
# run the picket fence analysis using pylinac
# note the use of `BIN_FILE` rather than `FILE` since we are dealing with an image
pf = pylinac.PicketFence(BIN_FILE.path)
pf.analyze()
# our dictionary of results to return
pf_upload_analysis = {
'percent passing': pf.percent_passing,
'max error': pf.max_error,
'number of pickets': pf.num_pickets,
'orientation': pf.orientation,
}
# create a pylinac PDF and create an attachment with it
data = io.BytesIO()
pf.publish_pdf(data)
UTILS.write_file('testingpfpdf.pdf', data)
# convert the image to a png file so it can be displayed when performing the test list
UTILS.write_file('pf-image.png', pf.image)
#. Name:
PF orientation (Left-Right, Up-down)
Macro name:
pf_orientation
Category:
Choose existing Category
Type:
String Composite
Calculation procedure:
.. code-block:: python
pf_orientation = pf_upload_analysis['orientation']
#. Name:
PF pickets found (#)
Macro name:
pf_num_pickets
Category:
Choose existing Category
Type:
Composite
Calculation procedure:
.. code-block:: python
pf_num_pickets = pf_upload_analysis['number of pickets']
#. Name:
PF maximum leaf error (mm)
Macro name:
pf_maximum_error
Category:
Choose existing Category
Type:
Composite
Calculation procedure:
.. code-block:: python
pf_maximum_error = pf_upload_analysis['max error']
#. Name:
PF leaves % passing
Macro name:
pf_leaves_pct_passing
Category:
Choose existing Category
Type:
Composite
Calculation procedure:
.. code-block:: python
pf_leaves_pct_passing = pf_upload_analysis['percent passing']
After you have created the Tests, create a Test List called `Picket Fence` that
consists of the 5 Tests we just created:
.. figure:: images/test_list_def.png
:alt: The Picket Fence Test List Definition
The Picket Fence Test List Definition
Next :ref:`assign this test list to one or more Units `:
.. figure:: images/assign_to_unit.png
:alt: Assigning Picket Fence Test List to Unit
Assigning Picket Fence Test List to Unit
and :ref:`set References and Tolerances ` on the `Maximum Leaf
Error (mm)` and `PF leaves % passing` as shown below:
.. figure:: images/ref_tols.png
:alt: References and Tolerances for Picket Fence test
References and Tolerances for Picket Fence test
The Test List is now ready to perform!
Performing the Test List via the web UI
---------------------------------------
Navigate to the Test List selection for this Unit and click `Perform` next to
the `Picket Fence` Test List:
.. figure:: images/perform_list.png
:alt: Selecting the Picket Fence Test List
Selecting the Picket Fence Test List
on the Test List page, click the Upload button and select your picket fence
dicom (or other image format file). After the file is uploaded you will see
your other test values automatically populated as well as the image shown:
.. figure:: images/uploaded.png
:alt: Test list values after file upload
Test list values after file upload
Click *Submit QC Results* and you are done!
Performing the Test List via the API
------------------------------------
As of version 0.3.0, :ref:`QATrack+ includes an API ` which
can be used for automating the entry of Test List data. An example of
using the API via a Python script is shown here, although the process should
be similar in most other programming languages!
Obtain an API token
~~~~~~~~~~~~~~~~~~~
Before you can access the API, you need to have an API token which can either be
created through the Admin section or retrieved programmaticaly:
.. code-block:: python
import requests
root = "http://yourservernamehere/api"
token_url = root + "/get-token/"
resp = requests.post(token_url, {'username': 'user', 'password': 'password'})
token = resp.json()['token']
This token must be included with every request to the API.
Find the Unit Test Collection we want to perform
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
First we will use the API to retrieve the URL of the :term:`Unit Test Collection`
we want to perform:
.. code-block:: python
import base64
import requests
# the request headers must include the API token
api_token = "YOUR API TOKEN HERE"
headers = {"Authorization": "Token %s" % api_token}
root = "http://yourservernamehere/api"
unit_name = "TB1"
test_list_name = "Picket Fence"
url = root + '/qa/unittestcollections/?unit__name__icontains=%s&test_list__name__icontains=%s' % (unit_name, test_list_name)
# find the UnitTestCollection we want to perform
resp = requests.get(url, headers=headers)
utc_url = resp.json()['results'][0]['url']
# prepare the data to submit to the API. Binary files need to be base64 encoded before posting!
data = {
'unit_test_collection': utc_url,
'work_started': "2018-09-19 10:00",
'work_completed': "2018-09-19 10:30",
'comment': "Performed via the API!", # optional
'tests': {
'pf_upload_analysis': { # pf_upload_analysis is the name of our upload test
'filename': 'picket.dcm', # path to file
'value': base64.b64encode(open("/home/randlet/Downloads/picket.dcm", 'rb').read()).decode(),
'encoding': 'base64'
},
},
'attachments': [] # optional
}
# send our data to the server
resp = requests.post(root + "/qa/testlistinstances/", json=data, headers=headers)
if resp.status_code == requests.codes.CREATED: # http code 201
completed_url = resp.json()['site_url']
print("Test List performed successfully! View your Test List Instance at %s" % completed_url)
else:
print("Your request failed with error %s (%s)" (resp.status_code, resp.reason))
Running the script should show:
.. code-block:: shell
Test List performed successfully! View your Test List Instance at http://yourservername/qa/session/details/60/
and then viewing that link your browser:
.. figure:: images/after_api_post.png
:alt: Viewing Test List Details after posting image via API
Viewing Test List Details after posting image via API
Acknowledgements
----------------
This Test List was originally created with assistance from James Kerns, author
of pylinac.