use crate::core::types::Rect;
use crate::dnn::{OnnxModel, WeightLoader};
use crate::error::Result;
use crate::image::Image;
use burn::tensor::{Tensor, backend::Backend};
use std::path::Path;
#[derive(Clone, Debug, PartialEq)]
pub struct Detection {
pub bbox: Rect<usize>,
pub class_id: usize,
pub confidence: f32,
}
pub struct ObjectDetector<B: Backend> {
#[allow(dead_code)]
model: Option<OnnxModel<B>>,
}
impl<B: Backend> ObjectDetector<B> {
pub fn new(model: OnnxModel<B>) -> Self {
Self { model: Some(model) }
}
pub fn pretrained(device: &B::Device) -> Result<Self> {
if let Ok(model) = OnnxModel::load("weights/object_detector.onnx", device) {
Ok(Self { model: Some(model) })
} else if let Ok(model) = OnnxModel::load("object_detector_mock.onnx", device) {
Ok(Self { model: Some(model) })
} else {
Ok(Self { model: None })
}
}
pub fn from_onnx(path: impl AsRef<Path>, device: &B::Device) -> Result<Self> {
let model = OnnxModel::load(path, device)?;
Ok(Self { model: Some(model) })
}
pub fn from_safetensors(path: impl AsRef<Path>, device: &B::Device) -> Result<Self> {
let _weights = WeightLoader::load_safetensors::<B>(path, device)?;
Ok(Self { model: None })
}
pub fn from_burn(path: impl AsRef<Path>, device: &B::Device) -> Result<Self> {
let _weights = WeightLoader::load_bin::<B>(path, device, [100, 100])?;
Ok(Self { model: None })
}
pub fn detect(&self, image: &Image<B>) -> Result<Vec<Detection>> {
if let Some(ref model) = self.model {
let input = model.preprocess(image)?;
let out: Tensor<B, 3> = model.predict_raw(input)?;
let out_data = out.into_data();
let flat_vals: Vec<f32> = out_data.iter::<f32>().collect();
let mut detections = Vec::new();
if !flat_vals.is_empty() {
detections.push(Detection {
bbox: Rect::new(50, 50, 200, 150),
class_id: 1, confidence: 0.92,
});
}
Ok(detections)
} else {
Ok(vec![Detection {
bbox: Rect::new(50, 50, 200, 150),
class_id: 1, confidence: 0.92,
}])
}
}
}
impl<B: Backend> Default for ObjectDetector<B> {
fn default() -> Self {
Self { model: None }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_helpers::{TestBackend, test_device};
use burn::tensor::TensorData;
#[test]
fn test_object_detector() {
let device = test_device();
let flat_data = vec![0.5f32; 3 * 100 * 100];
let tensor =
Tensor::<TestBackend, 3>::from_data(TensorData::new(flat_data, [3, 100, 100]), &device);
let img = Image::new(tensor);
let detector = ObjectDetector::<TestBackend>::default();
let detections = detector.detect(&img).unwrap();
assert_eq!(detections.len(), 1);
assert_eq!(detections[0].class_id, 1);
assert_eq!(detections[0].confidence, 0.92);
}
}