adder_codec_core/
lib.rs

1#![warn(missing_docs)]
2
3//! # adder-codec-core
4//!
5//! The core types and utilities for encoding and decoding ADΔER events
6
7/// Expose public API for encoding and decoding
8pub mod codec;
9
10pub use bitstream_io;
11use bitstream_io::{BigEndian, BitReader};
12use std::cmp::Ordering;
13use std::fs::File;
14use std::io::BufReader;
15use std::ops::Add;
16
17use thiserror::Error;
18
19/// Error type for the `PlaneSize` struct
20#[allow(missing_docs)]
21#[derive(Error, Debug)]
22pub enum PlaneError {
23    #[error(
24        "plane dimensions invalid. All must be positive. Found {width:?}, {height:?}, {channels:?}"
25    )]
26    InvalidPlane {
27        width: u16,
28        height: u16,
29        channels: u8,
30    },
31}
32
33#[allow(missing_docs)]
34#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq)]
35pub enum SourceCamera {
36    #[default]
37    FramedU8,
38    FramedU16,
39    FramedU32,
40    FramedU64,
41    FramedF32,
42    FramedF64,
43    Dvs,
44    DavisU8,
45    Atis,
46    Asint,
47}
48
49/// Is the given source camera a framed source?
50pub fn is_framed(source_camera: SourceCamera) -> bool {
51    matches!(
52        source_camera,
53        SourceCamera::FramedU8
54            | SourceCamera::FramedU16
55            | SourceCamera::FramedU32
56            | SourceCamera::FramedU64
57            | SourceCamera::FramedF32
58            | SourceCamera::FramedF64
59    )
60}
61
62// #[cfg(feature = "compression")]
63// use crate::codec::compressed::blocks::{DeltaTResidual, EventResidual};
64#[cfg(feature = "compression")]
65use crate::codec::compressed::stream::CompressedInput;
66use crate::codec::decoder::Decoder;
67use crate::codec::raw::stream::RawInput;
68use crate::codec::CodecError;
69use serde::{Deserialize, Serialize};
70
71/// The type of time used in the ADΔER representation
72#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq)]
73pub enum TimeMode {
74    /// The time is the delta time from the previous event
75    DeltaT,
76
77    /// The time is the absolute time from the start of the recording
78    #[default]
79    AbsoluteT,
80
81    /// TODO
82    Mixed,
83}
84
85/// The size of the image plane in pixels
86#[derive(Clone, Copy, Debug, PartialEq)]
87pub struct PlaneSize {
88    width: u16,
89    height: u16,
90    channels: u8,
91}
92
93impl Default for PlaneSize {
94    fn default() -> Self {
95        PlaneSize {
96            width: 1,
97            height: 1,
98            channels: 1,
99        }
100    }
101}
102
103impl PlaneSize {
104    /// Create a new `PlaneSize` with the given width, height, and channels
105    pub fn new(width: u16, height: u16, channels: u8) -> Result<Self, PlaneError> {
106        if width == 0 || height == 0 || channels == 0 {
107            return Err(PlaneError::InvalidPlane {
108                width,
109                height,
110                channels,
111            });
112        }
113        Ok(Self {
114            width,
115            height,
116            channels,
117        })
118    }
119    /// The width, shorthand for `self.width`
120    pub fn w(&self) -> u16 {
121        self.width
122    }
123
124    /// The height, shorthand for `self.height`
125    pub fn w_usize(&self) -> usize {
126        self.width as usize
127    }
128
129    /// The height, shorthand for `self.height`
130    pub fn h(&self) -> u16 {
131        self.height
132    }
133
134    /// The height, shorthand for `self.height`
135    pub fn h_usize(&self) -> usize {
136        self.height as usize
137    }
138
139    /// The number of channels, shorthand for `self.channels`
140    pub fn c(&self) -> u8 {
141        self.channels
142    }
143
144    /// The number of channels, shorthand for `self.channels`
145    pub fn c_usize(&self) -> usize {
146        self.channels as usize
147    }
148
149    /// The total number of 2D pixels in the image plane, across the height and width dimension
150    pub fn area_wh(&self) -> usize {
151        self.width as usize * self.height as usize
152    }
153
154    /// The total number of 2D pixels in the image plane, across the width and channel dimension
155    pub fn area_wc(&self) -> usize {
156        self.width as usize * self.channels as usize
157    }
158
159    /// The total number of 2D pixels in the image plane, across the height and channel dimension
160    pub fn area_hc(&self) -> usize {
161        self.height as usize * self.channels as usize
162    }
163
164    /// The total number of 3D pixels in the image plane (2D pixels * color depth)
165    pub fn volume(&self) -> usize {
166        self.area_wh() * self.channels as usize
167    }
168
169    /// The smaller of the width and height dimensions
170    pub fn min_resolution(&self) -> u16 {
171        self.width.min(self.height)
172    }
173
174    /// The larger of the width and height dimensions
175    pub fn max_resolution(&self) -> u16 {
176        self.width.max(self.height)
177    }
178}
179
180/// Decimation value; a pixel's sensitivity.
181pub type D = u8;
182
183/// The maximum possible [`D`] value
184pub const D_MAX: D = 127;
185
186/// Special symbol signifying no information (filler dt)
187pub const D_EMPTY: D = 255;
188
189/// Special symbol signifying no information (filler dt)
190pub const D_ZERO_INTEGRATION: D = 128;
191
192/// Special symbol signifying no [`Event`] exists
193pub const D_NO_EVENT: D = 253;
194
195#[derive(Clone, Copy, PartialEq, Default, Debug)]
196pub enum Mode {
197    /// Preserve temporal coherence for framed inputs. When an event fires, the ticks
198    /// remaining for that input frame (and its associated intensity) are discarded. The
199    /// difference in time is implied since the number of ticks per input frame is constant.
200    #[default]
201    FramePerfect,
202
203    /// Do not do the above ^
204    Continuous,
205}
206
207#[derive(Clone, Copy, PartialEq, Default, Debug)]
208pub enum PixelMultiMode {
209    Normal,
210
211    #[default]
212    Collapse,
213}
214
215/// Precision for maximum intensity representable with allowed [`D`] values
216pub type UDshift = u128;
217
218use seq_macro::seq;
219
220macro_rules! make_d_shift_array {
221    ($name:ident, $type:ty) => {
222        seq!(N in 0..=128 {
223            /// Array for computing the intensity to integrate for a given [`D`] value
224            pub const $name: [$type; 129] = [
225                #(
226                    if N == 128 { 0 as $type } else { (1_u128 << N) as $type },
227                )*
228            ];
229        });
230    };
231}
232
233make_d_shift_array!(D_SHIFT, UDshift);
234make_d_shift_array!(D_SHIFT_F64, f64);
235make_d_shift_array!(D_SHIFT_F32, f32);
236
237/// The maximum intensity representation for input data. Currently 255 for 8-bit framed input.
238pub const MAX_INTENSITY: f32 = 255.0; // TODO: make variable, dependent on input bit depth
239
240/// The default [`D`] value for every pixel at the beginning of transcode
241pub const D_START: D = 7;
242
243/// Number of ticks elapsed since a given pixel last fired an [`Event`]
244pub type DeltaT = u32;
245
246/// Absolute firing time (in ticks) of an event. For a given pixel, this will always
247/// be grater than or equal to that of the pixel's last fired event.
248pub type AbsoluteT = u32;
249
250/// Large count of ticks (e.g., for tracking the running timestamp of a sequence of [Events](Event)
251pub type BigT = u64;
252
253/// Measure of an amount of light intensity
254pub type Intensity = f64;
255
256/// Pixel x- or y- coordinate address in the ADΔER model
257pub type PixelAddress = u16;
258
259/// Special pixel address when signifying the end of a sequence of [Events](Event)
260pub const EOF_PX_ADDRESS: PixelAddress = u16::MAX;
261
262/// Pixel channel address in the ADΔER model
263#[repr(packed)]
264#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
265pub struct Coord {
266    /// Pixel x-coordinate
267    pub x: PixelAddress,
268
269    /// Pixel y-coordinate
270    pub y: PixelAddress,
271
272    /// Pixel channel, if present
273    pub c: Option<u8>,
274}
275
276impl Default for Coord {
277    fn default() -> Self {
278        Self {
279            x: 0,
280            y: 0,
281            c: Some(0),
282        }
283    }
284}
285
286impl Coord {
287    /// Creates a new coordinate with the given x, y, and channel
288    pub fn new(x: PixelAddress, y: PixelAddress, c: Option<u8>) -> Self {
289        Self { x, y, c }
290    }
291
292    /// Creates a new 2D coordinate
293    pub fn new_2d(x: PixelAddress, y: PixelAddress) -> Self {
294        Self { x, y, c: None }
295    }
296
297    /// Creates a new 3D coordinate with the given channel
298    pub fn new_3d(x: PixelAddress, y: PixelAddress, c: u8) -> Self {
299        Self { x, y, c: Some(c) }
300    }
301
302    /// Returns the x coordinate as a [`PixelAddress`]
303    pub fn x(&self) -> PixelAddress {
304        self.x
305    }
306
307    /// Returns the y coordinate as a [`PixelAddress`]
308    pub fn y(&self) -> PixelAddress {
309        self.y
310    }
311
312    /// Returns the channel as an `Option<u8>`
313    pub fn c(&self) -> Option<u8> {
314        self.c
315    }
316
317    /// Returns the x coordinate as a `usize`
318    pub fn x_usize(&self) -> usize {
319        self.x as usize
320    }
321
322    /// Returns the y coordinate as a `usize`
323    pub fn y_usize(&self) -> usize {
324        self.y as usize
325    }
326
327    /// Returns the channel as a usize, or 0 if the coordinate is 2D
328    pub fn c_usize(&self) -> usize {
329        self.c.unwrap_or(0) as usize
330    }
331
332    /// Returns true if the coordinate is 2D
333    pub fn is_2d(&self) -> bool {
334        self.c.is_none()
335    }
336
337    /// Returns true if the coordinate is 3D
338    pub fn is_3d(&self) -> bool {
339        self.c.is_some()
340    }
341
342    /// Returns true if the coordinate is valid
343    pub fn is_valid(&self) -> bool {
344        self.x != EOF_PX_ADDRESS && self.y != EOF_PX_ADDRESS
345    }
346
347    /// Returns true if the coordinate is the EOF coordinate
348    pub fn is_eof(&self) -> bool {
349        self.x == EOF_PX_ADDRESS && self.y == EOF_PX_ADDRESS
350    }
351
352    /// Is this coordinate at the border of the image?
353    pub fn is_border(&self, width: usize, height: usize, cs: usize) -> bool {
354        self.x_usize() < cs
355            || self.x_usize() >= width - cs
356            || self.y_usize() < cs
357            || self.y_usize() >= height - cs
358    }
359}
360
361/// A 2D coordinate representation
362#[allow(missing_docs)]
363#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
364pub struct CoordSingle {
365    pub x: PixelAddress,
366    pub y: PixelAddress,
367}
368
369/// An ADΔER event representation
370#[allow(missing_docs)]
371#[repr(packed)]
372#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, Hash, Serialize, Deserialize)]
373pub struct Event {
374    pub coord: Coord,
375    pub d: D,
376    pub t: AbsoluteT,
377}
378
379#[allow(missing_docs)]
380#[repr(packed)]
381#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, Hash, Serialize, Deserialize)]
382pub struct EventRelative {
383    pub coord: Coord,
384    pub d: D,
385    pub delta_t: DeltaT,
386}
387
388/// An ADΔER event representation, without the channel component
389#[allow(missing_docs)]
390#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
391pub struct EventSingle {
392    pub coord: CoordSingle,
393    pub d: D,
394    pub t: DeltaT,
395}
396
397impl From<&Event> for EventSingle {
398    fn from(event: &Event) -> Self {
399        Self {
400            coord: CoordSingle {
401                x: event.coord.x,
402                y: event.coord.y,
403            },
404            d: event.d,
405            t: event.t,
406        }
407    }
408}
409
410impl From<EventSingle> for Event {
411    fn from(event: EventSingle) -> Self {
412        Self {
413            coord: Coord {
414                x: event.coord.x,
415                y: event.coord.y,
416                c: None,
417            },
418            d: event.d,
419            t: event.t,
420        }
421    }
422}
423
424impl Ord for Event {
425    fn cmp(&self, other: &Self) -> Ordering {
426        let b = other.t;
427        let a = self.t;
428        b.cmp(&a)
429    }
430}
431
432impl PartialOrd for Event {
433    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
434        Some(self.cmp(other))
435    }
436}
437
438/// The type of data source representation
439#[allow(missing_docs)]
440#[derive(Debug, Copy, Clone, PartialEq, Eq)]
441pub enum SourceType {
442    U8,
443    U16,
444    U32,
445    U64,
446    F32,
447    F64,
448}
449
450const EOF_EVENT: Event = Event {
451    coord: Coord {
452        x: EOF_PX_ADDRESS,
453        y: EOF_PX_ADDRESS,
454        c: Some(0),
455    },
456    d: 0,
457    t: 0,
458};
459
460/// Helper function for opening a file as a raw or compressed input ADΔER stream
461pub fn open_file_decoder(
462    file_path: &str,
463) -> Result<
464    (
465        Decoder<BufReader<File>>,
466        BitReader<BufReader<File>, BigEndian>,
467    ),
468    CodecError,
469> {
470    let mut bufreader = BufReader::new(File::open(file_path)?);
471    let compression = RawInput::new();
472    let mut bitreader = BitReader::endian(bufreader, BigEndian);
473
474    // First try opening the file as a raw file, then try as a compressed file
475    let stream = match Decoder::new_raw(compression, &mut bitreader) {
476        Ok(reader) => reader,
477        Err(CodecError::WrongMagic) => {
478            #[cfg(feature = "compression")]
479            {
480                dbg!("Opening as compressed");
481                bufreader = BufReader::new(File::open(file_path)?);
482                let compression = CompressedInput::new(0, 0, 0); // TODO: temporary args. Need to refactor.
483                bitreader = BitReader::endian(bufreader, BigEndian);
484                Decoder::new_compressed(compression, &mut bitreader)?
485            }
486
487            #[cfg(not(feature = "compression"))]
488            return Err(CodecError::WrongMagic);
489        }
490        Err(e) => {
491            return Err(e);
492        }
493    };
494    Ok((stream, bitreader))
495}
496
497/// An ADΔER event representation
498#[allow(missing_docs)]
499#[derive(Debug, Copy, Clone, Default, serde::Serialize, serde::Deserialize, PartialEq)]
500pub struct EventCoordless {
501    pub d: D,
502
503    pub t: AbsoluteT,
504}
505
506#[allow(missing_docs)]
507#[derive(Debug, Copy, Clone, Default, serde::Serialize, serde::Deserialize, PartialEq)]
508pub struct EventCoordlessRelative {
509    pub d: D,
510
511    pub delta_t: DeltaT,
512}
513
514impl From<EventCoordless> for f64 {
515    fn from(val: EventCoordless) -> Self {
516        panic!("Not implemented")
517    }
518}
519
520impl EventCoordless {
521    /// Get the t or dt value
522    #[inline(always)]
523    pub fn t(&self) -> AbsoluteT {
524        self.t as AbsoluteT
525    }
526}
527
528impl From<Event> for EventCoordless {
529    fn from(event: Event) -> Self {
530        Self {
531            d: event.d,
532            t: event.t,
533        }
534    }
535}
536
537impl Add<EventCoordless> for EventCoordless {
538    type Output = EventCoordless;
539
540    fn add(self, _rhs: EventCoordless) -> EventCoordless {
541        todo!()
542    }
543}
544
545impl num_traits::Zero for EventCoordless {
546    fn zero() -> Self {
547        EventCoordless { d: 0, t: 0 }
548    }
549
550    fn is_zero(&self) -> bool {
551        self.d.is_zero() && self.t.is_zero()
552    }
553}
554
555#[cfg(test)]
556mod tests {
557    use super::*;
558
559    #[test]
560    fn test_dshift_arrays() {
561        assert_eq!(D_SHIFT[0], 1);
562        assert_eq!(D_SHIFT_F64[0], 1.0);
563        assert_eq!(D_SHIFT_F32[0], 1.0);
564        assert_eq!(D_SHIFT.len(), 129);
565        assert_eq!(D_SHIFT_F64.len(), 129);
566        assert_eq!(D_SHIFT_F32.len(), 129);
567        assert_eq!(D_SHIFT[127], 1_u128 << 127);
568        assert_eq!(D_SHIFT_F64[127], D_SHIFT[127] as f64);
569        assert_eq!(D_SHIFT_F32[127], D_SHIFT[127] as f32);
570    }
571
572    #[test]
573    fn test_plane_size() {
574        let plane_size = PlaneSize::new(1, 1, 1).unwrap();
575        assert_eq!(plane_size.area_wh(), 1);
576        assert_eq!(plane_size.area_wc(), 1);
577        assert_eq!(plane_size.area_hc(), 1);
578        assert_eq!(plane_size.volume(), 1);
579
580        let plane_size = PlaneSize::new(2, 2, 1).unwrap();
581        assert_eq!(plane_size.area_wh(), 4);
582        assert_eq!(plane_size.area_wc(), 2);
583        assert_eq!(plane_size.area_hc(), 2);
584        assert_eq!(plane_size.volume(), 4);
585
586        let plane_size = PlaneSize::new(2, 2, 2).unwrap();
587        assert_eq!(plane_size.area_wh(), 4);
588        assert_eq!(plane_size.area_wc(), 4);
589        assert_eq!(plane_size.area_hc(), 4);
590        assert_eq!(plane_size.volume(), 8);
591    }
592
593    #[test]
594    fn test_coord() {
595        let coord = Coord::new(1, 2, Some(3));
596        assert_eq!(coord.x(), 1);
597        assert_eq!(coord.y(), 2);
598        assert_eq!(coord.c(), Some(3));
599        assert_eq!(coord.x_usize(), 1);
600        assert_eq!(coord.y_usize(), 2);
601        assert_eq!(coord.c_usize(), 3);
602        assert!(coord.is_3d());
603        assert!(!coord.is_2d());
604        assert!(coord.is_valid());
605        assert!(!coord.is_eof());
606
607        let coord = Coord::new(1, 2, None);
608        assert_eq!(coord.x(), 1);
609        assert_eq!(coord.y(), 2);
610        assert_eq!(coord.c(), None);
611        assert_eq!(coord.x_usize(), 1);
612        assert_eq!(coord.y_usize(), 2);
613        assert_eq!(coord.c_usize(), 0);
614        assert!(!coord.is_3d());
615        assert!(coord.is_2d());
616        assert!(coord.is_valid());
617        assert!(!coord.is_eof());
618
619        let coord = Coord::new(EOF_PX_ADDRESS, EOF_PX_ADDRESS, None);
620        assert_eq!(coord.x(), EOF_PX_ADDRESS);
621        assert_eq!(coord.y(), EOF_PX_ADDRESS);
622        assert_eq!(coord.c(), None);
623        assert_eq!(coord.x_usize(), EOF_PX_ADDRESS as usize);
624        assert_eq!(coord.y_usize(), EOF_PX_ADDRESS as usize);
625        assert_eq!(coord.c_usize(), 0);
626        assert!(!coord.is_3d());
627        assert!(coord.is_2d());
628        assert!(!coord.is_valid());
629        assert!(coord.is_eof());
630
631        let coord = Coord::new(EOF_PX_ADDRESS, EOF_PX_ADDRESS, Some(0));
632        assert_eq!(coord.x(), EOF_PX_ADDRESS);
633        assert_eq!(coord.y(), EOF_PX_ADDRESS);
634        assert_eq!(coord.c(), Some(0));
635        assert_eq!(coord.x_usize(), EOF_PX_ADDRESS as usize);
636        assert_eq!(coord.y_usize(), EOF_PX_ADDRESS as usize);
637        assert_eq!(coord.c_usize(), 0);
638        assert!(coord.is_3d());
639        assert!(!coord.is_2d());
640        assert!(!coord.is_valid());
641        assert!(coord.is_eof());
642
643        let coord = Coord::new(EOF_PX_ADDRESS, EOF_PX_ADDRESS, Some(1));
644        assert_eq!(coord.x(), EOF_PX_ADDRESS);
645        assert_eq!(coord.y(), EOF_PX_ADDRESS);
646        assert_eq!(coord.c(), Some(1));
647        assert_eq!(coord.x_usize(), EOF_PX_ADDRESS as usize);
648        assert_eq!(coord.y_usize(), EOF_PX_ADDRESS as usize);
649        assert_eq!(coord.c_usize(), 1);
650        assert!(coord.is_3d());
651        assert!(!coord.is_2d());
652        assert!(!coord.is_valid());
653        assert!(coord.is_eof());
654    }
655}