Skip to main content

eventcv_core/representation/
point_set.rs

1use super::{event_index, Representation, RepresentationError};
2use crate::EventStream;
3
4#[derive(Clone, Copy, Debug, Default)]
5pub struct PointSet;
6
7#[derive(Clone, Debug, PartialEq)]
8pub struct EventPointSet {
9    data: Vec<f32>,
10    len: usize,
11}
12
13impl EventPointSet {
14    pub fn data(&self) -> &[f32] {
15        &self.data
16    }
17
18    pub fn shape(&self) -> (usize, usize) {
19        (self.len, 4)
20    }
21
22    pub fn columns(&self) -> (&'static str, &'static str, &'static str, &'static str) {
23        ("x", "y", "t", "p")
24    }
25}
26
27impl Representation for PointSet {
28    type Output = EventPointSet;
29
30    fn generate(&self, stream: &EventStream) -> Result<EventPointSet, RepresentationError> {
31        let (width, height) = stream.sensor_size();
32        let capacity = stream
33            .len()
34            .checked_mul(4)
35            .ok_or(RepresentationError::SizeOverflow)?;
36        let mut data = Vec::with_capacity(capacity);
37        let minimum_time = stream
38            .iter()
39            .map(|event| event.timestamp)
40            .min()
41            .unwrap_or(0);
42        let maximum_time = stream
43            .iter()
44            .map(|event| event.timestamp)
45            .max()
46            .unwrap_or(0);
47        let duration = maximum_time - minimum_time;
48
49        for event in stream.iter() {
50            event_index(event, width, height)?;
51            data.extend([
52                normalize_coordinate(event.x, width),
53                normalize_coordinate(event.y, height),
54                if duration == 0 {
55                    0.0
56                } else {
57                    (event.timestamp - minimum_time) as f32 / duration as f32
58                },
59                if event.polarity { 1.0 } else { -1.0 },
60            ]);
61        }
62
63        Ok(EventPointSet {
64            data,
65            len: stream.len(),
66        })
67    }
68}
69
70fn normalize_coordinate(coordinate: usize, length: usize) -> f32 {
71    if length <= 1 {
72        0.0
73    } else {
74        coordinate as f32 / (length - 1) as f32
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use ndarray::array;
81
82    use super::{PointSet, Representation};
83    use crate::EventStream;
84
85    #[test]
86    fn normalizes_points_without_reordering_events() {
87        let stream = EventStream::from_array2(
88            array![[1, 0, 30, 0], [0, 2, 10, 1], [1, 1, 20, 1]],
89            2,
90            3,
91            0.001,
92        );
93
94        let points = PointSet.generate(&stream).unwrap();
95
96        assert_eq!(points.shape(), (3, 4));
97        assert_eq!(
98            points.data(),
99            &[1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.5, 0.5, 1.0]
100        );
101    }
102
103    #[test]
104    fn zero_duration_streams_have_zero_normalized_time() {
105        let stream = EventStream::from_array2(array![[0, 0, 10, 1], [1, 0, 10, 0]], 2, 1, 0.001);
106
107        let points = PointSet.generate(&stream).unwrap();
108
109        assert_eq!(points.data()[2], 0.0);
110        assert_eq!(points.data()[6], 0.0);
111    }
112}