Initial commit
This commit is contained in:
200
docs/tutorials/robotics/camera-frustums.md
Normal file
200
docs/tutorials/robotics/camera-frustums.md
Normal file
@@ -0,0 +1,200 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user