Projector
The Projector classes compute a forward or a backward projection for individual LORs (Line of Response). A forward projection projects a line on an image grid and sums the intersecting voxels. A backprojection distributes a given value into the image grid.
Available Projector Types
YRT-PET provides two projector implementations:
ProjectorSiddon - Siddon projector, faster but less accurate since it does not model the crystal thickness (except with the multi-ray Siddon).
ProjectorDD - Distance-Driven projector, more accurate but slower.
Python Usage
import pyyrtpet as yrt
import numpy as np
# Define a scanner using geometric parameters
scanner = yrt.Scanner(
scanner_name='MYSCANNER',
axial_fov=25.0, # Axial field of view in mm
crystal_size_z=2.0, # Crystal size in axial direction (mm)
crystal_size_trans=2.0, # Crystal size in transaxial direction (mm)
crystal_depth=10.0, # Crystal depth (mm)
scanner_radius=161.0, # Scanner radius (mm)
dets_per_ring=256, # Number of detectors per ring
num_rings=8, # Number of detector rings
num_doi=1, # Number of DOI layers
max_ring_diff=7, # Maximum ring difference
min_ang_diff=1, # Minimum angular difference (in number of crystals)
dets_per_block=32 # Number of crystals per block (transaxial)
)
# Define image grid parameters
img_params = yrt.ImageParams(
nx=64, # Number of voxels in x
ny=64, # Number of voxels in y
nz=32, # Number of voxels in z
length_x=scanner.scannerRadius*2,
length_y=scanner.scannerRadius*2,
length_z=scanner.axialFOV
)
# Create an empty image
image = yrt.ImageOwned(img_params)
image.allocate()
image.fill(0.0)
# Create Projector Parameters
proj_params = yrt.ProjectorParams(scanner)
proj_params.addTOF(300.0, 3)
# Set the projector parameters here
# Create a Distance-Driven projector
projector = yrt.ProjectorDD(proj_params)
# Define a Line of Response (LOR) - a line connecting two detectors
# Define two points representing a line through the FOV
p1 = yrt.Vector3D(0.0, -scanner.scannerRadius, 0.0) # Point at the top of the ring
p2 = yrt.Vector3D(0.0, scanner.scannerRadius, 0.0) # Opposite side
lor = yrt.Line3D(p1, p2)
# For DD projector, we need detector orientation (as unit vectors).
# These are computed from the scanner geometry.
# Here we use simplified unit vectors for demonstration.
n1 = yrt.Vector3D(0.0, -1.0, 0.0)
n2 = yrt.Vector3D(0.0, 1.0, 0.0)
# Perform single backprojection
# Parameters: image, LOR, detector_orient_1, detector_orient_2, projection_value,
# dynamic_frame, tof_helper, tof_value
# `projection_value` is the value that will be backprojected
# `tof_helper` is an object used to compute the weight of each pixel w.r.t. the TOF kernel
# `tof_value` is the TOF measure in picoseconds to use for the backprojection.
# We use -50ps here for example
tof_helper = projector.getTOFHelper()
projector.backProjection(
image, lor, n1, n2, 6, 0, tof_helper, -50
)
# Ensure that we populated at least some pixels
image_np = np.array(image, copy=False)
assert image_np.max() > 0
# Forward projection
# This time, we will use the Siddon projector
projector = yrt.ProjectorSiddon(proj_params)
# Define a LOR
p1 = yrt.Vector3D(-scanner.scannerRadius, 0.0, 0.0) # Point at the left of the ring
p2 = yrt.Vector3D(scanner.scannerRadius, 0.0, 0.0) # Opposite side
lor = yrt.Line3D(p1, p2)
# For the single-ray Siddon projector, we do not need to specify the
# detector orientation
# Perform single forward projection
tof_helper = projector.getTOFHelper()
forward_proj = projector.forwardProjection(
image, lor, n1, n2, 0, 0, tof_helper, 0
)
# Ensure we intersected at least some voxels
assert forward_proj > 0
Siddon vs Distance-Driven
The two projector implementations have different characteristics:
Feature |
Siddon |
Distance-Driven |
|---|---|---|
Speed |
Faster |
Slower |
Accuracy |
Lower |
Higher |
Time-of-Flight support |
Yes |
Yes |
Projection-space PSF |
No |
Yes |
Modeling crystal thickness |
Only with multi-ray Siddon |
Yes |
Siddon-specific Methods
# Siddon projector supports multi-ray configuration
projector_siddon = yrt.ProjectorSiddon(proj_params)
# Set number of rays for multi-ray sampling
projector_siddon.setNumRays(5) # Use 5 rays per LOR
assert projector_siddon.getNumRays() == 5
Single LOR Projection Methods (Siddon)
The Siddon projector provides static methods for single LOR projections:
# Forward projection - returns contribution of image along the LOR
value = yrt.ProjectorSiddon.singleForwardProjection(
image, # Input image
lor, # Line of Response
0, # Dynamic frame index
None, # TOF helper (or None)
0.0 # TOF value
)
# Back projection - adds contribution to image along the LOR
yrt.ProjectorSiddon.singleBackProjection(
image, # Output image (modified in-place)
lor, # Line of Response
1.0 , # Value to backproject
0, # Dynamic frame index
None, # TOF helper (or None)
0.0 # TOF value
)
Notes
The Siddon projector does NOT support projection-space PSF. If you try to add a PSF to a Siddon projector, it will be ignored with a warning. Use the Distance-Driven projector for PSF-aware projections.
For a full forward/backward projection on an entire dataset, use
OperatorProjectorSee operator-projector.md for details