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>);