Skip to content

Commit

Permalink
Derive pinhole camera geometry from DRR and pose
Browse files Browse the repository at this point in the history
  • Loading branch information
eigenvivek committed Dec 4, 2024
1 parent 30b5953 commit 8fecc98
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 1 deletion.
1 change: 1 addition & 0 deletions diffdrr/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@
'diffdrr.renderers._get_xyzs': ('api/renderers.html#_get_xyzs', 'diffdrr/renderers.py'),
'diffdrr.renderers.reduce': ('api/renderers.html#reduce', 'diffdrr/renderers.py')},
'diffdrr.utils': { 'diffdrr.utils.get_focal_length': ('api/utils.html#get_focal_length', 'diffdrr/utils.py'),
'diffdrr.utils.get_pinhole_camera': ('api/utils.html#get_pinhole_camera', 'diffdrr/utils.py'),
'diffdrr.utils.get_principal_point': ('api/utils.html#get_principal_point', 'diffdrr/utils.py'),
'diffdrr.utils.make_intrinsic_matrix': ('api/utils.html#make_intrinsic_matrix', 'diffdrr/utils.py'),
'diffdrr.utils.parse_intrinsic_matrix': ('api/utils.html#parse_intrinsic_matrix', 'diffdrr/utils.py'),
Expand Down
78 changes: 77 additions & 1 deletion diffdrr/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# AUTOGENERATED! DO NOT EDIT! File to edit: ../notebooks/api/07_utils.ipynb.

# %% auto 0
__all__ = ['get_focal_length', 'get_principal_point', 'parse_intrinsic_matrix', 'make_intrinsic_matrix', 'resample']
__all__ = ['get_focal_length', 'get_principal_point', 'parse_intrinsic_matrix', 'make_intrinsic_matrix', 'resample',
'get_pinhole_camera']

# %% ../notebooks/api/07_utils.ipynb 4
def get_focal_length(
Expand Down Expand Up @@ -110,3 +111,78 @@ def resample(
x = resize(x, (height, width))

return x

# %% ../notebooks/api/07_utils.ipynb 10
from kornia.geometry.calibration import solve_pnp_dlt
from kornia.geometry.camera.pinhole import PinholeCamera

from .drr import DRR
from .pose import RigidTransform


def get_pinhole_camera(drr: DRR, pose: RigidTransform) -> PinholeCamera:
# Move everything to CPU and use double precision
drr = drr.to(device="cpu", dtype=torch.float64)
pose = pose.to(device="cpu", dtype=torch.float64)

# Make the intrinsic matrix (in pixels)
fx = drr.detector.sdd / drr.detector.delx
fy = drr.detector.sdd / drr.detector.dely
u0 = drr.detector.x0 / drr.detector.delx + drr.detector.width / 2
v0 = drr.detector.y0 / drr.detector.dely + drr.detector.height / 2
intrinsics = torch.tensor(
[
[
[fx, 0.0, u0, 0.0],
[0.0, fy, v0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
]
],
dtype=torch.float64,
)

# Get matching 3D and 2D points for PnP
(xmin, xmax), (ymin, ymax), (zmin, zmax) = drr.subject.volume.get_bounds()
X = torch.tensor(
[
[
[xmin, ymin, zmin],
[xmax, ymin, zmin],
[xmin, ymax, zmin],
[xmax, ymax, zmin],
[xmin, ymin, zmax],
[xmax, ymin, zmax],
[xmin, ymax, zmax],
[xmax, ymax, zmax],
]
],
dtype=torch.float64,
)
x = drr.perspective_projection(pose, X)

# Solve for the extrinsic matrix with PnP
extrinsics = torch.eye(4, dtype=torch.float64)[None]
extrinsics[:, :3, :] = solve_pnp_dlt(X, x, intrinsics[..., :3, :3])

# Make the pinhole camera, converted back to single precision
camera = PinholeCamera(
intrinsics.to(torch.float32),
extrinsics.to(torch.float32),
torch.tensor([drr.detector.height]),
torch.tensor([drr.detector.width]),
)

# Append the necessary intrinsics
camera.f = drr.detector.sdd
camera.delx = drr.detector.delx
camera.dely = drr.detector.dely
camera.x0 = drr.detector.x0
camera.y0 = drr.detector.y0

# Define a function to get the camera center
camera.center = (
lambda: -camera.extrinsics[0, :3, :3].T @ camera.extrinsics[0, :3, 3]
)

return camera
93 changes: 93 additions & 0 deletions notebooks/api/07_utils.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,99 @@
" return x"
]
},
{
"cell_type": "markdown",
"id": "ea840862-1443-4ecd-8c76-f64aefa6feae",
"metadata": {},
"source": [
"## Pinhole camera's\n",
"\n",
"Convert the intrinsic and extrinsic geometries, as implemented in DiffDRR, to a standard pinhole camera."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "546d3c18-608a-45d2-9809-2914c74018c9",
"metadata": {},
"outputs": [],
"source": [
"#| export\n",
"from kornia.geometry.calibration import solve_pnp_dlt\n",
"from kornia.geometry.camera.pinhole import PinholeCamera\n",
"\n",
"from diffdrr.drr import DRR\n",
"from diffdrr.pose import RigidTransform\n",
"\n",
"\n",
"def get_pinhole_camera(drr: DRR, pose: RigidTransform) -> PinholeCamera:\n",
" # Move everything to CPU and use double precision\n",
" drr = drr.to(device=\"cpu\", dtype=torch.float64)\n",
" pose = pose.to(device=\"cpu\", dtype=torch.float64)\n",
"\n",
" # Make the intrinsic matrix (in pixels)\n",
" fx = drr.detector.sdd / drr.detector.delx\n",
" fy = drr.detector.sdd / drr.detector.dely\n",
" u0 = drr.detector.x0 / drr.detector.delx + drr.detector.width / 2\n",
" v0 = drr.detector.y0 / drr.detector.dely + drr.detector.height / 2\n",
" intrinsics = torch.tensor(\n",
" [\n",
" [\n",
" [fx, 0.0, u0, 0.0],\n",
" [0.0, fy, v0, 0.0],\n",
" [0.0, 0.0, 1.0, 0.0],\n",
" [0.0, 0.0, 0.0, 1.0],\n",
" ]\n",
" ],\n",
" dtype=torch.float64,\n",
" )\n",
"\n",
" # Get matching 3D and 2D points for PnP\n",
" (xmin, xmax), (ymin, ymax), (zmin, zmax) = drr.subject.volume.get_bounds()\n",
" X = torch.tensor(\n",
" [\n",
" [\n",
" [xmin, ymin, zmin],\n",
" [xmax, ymin, zmin],\n",
" [xmin, ymax, zmin],\n",
" [xmax, ymax, zmin],\n",
" [xmin, ymin, zmax],\n",
" [xmax, ymin, zmax],\n",
" [xmin, ymax, zmax],\n",
" [xmax, ymax, zmax],\n",
" ]\n",
" ],\n",
" dtype=torch.float64,\n",
" )\n",
" x = drr.perspective_projection(pose, X)\n",
"\n",
" # Solve for the extrinsic matrix with PnP\n",
" extrinsics = torch.eye(4, dtype=torch.float64)[None]\n",
" extrinsics[:, :3, :] = solve_pnp_dlt(X, x, intrinsics[..., :3, :3])\n",
"\n",
" # Make the pinhole camera, converted back to single precision\n",
" camera = PinholeCamera(\n",
" intrinsics.to(torch.float32),\n",
" extrinsics.to(torch.float32),\n",
" torch.tensor([drr.detector.height]),\n",
" torch.tensor([drr.detector.width]),\n",
" )\n",
"\n",
" # Append the necessary intrinsics\n",
" camera.f = drr.detector.sdd\n",
" camera.delx = drr.detector.delx\n",
" camera.dely = drr.detector.dely\n",
" camera.x0 = drr.detector.x0\n",
" camera.y0 = drr.detector.y0\n",
"\n",
" # Define a function to get the camera center\n",
" camera.center = (\n",
" lambda: -camera.extrinsics[0, :3, :3].T @ camera.extrinsics[0, :3, 3]\n",
" )\n",
"\n",
" return camera"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand Down

0 comments on commit 8fecc98

Please # to comment.