use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Detection {
pub timestamp: u64,
pub class_id: u32,
pub class_name: String,
pub confidence: f32,
pub bbox: BoundingBox,
#[serde(skip_serializing_if = "Option::is_none")]
pub track_id: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub position_3d: Option<[f32; 3]>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BoundingBox {
pub x: f32,
pub y: f32,
pub width: f32,
pub height: f32,
}
crate::impl_bounding_box!(BoundingBox, extras);
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Pose {
pub timestamp: u64,
pub position: [f32; 3],
pub orientation: [f32; 4],
#[serde(skip_serializing_if = "Option::is_none")]
pub frame_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub covariance: Option<Vec<f32>>,
}
impl Detection {
pub fn new(class_id: u32, class_name: String, confidence: f32, bbox: BoundingBox) -> Self {
Self {
timestamp: crate::prelude::now_micros(),
class_id,
class_name,
confidence,
bbox,
track_id: None,
position_3d: None,
}
}
pub fn is_confident(&self, threshold: f32) -> bool {
self.confidence >= threshold
}
pub fn center(&self) -> (f32, f32) {
self.bbox.center()
}
pub fn area(&self) -> f32 {
self.bbox.area()
}
}
impl Pose {
pub fn identity() -> Self {
Self {
timestamp: crate::prelude::now_micros(),
position: [0.0, 0.0, 0.0],
orientation: [0.0, 0.0, 0.0, 1.0],
frame_id: None,
covariance: None,
}
}
pub fn new_2d(x: f32, y: f32, yaw: f32) -> Self {
let half_yaw = yaw / 2.0;
let qz = half_yaw.sin();
let qw = half_yaw.cos();
Self {
timestamp: crate::prelude::now_micros(),
position: [x, y, 0.0],
orientation: [0.0, 0.0, qz, qw],
frame_id: None,
covariance: None,
}
}
pub fn distance_to(&self, other: &Pose) -> f32 {
super::geometry3::distance_3d(self.position, other.position)
}
pub fn distance_2d_to(&self, other: &Pose) -> f32 {
super::geometry3::distance_2d(self.position, other.position)
}
pub fn normalize_orientation(&mut self) {
super::geometry3::normalize_quaternion(&mut self.orientation);
}
}
impl Default for Pose {
fn default() -> Self {
Self::identity()
}
}
impl TrackingResult {
pub fn new(track_id: u32, detection: Detection) -> Self {
Self {
timestamp: crate::prelude::now_micros(),
track_id,
detection,
velocity_2d: None,
age: 0,
time_since_update: 0,
confidence: 1.0,
}
}
pub fn is_active(&self) -> bool {
self.time_since_update == 0
}
pub fn speed(&self) -> Option<f32> {
self.velocity_2d.map(|v| (v[0] * v[0] + v[1] * v[1]).sqrt())
}
pub fn is_confident(&self, threshold: f32) -> bool {
self.confidence >= threshold
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrackingResult {
pub timestamp: u64,
pub track_id: u32,
pub detection: Detection,
#[serde(skip_serializing_if = "Option::is_none")]
pub velocity_2d: Option<[f32; 2]>,
pub age: u32,
pub time_since_update: u32,
pub confidence: f32,
}