eventcv_core/representation/
time_surface.rs1use super::{
2 age_ms, event_index, frame_len, reference_time, validate_positive, EventFrame, EventFrameData,
3 Representation, RepresentationError, RepresentationKind,
4};
5use crate::EventStream;
6
7#[derive(Clone, Copy, Debug)]
8pub struct TimeSurface {
9 tau_ms: f64,
10}
11
12impl TimeSurface {
13 pub fn new(tau_ms: f64) -> Self {
14 Self { tau_ms }
15 }
16}
17
18impl Default for TimeSurface {
19 fn default() -> Self {
20 Self::new(30.0)
21 }
22}
23
24impl Representation for TimeSurface {
25 type Output = EventFrame;
26
27 fn generate(&self, stream: &EventStream) -> Result<EventFrame, RepresentationError> {
28 validate_positive(self.tau_ms, "tau_ms")?;
29 let (width, height, length) = frame_len(stream, 2)?;
30 let plane_len = width * height;
31 let mut latest = vec![None; length];
32
33 for event in stream.iter() {
34 let index =
35 event_index(event, width, height)? + if event.polarity { 0 } else { plane_len };
36 if latest[index].is_none_or(|timestamp| event.timestamp > timestamp) {
37 latest[index] = Some(event.timestamp);
38 }
39 }
40
41 let mut values = vec![0_f32; length];
42 if let Some(reference) = reference_time(stream) {
43 for (value, timestamp) in values.iter_mut().zip(latest) {
44 if let Some(timestamp) = timestamp {
45 *value = (-age_ms(stream, reference, timestamp) / self.tau_ms).exp() as f32;
46 }
47 }
48 }
49
50 Ok(EventFrame {
51 data: EventFrameData::F32(values),
52 channels: 2,
53 width,
54 height,
55 kind: RepresentationKind::TimeSurface,
56 channel_names: vec!["positive".to_owned(), "negative".to_owned()],
57 })
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use ndarray::array;
64
65 use super::{Representation, TimeSurface};
66 use crate::{representation::EventFrameData, EventStream};
67
68 #[test]
69 fn uses_latest_event_per_pixel_and_polarity() {
70 let stream = EventStream::from_array2(
71 array![[0, 0, 30_000, 1], [1, 0, 20_000, 0], [0, 0, 10_000, 1]],
72 2,
73 1,
74 0.001,
75 );
76
77 let frame = TimeSurface::new(10.0).generate(&stream).unwrap();
78 let EventFrameData::F32(values) = frame.data() else {
79 panic!("time surfaces must use float32 data");
80 };
81
82 assert_eq!(values[0], 1.0);
83 assert_eq!(values[1], 0.0);
84 assert!((values[3] - (-1.0_f32).exp()).abs() < 1e-6);
85 }
86}