Skip to content

Commit e501ba5

Browse files
authored
Make volume loading more flexible (#320)
* Makes centering optional * Adds the option to pass a pretransform to the volume's affine matrix
1 parent f9ff7dc commit e501ba5

File tree

2 files changed

+34
-14
lines changed

2 files changed

+34
-14
lines changed

diffdrr/data.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,18 @@ def load_example_ct(
3737
)
3838

3939
# %% ../notebooks/api/03_data.ipynb 6
40+
from .pose import RigidTransform
41+
42+
4043
def read(
4144
volume: str | Path | ScalarImage, # CT volume
4245
labelmap: str | Path | LabelMap = None, # Labelmap for the CT volume
4346
labels: int | list = None, # Labels from the mask of structures to render
4447
orientation: str | None = "AP", # Frame-of-reference change
4548
bone_attenuation_multiplier: float = 1.0, # Scalar multiplier on density of high attenuation voxels
4649
fiducials: torch.Tensor = None, # 3D fiducials in world coordinates
50+
transform: RigidTransform = None, # RigidTransform to apply to the volume's affine
51+
center_volume: bool = True, # Move the volume's isocenter to the world origin
4752
**kwargs, # Any additional information to be stored in the torchio.Subject
4853
) -> Subject:
4954
"""
@@ -57,10 +62,6 @@ def read(
5762
else:
5863
volume = ScalarImage(volume)
5964

60-
# Convert the volume to density
61-
density = transform_hu_to_density(volume.data, bone_attenuation_multiplier)
62-
density = ScalarImage(tensor=density, affine=volume.affine)
63-
6465
# Read the mask if passed
6566
if labelmap is not None:
6667
if isinstance(labelmap, LabelMap):
@@ -71,6 +72,15 @@ def read(
7172
else:
7273
mask = None
7374

75+
# Optionally apply transform
76+
if transform is not None:
77+
T = transform.matrix[0].numpy()
78+
volume = ScalarImage(tensor=volume.data, affine=T.dot(volume.affine))
79+
80+
# Convert the volume to density
81+
density = transform_hu_to_density(volume.data, bone_attenuation_multiplier)
82+
density = ScalarImage(tensor=density, affine=volume.affine)
83+
7484
# Frame-of-reference change
7585
if orientation == "AP":
7686
# Rotates the C-arm about the x-axis by 90 degrees
@@ -117,9 +127,9 @@ def read(
117127
**kwargs,
118128
)
119129

120-
# Canonicalize the images by converting to RAS+ and moving the
121-
# Subject's isocenter to the origin in world coordinates
122-
subject = canonicalize(subject)
130+
# Move the subject's isocenter to the origin in world coordinates
131+
if center_volume:
132+
subject = canonicalize(subject)
123133

124134
# Apply mask
125135
if labels is not None:

notebooks/api/03_data.ipynb

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,18 @@
108108
"outputs": [],
109109
"source": [
110110
"#| export\n",
111+
"from diffdrr.pose import RigidTransform\n",
112+
"\n",
113+
"\n",
111114
"def read(\n",
112115
" volume: str | Path | ScalarImage, # CT volume\n",
113116
" labelmap: str | Path | LabelMap = None, # Labelmap for the CT volume\n",
114117
" labels: int | list = None, # Labels from the mask of structures to render\n",
115118
" orientation: str | None = \"AP\", # Frame-of-reference change\n",
116119
" bone_attenuation_multiplier: float = 1.0, # Scalar multiplier on density of high attenuation voxels\n",
117120
" fiducials: torch.Tensor = None, # 3D fiducials in world coordinates\n",
121+
" transform: RigidTransform = None, # RigidTransform to apply to the volume's affine\n",
122+
" center_volume: bool = True, # Move the volume's isocenter to the world origin\n",
118123
" **kwargs, # Any additional information to be stored in the torchio.Subject\n",
119124
") -> Subject:\n",
120125
" \"\"\"\n",
@@ -128,10 +133,6 @@
128133
" else:\n",
129134
" volume = ScalarImage(volume)\n",
130135
"\n",
131-
" # Convert the volume to density\n",
132-
" density = transform_hu_to_density(volume.data, bone_attenuation_multiplier)\n",
133-
" density = ScalarImage(tensor=density, affine=volume.affine)\n",
134-
"\n",
135136
" # Read the mask if passed\n",
136137
" if labelmap is not None:\n",
137138
" if isinstance(labelmap, LabelMap):\n",
@@ -142,6 +143,15 @@
142143
" else:\n",
143144
" mask = None\n",
144145
"\n",
146+
" # Optionally apply transform\n",
147+
" if transform is not None:\n",
148+
" T = transform.matrix[0].numpy()\n",
149+
" volume = ScalarImage(tensor=volume.data, affine=T.dot(volume.affine))\n",
150+
" \n",
151+
" # Convert the volume to density\n",
152+
" density = transform_hu_to_density(volume.data, bone_attenuation_multiplier)\n",
153+
" density = ScalarImage(tensor=density, affine=volume.affine)\n",
154+
"\n",
145155
" # Frame-of-reference change\n",
146156
" if orientation == \"AP\":\n",
147157
" # Rotates the C-arm about the x-axis by 90 degrees\n",
@@ -188,9 +198,9 @@
188198
" **kwargs,\n",
189199
" )\n",
190200
"\n",
191-
" # Canonicalize the images by converting to RAS+ and moving the\n",
192-
" # Subject's isocenter to the origin in world coordinates\n",
193-
" subject = canonicalize(subject)\n",
201+
" # Move the subject's isocenter to the origin in world coordinates\n",
202+
" if center_volume:\n",
203+
" subject = canonicalize(subject)\n",
194204
"\n",
195205
" # Apply mask\n",
196206
" if labels is not None:\n",

0 commit comments

Comments
 (0)