cortical_io/
density.rs

1use std::collections::BTreeSet;
2
3use num::Float;
4use num_traits::{FromPrimitive, Zero};
5use crate::find_peaks::PeakFinder;
6
7pub fn gaussian(x1: f32, y1: f32, x2: f32, y2: f32, radius: f32) -> f32 {
8    let pi = std::f32::consts::PI;
9    let numerator = 1.0 / (2.0 * pi);
10    let denominator = 0.4;
11
12    let exponent =
13        -1.0
14            * (
15                3.0
16                * (
17                    (x1 - x2).powi(2)
18                    + (y1 - y2).powi(2)
19                ).sqrt()
20                / radius
21            ).powi(2)
22            / denominator;
23
24    let exponent = exponent.exp();
25
26    numerator * exponent
27}
28
29pub fn kde(x: f32, y: f32, points: &Vec<(f32, f32)>, radius: f32) -> f32 {
30    let mut sum = 0.0;
31
32    for point in points.iter() {
33        sum += gaussian(x, y, point.0, point.1, radius);
34    }
35
36    sum
37}
38
39fn amax(
40    vec: &[f32; 16384],
41) -> (usize, f32) {
42    let mut max = f32::zero();
43    let mut pos = 0;
44
45    for (i, val) in vec.iter().enumerate() {
46        if *val > max {
47            max = *val;
48            pos = i;
49        }
50    }
51
52    (pos, max)
53}
54
55const LOCALITY: f32 = 5.0f32;
56
57pub struct Kde {
58    pub data: [u32; 16384],
59    pub points: Vec<(f32, f32)>,
60    pub kde: [f32; 16384],
61
62    pub densest_points: BTreeSet<usize>,
63
64    pub x_min: f32,
65    pub x_max: f32,
66    pub y_min: f32,
67    pub y_max: f32,
68
69    pub radius: f32,
70}
71
72impl Kde {
73    pub fn new(vec: &[u32; 16384]) -> Kde {
74        let mut data = [0u32; 16384];
75
76        data.copy_from_slice(vec.as_slice());
77
78
79        Kde {
80            data,
81            points: Vec::new(),
82            kde: [0.0; 16384],
83
84            densest_points: BTreeSet::new(),
85
86            x_min: 0.0,
87            x_max: 0.0,
88            y_min: 0.0,
89            y_max: 0.0,
90
91            radius: 10.0,
92        }
93    }
94
95    pub fn clear(&mut self) {
96        self.points = Vec::new();
97        self.kde = [0.0f32; 16384];
98
99        self.densest_points = BTreeSet::new();
100
101        self.x_min = 0.0f32;
102        self.x_max = 0.0f32;
103        self.y_min = 0.0f32;
104        self.y_max = 0.0f32;
105
106        self.radius = 10.0f32;
107    }
108
109    pub fn build_points(&mut self) {
110        for y in 0..16384 {
111            if self.data[y] <= 0 {
112                continue;
113            }
114
115            self.points
116                .push(
117                    (
118                        (y / 128) as f32,
119                        (y % 128) as f32
120                    )
121                );
122        }
123    }
124
125    pub fn determine_kde_params(&mut self) -> Option<()> {
126        // find the min and max of x and y respectively
127        self.x_min = self.points.iter().map(|p| p.0).min_by(|a, b| a.partial_cmp(b).unwrap()).unwrap();
128        self.x_max = self.points.iter().map(|p| p.0).max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap();
129        self.y_min = self.points.iter().map(|p| p.1).min_by(|a, b| a.partial_cmp(b).unwrap()).unwrap();
130        self.y_max = self.points.iter().map(|p| p.1).max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap();
131
132        let dx = self.x_max - self.x_min;
133        let dy = self.y_max - self.y_min;
134
135        self.radius = dx.min(dy) / LOCALITY;
136
137        Some(())
138    }
139
140    pub fn calculate_kde(&mut self) {
141        for y in 0..128 {
142            for x in 0..128 {
143                self.kde[(x * 128) + y] =
144                    kde(
145                        x as f32,
146                        y as f32,
147                        &self.points,
148                        self.radius,
149                    );
150            }
151        }
152    }
153
154    pub fn determine_densest_points(&mut self) {
155        let mut pf =
156            PeakFinder::new(&self.kde);
157
158        pf.with_min_prominence(2.0);
159
160        let peaks =
161            pf.find_peaks();
162
163        let peaks =
164            peaks.iter()
165                .map(|p| p.clone().position.collect::<Vec<_>>())
166                .flatten()
167                .collect::<Vec<_>>();
168
169        // find the densest area in kde_vec
170        for peak in peaks {
171            let (x, y) = (peak / 128, peak % 128);
172
173            let cutoff = 10.0;
174
175            // find all points within 5 pixels of the densest point in "points"
176            for point in self.points.iter() {
177                if (point.0 - x as f32).abs() < cutoff
178                    && (point.1 - y as f32).abs() < cutoff {
179                    let idx = point.0 as u32 * 128 + point.1 as u32;
180
181                    if self.data[idx as usize] > 0 {
182                        self.densest_points.insert(idx as usize);
183                    }
184                }
185            }
186        }
187
188        dbg!(&self.densest_points);
189    }
190
191    pub fn fit_kde(&mut self) {
192        let (min, max) =
193            self.kde
194                .iter()
195                .fold(
196                    (std::f32::MAX, std::f32::MIN),
197                    |(min, max), &x|
198                        (
199                            min.min(x),
200                            max.max(x)
201                        ),
202                );
203
204        // fit all f32 values in kde_dev into 0..255
205        self.kde
206            .iter_mut()
207            .for_each(|x|
208                *x = ((*x - min) / (max - min)) * 255.0
209            );
210    }
211
212    pub fn get_kde_data(&self) -> [u32; 16384] {
213        let mut kde_data = [0u32; 16384];
214
215        for (i, val) in self.kde.iter().enumerate() {
216            kde_data[i] = *val as u32;
217        }
218
219        kde_data
220    }
221
222    pub fn run(&mut self) {
223        self.build_points();
224        self.determine_kde_params();
225        self.calculate_kde();
226        self.determine_densest_points();
227        self.fit_kde();
228    }
229}
230
231pub struct Density {
232    pub data: [u32; 16384],
233}
234
235impl Density {
236    pub fn new(vec: &[u32]) -> Self {
237        assert_eq!(vec.len(), 16384);
238
239        let mut data = [0u32; 16384];
240
241        data.copy_from_slice(vec);
242
243        Self {
244            data,
245        }
246    }
247
248    pub fn set_data(&mut self, vec: &[u32; 16384]) {
249        let mut data = [0u32; 16384];
250
251        data.copy_from_slice(vec.as_slice());
252
253        self.data = data;
254    }
255
256    pub fn get_data(&self) -> &[u32; 16384] {
257        &self.data
258    }
259
260    pub fn filter_points_min(&mut self, min: u32) {
261        self.data
262            .iter_mut()
263            .filter(|b| **b < min)
264            .for_each(|b| *b = u32::zero());
265    }
266
267    pub fn kde(&mut self) -> Kde {
268        let mut kde =
269            Kde::new(&self.data);
270
271        kde.run();
272
273        kde
274    }
275}