cecile_supercool_tracker/
examples.rs

1pub mod iou;
2
3use crate::distance::euclidean;
4use crate::track::utils::FromVec;
5use crate::track::{
6    Feature, MetricOutput, MetricQuery, NoopLookup, Observation, ObservationAttributes,
7    ObservationMetric, ObservationsDb, TrackAttributes, TrackAttributesUpdate, TrackStatus,
8};
9use crate::utils::bbox::BoundingBox;
10use anyhow::Result;
11use rand::distributions::Uniform;
12use rand::prelude::ThreadRng;
13use rand::Rng;
14use std::time::{Duration, SystemTime, UNIX_EPOCH};
15use thiserror::Error;
16
17#[derive(Debug, Error)]
18pub enum AppError {
19    #[error("Only single feature vector can be set")]
20    SetError,
21    #[error("Incompatible attributes")]
22    Incompatible,
23}
24
25#[derive(Debug, Clone, Default)]
26pub struct SimpleAttrs {
27    set: bool,
28}
29
30#[derive(Default, Clone)]
31pub struct SimpleAttributeUpdate;
32
33impl TrackAttributesUpdate<SimpleAttrs> for SimpleAttributeUpdate {
34    fn apply(&self, attrs: &mut SimpleAttrs) -> Result<()> {
35        if attrs.set {
36            return Err(AppError::SetError.into());
37        }
38        attrs.set = true;
39        Ok(())
40    }
41}
42
43impl TrackAttributes<SimpleAttrs, f32> for SimpleAttrs {
44    type Update = SimpleAttributeUpdate;
45    type Lookup = NoopLookup<SimpleAttrs, f32>;
46
47    fn compatible(&self, other: &SimpleAttrs) -> bool {
48        self.set && other.set
49    }
50
51    fn merge(&mut self, other: &SimpleAttrs) -> Result<()> {
52        if self.compatible(other) {
53            Ok(())
54        } else {
55            Err(AppError::Incompatible.into())
56        }
57    }
58
59    fn baked(&self, _observations: &ObservationsDb<f32>) -> Result<TrackStatus> {
60        if self.set {
61            Ok(TrackStatus::Ready)
62        } else {
63            Ok(TrackStatus::Pending)
64        }
65    }
66}
67
68#[derive(Default, Clone)]
69pub struct SimpleMetric;
70
71impl ObservationMetric<SimpleAttrs, f32> for SimpleMetric {
72    fn metric(&self, mq: &MetricQuery<'_, SimpleAttrs, f32>) -> MetricOutput<f32> {
73        let (e1, e2) = (mq.candidate_observation, mq.track_observation);
74        Some((
75            f32::calculate_metric_object(&e1.attr().as_ref(), &e2.attr().as_ref()),
76            match (e1.feature().as_ref(), e2.feature().as_ref()) {
77                (Some(x), Some(y)) => Some(euclidean(x, y)),
78                _ => None,
79            },
80        ))
81    }
82
83    fn optimize(
84        &mut self,
85        _feature_class: u64,
86        _merge_history: &[u64],
87        _attrs: &mut SimpleAttrs,
88        _features: &mut Vec<Observation<f32>>,
89        _prev_length: usize,
90        _is_merge: bool,
91    ) -> Result<()> {
92        Ok(())
93    }
94}
95
96#[derive(Debug, Clone, Default)]
97pub struct UnboundAttrs;
98
99#[derive(Default, Clone)]
100pub struct UnboundAttributeUpdate;
101
102impl TrackAttributesUpdate<UnboundAttrs> for UnboundAttributeUpdate {
103    fn apply(&self, _attrs: &mut UnboundAttrs) -> Result<()> {
104        Ok(())
105    }
106}
107
108impl TrackAttributes<UnboundAttrs, f32> for UnboundAttrs {
109    type Update = UnboundAttributeUpdate;
110    type Lookup = NoopLookup<UnboundAttrs, f32>;
111
112    fn compatible(&self, _other: &UnboundAttrs) -> bool {
113        true
114    }
115
116    fn merge(&mut self, _other: &UnboundAttrs) -> Result<()> {
117        Ok(())
118    }
119
120    fn baked(&self, _observations: &ObservationsDb<f32>) -> Result<TrackStatus> {
121        Ok(TrackStatus::Ready)
122    }
123}
124
125#[derive(Default, Clone)]
126pub struct UnboundMetric;
127
128impl ObservationMetric<UnboundAttrs, f32> for UnboundMetric {
129    fn metric(&self, mq: &MetricQuery<'_, UnboundAttrs, f32>) -> MetricOutput<f32> {
130        let (e1, e2) = (mq.candidate_observation, mq.track_observation);
131        Some((
132            f32::calculate_metric_object(&e1.attr().as_ref(), &e2.attr().as_ref()),
133            match (e1.feature().as_ref(), e2.feature().as_ref()) {
134                (Some(x), Some(y)) => Some(euclidean(x, y)),
135                _ => None,
136            },
137        ))
138    }
139
140    fn optimize(
141        &mut self,
142        _feature_class: u64,
143        _merge_history: &[u64],
144        _attrs: &mut UnboundAttrs,
145        _features: &mut Vec<Observation<f32>>,
146        _prev_length: usize,
147        _is_merge: bool,
148    ) -> Result<()> {
149        Ok(())
150    }
151}
152
153pub fn vec2(x: f32, y: f32) -> Feature {
154    Feature::from_vec(vec![x, y])
155}
156
157pub struct FeatGen2 {
158    x: f32,
159    y: f32,
160    gen: ThreadRng,
161    dist: Uniform<f32>,
162}
163
164impl FeatGen2 {
165    pub fn new(x: f32, y: f32, drift: f32) -> Self {
166        Self {
167            x,
168            y,
169            gen: rand::thread_rng(),
170            dist: Uniform::new(-drift, drift),
171        }
172    }
173}
174
175impl Iterator for FeatGen2 {
176    type Item = Observation<f32>;
177
178    fn next(&mut self) -> Option<Self::Item> {
179        self.x += self.gen.sample(self.dist);
180        self.y += self.gen.sample(self.dist);
181        Some(Observation::new(
182            Some(self.gen.sample(self.dist) + 0.7),
183            Some(vec2(self.x, self.y)),
184        ))
185    }
186}
187
188pub struct BoxGen2 {
189    x: f32,
190    y: f32,
191    width: f32,
192    height: f32,
193    gen: ThreadRng,
194    dist_pos: Uniform<f32>,
195    dist_box: Uniform<f32>,
196}
197
198impl BoxGen2 {
199    pub fn new(x: f32, y: f32, width: f32, height: f32, pos_drift: f32, box_drift: f32) -> Self {
200        Self {
201            x,
202            y,
203            width,
204            height,
205            gen: rand::thread_rng(),
206            dist_pos: Uniform::new(-pos_drift, pos_drift),
207            dist_box: Uniform::new(-box_drift, box_drift),
208        }
209    }
210    pub fn new_monotonous(
211        x: f32,
212        y: f32,
213        width: f32,
214        height: f32,
215        pos_drift: f32,
216        box_drift: f32,
217    ) -> Self {
218        Self {
219            x,
220            y,
221            width,
222            height,
223            gen: rand::thread_rng(),
224            dist_pos: Uniform::new(0.0, pos_drift),
225            dist_box: Uniform::new(-box_drift, box_drift),
226        }
227    }
228}
229
230impl Iterator for BoxGen2 {
231    type Item = BoundingBox;
232
233    fn next(&mut self) -> Option<Self::Item> {
234        self.x += self.gen.sample(self.dist_pos);
235        self.y += self.gen.sample(self.dist_pos);
236
237        self.width += self.gen.sample(self.dist_box);
238        self.height += self.gen.sample(self.dist_box);
239
240        if self.width < 1.0 {
241            self.width = 1.0;
242        }
243        if self.height < 1.0 {
244            self.height = 1.0;
245        }
246
247        Some(BoundingBox::new(self.x, self.y, self.width, self.height))
248    }
249}
250
251#[inline]
252pub fn current_time_span() -> Duration {
253    SystemTime::now().duration_since(UNIX_EPOCH).unwrap()
254}
255
256#[inline]
257pub fn current_time_ms() -> u128 {
258    current_time_span().as_millis()
259}
260
261#[inline]
262pub fn current_time_sec() -> u64 {
263    current_time_span().as_secs()
264}
265
266pub struct FeatGen {
267    x: f32,
268    len: usize,
269    gen: ThreadRng,
270    dist: Uniform<f32>,
271}
272
273impl FeatGen {
274    pub fn new(x: f32, len: usize, drift: f32) -> Self {
275        Self {
276            x,
277            len,
278            gen: rand::thread_rng(),
279            dist: Uniform::new(-drift, drift),
280        }
281    }
282}
283
284impl Iterator for FeatGen {
285    type Item = Observation<()>;
286
287    fn next(&mut self) -> Option<Self::Item> {
288        let v = (0..self.len)
289            .map(|_| self.x + self.gen.sample(self.dist))
290            .collect::<Vec<_>>();
291        Some(Observation::<()>::new(None, Some(Feature::from_vec(v))))
292    }
293}