Skip to content

Scene

Optional dependencies

To use this module, install the optional dependency nanodrr[scene].

nanodrr.scene

visualize_scene

visualize_scene(
    subject: Subject,
    k_inv: Float[Tensor, "B 3 3"],
    rt_inv: Float[Tensor, "B 4 4"],
    sdd: Float[Tensor, B],
    height: int,
    width: int,
    render_imgs: bool = True,
    single_channel: bool = False,
    culling: str | None = "back",
    verbose: bool = False,
    **kwargs
) -> Plotter

Render a DRR and return a 3D scene with camera frustums and anatomy.

PARAMETER DESCRIPTION
subject

The subject containing the CT volume and labelmap.

TYPE: Subject

k_inv

Inverse intrinsic matrices.

TYPE: Float[Tensor, 'B 3 3']

rt_inv

Camera-to-world transforms.

TYPE: Float[Tensor, 'B 4 4']

sdd

Source-to-detector distances.

TYPE: Float[Tensor, B]

height

Detector height in pixels.

TYPE: int

width

Detector width in pixels.

TYPE: int

render_imgs

If True, render DRRs before plotting

TYPE: bool DEFAULT: True

single_channel

If True, sum channels before texturing the detector.

TYPE: bool DEFAULT: False

culling

Face culling mode passed to each mesh (e.g. "back").

TYPE: str | None DEFAULT: 'back'

verbose

If True, print progress during mesh extraction.

TYPE: bool DEFAULT: False

**kwargs

Additional arguments forwarded to :func:render.

DEFAULT: {}

RETURNS DESCRIPTION
Plotter

A PyVista plotter with the anatomy mesh and camera frustums added.

Source code in src/nanodrr/scene/scene.py
def visualize_scene(
    subject: Subject,
    k_inv: Float[torch.Tensor, "B 3 3"],
    rt_inv: Float[torch.Tensor, "B 4 4"],
    sdd: Float[torch.Tensor, "B"],
    height: int,
    width: int,
    render_imgs: bool = True,
    single_channel: bool = False,
    culling: str | None = "back",
    verbose: bool = False,
    **kwargs,
) -> pv.Plotter:
    """Render a DRR and return a 3D scene with camera frustums and anatomy.

    Args:
        subject: The subject containing the CT volume and labelmap.
        k_inv: Inverse intrinsic matrices.
        rt_inv: Camera-to-world transforms.
        sdd: Source-to-detector distances.
        height: Detector height in pixels.
        width: Detector width in pixels.
        render_imgs: If True, render DRRs before plotting
        single_channel: If True, sum channels before texturing the detector.
        culling: Face culling mode passed to each mesh (e.g. `"back"`).
        verbose: If True, print progress during mesh extraction.
        **kwargs: Additional arguments forwarded to :func:`render`.

    Returns:
        A PyVista plotter with the anatomy mesh and camera frustums added.
    """
    # Get a mesh from the subject's labelmap
    mesh = label_to_mesh(subject, verbose)

    # Render the DRR
    img = None
    if render_imgs:
        img = render(subject, k_inv, rt_inv, sdd, height, width, **kwargs)
        img = img.sum(dim=1, keepdim=True) if single_channel else img

    # Make the cameras
    cameras = make_cameras(k_inv, rt_inv, sdd, height, width, img)

    # Make the scene
    pl = pv.Plotter()
    pl.add_mesh(mesh)
    for cam in cameras:
        if render_imgs:
            pl.add_mesh(cam["detector"], texture=cam["texture"], lighting=False, culling=culling)
        pl.add_mesh(cam["camera"], show_edges=True, line_width=3, culling=culling)
        pl.add_mesh(cam["principal_ray"], line_width=3, color="lime", culling=culling)
    return pl