|
8 | 8 | from torch.nn.functional import normalize
|
9 | 9 |
|
10 | 10 | # %% auto 0
|
11 |
| -__all__ = ['Detector'] |
| 11 | +__all__ = ['Detector', 'get_focal_length', 'get_principal_point', 'parse_intrinsic_matrix', 'make_intrinsic_matrix'] |
12 | 12 |
|
13 | 13 | # %% ../notebooks/api/02_detector.ipynb 5
|
14 | 14 | from .pose import RigidTransform
|
15 |
| -from .utils import make_intrinsic_matrix |
16 | 15 |
|
17 | 16 |
|
18 | 17 | class Detector(torch.nn.Module):
|
19 | 18 | """Construct a 6 DoF X-ray detector system. This model is based on a C-Arm."""
|
20 | 19 |
|
21 | 20 | def __init__(
|
22 | 21 | 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 |
31 | 30 | n_subsample: int | None = None, # Number of target points to randomly sample
|
32 | 31 | reverse_x_axis: bool = False, # If pose includes reflection (in E(3) not SE(3)), reverse x-axis
|
33 | 32 | ):
|
@@ -92,15 +91,7 @@ def calibration(self):
|
92 | 91 | @property
|
93 | 92 | def intrinsic(self):
|
94 | 93 | """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) |
104 | 95 |
|
105 | 96 | # %% ../notebooks/api/02_detector.ipynb 6
|
106 | 97 | @patch
|
@@ -157,3 +148,51 @@ def forward(self: Detector, extrinsic: RigidTransform, calibration: RigidTransfo
|
157 | 148 | source = pose(self.source)
|
158 | 149 | target = pose(target)
|
159 | 150 | 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 | + ) |
0 commit comments