235 lines
8.5 KiB
Rust
235 lines
8.5 KiB
Rust
use anyhow::Result;
|
||
use log::{error, info, warn};
|
||
use std::sync::Arc;
|
||
use std::time::Duration;
|
||
use tokio::sync::mpsc::{self, Sender};
|
||
use tokio::time;
|
||
|
||
// 导入Camera模块组件
|
||
use meteor_detect::camera::{CameraController, CameraSettings, ExposureMode, Resolution, FrameBuffer, Frame};
|
||
use meteor_detect::config::Config;
|
||
|
||
/// 演示如何使用相机模块构建完整的流星检测系统
|
||
#[tokio::main]
|
||
async fn main() -> Result<()> {
|
||
// 初始化日志
|
||
env_logger::init();
|
||
|
||
// 1. 创建和初始化相机
|
||
let config = create_detector_config();
|
||
let mut camera = CameraController::new(&config).await?;
|
||
|
||
info!("初始化相机系统");
|
||
camera.initialize().await?;
|
||
|
||
info!("启动相机捕获");
|
||
camera.start_capture().await?;
|
||
|
||
// 2. 获取帧缓冲器的引用(用于检测器访问)
|
||
let frame_buffer = camera.get_frame_buffer();
|
||
|
||
// 3. 创建通信通道
|
||
// 用于从检测器向主程序发送事件
|
||
let (event_tx, mut event_rx) = mpsc::channel(10);
|
||
|
||
// 用于从健康监控向主程序发送健康状态
|
||
let (health_tx, mut health_rx) = mpsc::channel(10);
|
||
|
||
// 4. 启动检测器任务,从缓冲区读取帧进行处理
|
||
start_detector_task(frame_buffer.clone(), event_tx).await;
|
||
|
||
// 5. 启动健康监控任务 - 只发送健康状态,而不是直接操作相机
|
||
start_health_monitor_task(health_tx).await;
|
||
|
||
// 6. 主线程处理检测事件和健康状态
|
||
info!("等待检测事件...");
|
||
let mut saved_events = 0;
|
||
|
||
// 创建轮询健康状态的定时器
|
||
let mut health_interval = time::interval(Duration::from_secs(30));
|
||
|
||
loop {
|
||
tokio::select! {
|
||
// 处理检测事件
|
||
Some(event) = event_rx.recv() => {
|
||
info!("收到流星检测事件: 时间={}, 置信度={:.2}",
|
||
event.timestamp, event.confidence);
|
||
|
||
// 保存事件视频
|
||
match camera.save_meteor_event(
|
||
event.timestamp,
|
||
event.confidence,
|
||
event.bounding_box,
|
||
5, // 事件前5秒
|
||
3, // 事件后3秒
|
||
).await {
|
||
Ok(saved_event) => {
|
||
info!("已保存流星事件视频: {}", saved_event.video_path);
|
||
saved_events += 1;
|
||
|
||
// 在这里可以添加额外处理,如上传到云存储、发送通知等
|
||
},
|
||
Err(e) => {
|
||
error!("保存流星事件失败: {}", e);
|
||
}
|
||
}
|
||
|
||
// 演示目的,保存3个事件后退出
|
||
if saved_events >= 3 {
|
||
info!("已保存足够的事件,退出处理循环");
|
||
break;
|
||
}
|
||
},
|
||
|
||
// 处理健康检查的时间间隔
|
||
_ = health_interval.tick() => {
|
||
// 直接在主线程中执行健康检查
|
||
match camera.check_health().await {
|
||
Ok(is_healthy) => {
|
||
if !is_healthy {
|
||
warn!("相机健康检查失败,可能需要干预");
|
||
} else {
|
||
info!("相机健康状态: 正常");
|
||
}
|
||
},
|
||
Err(e) => {
|
||
error!("健康检查失败: {}", e);
|
||
}
|
||
}
|
||
|
||
// 获取和记录相机状态
|
||
if let Ok(status) = camera.get_status().await {
|
||
info!("相机状态: {}", status);
|
||
}
|
||
},
|
||
|
||
// 接收健康监控发送的消息(演示目的,实际中可以根据需要处理)
|
||
Some(health_msg) = health_rx.recv() => {
|
||
info!("收到健康监控消息: {}", health_msg);
|
||
},
|
||
|
||
// 如果所有通道都已关闭,退出循环
|
||
else => break,
|
||
}
|
||
}
|
||
|
||
// 7. 清理资源
|
||
info!("停止相机捕获");
|
||
camera.stop_capture().await?;
|
||
|
||
info!("流星检测系统演示完成");
|
||
Ok(())
|
||
}
|
||
|
||
/// 启动检测器任务
|
||
async fn start_detector_task(frame_buffer: Arc<FrameBuffer>, event_tx: Sender<DetectionEvent>) {
|
||
tokio::spawn(async move {
|
||
info!("启动流星检测器");
|
||
let mut detection_count = 0;
|
||
let mut last_detection_time = chrono::Utc::now();
|
||
|
||
// 模拟检测循环
|
||
loop {
|
||
// 模拟帧分析(实际应用中会连续分析每一帧)
|
||
time::sleep(Duration::from_secs(2)).await;
|
||
|
||
// 从帧缓冲区获取最新帧
|
||
if let Some(frame) = frame_buffer.get(0) {
|
||
let now = chrono::Utc::now();
|
||
|
||
// 确保距离上次检测至少10秒(防止重复检测)
|
||
if (now - last_detection_time).num_seconds() >= 10 {
|
||
// 这里应该是实际的检测算法
|
||
// 为演示目的,我们随机生成一些检测结果
|
||
let detection_seed = rand::random::<f32>();
|
||
|
||
if detection_seed < 0.3 { // 30%的概率检测到流星
|
||
detection_count += 1;
|
||
last_detection_time = now;
|
||
|
||
info!("检测到流星 #{}", detection_count);
|
||
|
||
// 发送检测事件到主线程
|
||
let event = DetectionEvent {
|
||
timestamp: now,
|
||
confidence: 0.7 + (detection_seed * 0.3), // 0.7-1.0之间的置信度
|
||
bounding_box: (
|
||
(rand::random::<f32>() * 800.0) as u32, // x
|
||
(rand::random::<f32>() * 600.0) as u32, // y
|
||
(50.0 + rand::random::<f32>() * 100.0) as u32, // width
|
||
(50.0 + rand::random::<f32>() * 100.0) as u32, // height
|
||
),
|
||
};
|
||
|
||
if event_tx.send(event).await.is_err() {
|
||
warn!("无法发送检测事件,接收端可能已关闭");
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
warn!("无法获取帧,缓冲区可能为空");
|
||
time::sleep(Duration::from_millis(500)).await;
|
||
}
|
||
|
||
// 演示目的,5次检测后退出
|
||
if detection_count >= 5 {
|
||
info!("已达到预设检测次数,检测器退出");
|
||
break;
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
/// 启动健康监控任务
|
||
async fn start_health_monitor_task(health_tx: Sender<String>) {
|
||
tokio::spawn(async move {
|
||
info!("启动健康监控任务 (模拟)");
|
||
let mut interval = time::interval(Duration::from_secs(45));
|
||
|
||
// 简单模拟健康监控,不直接访问相机
|
||
// 在实际应用中,这可能会监控系统各个部分的状态
|
||
loop {
|
||
interval.tick().await;
|
||
|
||
// 发送简单的健康状态消息回主线程
|
||
// 这是一个简化的演示
|
||
if health_tx.send("系统运行正常".to_string()).await.is_err() {
|
||
warn!("无法发送健康状态,接收端可能已关闭");
|
||
break;
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
/// 创建用于检测系统的配置
|
||
fn create_detector_config() -> Config {
|
||
let camera_settings = CameraSettings {
|
||
device: "0".to_string(),
|
||
// 对于流星检测,建议使用更高分辨率
|
||
resolution: Resolution::HD1080p,
|
||
fps: 30,
|
||
// 对于夜间观测,手动曝光通常更好
|
||
exposure: ExposureMode::Manual(500000), // 500毫秒曝光
|
||
// 增加增益以提高低光灵敏度
|
||
gain: 200,
|
||
focus_locked: true,
|
||
};
|
||
|
||
Config {
|
||
camera: camera_settings,
|
||
// 其他配置字段,使用其默认值
|
||
..Default::default()
|
||
}
|
||
}
|
||
|
||
/// 流星检测事件
|
||
struct DetectionEvent {
|
||
/// 事件时间戳
|
||
timestamp: chrono::DateTime<chrono::Utc>,
|
||
/// 检测置信度 (0-1)
|
||
confidence: f32,
|
||
/// 边界框 (x, y, 宽度, 高度)
|
||
bounding_box: (u32, u32, u32, u32),
|
||
}
|