Usage¶
This page provides a guide on how to use the VITools library for running virtual imaging trials. We will cover the core components: Phantom, Scanner, and Study.
Creating a Phantom¶
The Phantom class is a container for a numpy array and some metadata, such as the patient’s age and voxel spacings. Here’s how to create a Phantom object:
import numpy as np
from VITools.phantom import Phantom
# Create a simple phantom from a numpy array
image_array = np.zeros((10, 20, 30))
my_phantom = Phantom(img=image_array, spacings=(1.0, 0.5, 0.5))
>>> print(my_phantom)
Phantom Class: Phantom
Age (years): 0
Shape (voxels): (10, 20, 30)
Size (mm): (10.0, 10.0, 15.0)
Using the Scanner¶
The Scanner class is the wrapper around the simulation backend. It takes a Phantom and simulates a CT scan, generating projection data and a reconstructed image. Currently, Scanner defaults to wrapping the XCIST backend.
First, you need to instantiate a Phantom. For this example, we will use a phantom from the available phantom plugins:
from VITools.study import get_available_phantoms
# Get a list of available phantoms
available_phantoms = get_available_phantoms()
>>> print(f"Available phantoms: {list(available_phantoms.keys())}")
Available phantoms: ['Water Phantom']
Water Phantom comes builtin by default but other phantoms can be extend by installing plugins or defining custom phantoms. See src/VITools/examples.py for an example.
phantom_class = available_phantoms['Water Phantom']
phantom = phantom_class()
>>> phantom
Phantom Class: WaterPhantom
Age (years): 0
Shape (voxels): (100, 100, 100)
Size (mm): (100.0, 200.0, 200.0)
Now, we can pass the Phantom object to the Scanner. The scanner_model argument maps to a configuration file understood by the backend (XCIST).
from VITools.scanner import Scanner
scanner = Scanner(phantom=phantom, scanner_model='Scanner_Default')
>>> scanner
Initializing Scanner object...
----------
Scanner default_series
Scanner: Scanner_Default
Simulation Platform: CATSIM
scanner.run_scan(mA=250, kVp=120, views=100, startZ=-4, endZ=4)
After the scan is complete, you can run a reconstruction:
scanner.run_recon(kernel='soft', fov=300)
reconstructed_image = scanner.recon
>>> print(f"Reconstructed image shape: {reconstructed_image.shape}")
Reconstructed image shape: (7, 512, 512)
You can also save the reconstructed image to a DICOM series:
>>> scanner.write_to_dicom('output_dicom/my_scan.dcm')
[PosixPath('output_dicom/my_scan_000.dcm'),
PosixPath('output_dicom/my_scan_001.dcm'),
PosixPath('output_dicom/my_scan_002.dcm'),
PosixPath('output_dicom/my_scan_003.dcm'),
PosixPath('output_dicom/my_scan_004.dcm'),
PosixPath('output_dicom/my_scan_005.dcm'),
PosixPath('output_dicom/my_scan_006.dcm')]
Setting up a Study¶
The Study class manages a series of simulations, allowing you to vary parameters and run them in a structured way.
You can create a study and add a scan like this:
from VITools.study import Study
# Create a Study instance
study = Study()
# Append a new scan to the study
study.append(
phantom='Water Phantom',
scanner_model='Scanner_Default',
kVp=120,
mA=200,
pitch=0.0,
views=100,
scan_coverage=[-4, 5],
recon_kernel='standard',
output_directory='my_study_results'
)
# You can now run all the scans defined in the study
study.run_all(parallel=False)
Command Line Interface¶
VITools provides a command-line interface (CLI) to easily run simulations defined in a CSV file. This is particularly useful for batch processing or running studies on remote servers.
The generate command takes a CSV file path as an argument and executes the study plan defined within it.
generate example_study_plan.csv
The input CSV file must contain specific columns that define the parameters for each scan. The required columns are:
case_id: A unique identifier for the case (e.g., ‘case_0001’).
phantom: The name of the phantom to use (must be a registered phantom).
scanner_model: The name of the scanner model (e.g., ‘Scanner_Default’).
kVp: The tube voltage in kV.
mA: The tube current in mA.
views: The number of views per rotation.
pitch: The helical pitch.
scan_coverage: The start and end Z positions of the scan (e.g., ‘[-50, 50]’ or ‘dynamic’).
recon_kernel: The reconstruction kernel (e.g., ‘standard’, ‘soft’).
slice_thickness: The slice thickness in mm.
slice_increment: The slice increment in mm.
fov: The Field of View in mm.
output_directory: The directory where the results will be saved.
remove_raw: (Optional) Boolean indicating whether to remove raw data after reconstruction.
Sample CSV Content
Below is an example of a valid CSV file content using the built-in ‘Water Phantom’:
case_id,phantom,scanner_model,kVp,mA,views,pitch,scan_coverage,recon_kernel,slice_thickness,slice_increment,fov,output_directory,remove_raw,seed
case_0000,Water Phantom,Scanner_Default,120.0,200.0,1000.0,0.0,"[-50, 50]",standard,1,1,250.0,/tmp/results/case_0000,True,42
case_0001,Water Phantom,Scanner_Default,120.0,200.0,1000.0,0.0,"[-50, 50]",soft,1,1,250.0,/tmp/results/case_0001,True,43
Cleaning Incomplete Simulations¶
If a batch simulation process is interrupted or fails, you can use the vit_clean command to remove the output directories of incomplete simulations while preserving the results of completed ones. This helps in freeing up space and preparing for a clean restart or analysis.
The vit_clean command takes the root folder of the study (which must contain the *_study_plan.csv file) as an argument.
vit_clean /path/to/study_root
Or you can point directly to the study plan CSV:
vit_clean /path/to/study_root/my_study_plan.csv
This will: 1. Load the study plan. 2. Identify completed scans by checking for metadata_*.csv files. 3. Remove the output directories of any scans that are not marked as complete.
This provides a basic overview of how to use the VITools library. For more advanced usage and details on the available classes and functions, please refer to the API documentation.