201 lines
4.7 KiB
Markdown
201 lines
4.7 KiB
Markdown
# 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
|
||
|
||
```python
|
||
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:
|
||
|
||
```python
|
||
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
|
||
|
||
```python
|
||
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:
|
||
|
||
```python
|
||
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
|