Python Exercise #1C – Film Calibrator

Radiosensitive film is frequently used by radiation oncology medical physicists for quality assurance measurements. The physicist is sometimes interested in obtaining a calibrated dose value (as opposed to relative values). One calibration method, using calculated optical density (OD) values, involves the use of pre-irradiation film scanning:

\mathrm{OD} = -\log_{10}(\frac{\mathrm{PV}_\mathrm{pre}}{\mathrm{PV}_\mathrm{post}})

where PV is the pixel value of interest. The third python exercise, detailed here, was to develop software for the calculation of dose from pre- and post-irradiation scanned film.

This problem can be broken up into the following components:

  • Opening TIFF images (commonly used for film scans);
  • Calibration of dose (using a polynomial calibration relationship);
  • Writing the dose plane (as a text image).

This post will discuss the solution to each of these smaller problems. Please note that this discussion assumes the use of Python 3.

Opening TIFF images

The Python Imaging Library (PIL) provides easy-to-use image reading and writing functionality. Combined with NumPy, the importing of *.tif files as an array is very simple:

import numpy as np
from PIL import Image

input_image = Image.open(input_filepath)
input_imarray = np.array(input_image)

The user can be prompted to enter the path to the pre- and post- scan images, in the following way:

pre_scan_filepath = input("Pre-irradiation scan image file: ")
post_scan_filepath = input("Post-irradiation scan image file: ")

These paths can be validated using the isfile() method:

import os.path
os.path.isfile(pre_scan_filepath)

The validation of user input is discussed in the solution to the first exercise here.

Dose calculation

The calculation of absolute dose requires a calibration relationship, which can be obtained from irradiations of known dose. The example relationship provided with the exercise was a 2nd order polynomial, obtained from actual EBT3 measurements:

\mathrm{D} = (26.06 \times \mathrm{OD}^2) + (3.2249 \times \mathrm{OD}) + 0.1213

Calibration relationships vary between batches of film, and so it would be more appropriate to prompt the user to enter specific calibration relationship coefficients:

coefficient_zero = input("Constant term of calibration polynomial (c): ")
coefficient_one = input("First coefficient of calibration polynomial (m1): ")
coefficient_two = input("Second coefficient of calibration polynomial (m2): ")

The validation of user input is discussed in the solution to the first exercise here.

The calculation of OD from two images (assumed to have the same dimensions) can be done like so:

pre_scan_array = np.array(pre_scan_image)
post_scan_array = np.array(post_scan_image)
od_array = np.log10(pre_scan_array / post_scan_array)

The dose values can be obtained using:

dose_array = (coefficient_two * od_array ** 2) + (coefficient_one * od_array) + coefficient_zero

Saving dose planes

There are many methods by which the resultant dose array could be written to disk. NumPy offers a savetxt() method that allows the simple production of csv files:

np.savetxt('dose.csv',dose_array,delimiter=',')