154 lines
4.9 KiB
Rust
154 lines
4.9 KiB
Rust
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<Utc>,
|
|
pub index: u64,
|
|
}
|
|
|
|
impl Frame {
|
|
pub fn new(image: core::Mat, timestamp: DateTime<Utc>, 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<Self, Box<dyn std::error::Error>> {
|
|
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<Self, Box<dyn std::error::Error>> {
|
|
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<Frame, Box<dyn std::error::Error>> {
|
|
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<dyn std::error::Error>> {
|
|
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::<i32>().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(())
|
|
}
|