Skip to content

Commit e41c365

Browse files
authored
Improve docstrings (#356)
* Add a combined function to plot images and mask * Fix circular imports * Allow setting of reverse_x_axis and n_subsamples * Make a deepcopy of the DRR module * Expose the DRR's device and dtype * Make intrinsic matrix calculation more explicit * Simplify the Detector * Implement a custom PinholeCamera class * Add the projection matrix and pose
1 parent 6988bfd commit e41c365

File tree

9 files changed

+403
-277
lines changed

9 files changed

+403
-277
lines changed

diffdrr/_modidx.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,19 @@
2222
'diffdrr.detector.Detector.reorient': ('api/detector.html#detector.reorient', 'diffdrr/detector.py'),
2323
'diffdrr.detector.Detector.sdd': ('api/detector.html#detector.sdd', 'diffdrr/detector.py'),
2424
'diffdrr.detector.Detector.x0': ('api/detector.html#detector.x0', 'diffdrr/detector.py'),
25-
'diffdrr.detector.Detector.y0': ('api/detector.html#detector.y0', 'diffdrr/detector.py')},
25+
'diffdrr.detector.Detector.y0': ('api/detector.html#detector.y0', 'diffdrr/detector.py'),
26+
'diffdrr.detector.get_focal_length': ('api/detector.html#get_focal_length', 'diffdrr/detector.py'),
27+
'diffdrr.detector.get_principal_point': ('api/detector.html#get_principal_point', 'diffdrr/detector.py'),
28+
'diffdrr.detector.make_intrinsic_matrix': ( 'api/detector.html#make_intrinsic_matrix',
29+
'diffdrr/detector.py'),
30+
'diffdrr.detector.parse_intrinsic_matrix': ( 'api/detector.html#parse_intrinsic_matrix',
31+
'diffdrr/detector.py')},
2632
'diffdrr.drr': { 'diffdrr.drr.DRR': ('api/drr.html#drr', 'diffdrr/drr.py'),
2733
'diffdrr.drr.DRR.__init__': ('api/drr.html#drr.__init__', 'diffdrr/drr.py'),
2834
'diffdrr.drr.DRR.affine': ('api/drr.html#drr.affine', 'diffdrr/drr.py'),
2935
'diffdrr.drr.DRR.affine_inverse': ('api/drr.html#drr.affine_inverse', 'diffdrr/drr.py'),
36+
'diffdrr.drr.DRR.device': ('api/drr.html#drr.device', 'diffdrr/drr.py'),
37+
'diffdrr.drr.DRR.dtype': ('api/drr.html#drr.dtype', 'diffdrr/drr.py'),
3038
'diffdrr.drr.DRR.forward': ('api/drr.html#drr.forward', 'diffdrr/drr.py'),
3139
'diffdrr.drr.DRR.inverse_projection': ('api/drr.html#drr.inverse_projection', 'diffdrr/drr.py'),
3240
'diffdrr.drr.DRR.n_patches': ('api/drr.html#drr.n_patches', 'diffdrr/drr.py'),
@@ -167,11 +175,12 @@
167175
'diffdrr.renderers._get_voxel': ('api/renderers.html#_get_voxel', 'diffdrr/renderers.py'),
168176
'diffdrr.renderers._get_xyzs': ('api/renderers.html#_get_xyzs', 'diffdrr/renderers.py'),
169177
'diffdrr.renderers.reduce': ('api/renderers.html#reduce', 'diffdrr/renderers.py')},
170-
'diffdrr.utils': { 'diffdrr.utils.get_focal_length': ('api/utils.html#get_focal_length', 'diffdrr/utils.py'),
178+
'diffdrr.utils': { 'diffdrr.utils.PinholeCamera': ('api/utils.html#pinholecamera', 'diffdrr/utils.py'),
179+
'diffdrr.utils.PinholeCamera.__init__': ('api/utils.html#pinholecamera.__init__', 'diffdrr/utils.py'),
180+
'diffdrr.utils.PinholeCamera.center': ('api/utils.html#pinholecamera.center', 'diffdrr/utils.py'),
181+
'diffdrr.utils.PinholeCamera.pose': ('api/utils.html#pinholecamera.pose', 'diffdrr/utils.py'),
182+
'diffdrr.utils.PinholeCamera.projmat': ('api/utils.html#pinholecamera.projmat', 'diffdrr/utils.py'),
171183
'diffdrr.utils.get_pinhole_camera': ('api/utils.html#get_pinhole_camera', 'diffdrr/utils.py'),
172-
'diffdrr.utils.get_principal_point': ('api/utils.html#get_principal_point', 'diffdrr/utils.py'),
173-
'diffdrr.utils.make_intrinsic_matrix': ('api/utils.html#make_intrinsic_matrix', 'diffdrr/utils.py'),
174-
'diffdrr.utils.parse_intrinsic_matrix': ('api/utils.html#parse_intrinsic_matrix', 'diffdrr/utils.py'),
175184
'diffdrr.utils.resample': ('api/utils.html#resample', 'diffdrr/utils.py')},
176185
'diffdrr.visualization': { 'diffdrr.visualization._make_camera_frustum_mesh': ( 'api/visualization.html#_make_camera_frustum_mesh',
177186
'diffdrr/visualization.py'),
@@ -184,6 +193,8 @@
184193
'diffdrr.visualization.labelmap_to_mesh': ( 'api/visualization.html#labelmap_to_mesh',
185194
'diffdrr/visualization.py'),
186195
'diffdrr.visualization.plot_drr': ('api/visualization.html#plot_drr', 'diffdrr/visualization.py'),
196+
'diffdrr.visualization.plot_img_and_mask': ( 'api/visualization.html#plot_img_and_mask',
197+
'diffdrr/visualization.py'),
187198
'diffdrr.visualization.plot_mask': ('api/visualization.html#plot_mask', 'diffdrr/visualization.py'),
188199
'diffdrr.visualization.visualize_scene': ( 'api/visualization.html#visualize_scene',
189200
'diffdrr/visualization.py')}}}

diffdrr/detector.py

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,25 @@
88
from torch.nn.functional import normalize
99

1010
# %% auto 0
11-
__all__ = ['Detector']
11+
__all__ = ['Detector', 'get_focal_length', 'get_principal_point', 'parse_intrinsic_matrix', 'make_intrinsic_matrix']
1212

1313
# %% ../notebooks/api/02_detector.ipynb 5
1414
from .pose import RigidTransform
15-
from .utils import make_intrinsic_matrix
1615

1716

1817
class Detector(torch.nn.Module):
1918
"""Construct a 6 DoF X-ray detector system. This model is based on a C-Arm."""
2019

2120
def __init__(
2221
self,
23-
sdd: float, # Source-to-detector distance (i.e., focal length)
24-
height: int, # Height of the X-ray detector
25-
width: int, # Width of the X-ray detector
26-
delx: float, # Pixel spacing in the X-direction
27-
dely: float, # Pixel spacing in the Y-direction
28-
x0: float, # Principal point X-offset
29-
y0: float, # Principal point Y-offset
30-
reorient: torch.tensor, # Frame-of-reference change matrix
22+
sdd: float, # Source-to-detector distance (in units length)
23+
height: int, # Y-direction length (in units pixels)
24+
width: int, # X-direction length (in units pixels)
25+
delx: float, # X-direction spacing (in units length / pixel)
26+
dely: float, # Y-direction spacing (in units length / pixel)
27+
x0: float, # Principal point x-coordinate (in units length)
28+
y0: float, # Principal point y-coordinate (in units length)
29+
reorient: torch.Tensor, # Frame-of-reference change matrix
3130
n_subsample: int | None = None, # Number of target points to randomly sample
3231
reverse_x_axis: bool = False, # If pose includes reflection (in E(3) not SE(3)), reverse x-axis
3332
):
@@ -92,15 +91,7 @@ def calibration(self):
9291
@property
9392
def intrinsic(self):
9493
"""The 3x3 intrinsic matrix."""
95-
return make_intrinsic_matrix(
96-
self.sdd,
97-
self.delx,
98-
self.dely,
99-
self.width,
100-
self.height,
101-
self.y0,
102-
self.x0,
103-
).to(self.source)
94+
return make_intrinsic_matrix(self).to(self.source)
10495

10596
# %% ../notebooks/api/02_detector.ipynb 6
10697
@patch
@@ -157,3 +148,51 @@ def forward(self: Detector, extrinsic: RigidTransform, calibration: RigidTransfo
157148
source = pose(self.source)
158149
target = pose(target)
159150
return source, target
151+
152+
# %% ../notebooks/api/02_detector.ipynb 9
153+
def get_focal_length(
154+
intrinsic, # Intrinsic matrix (3 x 3 tensor)
155+
delx: float, # X-direction spacing (in units length)
156+
dely: float, # Y-direction spacing (in units length)
157+
) -> float: # Focal length (in units length)
158+
fx = intrinsic[0, 0]
159+
fy = intrinsic[1, 1]
160+
return abs((fx * delx) + (fy * dely)).item() / 2.0
161+
162+
# %% ../notebooks/api/02_detector.ipynb 10
163+
def get_principal_point(
164+
intrinsic, # Intrinsic matrix (3 x 3 tensor)
165+
height: int, # Y-direction length (in units pixels)
166+
width: int, # X-direction length (in units pixels)
167+
delx: float, # X-direction spacing (in units length)
168+
dely: float, # Y-direction spacing (in units length)
169+
):
170+
x0 = delx * (intrinsic[0, 2] - width / 2)
171+
y0 = dely * (intrinsic[1, 2] - height / 2)
172+
return x0.item(), y0.item()
173+
174+
# %% ../notebooks/api/02_detector.ipynb 11
175+
def parse_intrinsic_matrix(
176+
intrinsic, # Intrinsic matrix (3 x 3 tensor)
177+
height: int, # Y-direction length (in units pixels)
178+
width: int, # X-direction length (in units pixels)
179+
delx: float, # X-direction spacing (in units length)
180+
dely: float, # Y-direction spacing (in units length)
181+
):
182+
focal_length = get_focal_length(intrinsic, delx, dely)
183+
x0, y0 = get_principal_point(intrinsic, height, width, delx, dely)
184+
return focal_length, x0, y0
185+
186+
# %% ../notebooks/api/02_detector.ipynb 12
187+
def make_intrinsic_matrix(detector: Detector):
188+
fx = detector.sdd / detector.delx
189+
fy = detector.sdd / detector.dely
190+
u0 = detector.x0 / detector.delx + detector.width / 2
191+
v0 = detector.y0 / detector.dely + detector.height / 2
192+
return torch.tensor(
193+
[
194+
[fx, 0.0, u0],
195+
[0.0, fy, v0],
196+
[0.0, 0.0, 1.0],
197+
]
198+
)

diffdrr/drr.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,14 @@ def affine_inverse(self):
124124
def n_patches(self):
125125
return (self.detector.height * self.detector.width) // (self.patch_size**2)
126126

127+
@property
128+
def device(self):
129+
return self.density.device
130+
131+
@property
132+
def dtype(self):
133+
return self.density.dtype
134+
127135
# %% ../notebooks/api/00_drr.ipynb 8
128136
def reshape_subsampled_drr(img: torch.Tensor, detector: Detector, batch_size: int):
129137
n_points = detector.height * detector.width
@@ -212,6 +220,8 @@ def set_intrinsics_(
212220
dely: float = None,
213221
x0: float = None,
214222
y0: float = None,
223+
n_subsample: int = None,
224+
reverse_x_axis: bool = None,
215225
):
216226
"""Set new intrinsic parameters (inplace)."""
217227
self.detector = Detector(
@@ -222,9 +232,9 @@ def set_intrinsics_(
222232
dely if dely is not None else self.detector.dely,
223233
x0 if x0 is not None else self.detector.x0,
224234
y0 if y0 is not None else self.detector.y0,
225-
n_subsample=self.detector.n_subsample,
226-
reverse_x_axis=self.detector.reverse_x_axis,
227-
reorient=self.subject.reorient,
235+
self.subject.reorient,
236+
n_subsample if n_subsample is not None else self.detector.n_subsample,
237+
reverse_x_axis if reverse_x_axis is not None else self.detector.reverse_x_axis,
228238
).to(self.density)
229239

230240
# %% ../notebooks/api/00_drr.ipynb 12

0 commit comments

Comments
 (0)