Core Modules

The following is the API documentation for the core modules of pylinac. These can be used directly, or as the base for mixin classes or methods.

Image Module

This module holds classes for image loading and manipulation.

pylinac.core.image.equate_images(image1: Union[DicomImage, ArrayImage, FileImage, LinacDicomImage], image2: Union[DicomImage, ArrayImage, FileImage, LinacDicomImage]) → Tuple[Union[pylinac.core.image.DicomImage, pylinac.core.image.ArrayImage, pylinac.core.image.FileImage, pylinac.core.image.LinacDicomImage], Union[pylinac.core.image.DicomImage, pylinac.core.image.ArrayImage, pylinac.core.image.FileImage, pylinac.core.image.LinacDicomImage]][source]
Crop and resize two images to make them:
  • The same pixel dimensions
  • The same DPI

The usefulness of the function comes when trying to compare images from different sources. The best example is calculating gamma on a machine log fluence and EPID image. The physical and pixel dimensions must be normalized, the SID normalized

Parameters:
Returns:

pylinac.core.image.is_image(path: Union[str, _io.BytesIO, DicomImage, ArrayImage, FileImage, LinacDicomImage, numpy.ndarray]) → bool[source]

Determine whether the path is a valid image file.

Returns:
Return type:bool
pylinac.core.image.retrieve_image_files(path: str) → List[str][source]

Retrieve the file names of all the valid image files in the path.

Returns:Contains strings pointing to valid image paths.
Return type:list
pylinac.core.image.load(path: Union[str, DicomImage, ArrayImage, FileImage, LinacDicomImage, numpy.ndarray, BinaryIO], **kwargs) → Union[pylinac.core.image.DicomImage, pylinac.core.image.ArrayImage, pylinac.core.image.FileImage, pylinac.core.image.LinacDicomImage][source]

Load a DICOM image, JPG/TIF/BMP image, or numpy 2D array.

Parameters:
  • path (str, file-object) – The path to the image file or data stream or array.
  • kwargs – See FileImage, DicomImage, or ArrayImage for keyword arguments.
Returns:

Return type depends on input image.

Return type:

FileImage, ArrayImage, or DicomImage

Examples

Load an image from a file and then apply a filter:

>>> from pylinac.core.image import load
>>> my_image = r"C:\QA\image.tif"
>>> img = load(my_image)  # returns a FileImage
>>> img.filter(5)

Loading from an array is just like loading from a file:

>>> arr = np.arange(36).reshape(6, 6)
>>> img = load(arr)  # returns an ArrayImage
pylinac.core.image.load_url(url: str, progress_bar: bool = True, **kwargs) → Union[pylinac.core.image.DicomImage, pylinac.core.image.ArrayImage, pylinac.core.image.FileImage, pylinac.core.image.LinacDicomImage][source]

Load an image from a URL.

Parameters:
  • url (str) –

    A string pointing to a valid URL that points to a file.

    Note

    For some images (e.g. Github), the raw binary URL must be used, not simply the basic link.

  • progress_bar (bool) – Whether to display a progress bar of download status.
pylinac.core.image.load_multiples(image_file_list: Sequence[T_co], method: str = 'mean', stretch_each: bool = True, **kwargs) → Union[pylinac.core.image.DicomImage, pylinac.core.image.ArrayImage, pylinac.core.image.FileImage, pylinac.core.image.LinacDicomImage][source]

Combine multiple image files into one superimposed image.

Parameters:
  • image_file_list (list) – A list of the files to be superimposed.
  • method ({'mean', 'max', 'sum'}) – A string specifying how the image values should be combined.
  • stretch_each (bool) – Whether to normalize the images being combined by stretching their high/low values to the same values across images.
  • kwargs – Further keyword arguments are passed to the load function and stretch function.

Examples

Load multiple images:

>>> from pylinac.core.image import load_multiples
>>> paths = ['starshot1.tif', 'starshot2.tif']
>>> superimposed_img = load_multiples(paths)
class pylinac.core.image.BaseImage(path: Union[str, _io.BytesIO, DicomImage, ArrayImage, FileImage, LinacDicomImage, numpy.ndarray, _io.BufferedReader])[source]

Bases: object

Base class for the Image classes.

path

The path to the image file.

Type:str
array

The actual image pixel array.

Type:numpy.ndarray
Parameters:path (str) – The path to the image.
classmethod from_multiples(filelist: List[str], method: str = 'mean', stretch: bool = True, **kwargs) → Union[pylinac.core.image.DicomImage, pylinac.core.image.ArrayImage, pylinac.core.image.FileImage, pylinac.core.image.LinacDicomImage][source]

Load an instance from multiple image items. See load_multiples().

center

Return the center position of the image array as a Point.

physical_shape

The physical size of the image in mm.

plot(ax: matplotlib.axes._axes.Axes = None, show: bool = True, clear_fig: bool = False, **kwargs) → matplotlib.axes._axes.Axes[source]

Plot the image.

Parameters:
  • ax (matplotlib.Axes instance) – The axis to plot the image to. If None, creates a new figure.
  • show (bool) – Whether to actually show the image. Set to false when plotting multiple items.
  • clear_fig (bool) – Whether to clear the prior items on the figure before plotting.
filter(size: Union[float, int] = 0.05, kind: str = 'median') → None[source]

Filter the profile.

Parameters:
  • size (int, float) – Size of the median filter to apply. If a float, the size is the ratio of the length. Must be in the range 0-1. E.g. if size=0.1 for a 1000-element array, the filter will be 100 elements. If an int, the filter is the size passed.
  • kind ({'median', 'gaussian'}) – The kind of filter to apply. If gaussian, size is the sigma value.
crop(pixels: int = 15, edges: Tuple[str, ...] = ('top', 'bottom', 'left', 'right')) → None[source]

Removes pixels on all edges of the image in-place.

Parameters:
  • pixels (int) – Number of pixels to cut off all sides of the image.
  • edges (tuple) – Which edges to remove from. Can be any combination of the four edges.
remove_edges(pixels: int = 15, edges: Tuple[str, ...] = ('top', 'bottom', 'left', 'right')) → None[source]

Removes pixels on all edges of the image in-place.

Parameters:
  • pixels (int) – Number of pixels to cut off all sides of the image.
  • edges (tuple) – Which edges to remove from. Can be any combination of the four edges.
flipud() → None[source]

Flip the image array upside down in-place. Wrapper for np.flipud()

fliplr() → None[source]

Flip the image array upside down in-place. Wrapper for np.fliplr()

invert() → None[source]

Invert (imcomplement) the image.

roll(direction: str = 'x', amount: int = 1) → None[source]

Roll the image array around in-place. Wrapper for np.roll().

Parameters:
  • direction ({'x', 'y'}) – The axis to roll over.
  • amount (int) – The amount of elements to roll over.
rot90(n: int = 1) → None[source]

Wrapper for numpy.rot90; rotate the array by 90 degrees CCW.

threshold(threshold: int, kind: str = 'high') → None[source]

Apply a high- or low-pass threshold filter.

Parameters:
  • threshold (int) – The cutoff value.
  • kind (str) – If high (default), will apply a high-pass threshold. All values above the cutoff are left as-is. Remaining points are set to 0. If low, will apply a low-pass threshold.
as_binary(threshold: int) → Union[pylinac.core.image.DicomImage, pylinac.core.image.ArrayImage, pylinac.core.image.FileImage, pylinac.core.image.LinacDicomImage][source]

Return a binary (black & white) image based on the given threshold.

Parameters:threshold (int, float) – The threshold value. If the value is above or equal to the threshold it is set to 1, otherwise to 0.
Returns:
Return type:ArrayImage
dist2edge_min(point: Union[pylinac.core.geometry.Point, Tuple]) → float[source]

Calculates minimum distance from given point to image edges.

Parameters:point (geometry.Point, tuple) –
Returns:
Return type:float
ground() → float[source]

Ground the profile such that the lowest value is 0.

Note

This will also “ground” profiles that are negative or partially-negative. For such profiles, be careful that this is the behavior you desire.

Returns:The amount subtracted from the image.
Return type:float
normalize(norm_val: Union[str, int, float] = 'max') → None[source]

Normalize the image values to the given value.

Parameters:norm_val (str, number) – If a string, must be ‘max’, which normalizes the values to the maximum value. If a number, normalizes all values to that number.
check_inversion(box_size: int = 20, position: Sequence[T_co] = (0.0, 0.0)) → None[source]

Check the image for inversion by sampling the 4 image corners. If the average value of the four corners is above the average pixel value, then it is very likely inverted.

Parameters:
  • box_size (int) – The size in pixels of the corner box to detect inversion.
  • position (2-element sequence) – The location of the sampling boxes.
check_inversion_by_histogram(percentiles=(5, 50, 95)) → bool[source]

Check the inversion of the image using histogram analysis. The assumption is that the image is mostly background-like values and that there is a relatively small amount of dose getting to the image (e.g. a picket fence image). This function looks at the distance from one percentile to another to determine if the image should be inverted.

Parameters:percentiles (3-element tuple) – The 3 percentiles to compare. Default is (5, 50, 95). Recommend using (x, 50, y). To invert the other way (where pixel value is decreasing with dose, reverse the percentiles, e.g. (95, 50, 5).
gamma(comparison_image: Union[DicomImage, ArrayImage, FileImage, LinacDicomImage], doseTA: Union[int, float] = 1, distTA: Union[int, float] = 1, threshold: Union[int, float] = 0.1, ground: bool = True, normalize: bool = True) → numpy.ndarray[source]

Calculate the gamma between the current image (reference) and a comparison image.

New in version 1.2.

The gamma calculation is based on Bakai et al eq.6, which is a quicker alternative to the standard Low gamma equation.

Parameters:
  • comparison_image ({ArrayImage, DicomImage, or FileImage}) – The comparison image. The image must have the same DPI/DPMM to be comparable. The size of the images must also be the same.
  • doseTA (int, float) – Dose-to-agreement in percent; e.g. 2 is 2%.
  • distTA (int, float) – Distance-to-agreement in mm.
  • threshold (float) – The dose threshold percentage of the maximum dose, below which is not analyzed. Must be between 0 and 1.
  • ground (bool) – Whether to “ground” the image values. If true, this sets both datasets to have the minimum value at 0. This can fix offset errors in the data.
  • normalize (bool) – Whether to normalize the images. This sets the max value of each image to the same value.
Returns:

gamma_map – The calculated gamma map.

Return type:

numpy.ndarray

See also

equate_images()

class pylinac.core.image.DicomImage(path: Union[str, _io.BytesIO, _io.BufferedReader], *, dtype=None, dpi: Union[int, float] = None, sid: Union[int, float] = None)[source]

Bases: pylinac.core.image.BaseImage

An image from a DICOM RTImage file.

metadata

The dataset of the file as returned by pydicom without pixel data.

Type:pydicom Dataset
Parameters:
  • path (str, file-object) – The path to the file or the data stream.
  • dtype (dtype, None, optional) – The data type to cast the image data as. If None, will use whatever raw image format is.
  • dpi (int, float) –

    The dots-per-inch of the image, defined at isocenter.

    Note

    If a DPI tag is found in the image, that value will override the parameter, otherwise this one will be used.

  • sid (int, float) – The Source-to-Image distance in mm.
save(filename: str) → str[source]

Save the image instance back out to a .dcm file.

Returns:
Return type:A string pointing to the new filename.
sid

The Source-to-Image in mm.

dpi

The dots-per-inch of the image, defined at isocenter.

dpmm

The Dots-per-mm of the image, defined at isocenter. E.g. if an EPID image is taken at 150cm SID, the dpmm will scale back to 100cm.

cax

The position of the beam central axis. If no DICOM translation tags are found then the center is returned.

class pylinac.core.image.LinacDicomImage(path: str, use_filenames: bool = False)[source]

Bases: pylinac.core.image.DicomImage

DICOM image taken on a linac. Also allows passing of gantry/coll/couch values via the filename.

gantry_angle

Gantry angle of the irradiation.

collimator_angle

Collimator angle of the irradiation.

couch_angle

Couch angle of the irradiation.

class pylinac.core.image.FileImage(path: str, *, dpi: Union[int, float] = None, sid: Union[int, float] = None, dtype=None)[source]

Bases: pylinac.core.image.BaseImage

An image from a “regular” file (.tif, .jpg, .bmp).

info

The info dictionary as generated by Pillow.

Type:dict
sid

The SID value as passed in upon construction.

Type:float
Parameters:
  • path (str, file-object) – The path to the file or a data stream.
  • dpi (int, float) –

    The dots-per-inch of the image, defined at isocenter.

    Note

    If a DPI tag is found in the image, that value will override the parameter, otherwise this one will be used.

  • sid (int, float) – The Source-to-Image distance in mm.
  • dtype (numpy.dtype) – The data type to cast the array as.
dpi

The dots-per-inch of the image, defined at isocenter.

dpmm

The Dots-per-mm of the image, defined at isocenter. E.g. if an EPID image is taken at 150cm SID, the dpmm will scale back to 100cm.

class pylinac.core.image.ArrayImage(array: numpy.array, *, dpi: Union[int, float] = None, sid: Union[int, float] = None, dtype=None)[source]

Bases: pylinac.core.image.BaseImage

An image constructed solely from a numpy array.

Parameters:
  • array (numpy.ndarray) – The image array.
  • dpi (int, float) –

    The dots-per-inch of the image, defined at isocenter.

    Note

    If a DPI tag is found in the image, that value will override the parameter, otherwise this one will be used.

  • sid (int, float) – The Source-to-Image distance in mm.
  • dtype (dtype, None, optional) – The data type to cast the image data as. If None, will use whatever raw image format is.
dpmm

The Dots-per-mm of the image, defined at isocenter. E.g. if an EPID image is taken at 150cm SID, the dpmm will scale back to 100cm.

dpi

The dots-per-inch of the image, defined at isocenter.

class pylinac.core.image.DicomImageStack(folder: str, dtype=None, min_number: int = 39, check_uid: bool = True)[source]

Bases: object

A class that loads and holds a stack of DICOM images (e.g. a CT dataset). The class can take a folder or zip file and will read CT images. The images must all be the same size. Supports indexing to individual images.

images

Holds instances of DicomImage. Can be accessed via index; i.e. self[0] == self.images[0].

Type:list

Examples

Load a folder of Dicom images >>> from pylinac import image >>> img_folder = r”folder/qa/cbct/june” >>> dcm_stack = image.DicomImageStack(img_folder) # loads and sorts the images >>> dcm_stack.plot(3) # plot the 3rd image

Load a zip archive >>> img_folder_zip = r”archive/qa/cbct/june.zip” # save space and zip your CBCTs >>> dcm_stack = image.DicomImageStack.from_zip(img_folder_zip)

Load as a certain data type >>> dcm_stack_uint32 = image.DicomImageStack(img_folder, dtype=np.uint32)

Load a folder with DICOM CT images.

Parameters:
  • folder (str) – Path to the folder.
  • dtype (dtype, None, optional) – The data type to cast the image data as. If None, will use whatever raw image format is.
classmethod from_zip(zip_path: str, dtype=None)[source]

Load a DICOM ZIP archive.

Parameters:
  • zip_path (str) – Path to the ZIP archive.
  • dtype (dtype, None, optional) – The data type to cast the image data as. If None, will use whatever raw image format is.
static is_CT_slice(file: str) → bool[source]

Test if the file is a CT Image storage DICOM file.

plot(slice: int = 0) → None[source]

Plot a slice of the DICOM dataset.

Parameters:slice (int) – The slice to plot.
metadata

The metadata of the first image; shortcut attribute. Only attributes that are common throughout the stack should be used, otherwise the individual image metadata should be used.

Geometry Module

Module for classes that represent common geometric objects or patterns.

pylinac.core.geometry.tan(degrees: Union[int, float]) → float[source]

Calculate the tangent of the given degrees.

pylinac.core.geometry.cos(degrees: Union[int, float]) → float[source]

Calculate the cosine of the given degrees.

pylinac.core.geometry.sin(degrees: Union[int, float]) → float[source]

Calculate the sine of the given degrees.

class pylinac.core.geometry.Point(x: Union[int, float, tuple, Point] = 0, y: Union[int, float] = 0, z: Union[int, float] = 0, idx: Optional[int] = None, value: Union[int, float, None] = None, as_int: bool = False)[source]

Bases: object

A geometric point with x, y, and z coordinates/attributes.

Parameters:
  • x (number-like, Point, iterable) – x-coordinate or iterable type containing all coordinates. If iterable, values are assumed to be in order: (x,y,z).
  • y (number-like, optional) – y-coordinate
  • idx (int, optional) – Index of point. Useful for sequential coordinates; e.g. a point on a circle profile is sometimes easier to describe in terms of its index rather than x,y coords.
  • value (number-like, optional) – value at point location (e.g. pixel value of an image)
  • as_int (boolean) – If True, coordinates are converted to integers.
distance_to(thing: Union[Point, Circle]) → float[source]

Calculate the distance to the given point.

Parameters:thing (Circle, Point, 2 element iterable) – The other thing to calculate distance to.
as_array(only_coords: bool = True) → numpy.array[source]

Return the point as a numpy array.

class pylinac.core.geometry.Circle(center_point: Union[pylinac.core.geometry.Point, Iterable[T_co]] = (0, 0), radius: float = 0)[source]

Bases: object

A geometric circle with center Point, radius, and diameter.

Parameters:
  • center_point (Point, optional) – Center point of the wobble circle.
  • radius (float, optional) – Radius of the wobble circle.
diameter

Get the diameter of the circle.

plot2axes(axes, edgecolor: str = 'black', fill: bool = False) → None[source]

Plot the Circle on the axes.

Parameters:
  • axes (matplotlib.axes.Axes) – An MPL axes to plot to.
  • edgecolor (str) – The color of the circle.
  • fill (bool) – Whether to fill the circle with color or leave hollow.
class pylinac.core.geometry.Vector(x: Union[int, float] = 0, y: Union[int, float] = 0, z: Union[int, float] = 0)[source]

Bases: object

A vector with x, y, and z coordinates.

as_scalar() → float[source]

Return the scalar equivalent of the vector.

distance_to(thing: Union[pylinac.core.geometry.Circle, pylinac.core.geometry.Point]) → float[source]

Calculate the distance to the given point.

Parameters:thing (Circle, Point, 2 element iterable) – The other point to calculate distance to.
pylinac.core.geometry.vector_is_close(vector1: pylinac.core.geometry.Vector, vector2: pylinac.core.geometry.Vector, delta: float = 0.1) → bool[source]

Determine if two vectors are with delta of each other; this is a simple coordinate comparison check.

class pylinac.core.geometry.Line(point1: Union[pylinac.core.geometry.Point, Tuple[float, float]], point2: Union[pylinac.core.geometry.Point, Tuple[float, float]])[source]

Bases: object

A line that is represented by two points or by m*x+b.

Notes

Calculations of slope, etc are from here: http://en.wikipedia.org/wiki/Linear_equation and here: http://www.mathsisfun.com/algebra/line-equation-2points.html

Parameters:
  • point1 (Point) – One point of the line
  • point2 (Point) – Second point along the line.
m

Return the slope of the line.

m = (y1 - y2)/(x1 - x2)

From: http://www.purplemath.com/modules/slope.htm

b

Return the y-intercept of the line.

b = y - m*x

y(x) → float[source]

Return y-value along line at position x.

x(y) → float[source]

Return x-value along line at position y.

center

Return the center of the line as a Point.

length

Return length of the line, if finite.

distance_to(point) → float[source]

Calculate the minimum distance from the line to a point.

Equations are from here: http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html #14

Parameters:point (Point, iterable) – The point to calculate distance to.
plot2axes(axes: matplotlib.axes._axes.Axes, width: Union[int, float] = 1, color: str = 'w') → None[source]

Plot the line to an axes.

Parameters:
  • axes (matplotlib.axes.Axes) – An MPL axes to plot to.
  • color (str) – The color of the line.
class pylinac.core.geometry.Rectangle(width: float, height: float, center: Union[pylinac.core.geometry.Point, Tuple], as_int: bool = False)[source]

Bases: object

A rectangle with width, height, center Point, top-left corner Point, and bottom-left corner Point.

Parameters:
  • width (number) – Width of the rectangle.
  • height (number) – Height of the rectangle.
  • center (Point, iterable, optional) – Center point of rectangle.
  • as_int (bool) – If False (default), inputs are left as-is. If True, all inputs are converted to integers.
br_corner

The location of the bottom right corner.

bl_corner

The location of the bottom left corner.

tl_corner

The location of the top left corner.

tr_corner

The location of the top right corner.

plot2axes(axes: matplotlib.axes._axes.Axes, edgecolor: str = 'black', angle: float = 0.0, fill: bool = False, alpha: float = 1, facecolor: str = 'g', label=None)[source]

Plot the Rectangle to the axes.

Parameters:
  • axes (matplotlib.axes.Axes) – An MPL axes to plot to.
  • edgecolor (str) – The color of the circle.
  • angle (float) – Angle of the rectangle.
  • fill (bool) – Whether to fill the rectangle with color or leave hollow.

Profile Module

Module of objects that resemble or contain a profile, i.e. a 1 or 2-D f(x) representation.

pylinac.core.profile.stretch(array: numpy.ndarray, min: int = 0, max: int = 1, fill_dtype: Optional[numpy.dtype] = None) → numpy.ndarray[source]

‘Stretch’ the profile to the fit a new min and max value and interpolate in between. From: http://www.labri.fr/perso/nrougier/teaching/numpy.100/ exercise #17

Parameters:
  • array (numpy.ndarray) – The numpy array to stretch.
  • min (number) – The new minimum of the values.
  • max (number) – The new maximum value.
  • fill_dtype (numpy data type) – If None (default), the array will be stretched to the passed min and max. If a numpy data type (e.g. np.int16), the array will be stretched to fit the full range of values of that data type. If a value is given for this parameter, it overrides min and max.
class pylinac.core.profile.ProfileMixin[source]

Bases: object

A mixin to provide various manipulations of 1D profile data.

invert() → None[source]

Invert (imcomplement) the profile.

normalize(norm_val: Union[str, int, float] = 'max') → None[source]

Normalize the profile to the given value.

Parameters:norm_val (str, number) – If a string, must be ‘max’, which normalizes the values to the maximum value. If a number, normalizes all values to that number.
stretch(min: Union[int, float] = 0, max: Union[int, float] = 1) → None[source]

‘Stretch’ the profile to the min and max parameter values.

Parameters:
  • min (number) – The new minimum of the values
  • max (number) – The new maximum value.
ground() → float[source]

Ground the profile such that the lowest value is 0.

Returns:The minimum value that was used as the grounding value.
Return type:float
filter(size: Union[int, float] = 0.05, kind: str = 'median') → None[source]

Filter the profile.

Parameters:
  • size (float, int) – Size of the median filter to apply. If a float, the size is the ratio of the length. Must be in the range 0-1. E.g. if size=0.1 for a 1000-element array, the filter will be 100 elements. If an int, the filter is the size passed.
  • kind ({'median', 'gaussian'}) – The kind of filter to apply. If gaussian, size is the sigma value.
class pylinac.core.profile.Interpolation[source]

Bases: enum.Enum

Interpolation Enum

NONE = None
LINEAR = 'Linear'
SPLINE = 'Spline'
class pylinac.core.profile.Normalization[source]

Bases: enum.Enum

Normalization method Enum

NONE = None
GEOMETRIC_CENTER = 'Geometric center'
BEAM_CENTER = 'Beam center'
MAX = 'Max'
class pylinac.core.profile.Edge[source]

Bases: enum.Enum

Edge detection Enum

FWHM = 'FWHM'
INFLECTION_DERIVATIVE = 'Inflection Derivative'
INFLECTION_HILL = 'Inflection Hill'
class pylinac.core.profile.SingleProfile(values: numpy.ndarray, dpmm: float = None, interpolation: Union[pylinac.core.profile.Interpolation, str, None] = <Interpolation.LINEAR: 'Linear'>, ground: bool = True, interpolation_resolution_mm: float = 0.1, interpolation_factor: float = 10, normalization_method: Union[pylinac.core.profile.Normalization, str] = <Normalization.BEAM_CENTER: 'Beam center'>, edge_detection_method: Union[pylinac.core.profile.Edge, str] = <Edge.FWHM: 'FWHM'>, edge_smoothing_ratio: float = 0.003, hill_window_ratio: float = 0.1)[source]

Bases: pylinac.core.profile.ProfileMixin

A profile that has one large signal, e.g. a radiation beam profile. Signal analysis methods are given, mostly based on FWXM and on Hill function calculations. Profiles with multiple peaks are better suited by the MultiProfile class.

Parameters:
  • values – The profile numpy array. Must be 1D.
  • dpmm – The dots (pixels) per mm. Pass to get info like beam width in distance units in addition to pixels
  • interpolation – Interpolation technique.
  • ground – Whether to ground the profile (set min value to 0). Helpful most of the time.
  • interpolation_resolution_mm – The resolution that the interpolation will scale to. Only used if dpmm is passed and interpolation is set. E.g. if the dpmm is 0.5 and the resolution is set to 0.1mm the data will be interpolated to have a new dpmm of 10 (1/0.1).
  • interpolation_factor – The factor to multiply the data by. Only used if interpolation is used and dpmm is NOT passed. E.g. 10 will perfectly decimate the existing data according to the interpolation method passed.
  • normalization_method – How to pick the point to normalize the data to.
  • edge_detection_method – The method by which to detect the field edge. FWHM is reasonable most of the time except for FFF beams. Inflection-derivative will use the max gradient to determine the field edge. Note that this may not be the 50% height. In fact, for FFF beams it shouldn’t be. Inflection methods are better for FFF and other unusual beam shapes.
  • edge_smoothing_ratio

    Only applies to INFLECTION_DERIVATIVE and INFLECTION_HILL.

    The ratio of the length of the values to use as the sigma for a Gaussian filter applied before searching for the inflection. E.g. 0.005 with a profile of 1000 points will result in a sigma of 5. This helps make the inflection point detection more robust to noise. Increase for noisy data.

  • hill_window_ratio – The ratio of the field size to use as the window to fit the Hill function. E.g. 0.2 will using a window centered about each edge with a width of 20% the size of the field width. Only applies when the edge detection is INFLECTION_HILL.
geometric_center() → dict[source]

The geometric center (i.e. the device center)

beam_center() → dict[source]

The center of the detected beam. This can account for asymmetries in the beam position (e.g. offset jaws)

fwxm_data(x: int = 50) → dict[source]

Return the width at X-Max, where X is the percentage height.

Parameters:x – The percent height of the profile. E.g. x = 50 is 50% height, i.e. FWHM.
field_data(in_field_ratio: float = 0.8, slope_exclusion_ratio=0.2) → dict[source]

Return the width at X-Max, where X is the percentage height.

Parameters:
  • in_field_ratio – In Field Ratio: 1.0 is the entire detected field; 0.8 would be the central 80%, etc.
  • slope_exclusion_ratio

    Ratio of the field width to use as the cutoff between “top” calculation and “slope” calculation. Useful for FFF beams. This area is centrally located in the field. E.g. 0.2 will use the central 20% of the field to calculate the “top” value. To calculate the slope of each side, the field width between the edges of the in_field_ratio and the slope exclusion region are used.

    Warning

    The “top” value is always calculated. For FFF beams this should be reasonable, but for flat beams this value may end up being non-sensible.

inflection_data() → dict[source]

Calculate the profile inflection values using either the 2nd derivative or a fitted Hill function.

Note

This only applies if the edge detection method is INFLECTION_….

penumbra(lower: int = 20, upper: int = 80)[source]

Calculate the penumbra of the field. Dependent on the edge detection method.

Parameters:
  • lower – The lower % of the beam to use. If the edge method is FWHM, this is the typical % penumbra you’re thinking. If the inflection method is used it will be the value/50 of the inflection point value. E.g. if the inflection point is perfectly at 50% with a lower of 20, then the penumbra value here will be 20% of the maximum. If the inflection point is at 30% of the max value (say for a FFF beam) then the lower penumbra will be lower/50 of the inflection point or 0.3*lower/50.
  • upper – Upper % of the beam to use. See lower for details.
field_calculation(in_field_ratio: float = 0.8, calculation: str = 'mean') → Union[float, Tuple[float, float]][source]

Perform an operation on the field values of the profile. This function is useful for determining field symmetry and flatness.

Parameters:
  • in_field_ratio – Ratio of the field width to use in the calculation.
  • calculation ({'mean', 'median', 'max', 'min', 'area'}) – Calculation to perform on the field values.
plot() → None[source]

Plot the profile.

class pylinac.core.profile.MultiProfile(values: Union[numpy.ndarray, Sequence[T_co]])[source]

Bases: pylinac.core.profile.ProfileMixin

A class for analyzing 1-D profiles that contain multiple signals. Methods are mostly for finding & filtering the signals, peaks, valleys, etc. Profiles with a single peak (e.g. radiation beam profiles) are better suited by the SingleProfile class.

values

The array of values passed in on instantiation.

Type:ndarray
peaks

List of Points, containing value and index information.

Type:list
valleys

Same as peaks, but for valleys.

Type:list
Parameters:values (iterable) – Array of profile values.
plot(ax: Optional[matplotlib.axes._axes.Axes] = None) → None[source]

Plot the profile.

Parameters:ax (plt.Axes) – An axis to plot onto. Optional.
find_peaks(threshold: Union[float, int] = 0.3, min_distance: Union[float, int] = 0.05, max_number: int = None, search_region: Tuple = (0.0, 1.0), peak_sort='prominences') → Tuple[numpy.ndarray, numpy.ndarray][source]

Find the peaks of the profile using a simple maximum value search. This also sets the peaks attribute.

Parameters:
  • threshold (int, float) – The value the peak must be above to be considered a peak. This removes “peaks” that are in a low-value region. If passed an int, the actual value is the threshold. E.g. when passed 15, any peak less with a value <15 is removed. If passed a float, it will threshold as a percent. Must be between 0 and 1. E.g. when passed 0.4, any peak <40% of the maximum value will be removed.
  • min_distance (int, float) – If passed an int, parameter is the number of elements apart a peak must be from neighboring peaks. If passed a float, must be between 0 and 1 and represents the ratio of the profile to exclude. E.g. if passed 0.05 with a 1000-element profile, the minimum peak width will be 0.05*1000 = 50 elements.
  • max_number (int, None) – Specify up to how many peaks will be returned. E.g. if 3 is passed in and 5 peaks are found, only the 3 largest peaks will be returned. If None, no limit will be applied.
  • search_region (tuple of ints, floats, or both) – The region within the profile to search. The tuple specifies the (left, right) edges to search. This allows exclusion of edges from the search. If a value is an int, it is taken as is. If a float, must be between 0 and 1 and is the ratio of the profile length. The left value must be less than the right.
Returns:

indices – The indices and values of the peaks.

Return type:

ndarray, values, ndarray

find_valleys(threshold: Union[float, int] = 0.3, min_distance: Union[float, int] = 0.05, max_number: int = None, search_region: Tuple = (0.0, 1.0)) → Tuple[numpy.ndarray, numpy.ndarray][source]

Find the valleys (minimums) of the profile using a simple minimum value search.

Returns:indices – The indices and values of the valleys.
Return type:ndarray, values, ndarray

See also

find_peaks() : Further parameter info.

find_fwxm_peaks(threshold: Union[float, int] = 0.3, min_distance: Union[float, int] = 0.05, max_number: int = None, search_region: Tuple = (0.0, 1.0), peak_sort: str = 'prominences', required_prominence=None) → Tuple[numpy.ndarray, numpy.ndarray][source]

Find peaks using the center of the FWXM (rather than by max value).

Parameters:x (int, float) – The Full-Width-X-Maximum desired. E.g. 0.7 will return the FW70%M. Values must be between 0 and 100.

See also

find_peaks()
Further parameter info
class pylinac.core.profile.CircleProfile(center: pylinac.core.geometry.Point, radius: Union[int, float], image_array: numpy.ndarray, start_angle: Union[float, int] = 0, ccw: bool = True, sampling_ratio: float = 1.0)[source]

Bases: pylinac.core.profile.MultiProfile, pylinac.core.geometry.Circle

A profile in the shape of a circle.

image_array

The 2D image array.

Type:ndarray
start_angle

Starting position of the profile in radians; 0 is right (0 on unit circle).

Type:int, float
ccw

How the profile is/was taken; clockwise or counter-clockwise.

Type:bool
Parameters:
  • image_array (ndarray) – The 2D image array.
  • start_angle (int, float) – Starting position of the profile in radians; 0 is right (0 on unit circle).
  • ccw (bool) – If True (default), the profile will proceed counter-clockwise (the direction on the unit circle). If False, will proceed clockwise.
  • sampling_ratio (float) – The ratio of pixel sampling to real pixels. E.g. if 1.0, the profile will have approximately the same number of elements as was encountered in the profile. A value of 2.0 will sample the profile at 2x the number of elements.

See also

Circle : Further parameter info.

size

The elemental size of the profile.

x_locations

The x-locations of the profile values.

y_locations

The x-locations of the profile values.

find_peaks(threshold: Union[float, int] = 0.3, min_distance: Union[float, int] = 0.05, max_number: int = None, search_region: Tuple[float, float] = (0.0, 1.0)) → Tuple[numpy.ndarray, numpy.ndarray][source]

Overloads Profile to also map peak locations to the image.

find_valleys(threshold: Union[float, int] = 0.3, min_distance: Union[float, int] = 0.05, max_number: int = None, search_region: Tuple[float, float] = (0.0, 1.0)) → Tuple[numpy.ndarray, numpy.ndarray][source]

Overload Profile to also map valley locations to the image.

find_fwxm_peaks(threshold: Union[float, int] = 0.3, min_distance: Union[float, int] = 0.05, max_number: int = None, search_region: Tuple[float, float] = (0.0, 1.0)) → Tuple[numpy.ndarray, numpy.ndarray][source]

Overloads Profile to also map the peak locations to the image.

roll(amount: int) → None[source]

Roll the profile and x and y coordinates.

plot2axes(axes: matplotlib.axes._axes.Axes = None, edgecolor: str = 'black', fill: bool = False, plot_peaks: bool = True) → None[source]

Plot the circle to an axes.

Parameters:
  • axes (matplotlib.Axes, None) – The axes to plot on. If None, will create a new figure of the image array.
  • edgecolor (str) – Color of the Circle; must be a valid matplotlib color.
  • fill (bool) – Whether to fill the circle. matplotlib keyword.
  • plot_peaks (bool) – If True, plots the found peaks as well.
class pylinac.core.profile.CollapsedCircleProfile(center: pylinac.core.geometry.Point, radius: Union[int, float], image_array: Union[numpy.ndarray, ArrayImage], start_angle: int = 0, ccw: bool = True, sampling_ratio: float = 1.0, width_ratio: float = 0.1, num_profiles: int = 20)[source]

Bases: pylinac.core.profile.CircleProfile

A circular profile that samples a thick band around the nominal circle, rather than just a 1-pixel-wide profile to give a mean value.

Parameters:
  • width_ratio (float) – The “thickness” of the band to sample. The ratio is relative to the radius. E.g. if the radius is 20 and the width_ratio is 0.2, the “thickness” will be 4 pixels.
  • num_profiles (int) – The number of profiles to sample in the band. Profiles are distributed evenly within the band.

See also

CircleProfile : Further parameter info.

size

The elemental size of the profile.

plot2axes(axes: matplotlib.axes._axes.Axes = None, edgecolor: str = 'black', fill: bool = False, plot_peaks: bool = True) → None[source]

Add 2 circles to the axes: one at the maximum and minimum radius of the ROI.

See also

plot2axes() : Further parameter info.

pylinac.core.profile.find_peaks(values: numpy.ndarray, threshold: Union[float, int] = -inf, peak_separation: Union[float, int] = 0, max_number: int = None, fwxm_height: float = 0.5, min_width: int = 0, search_region: Tuple[float, float] = (0.0, 1.0), peak_sort='prominences', required_prominence=None) → Tuple[numpy.ndarray, dict][source]

Find the peaks of a 1D signal. Heavily relies on the scipy implementation.

Parameters:
  • values (array-like) – Signal values to search for peaks within.
  • threshold (int, float) – The value the peak must be above to be considered a peak. This removes “peaks” that are in a low-value region. If passed an int, the actual value is the threshold. E.g. when passed 15, any peak less with a value <15 is removed. If passed a float, it will threshold as a percent. Must be between 0 and 1. E.g. when passed 0.4, any peak <40% of the maximum value will be removed.
  • peak_separation (int, float) – If passed an int, parameter is the number of elements apart a peak must be from neighboring peaks. If passed a float, must be between 0 and 1 and represents the ratio of the profile to exclude. E.g. if passed 0.05 with a 1000-element profile, the minimum peak width will be 0.05*1000 = 50 elements.
  • max_number (int, None) – Specify up to how many peaks will be returned. E.g. if 3 is passed in and 5 peaks are found, only the 3 largest peaks will be returned.
  • fwxm_height (float) – The relative height at which a FWXM calculation is performed. Although this function finds simple max values, the underlying function can provide fwxm information as well.
  • min_width (int) – The minimum width of the peak.
  • search_region (tuple) – The search region to use within the values. Using between 0 and 1 will convert to a ratio of the indices. E.g. to search the middle half of the passed values, use (0.25, 0.75). Using ints above 1 will use the indices directly. E.g. (33, 71) will search between those two indices.
Returns:

  • peak_idxs (numpy.array) – The indices of the peaks found.
  • peak_props (dict) – A dict containing contextual peak data.

I/O Module

I/O helper functions for pylinac.

pylinac.core.io.is_dicom(file: str) → bool[source]

Boolean specifying if file is a proper DICOM file.

This function is a pared down version of read_preamble meant for a fast return. The file is read for a proper preamble (‘DICM’), returning True if so, and False otherwise. This is a conservative approach.

Parameters:file (str) – The path to the file.

See also

pydicom.filereader.read_preamble(), pydicom.filereader.read_partial()

pylinac.core.io.is_dicom_image(file: str) → bool[source]

Boolean specifying if file is a proper DICOM file with a image

Parameters:file (str) – The path to the file.

See also

pydicom.filereader.read_preamble(), pydicom.filereader.read_partial()

pylinac.core.io.retrieve_dicom_file(file: str) → pydicom.dataset.FileDataset[source]

Read and return the DICOM dataset.

Parameters:file (str) – The path to the file.
pylinac.core.io.is_zipfile(file: str) → bool[source]

Wrapper function for detecting if file is a true ZIP archive

class pylinac.core.io.TemporaryZipDirectory(zfile)[source]

Bases: tempfile.TemporaryDirectory

Creates a temporary directory that unpacks a ZIP archive.

Parameters:zfile (str) – String that points to a ZIP archive.
pylinac.core.io.retrieve_filenames(directory: str, func: Callable = None, recursive: bool = True, **kwargs) → List[str][source]

Retrieve file names in a directory.

Parameters:
  • directory (str) – The directory to walk over recursively.
  • func (function, None) – The function that validates if the file name should be kept. If None, no validation will be performed and all file names will be returned.
  • recursive (bool) – Whether to search only the root directory.
  • kwargs – Additional arguments passed to the func parameter.
pylinac.core.io.retrieve_demo_file(url: str, force: bool = False) → str[source]

Retrieve the demo file either by getting it from file or from a URL.

If the file is already on disk it returns the file name. If the file isn’t on disk, get the file from the URL and put it at the expected demo file location on disk for lazy loading next time.

Parameters:url (str) – The suffix to the url (location within the S3 bucket) pointing to the demo file.
pylinac.core.io.is_url(url: str) → bool[source]

Determine whether a given string is a valid URL.

Parameters:url (str) –
Returns:
Return type:bool
pylinac.core.io.get_url(url: str, destination: str = None, progress_bar: bool = True) → str[source]

Download a URL to a local file.

Parameters:
  • url (str) – The URL to download.
  • destination (str, None) – The destination of the file. If None is given the file is saved to a temporary directory.
  • progress_bar (bool) – Whether to show a command-line progress bar while downloading.
Returns:

filename – The location of the downloaded file.

Return type:

str

Notes

Progress bar use/example adapted from tqdm documentation: https://github.com/tqdm/tqdm

class pylinac.core.io.SNCProfiler(path: str, detector_row: int = 106, bias_row: int = 107, calibration_row: int = 108, data_row: int = -1, data_columns: slice = slice(5, 259, None))[source]

Bases: object

Load a file from a Sun Nuclear Profiler device. This accepts .prs files.

Parameters:
  • path (str) – Path to the .prs file.
  • detector_row
  • bias_row
  • calibration_row
  • data_row
  • data_columns – The range of columns that the data is in. Usually, there are some columns before and after the real data.
to_profiles(n_detectors_row: int = 63, **kwargs) → Tuple[pylinac.core.profile.SingleProfile, pylinac.core.profile.SingleProfile, pylinac.core.profile.SingleProfile, pylinac.core.profile.SingleProfile][source]

Convert the SNC data to SingleProfiles. These can be analyzed directly or passed to other modules like flat/sym.

Parameters:n_detectors_row (int) – The number of detectors in a given row. Note that they Y profile includes 2 extra detectors from the other 3.

ROI Module

pylinac.core.roi.bbox_center(region: skimage.measure._regionprops.RegionProperties) → pylinac.core.geometry.Point[source]

Return the center of the bounding box of an scikit-image region.

Parameters:region – A scikit-image region as calculated by skimage.measure.regionprops().
Returns:point
Return type:Point
class pylinac.core.roi.Contrast[source]

Bases: enum.Enum

Contrast calculation technique. See Visibility

MICHELSON = 'Michelson'
WEBER = 'Weber'
RATIO = 'Ratio'
class pylinac.core.roi.DiskROI(array: numpy.ndarray, angle: Union[float, int], roi_radius: Union[float, int], dist_from_center: Union[float, int], phantom_center: Union[Tuple, pylinac.core.geometry.Point])[source]

Bases: pylinac.core.geometry.Circle

An class representing a disk-shaped Region of Interest.

Parameters:
  • array (ndarray) – The 2D array representing the image the disk is on.
  • angle (int, float) – The angle of the ROI in degrees from the phantom center.
  • roi_radius (int, float) – The radius of the ROI from the center of the phantom.
  • dist_from_center (int, float) – The distance of the ROI from the phantom center.
  • phantom_center (tuple) – The location of the phantom center.
pixel_value

The median pixel value of the ROI.

std

The standard deviation of the pixel values.

circle_mask() → numpy.ndarray[source]

Return a mask of the image, only showing the circular ROI.

plot2axes(axes=None, edgecolor: str = 'black', fill: bool = False) → None[source]

Plot the Circle on the axes.

Parameters:
  • axes (matplotlib.axes.Axes) – An MPL axes to plot to.
  • edgecolor (str) – The color of the circle.
  • fill (bool) – Whether to fill the circle with color or leave hollow.
class pylinac.core.roi.LowContrastDiskROI(array: Union[numpy.ndarray, pylinac.core.image.ArrayImage], angle: float, roi_radius: float, dist_from_center: float, phantom_center: Union[tuple, pylinac.core.geometry.Point], contrast_threshold: Optional[float] = None, contrast_reference: Optional[float] = None, cnr_threshold: Optional[float] = None, contrast_method: pylinac.core.roi.Contrast = <Contrast.MICHELSON: 'Michelson'>, visibility_threshold: Optional[float] = 0.1)[source]

Bases: pylinac.core.roi.DiskROI

A class for analyzing the low-contrast disks.

Parameters:contrast_threshold (float, int) – The threshold for considering a bubble to be “seen”.
signal_to_noise

The signal to noise ratio.

contrast_to_noise

The contrast to noise ratio of the ROI

contrast

//en.wikipedia.org/wiki/Contrast_(vision).

Type:The contrast of the bubble. Uses the contrast method passed in the constructor. See https
cnr_constant

The contrast-to-noise value times the bubble diameter.

visibility

//www.osapublishing.org/josa/abstract.cfm?uri=josa-38-2-196. See also here: https://howradiologyworks.com/x-ray-cnr/. Finally, a review paper here: http://xrm.phys.northwestern.edu/research/pdf_papers/1999/burgess_josaa_1999.pdf Importantly, the Rose model is not applicable for high-contrast use cases.

Type:The visual perception of CNR. Uses the model from A Rose
Type:https
contrast_constant

The contrast value times the bubble diameter.

passed

Whether the disk ROI contrast passed.

passed_visibility

Whether the disk ROI’s visibility passed.

passed_contrast_constant

Boolean specifying if ROI pixel value was within tolerance of the nominal value.

passed_cnr_constant

Boolean specifying if ROI pixel value was within tolerance of the nominal value.

plot_color

Return one of two colors depending on if ROI passed.

plot_color_constant

Return one of two colors depending on if ROI passed.

plot_color_cnr

Return one of two colors depending on if ROI passed.

class pylinac.core.roi.HighContrastDiskROI(array: numpy.ndarray, angle: float, roi_radius: float, dist_from_center: float, phantom_center: Union[tuple, pylinac.core.geometry.Point], contrast_threshold: float)[source]

Bases: pylinac.core.roi.DiskROI

A class for analyzing the high-contrast disks.

Parameters:contrast_threshold (float, int) – The threshold for considering a bubble to be “seen”.
max

The max pixel value of the ROI.

min

The min pixel value of the ROI.

class pylinac.core.roi.RectangleROI(array, width, height, angle, dist_from_center, phantom_center)[source]

Bases: pylinac.core.geometry.Rectangle

Class that represents a rectangular ROI.

pixel_array

The pixel array within the ROI.

Mask Module

Module for processing “masked” arrays, i.e. binary images.

pylinac.core.mask.bounding_box(array: numpy.array) → Tuple[float, ...][source]

Get the bounding box values of an ROI in a 2D array.

pylinac.core.mask.filled_area_ratio(array: numpy.array) → float[source]

Return the ratio of filled pixels to empty pixels in the ROI bounding box.

For example a solid square would be 1.0, while a sold circle would be ~0.785.

pylinac.core.mask.square_ratio(array: numpy.array) → float[source]

Determine the width/height ratio of the ROI

Utilities Module

Utility functions for pylinac.

pylinac.core.utilities.convert_to_enum(value: Union[str, enum.Enum, None], enum: Type[enum.Enum]) → enum.Enum[source]

Convert a value to an enum representation from an enum value if needed

class pylinac.core.utilities.ResultBase[source]

Bases: object

pylinac_version = None
date_of_analysis = None
pylinac.core.utilities.clear_data_files()[source]

Delete all demo files, image classifiers, etc from the demo folder

pylinac.core.utilities.assign2machine(source_file: str, machine_file: str)[source]

Assign a DICOM RT Plan file to a specific machine. The source file is overwritten to contain the machine of the machine file.

Parameters:
  • source_file (str) – Path to the DICOM RTPlan file that contains the fields/plan desired (e.g. a Winston Lutz set of fields or Varian’s default PF files).
  • machine_file (str) – Path to a DICOM RTPlan file that has the desired machine. This is easily obtained from pushing a plan from the TPS for that specific machine. The file must contain at least one valid field.
pylinac.core.utilities.is_close(val: Union[int, float], target: Union[int, float, Sequence[T_co]], delta: Union[int, float] = 1)[source]

Return whether the value is near the target value(s).

Parameters:
  • val (number) – The value being compared against.
  • target (number, iterable) – If a number, the values are simply evaluated. If a sequence, each target is compared to val. If any values of target are close, the comparison is considered True.
Returns:

Return type:

bool

pylinac.core.utilities.simple_round(number: Union[int, float], decimals: int = 0) → float[source]

Round a number to the given number of decimals. Fixes small floating number errors.

pylinac.core.utilities.isnumeric(object) → bool[source]

Check whether the passed object is numeric in any sense.

pylinac.core.utilities.is_iterable(object) → bool[source]

Determine if an object is iterable.

class pylinac.core.utilities.Structure(**kwargs)[source]

Bases: object

A simple structure that assigns the arguments to the object.

pylinac.core.utilities.decode_binary(file: BinaryIO, dtype: Union[Type[int], Type[float], Type[str]], num_values: int = 1, cursor_shift: int = 0) → Union[int, float, str, numpy.ndarray][source]

Read in a raw binary file and convert it to given data types.

Parameters:
  • file – The open file object.
  • dtype – The expected data type to return. If int or float and num_values > 1, will return numpy array.
  • num_values

    The expected number of dtype to return

    Note

    This is not the same as the number of bytes.

  • cursor_shift (int) – The number of bytes to move the cursor forward after decoding. This is used if there is a reserved section after the read-in segment.
pylinac.core.utilities.open_path(path: str) → None[source]

Open the specified path in the system default viewer.

pylinac.core.utilities.file_exists(filename: str) → str[source]

Check if the file exists and if it does add a timestamp

Decorators Module

pylinac.core.decorators.timethis(func)[source]

Report execution time of function.

pylinac.core.decorators.lru_cache(*lru_args, **lru_kwargs)[source]

https://stackoverflow.com/a/33672499