API#

Dosepy.image#

NAME

Image module

DESCRIPTION

This module holds functionalities for tif image loading and manipulation. ArryaImage class is used as representation of dose distributions. The content is heavily based from pylinac, and omg_dosimetry

class Dosepy.image.ArrayImage(array: ndarray, *, dpi: float | None = None, sid: float | None = None, dtype=None)[source]#

An image constructed solely from a numpy array.

property dpi: float | None#

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

property dpmm: float | None#

The Dots-per-mm of the image, defined at isocenter.

gamma2D(reference, dose_ta=3, dist_ta=3, *, dose_threshold=10, dose_ta_Gy=False, local_norm=False, mask_radius=10, max_as_percentile=True, exclude_above=None)[source]#

Calculate gamma between the current image against a reference image. The images must have the same spatial resolution (dpi) to be comparable. The size of the images must also be the same. An array is ​​obtained. It represents the gamma indices at each position of the dose distribution, as well as the approval rate defined as the percentage of gamma values ​​that are less or equal to 1. The registration of dose distributions is assumed, i.e. the spatial coordinate of a point in the reference dose distribution is equal to the coordinate of the same point in the distribution to be evaluated.

Parameters:
  • reference (ArrayImage) – The reference image.

  • dose_ta (float, default = 3) – Dose-to-agreement. This value can be interpreted in 3 different ways depending on the dose_ta_Gy, local_norm and max_as_percentile parameters, which are described below.

  • dist_ta (float, default = 3) – Distance-to-agreement in mm.

  • dose_threshold (float, default = 10) – Dose threshold in percentage (0 to 100) with respect to the maximum dose of the reference distribution (or to 99th percentile if max_as_percentile = True). Any point in the dose distribution with a value less than the dose threshold, is excluded from the analysis.

  • dose_ta_Gy (bool, default: False) – If True, then “dose_ta” (the tolerance dose) is interpreted as an absolute value in Gray. If False (default), “dose_ta” is interpreted as a percentage.

  • local_norm (bool, default: False) – If the argument is True (local normalization), the tolerance dose percentage “dose_ta” is interpreted with respect to the local dose at each point of the reference distribution. If the argument is False (global normalization), the tolerance dose percentage “dose_ta” is interpreted with respect to the maximum of the distribution to be evaluated. * The dose_ta_Gy and local_norm arguments must NOT be selected as True simultaneously. * If you want to use the maximum of the distribution directly, use the parameter max_as_percentile = False (see explanation below).

  • mask_radius (float, default: 10) –

    Physical distance in millimeters used to limit the calculation to positions that are within a neighborhood given by mask_radius.

    The use of this mask allows reducing the calculation time due to the following process:

    For each point in the reference distribution, the calculation of the Gamma function is performed only with those points or positions of the distribution to be evaluated that are at a relative distance less than or equal to mask_radius, that is, with the points that are within the neighborhood given by mask_radius. The length of one side of the square mask is 2*mask_radius + 1.

    On the other hand, if you prefer to compare with all the points of the distribution to be evaluated, it is enough to enter a distance greater than the dimensions of the dose distribution (for example mask_radius = 1000).

  • max_as_percentile (bool, default: True) – If the argument is True, 99th percentile is used as an approximation of the maximum value of the dose distribution. This allows us to exclude artifacts or errors in specific positions. If the argument is False, the maximum value of the distribution is used.

  • exclude_above (float, default: None) – Dose limit in Gy. Any point in the evaluated distribution greater than exclude_above, is not accounted in the pass rate. dose_ta_Gy should be set as True.

Returns:

  • gamma_map (numpy.ndarray) – The calculated gamma distribution.

  • pass_rate (float) – Approval rate. It is calculated as the percentage of gamma values ​​<= 1. Points with dose below than the dose threshold are not accounted.

Notes

Percentile 99th of the dose distribution can be used as an approximation of the maximum value. This allows us to avoid artifacts or errors in specific positions of the distribution. (useful for example for spot labels are used in films).

It is assumed that both distributions have exactly the same physical dimensions, and the positions ​​for each point coincide with each other, that is, the images are registered.

Interpolation is not supported yet.

References

For more information about the operating mechanisms, effectiveness and accuracy of the gamma tool:

[1] M. Miften, A. Olch, et. al. “Tolerance Limits and Methodologies for IMRT Measurement-Based Verification QA: Recommendations of AAPM Task Group No. 218” Medical Physics, vol. 45, nº 4, pp. e53-e83, 2018.

[2] D. Low, W. Harms, S. Mutic y J. Purdy, «A technique for the quantitative evaluation of dose distributions,» Medical Physics, vol. 25, nº 5, pp. 656-661, 1998.

[3] L. A. Olivares-Jimenez, “Distribución de dosis en radioterapia de intensidad modulada usando películas de tinte radiocrómico : irradiación de cerebro completo con protección a hipocampo y columna con protección a médula” (Tesis de Maestría) Posgrado en Ciencias Físicas, IF-UNAM, México, 2019

Examples

Numpy arrays as dose distributions:

>>> # We import the Dosepy packages as well as numpy to create example arrays representing two dose distributions.
>>> from Dosepy.image import load
>>> import numpy as np
>>> # We generate the arrays, A and B, with the values ​​96 and 100 in all their elements.
>>> A = np.zeros((30, 30)) + 96
>>> B = np.zeros((30, 30)) + 100
>>> # We generate the dose distributions
>>> D_ref = load(A, dpi = 25.4)
>>> D_eval = load(B, dpi = 25.4)
>>> # On the variable D_eval, we apply the gamma2D method providing as arguments the reference distribution, D_ref, and the criteria (3%, 1 mm).
>>> gamma_distribution, pass_rate = D_eval.gamma2D( D_ref, 3, 1)
>>> print(f"Pass rate: {pass_rate:.1f} %")

CSV files (comma separated values):

>>> from Dosepy.image import load
>>> # Load "D_TPS.csv" y "D_FILM.csv"
>>> # The example .csv files are located within the Dosepy package, in the src/Dosepy/data
>>> np_film = np.genfromtxt('../D_FILM.csv', delimiter = ",", comments = "#")
>>> np_tps = np.genfromtxt('../D_TPS.csv', delimiter = ",", comments = "#")
>>> d_film = load(np_film, dpi=25.4)
>>> d_tps = load(np_tps, dpi=25.4)

We call the method gamma2D, with criteria 3%, 2 mm:

>>> g, pass_rate = d_tps.gamma2D(d_film, 3, 2)
>>> # Print the result
>>> print(f'Pass rate: {pass_rate:.1f} %')
>>> plt.imshow(g, vmax = 1.4)
>>> plt.show()
>>> # Pass rate: 98.9 %
property physical_shape#

The physical size of the image in mm.

reduce_resolution_as(reference)[source]#

Reduce the spatial resolution of the image to have the same a reference image. Usefull for gamma analysis. The physical dimensions of the images must be the same (within half of the reference resolution). The algorithm averages a number of pixels given by reference_resolution // image_resolution.

Parameters:

reference (ArrayImage) – The reference image that has the target resolution.

Raises:

AttributeError – If the physical dimensions of the images are not the same.

Examples

Create two images with different resolutions and reduce the resolution of one of them:

>>> from Dosepy.image import load
>>> import numpy as np
>>> # Generate the arrays, A and B.
>>> A = np.random.rand(100, 100)
>>> B = np.random.rand(10, 10)
>>> # Create the dose distributions.
>>> D_eval = load(A, dpi = 10)
>>> D_ref = load(B, dpi = 1)
>>> # Reduce the resolution of the image D_eval to have the same resolution as D_ref.
>>> D_eval.reduce_resolution_as(D_ref)
>>> # Print the new shape of the D_eval array.
>>> print(D_eval.shape) # (10, 10)
save_as_tif(file_name)[source]#

Used to save a dose distribution (in Gy) as a tif file (in cGy).

Parameters:

file_name (str) – File name as a string

class Dosepy.image.BaseImage(path: str | Path | ndarray)[source]#

Base abstract class for the Image classes.

path#

The path to the image file.

Type:

str

array#

The actual image pixel array.

Type:

numpy.ndarray

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.

fliplr() None[source]#

Flip the image array in the left/right direction. Wrapper for np.fliplr()

flipud() None[source]#

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

property physical_shape: tuple[float, float]#

The physical size of the image in mm.

rotate(angle: float, mode: str = 'edge', *args, **kwargs)[source]#

Rotate the image counter-clockwise. Simple wrapper for scikit-image. See https://scikit-image.org/docs/stable/api/skimage.transform.html#skimage.transform.rotate. All parameters are passed to that function.

class Dosepy.image.CalibImage(path: str | Path, **kwargs)[source]#

A tiff image used for calibration.

get_calibration(doses: list, func='P3', channel='R', roi=(5, 5), threshold=None)[source]#

Computes calibration curve. Use non-linear least squares to fit a function, func, to data. For more information see scipy.optimize.curve_fit.

Parameter#

doseslist

Doses values used to expose films for calibration.

funcstring

“P3”: Polynomial function of degree 3, using optical density as film response. “RF” or “Rational”: Rational function, using normalized pixel value relative to the unexposed film.

channelstr

Color channel. “R”: Red, “G”: Green and “B”: Blue, “M”: mean.

roituple

Width and height region of interest (roi) in millimeters, at the center of the film.

returns:

Instance of a Calibration class.

rtype:

Calibration

Examples

Load an image from a file and compute a calibration curve using green channel:

>>> from Dosepy.image import load
>>> path_to_image = r"C:\QA\image.tif"
>>> cal_image = load(path_to_image, for_calib = True)
>>> cal = cal_image.get_calibration(doses = [0, 0.5, 1, 2, 4, 6, 8, 10], channel = "G")
>>> # Plot the calibration curve
>>> cal.plot()
class Dosepy.image.DoseImage(array: ndarray, dpi: float, reference_point: list[float, float], orientation: tuple[int, int, int, int, int, int], dose_unit: str)[source]#

A dose distribution image.

class Dosepy.image.TiffImage(path: str | Path, *, dpi: float | None = None, sid: float | None = None)[source]#

An image from a tiff file.

sid#

The SID value as passed in upon construction.

Type:

float

props#

Image properties via imageio.v3.

Type:

imageio.core.v3_plugin_api.ImageProperties

doses_in_central_rois(cal, roi, show)[source]#

Dose in central film rois.

Parameters:
  • cal (Dosepy.calibration.Calibration) – Instance of a Calibration class

  • roi (tuple) – Width and height of a region of interest (roi) in millimeters (mm), at the center of the film.

  • show (bool) – Whether to actually show the image and rois.

Returns:

array – Doses on heach founded film.

Return type:

numpy.ndarray

property dpi: float | None#

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

property dpmm: float | None#

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.

get_stat(ch='G', roi=(5, 5), show=False) list[source]#

Get average and standar deviation from pixel values at a central ROI in each film.

Parameter#

chstr

Color channel. “R”: Red, “G”: Green, “B”: Blue and “M”: mean.

field_in_filmbool

True to show the rois used in the image.

roituple

Width and height of a region of interest (roi) in millimeters, at the center of the film.

showbool

Whether to actually show the image and rois.

returns:

mean, std

rtype:

list

Examples

Load an image from a file and compute a calibration curve using green channel:

>>> from dosepy.image import load
>>> path_to_image = r"C:\QA\image.tif"
>>> cal_image = load(path_to_image, for_calib = True)
>>> mean, std = cal_image.get_stat(ch = 'G', roi=(5,5), show = True)
>>> list(zip(mean, std))
plot(ax: Axes | None = None, show: bool = True, clear_fig: bool = False, **kwargs) 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.

  • kwargs – kwargs passed to plt.imshow()

to_dose(cal, clip=False)[source]#

Convert the tiff image to a dose distribution. The tiff file image has to contain an unirradiated film used as a reference for zero Gray.

Parameters:
  • cal (Calibration) – Instance of a Calibration class

  • clip (bool, default: False) – If True, limit the maximum dose to the greatest used for calibration. Useful to avoid very high doses.

Returns:

Dose distribution.

Return type:

ArrayImage

Dosepy.image.load(path: str | Path | ndarray, for_calib: bool = False, filter: int | None = None, **kwargs) ArrayImage | TiffImage | CalibImage[source]#

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

Parameters:
  • path (str, file-object) – The path to the image file or array.

  • for_calib (bool, default = False) – True if the image is going to be used to get a calibration curve.

  • filter (int) – If None (default), no filtering will be done to the image. If an int, will perform median filtering over image of size filter.

  • kwargs – See ArrayImage, TiffImage, or CalibImage for keyword arguments.

Return type:

ArrayImage, TiffImage

Examples

Load an image from a file:

>>> from Dosepy.image import load
>>> path_to_image = r"C:\QA\image.tif"
>>> img = load(path_to_image)  # returns a TiffImage

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

>>> arr = np.arange(36).reshape(6, 6)
>>> img = load(arr)  # returns an ArrayImage
Dosepy.image.load_images(paths: list)[source]#
Parameters:

paths (list) – List with the paths to the TIFF files.

Return type:

list of TIffImage

Dosepy.calibration#

NAME

Calibration module

DESCRIPTION

Module for the management of the calibration curve. Here are the functions to be used for fitting. See Calibration class for details.

class Dosepy.calibration.Calibration(y: list, x: list, func: str = 'P3', channel: str = 'R')[source]#

Class used to represent a calibration curve.

y#

The doses values that were used to expose films for calibration.

Type:

list

x#

Optical density if “P3” fit function is used, or normalized pixel value for “RF” fit function.

Type:

list

func#

The model function used for dose-film response relationship. “P3”: Polynomial function of degree 3. “RF”: Rational function.

Type:

str

channel#

Color channel. “R”: Red, “G”: Green and “B”: Blue.

Type:

str

popt#

Parameters of the function.

Type:

array

pcov#

The estimated approximate covariance of popt. The diagonals provide the variance of the parameter estimate. To compute one standard deviation errors on the parameters, use perr = np.sqrt(np.diag(pcov)).

Type:

2-D array

plot(ax: Axes | None = None, show: bool = True, **kwargs) Axes[source]#

Plot the calibration curve.

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.

  • kwargs – kwargs passed to plt.plot()

Dosepy.calibration.polynomial_g3(x, a, b, c, d)[source]#

Polynomial function of degree 3.

Dosepy.calibration.rational_func(x, a, b, c)[source]#

Rational function.

Dosepy.tiff2dose#

Dosepy.rtdose#