Skip to content

Commit

Permalink
add tests to reflect changes of #197. Also add documentation discussi…
Browse files Browse the repository at this point in the history
…ng image types and output calculations.
  • Loading branch information
jrkerns committed Sep 5, 2019
1 parent ab53d44 commit 2ee22d1
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 1 deletion.
45 changes: 45 additions & 0 deletions docs/source/winston_lutz.rst
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,55 @@ The following are invalid:
* mywl-gantry=0-coll=90-couch=315.dcm
* gan45_collimator30-table270.dcm

Using the filenames within the code is done by passing the ``use_filenames=True`` flag to the init method:

.. code-block:: python
my_directory = 'path/to/wl_images'
wl = WinstonLutz(my_directory, use_filenames=True)
.. note:: If using filenames any relevant axes must be defined, otherwise they will default to zero. For example,
if the acquisition was at gantry=45, coll=15, couch=0 then the filename must include both the gantry and collimator
in the name (<...gantry45...coll15....dcm>). For this example, the couch need not be defined since it is 0.

Image types & output definitions
--------------------------------

The following terms are used in pylinac's WL module and are worth defining.

**Image axis definitions/Image types**
Images are classified into 1 of 5 image types, depending on the position of the axes. The image type is then
used for determining whether to use the image for the given calculation. Image types allow the module to isolate the
analysis to a given axis if needed. E.g. for gantry iso size, as opposed to overall iso size, only the gantry should be moving
so that no other variables influence it's calculation.

* **Reference**: This is when all axes are at value 0 (gantry=coll=couch=0).
* **Gantry**: This is when all axes but gantry are at value 0, e.g. gantry=45, coll=0, couch=0.
* **Collimator**: This is when all axes but collimator are at value 0.
* **Couch**: This is when all axes but the couch are at value 0.
* **Combo**: This is when any two or more axes are not at 0.

**Analysis definitions**
Given the above terms, the following calculations are performed.

* **Maximum 2D CAX->BB distance**: Analyzes all images for BB-to-rad field center distances.
* **Median 2D CAX->BB distance**: Analyzes all images for BB-to-rad field center distances.
* **Shift of BB to isocenter**: The instructions of how to move the BB/couch in order to place the BB at the determined isocenter.
This uses **all** image types, however, axes where the image is parallel to the radiation field are not considered. E.g. when
calculating the vertical shift over the images, the image where gantry is 0 is not considered since vertical cannot be accurately determined.
Technically, pylinac will find the 2D shift from BB to rad field, then apply a 3D geometric transformation according to
the gantry angle to get the shift values.
* **Gantry 3D isocenter diameter**: Analyzes only the gantry axis images (see above image types). Applies backprojection of the
CAX in 3D and then minimizes a sphere that touches all the 3D backprojection lines.
* **[Couch, Collimator] 2D isocenter diameter**: Analyzes only the collimator or couch images to determine the planar
circle size of the isocenter according to the axis in question. These are treated separately because the 2D diameter of the
couch is in the plane normal to the vertical axis and the collimator planar isocenter size is normal to the CAX. If no
images are given that rotate about the axis in question (e.g. cardinal gantry angles only) the isocenter size will default to 0.
* **[Maximum, All][Gantry, Collimator, Couch, Combo, EPID] RMS deviation**: Analyzes the images for the axis in question to determine the overall RMS
inclusive of all 3 coordinate axes (vert, long, lat). I.e. this is the overall displacement as a function of the axis in question.
For EPID, the displacement is calculated as the distance from image center to BB for all images with couch=0. If no
images are given that rotate about the axis in question (e.g. cardinal gantry angles only) the isocenter size will default to 0.


Algorithm
---------
Expand Down
8 changes: 7 additions & 1 deletion tests_basic/test_winstonlutz.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import numpy as np

from pylinac import WinstonLutz
from pylinac.winston_lutz import GANTRY, COLLIMATOR, COUCH, REFERENCE, COMBO, ALL
from pylinac.winston_lutz import GANTRY, COLLIMATOR, COUCH, REFERENCE, COMBO, ALL, EPID
from pylinac.core.geometry import Vector, vector_is_close
from tests_basic import TEST_BANK_DIR, TEST_FILES_DIR
from tests_basic.utils import save_file, LoadingTestBase, LocationMixin
Expand Down Expand Up @@ -102,6 +102,7 @@ class WinstonLutzMixin(LocationMixin):
couch_iso_size = 0
cax2bb_max_distance = 0
cax2bb_median_distance = 0
epid_deviation = None
bb_shift_vector = Vector() # vector to place BB at iso
axis_of_rotation = {0: 'Reference'} # fill with as many {image#: known_axis_of_rotation} pairs as desired
print_results = False
Expand Down Expand Up @@ -135,6 +136,10 @@ def test_couch_iso(self):
if self.couch_iso_size is not None:
self.assertAlmostEqual(self.wl.couch_iso_size, self.couch_iso_size, delta=0.2)

def test_epid_deviation(self):
if self.epid_deviation is not None:
self.assertAlmostEqual(max(self.wl.axis_rms_deviation(EPID)), self.epid_deviation, delta=0.2)

def test_bb_max_distance(self):
self.assertAlmostEqual(self.wl.cax2bb_distance(metric='max'), self.cax2bb_max_distance, delta=0.2)

Expand All @@ -156,6 +161,7 @@ class WLDemo(WinstonLutzMixin, TestCase):
couch_iso_size = 1.1
cax2bb_max_distance = 1
cax2bb_median_distance = 0.7
epid_deviation = 1.3
axis_of_rotation = {0: 'Reference'}
bb_shift_vector = Vector(y=-0.1, z=0.3)

Expand Down

0 comments on commit 2ee22d1

Please sign in to comment.