eventcv_core/representation/
polarity.rs1use super::{
2 event_index, frame_len, EventFrame, EventFrameData, Representation, RepresentationError,
3 RepresentationKind,
4};
5use crate::EventStream;
6
7#[derive(Clone, Copy, Debug, Default)]
8pub struct Polarity {
9 normalize: bool,
10}
11
12impl Polarity {
13 pub fn new(normalize: bool) -> Self {
14 Self { normalize }
15 }
16
17 pub fn is_normalized(&self) -> bool {
18 self.normalize
19 }
20}
21
22impl Representation for Polarity {
23 type Output = EventFrame;
24
25 fn generate(&self, stream: &EventStream) -> Result<EventFrame, RepresentationError> {
26 let (width, height, frame_len) = frame_len(stream, 2)?;
27 let plane_len = width * height;
28 let mut counts = vec![0_u64; frame_len];
31
32 for event in stream.iter() {
33 let index = event_index(event, width, height)?;
34 let channel_offset = if event.polarity { 0 } else { plane_len };
35 counts[channel_offset + index] += 1;
36 }
37
38 let data = if self.normalize {
39 EventFrameData::U8(normalize_u8(counts))
40 } else {
41 EventFrameData::U64(counts)
42 };
43
44 Ok(EventFrame {
45 data,
46 channels: 2,
47 width,
48 height,
49 kind: RepresentationKind::Polarity,
50 channel_names: vec!["positive".to_owned(), "negative".to_owned()],
51 })
52 }
53}
54
55fn normalize_u8(counts: Vec<u64>) -> Vec<u8> {
56 let maximum = counts.iter().copied().max().unwrap_or(0);
57 if maximum == 0 {
58 return vec![0; counts.len()];
59 }
60
61 counts
62 .into_iter()
63 .map(|count| {
64 let scaled = count * u64::from(u8::MAX);
65 ((scaled + maximum / 2) / maximum) as u8
66 })
67 .collect()
68}
69
70#[cfg(test)]
71mod tests {
72 use ndarray::array;
73
74 use super::{Polarity, Representation};
75 use crate::{representation::EventFrameData, EventStream};
76
77 #[test]
78 fn accumulates_and_normalizes_polarities() {
79 let stream = EventStream::from_array2(
80 array![[0, 0, 10, 1], [0, 0, 11, 1], [1, 0, 12, 0]],
81 2,
82 1,
83 0.001,
84 );
85
86 let raw = Polarity::default().generate(&stream).unwrap();
87 let normalized = Polarity::new(true).generate(&stream).unwrap();
88
89 assert_eq!(raw.data(), &EventFrameData::U64(vec![2, 0, 0, 1]));
90 assert_eq!(normalized.data(), &EventFrameData::U8(vec![255, 0, 0, 128]));
91 }
92
93 #[test]
94 fn rejects_out_of_bounds_events() {
95 let stream = EventStream::from_array2(array![[2, 0, 10, 1]], 2, 2, 0.001);
96
97 let error = Polarity::default().generate(&stream).unwrap_err();
98
99 assert_eq!(
100 error.to_string(),
101 "event coordinate (2, 0) exceeds sensor size 2x2"
102 );
103 }
104
105 #[test]
106 fn counts_above_uint16_are_preserved() {
107 let event_count = usize::from(u16::MAX) + 1; let stream = EventStream::from_array2(
109 ndarray::Array2::from_shape_fn((event_count, 4), |(index, column)| match column {
110 2 => index as u64,
111 3 => 1,
112 _ => 0,
113 }),
114 1,
115 1,
116 0.001,
117 );
118
119 let raw = Polarity::default().generate(&stream).unwrap();
120
121 assert_eq!(
122 raw.data(),
123 &EventFrameData::U64(vec![event_count as u64, 0])
124 );
125 }
126}