Files
2025-11-30 09:05:02 +08:00

4.7 KiB
Raw Permalink Blame History

Camera Frustums in Robotics Visualization

Overview

Camera frustums are essential for visualizing camera viewpoints in robotics applications. Vuer allows you to programmatically insert camera frustums into the scene to represent camera positions and orientations.

Basic Frustum

from vuer import Vuer
from vuer.schemas import Scene, Frustum, DefaultScene
import asyncio

app = Vuer()

@app.spawn(start=True)
async def main(session):
    session.set @ Scene(
        DefaultScene(),

        Frustum(
            position=[0, 1, 2],
            rotation=[0, 0, 0],
            scale=[1, 1, 1],
            showImagePlane=True,
            showFrustum=True,
            showFocalPlane=True,
            key="camera-frustum",
        ),
    )

    while True:
        await asyncio.sleep(1.0)

app.run()

Frustum Configuration Options

showImagePlane

Display the image plane (where the image is captured).

showFrustum

Show the frustum wireframe (pyramid shape representing the camera's field of view).

showFocalPlane

Display the focal plane (plane at the focal length).

Position and Orientation

  • position: [x, y, z] coordinates
  • rotation: Euler angles [x, y, z] in radians
  • scale: [x, y, z] scale factors

Stress Test Example: 1,728 Frustums

The tutorial demonstrates a stress-test implementation with a large grid of frustums:

from vuer import Vuer, VuerSession
from vuer.schemas import Scene, Frustum, DefaultScene
import asyncio

app = Vuer()

@app.spawn(start=True)
async def main(session: VuerSession):
    frustums = []

    # Create 12×12×12 grid of frustums
    for x in range(12):
        for y in range(12):
            for z in range(12):
                frustums.append(
                    Frustum(
                        position=[x * 2, y * 2, z * 2],
                        scale=[0.5, 0.5, 0.5],
                        showImagePlane=True,
                        showFrustum=True,
                        showFocalPlane=False,
                        key=f"frustum-{x}-{y}-{z}",
                    )
                )

    session.set @ Scene(
        DefaultScene(),
        *frustums,  # Unpack all frustums into the scene
    )

    while True:
        await asyncio.sleep(1.0)

app.run()

This creates 1,728 frustum objects (12³), demonstrating the framework's capability to handle large numbers of camera visualization objects simultaneously.

Practical Use Case: Multi-Camera Robot

from vuer import Vuer
from vuer.schemas import Scene, Frustum, Urdf, DefaultScene
import asyncio

app = Vuer()

@app.spawn(start=True)
async def main(session):
    session.set @ Scene(
        DefaultScene(),

        # Robot model
        Urdf(
            src="/static/robot.urdf",
            position=[0, 0, 0],
            key="robot",
        ),

        # Front camera
        Frustum(
            position=[0.5, 0.5, 0],
            rotation=[0, 0, 0],
            scale=[0.3, 0.3, 0.3],
            showImagePlane=True,
            showFrustum=True,
            key="front-camera",
        ),

        # Left camera
        Frustum(
            position=[0, 0.5, 0.5],
            rotation=[0, -1.57, 0],
            scale=[0.3, 0.3, 0.3],
            showImagePlane=True,
            showFrustum=True,
            key="left-camera",
        ),

        # Right camera
        Frustum(
            position=[0, 0.5, -0.5],
            rotation=[0, 1.57, 0],
            scale=[0.3, 0.3, 0.3],
            showImagePlane=True,
            showFrustum=True,
            key="right-camera",
        ),
    )

    while True:
        await asyncio.sleep(1.0)

app.run()

Dynamic Frustum Updates

You can update frustum positions in real-time:

import math

@app.spawn(start=True)
async def main(session):
    session.set @ Scene(DefaultScene())

    for i in range(1000):
        # Orbit the frustum around the origin
        x = 3 * math.cos(i * 0.05)
        z = 3 * math.sin(i * 0.05)
        rotation_y = i * 0.05

        session.upsert @ Frustum(
            position=[x, 1, z],
            rotation=[0, rotation_y, 0],
            showImagePlane=True,
            showFrustum=True,
            key="orbiting-camera",
        )

        await asyncio.sleep(0.033)  # ~30 FPS

app.run()

Performance Considerations

The stress test with 1,728 frustums demonstrates that Vuer can handle:

  • Large numbers of visualization objects
  • Complex geometric primitives
  • Real-time rendering of camera representations

This makes it practical for robotics applications requiring:

  • Multi-camera system visualization
  • SLAM trajectory visualization
  • Sensor fusion displays
  • Camera calibration tools

Source

Documentation: https://docs.vuer.ai/en/latest/tutorials/robotics/frustums.html