4.7 KiB
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