use std::io; use std::path::PathBuf; use std::str::FromStr; use chrono::{Utc, Local, DateTime, TimeZone, FixedOffset}; use chrono::format::Fixed::TimezoneOffset; use opencv::{core, imgcodecs, imgproc, highgui, prelude::*}; // Simplified camera module for demo mod camera { use opencv::{core, prelude::*, videoio}; use chrono::{DateTime, Utc}; pub struct Frame { pub image: core::Mat, pub timestamp: DateTime, pub index: u64, } impl Frame { pub fn new(image: core::Mat, timestamp: DateTime, index: u64) -> Self { Self { image, timestamp, index } } } pub struct CameraDemo { capture: videoio::VideoCapture, frame_count: u64, } impl CameraDemo { pub fn new(device_id: i32) -> Result> { let capture = videoio::VideoCapture::new(device_id, videoio::CAP_ANY)?; if !capture.is_opened()? { return Err(format!("Failed to open camera device {}", device_id).into()); } Ok(Self { capture, frame_count: 0, }) } pub fn from_file(path: &str) -> Result> { let capture = videoio::VideoCapture::from_file(path, videoio::CAP_ANY)?; if !capture.is_opened()? { return Err(format!("Failed to open video file {}", path).into()); } Ok(Self { capture, frame_count: 0, }) } pub fn capture_frame(&mut self) -> Result> { let mut frame = core::Mat::default(); if self.capture.read(&mut frame)? { if frame.empty() { return Err("Captured frame is empty".into()); } let timestamp = Utc::now(); let index = self.frame_count; self.frame_count += 1; Ok(Frame::new(frame, timestamp, index)) } else { Err("Failed to capture frame".into()) } } } } fn main() -> Result<(), Box> { println!("*** Camera Module Demo ***"); println!("This demo captures frames from a camera device or video file and displays them"); println!("Press 'q' to quit"); println!(); println!("Choose input source:"); println!("1. Camera device"); println!("2. Video file"); let mut choice = String::new(); io::stdin().read_line(&mut choice)?; let mut camera_demo = match choice.trim() { "1" => { println!("Enter camera device ID (default is 0):"); let mut device_id = String::new(); io::stdin().read_line(&mut device_id)?; let device_id = device_id.trim().parse::().unwrap_or(0); println!("Opening camera device {}", device_id); camera::CameraDemo::new(device_id)? }, "2" => { println!("Enter video file path:"); let mut file_path = String::new(); io::stdin().read_line(&mut file_path)?; let file_path = file_path.trim(); println!("Opening video file: {}", file_path); camera::CameraDemo::from_file(file_path)? }, _ => { println!("Invalid choice, using default camera (device 0)"); camera::CameraDemo::new(0)? } }; highgui::named_window("Camera Module Demo", highgui::WINDOW_NORMAL)?; loop { match camera_demo.capture_frame() { Ok(frame) => { // Add timestamp to the frame let mut display_frame = frame.image.clone(); // Convert UTC timestamp to local time let local_timestamp = frame.timestamp.with_timezone(&Local); let timestamp_text = local_timestamp.format("%Y-%m-%d %H:%M:%S%.3f").to_string(); imgproc::put_text( &mut display_frame, ×tamp_text, core::Point::new(10, 30), imgproc::FONT_HERSHEY_SIMPLEX, 1.0, core::Scalar::new(0.0, 255.0, 0.0, 0.0), 2, imgproc::LINE_AA, false, )?; // Display the frame highgui::imshow("Camera Module Demo", &display_frame)?; // Break the loop if 'q' is pressed if highgui::wait_key(30)? == 'q' as i32 { break; } }, Err(e) => { println!("Error capturing frame: {}", e); break; } } } highgui::destroy_all_windows()?; Ok(()) }