Skip to main content

mecha10_controllers/
camera.rs

1//! Camera controller trait and types
2
3use crate::Controller;
4use async_trait::async_trait;
5use mecha10_core::sensor::{CameraInfo, DepthImage, RgbImage};
6use serde::{Deserialize, Serialize};
7
8/// Camera controller trait
9///
10/// Provides a unified interface for different camera types including:
11/// - RGB cameras (webcams, CSI cameras)
12/// - Depth cameras (RealSense, structured light)
13/// - RGBD cameras (RealSense D400 series)
14/// - Network cameras (RTSP streams)
15#[async_trait]
16pub trait CameraController: Controller {
17    /// Frame type produced by this camera
18    type Frame: Send + Sync;
19
20    /// Capture a single frame from the camera
21    ///
22    /// This will block until a frame is available or an error occurs.
23    async fn capture_frame(&mut self) -> Result<Self::Frame, Self::Error>;
24
25    /// Get camera intrinsics if available
26    ///
27    /// Returns calibration data including focal length, principal point,
28    /// and distortion coefficients. May return None if not calibrated.
29    fn intrinsics(&self) -> Option<CameraIntrinsics>;
30
31    /// Set camera parameters
32    ///
33    /// Adjust camera settings like exposure, gain, white balance, etc.
34    /// Not all parameters may be supported by all cameras.
35    async fn set_parameters(&mut self, params: CameraParameters) -> Result<(), Self::Error>;
36
37    /// Get current camera parameters
38    async fn get_parameters(&self) -> Result<CameraParameters, Self::Error>;
39
40    /// Get camera information
41    fn info(&self) -> CameraInfo;
42
43    /// Check if the camera supports depth
44    fn supports_depth(&self) -> bool {
45        self.capabilities().features.get("depth").copied().unwrap_or(false)
46    }
47
48    /// Check if the camera supports infrared
49    fn supports_infrared(&self) -> bool {
50        self.capabilities().features.get("infrared").copied().unwrap_or(false)
51    }
52}
53
54// ============================================================================
55// Camera Types
56// ============================================================================
57
58/// Camera frame types
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub enum CameraFrame {
61    /// RGB color image only
62    Rgb(RgbImage),
63
64    /// Depth image only
65    Depth(DepthImage),
66
67    /// Combined RGB + Depth (RGBD cameras)
68    Rgbd {
69        color: RgbImage,
70        depth: DepthImage,
71        aligned: bool,
72    },
73
74    /// Infrared image
75    Infrared {
76        timestamp: u64,
77        frame_id: u64,
78        width: u32,
79        height: u32,
80        data: Vec<u8>,
81    },
82}
83
84/// Camera intrinsics (calibration parameters)
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct CameraIntrinsics {
87    /// Image width in pixels
88    pub width: u32,
89
90    /// Image height in pixels
91    pub height: u32,
92
93    /// Focal length in X (pixels)
94    pub fx: f64,
95
96    /// Focal length in Y (pixels)
97    pub fy: f64,
98
99    /// Principal point X (pixels)
100    pub cx: f64,
101
102    /// Principal point Y (pixels)
103    pub cy: f64,
104
105    /// Distortion coefficients [k1, k2, p1, p2, k3]
106    pub distortion: Vec<f64>,
107
108    /// Distortion model ("plumb_bob", "fisheye", etc.)
109    pub distortion_model: String,
110}
111
112impl Default for CameraIntrinsics {
113    fn default() -> Self {
114        Self {
115            width: 640,
116            height: 480,
117            fx: 500.0,
118            fy: 500.0,
119            cx: 320.0,
120            cy: 240.0,
121            distortion: vec![0.0; 5],
122            distortion_model: "plumb_bob".to_string(),
123        }
124    }
125}
126
127/// Camera parameters that can be adjusted
128#[derive(Debug, Clone, Default, Serialize, Deserialize)]
129pub struct CameraParameters {
130    /// Auto exposure enabled
131    pub auto_exposure: Option<bool>,
132
133    /// Exposure time in microseconds (if manual exposure)
134    pub exposure_us: Option<u32>,
135
136    /// Auto white balance enabled
137    pub auto_white_balance: Option<bool>,
138
139    /// White balance temperature in Kelvin (if manual)
140    pub white_balance_k: Option<u32>,
141
142    /// Gain (0.0 - 1.0)
143    pub gain: Option<f32>,
144
145    /// Brightness (0.0 - 1.0)
146    pub brightness: Option<f32>,
147
148    /// Contrast (0.0 - 1.0)
149    pub contrast: Option<f32>,
150
151    /// Saturation (0.0 - 1.0)
152    pub saturation: Option<f32>,
153
154    /// Sharpness (0.0 - 1.0)
155    pub sharpness: Option<f32>,
156
157    /// Gamma (0.0 - 1.0)
158    pub gamma: Option<f32>,
159
160    /// Frame rate (fps)
161    pub frame_rate: Option<u32>,
162
163    /// Enable depth post-processing filters (for depth cameras)
164    pub depth_filtering: Option<bool>,
165
166    /// Depth units in meters per unit
167    pub depth_scale: Option<f32>,
168}
169
170// ============================================================================
171// Helper Types
172// ============================================================================
173
174/// Camera streaming state
175#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
176pub enum CameraStreamState {
177    /// Camera is not streaming
178    Stopped,
179
180    /// Camera is streaming
181    Streaming,
182
183    /// Camera stream is paused
184    Paused,
185
186    /// Camera encountered an error
187    Error,
188}
189
190/// Camera resolution
191#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
192pub struct Resolution {
193    pub width: u32,
194    pub height: u32,
195}
196
197impl Resolution {
198    pub fn new(width: u32, height: u32) -> Self {
199        Self { width, height }
200    }
201
202    /// VGA resolution (640x480)
203    pub const VGA: Self = Self {
204        width: 640,
205        height: 480,
206    };
207
208    /// HD resolution (1280x720)
209    pub const HD: Self = Self {
210        width: 1280,
211        height: 720,
212    };
213
214    /// Full HD resolution (1920x1080)
215    pub const FULL_HD: Self = Self {
216        width: 1920,
217        height: 1080,
218    };
219
220    /// 4K resolution (3840x2160)
221    pub const UHD_4K: Self = Self {
222        width: 3840,
223        height: 2160,
224    };
225}
226
227/// Pixel format
228#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
229pub enum PixelFormat {
230    /// 8-bit RGB
231    Rgb8,
232
233    /// 8-bit RGBA
234    Rgba8,
235
236    /// 8-bit BGR
237    Bgr8,
238
239    /// 8-bit BGRA
240    Bgra8,
241
242    /// Grayscale 8-bit
243    Gray8,
244
245    /// Grayscale 16-bit
246    Gray16,
247
248    /// Motion JPEG
249    Mjpeg,
250
251    /// H.264
252    H264,
253
254    /// YUV 4:2:2
255    Yuyv,
256}