convolve_nd/
array.rs

1use ndarray::{Array1, Array2, Array3};
2use crate::Convolution;
3use crate::kernel::SeparableKernel;
4use crate::dimensions::DimensionIterator;
5
6impl Convolution for Array1<f32> {
7    fn convolve<const KERNEL_SIZE: usize>(&mut self, kernel: SeparableKernel<KERNEL_SIZE>, stride: usize) {
8        let linear_kernel = kernel.values();
9
10        let sample_length = self.len();
11        
12        for index in 0..sample_length {
13            let mut signal_sum = 0.;
14
15            for (kernel_index, value) in linear_kernel.iter().enumerate() {
16                let relative_kernel_index = kernel_index as isize - (KERNEL_SIZE as isize / 2);
17                let signal_index = Self::compute_signal_index(
18                    stride,
19                    KERNEL_SIZE,
20                    relative_kernel_index,
21                    index,
22                    sample_length
23                );
24
25                signal_sum += self[signal_index as usize] * *value;
26            }
27
28            self[index] = signal_sum;
29        }
30    }
31}
32
33impl Convolution for Array2<f32> {
34    fn convolve<const KERNEL_SIZE: usize>(&mut self, kernel: SeparableKernel<KERNEL_SIZE>, stride: usize) {
35        let linear_kernel = kernel.values();
36
37        let (height, width) = self.dim();
38        let dimensions = self.raw_dim();
39
40        for (y, x) in dimensions.into_iter() {
41            let mut signal_sum = 0.;
42
43            for (kernel_index, value) in linear_kernel.iter().enumerate() {
44                let relative_kernel_index = kernel_index as isize - (KERNEL_SIZE as isize / 2);
45                let signal_index = Self::compute_signal_index(
46                    stride,
47                    KERNEL_SIZE,
48                    relative_kernel_index,
49                    x,
50                    width
51                );
52
53                signal_sum += self[[y, signal_index as usize]] * *value;
54            }
55
56            self[[y, x]] = signal_sum;
57        }
58
59        for (y, x) in dimensions.into_iter() {
60            let mut signal_sum = 0.;
61
62            for (kernel_index, value) in linear_kernel.iter().enumerate() {
63                let relative_kernel_index = kernel_index as isize - (KERNEL_SIZE as isize / 2);
64                let signal_index = Self::compute_signal_index(
65                    stride,
66                    KERNEL_SIZE,
67                    relative_kernel_index,
68                    y,
69                    height
70                );
71
72                signal_sum += self[[signal_index as usize, x]] * *value;
73            }
74
75            self[[y, x]] = signal_sum;
76        }
77    }
78}
79
80impl Convolution for Array3<f32> {
81    fn convolve<const KERNEL_SIZE: usize>(&mut self, kernel: SeparableKernel<KERNEL_SIZE>, stride: usize) {
82        let linear_kernel = kernel.values();
83        let (height, width, _) = self.dim();
84        let dimensions = self.raw_dim();
85
86        for (y, x, z) in dimensions.into_iter() {
87            let mut signal_sum = 0.;
88
89            for (kernel_index, value) in linear_kernel.iter().enumerate() {
90                let relative_kernel_index = kernel_index as isize - (KERNEL_SIZE as isize / 2);
91                let signal_index = Self::compute_signal_index(
92                    stride,
93                    KERNEL_SIZE,
94                    relative_kernel_index,
95                    x,
96                    width
97                );
98
99                signal_sum += self[[y, signal_index as usize, z]] * *value;
100            }
101
102            self[[y, x, z]] = signal_sum;
103        }
104
105        for (y, x, z) in dimensions.into_iter() {
106            let mut signal_sum = 0.;
107
108            for (kernel_index, value) in linear_kernel.iter().enumerate() {
109                let relative_kernel_index = kernel_index as isize - (KERNEL_SIZE as isize / 2);
110                let signal_index = Self::compute_signal_index(
111                    stride,
112                    KERNEL_SIZE,
113                    relative_kernel_index,
114                    y,
115                    height
116                );
117
118                signal_sum += self[[signal_index as usize, x, z]] * *value;
119            }
120
121            self[[y, x, z]] = signal_sum;
122        }
123    }
124}
125
126pub(crate) trait Aggregate {
127    fn min(&self) -> f32;
128    fn max(&self) -> f32;
129}
130
131macro_rules! impl_aggregate {
132    ($ty:ty) => {
133        impl Aggregate for $ty {
134            fn min(&self) -> f32 {
135                *self.iter()
136                    .reduce(|current, previous| {
137                        if current < previous {
138                            current
139                        } else {
140                            previous
141                        }
142                    })
143                    .unwrap()
144            }
145
146            fn max(&self) -> f32 {
147                *self
148                    .iter()
149                    .reduce(|current, previous| {
150                        if current > previous {
151                            current
152                        } else {
153                            previous
154                        }
155                    })
156                    .unwrap()
157            }
158        }
159    };
160}
161
162impl_aggregate!(Array1<f32>);
163impl_aggregate!(Array2<f32>);
164impl_aggregate!(Array3<f32>);