1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use adder_codec_core::{Event, PlaneSize};
use ndarray::Array3;
use std::error::Error;

// TODO: Explore optimal threshold values
const INTENSITY_THRESHOLD: i32 = 30;

#[rustfmt::skip]
const CIRCLE3: [[i32; 2]; 16] = [
    [0, 3], [1, 3], [2, 2], [3, 1],
    [3, 0], [3, -1], [2, -2], [1, -3],
    [0, -3], [-1, -3], [-2, -2], [-3, -1],
    [-3, 0], [-3, 1], [-2, 2], [-1, 3]
];

/// Check if the given event is a feature
pub fn is_feature(e: &Event, plane: PlaneSize, img: &Array3<i32>) -> Result<bool, Box<dyn Error>> {
    if e.coord.is_border(plane.w_usize(), plane.h_usize(), 3) {
        return Ok(false);
    }

    // let img = &self.running_intensities;
    let candidate: i32 = img[(e.coord.y_usize(), e.coord.x_usize(), 0)];

    let mut count = 0;
    if (img[(
        (e.coord.y as i32 + CIRCLE3[4][1]) as usize,
        (e.coord.x as i32 + CIRCLE3[4][0]) as usize,
        0,
    )] - candidate)
        .abs()
        > INTENSITY_THRESHOLD
    {
        count += 1;
    }
    if (img[(
        (e.coord.y as i32 + CIRCLE3[12][1]) as usize,
        (e.coord.x as i32 + CIRCLE3[12][0]) as usize,
        0,
    )] - candidate)
        .abs()
        > INTENSITY_THRESHOLD
    {
        count += 1;
    }
    if (img[(
        (e.coord.y as i32 + CIRCLE3[1][1]) as usize,
        (e.coord.x as i32 + CIRCLE3[1][0]) as usize,
        0,
    )] - candidate)
        .abs()
        > INTENSITY_THRESHOLD
    {
        count += 1;
    }

    if (img[(
        (e.coord.y as i32 + CIRCLE3[7][1]) as usize,
        (e.coord.x as i32 + CIRCLE3[7][0]) as usize,
        0,
    )] - candidate)
        .abs()
        > INTENSITY_THRESHOLD
    {
        count += 1;
    }

    if count <= 2 {
        return Ok(false);
    }

    let streak_size = 12;

    for i in 0..16 {
        // Are we looking at a bright or dark streak?
        let brighter = img[(
            (e.coord.y as i32 + CIRCLE3[i][1]) as usize,
            (e.coord.x as i32 + CIRCLE3[i][0]) as usize,
            0,
        )] > candidate;

        let mut did_break = false;

        for j in 0..streak_size {
            if brighter {
                if img[(
                    (e.coord.y as i32 + CIRCLE3[(i + j) % 16][1]) as usize,
                    (e.coord.x as i32 + CIRCLE3[(i + j) % 16][0]) as usize,
                    0,
                )] <= candidate + INTENSITY_THRESHOLD
                {
                    did_break = true;
                }
            } else if img[(
                (e.coord.y as i32 + CIRCLE3[(i + j) % 16][1]) as usize,
                (e.coord.x as i32 + CIRCLE3[(i + j) % 16][0]) as usize,
                0,
            )] >= candidate - INTENSITY_THRESHOLD
            {
                did_break = true;
            }
        }

        if !did_break {
            return Ok(true);
        }
    }

    Ok(false)
}