1use std::collections::VecDeque;
2
3use ndarray::{Array, Array1, ArrayBase, Axis, Data, Dimension, ScalarOperand, Zip};
4use num_traits::{FromPrimitive, Num};
5
6use crate::{array_like, filters::origin_check, pad_to, BorderMode};
7
8pub fn maximum_filter1d<S, A, D>(
21 data: &ArrayBase<S, D>,
22 size: usize,
23 axis: Axis,
24 mode: BorderMode<A>,
25 origin: isize,
26) -> Array<A, D>
27where
28 S: Data<Elem = A>,
29 A: Copy + Num + PartialOrd + ScalarOperand + FromPrimitive,
30 D: Dimension,
31{
32 let mut output = data.to_owned();
33 maximum_filter1d_to(data, size, axis, mode, origin, &mut output);
34 output
35}
36
37pub fn maximum_filter<S, A, D>(
47 data: &ArrayBase<S, D>,
48 size: usize,
49 mode: BorderMode<A>,
50 origin: isize,
51) -> Array<A, D>
52where
53 S: Data<Elem = A>,
54 A: Copy + Num + PartialOrd + ScalarOperand + FromPrimitive,
55 D: Dimension,
56{
57 let mut data = data.to_owned();
62 let mut output = array_like(&data, data.dim(), A::zero());
63
64 for d in 0..data.ndim() {
65 maximum_filter1d_to(&data, size, Axis(d), mode, origin, &mut output);
66 if d < data.ndim() - 1 {
67 std::mem::swap(&mut output, &mut data);
68 }
69 }
70 output
71}
72
73pub fn maximum_filter1d_to<S, A, D>(
77 data: &ArrayBase<S, D>,
78 size: usize,
79 axis: Axis,
80 mode: BorderMode<A>,
81 origin: isize,
82 output: &mut Array<A, D>,
83) where
84 S: Data<Elem = A>,
85 A: Copy + Num + PartialOrd + ScalarOperand + FromPrimitive,
86 D: Dimension,
87{
88 let lower = |a, b| a <= b;
89 let higher = |a, b| a >= b;
90 min_or_max_filter(data, size, axis, mode, origin, higher, lower, output);
91}
92
93pub fn minimum_filter1d<S, A, D>(
106 data: &ArrayBase<S, D>,
107 size: usize,
108 axis: Axis,
109 mode: BorderMode<A>,
110 origin: isize,
111) -> Array<A, D>
112where
113 S: Data<Elem = A>,
114 A: Copy + Num + PartialOrd + ScalarOperand + FromPrimitive,
115 D: Dimension,
116{
117 let mut output = data.to_owned();
118 minimum_filter1d_to(data, size, axis, mode, origin, &mut output);
119 output
120}
121
122pub fn minimum_filter<S, A, D>(
132 data: &ArrayBase<S, D>,
133 size: usize,
134 mode: BorderMode<A>,
135 origin: isize,
136) -> Array<A, D>
137where
138 S: Data<Elem = A>,
139 A: Copy + Num + PartialOrd + ScalarOperand + FromPrimitive,
140 D: Dimension,
141{
142 let mut data = data.to_owned();
147 let mut output = array_like(&data, data.dim(), A::zero());
148
149 for d in 0..data.ndim() {
150 minimum_filter1d_to(&data, size, Axis(d), mode, origin, &mut output);
151 if d < data.ndim() - 1 {
152 std::mem::swap(&mut output, &mut data);
153 }
154 }
155 output
156}
157
158pub fn minimum_filter1d_to<S, A, D>(
162 data: &ArrayBase<S, D>,
163 size: usize,
164 axis: Axis,
165 mode: BorderMode<A>,
166 origin: isize,
167 output: &mut Array<A, D>,
168) where
169 S: Data<Elem = A>,
170 A: Copy + Num + PartialOrd + ScalarOperand + FromPrimitive,
171 D: Dimension,
172{
173 let lower = |a, b| a <= b;
174 let higher = |a, b| a >= b;
175 min_or_max_filter(data, size, axis, mode, origin, lower, higher, output);
176}
177
178fn min_or_max_filter<S, A, D, F1, F2>(
180 data: &ArrayBase<S, D>,
181 filter_size: usize,
182 axis: Axis,
183 mode: BorderMode<A>,
184 origin: isize,
185 f1: F1,
186 f2: F2,
187 output: &mut Array<A, D>,
188) where
189 S: Data<Elem = A>,
190 A: Copy + Num + PartialOrd + ScalarOperand + FromPrimitive,
191 D: Dimension,
192 F1: Fn(A, A) -> bool,
193 F2: Fn(A, A) -> bool,
194{
195 if filter_size == 0 {
196 panic!("Incorrect filter size (0)");
197 }
198 if filter_size == 1 {
199 output.assign(data);
200 return;
201 }
202
203 let size1 = filter_size / 2;
204 let size2 = filter_size - size1 - 1;
205 let mode = mode.to_pad_mode();
206 let n = data.len_of(axis);
207 let pad = vec![origin_check(filter_size, origin, size1, size2)];
208 let mut buffer = Array1::from_elem(n + pad[0][0] + pad[0][1], mode.init());
209
210 #[derive(Copy, Clone, PartialEq)]
211 struct Pair<A> {
212 val: A,
213 death: usize,
214 }
215 let mut ring = VecDeque::<Pair<A>>::with_capacity(filter_size);
216
217 Zip::from(data.lanes(axis)).and(output.lanes_mut(axis)).for_each(|input, mut o| {
221 pad_to(&input, &pad, mode, &mut buffer);
222 let buffer = buffer.as_slice_memory_order().unwrap();
223
224 let mut o_idx = 0;
225 ring.push_back(Pair { val: buffer[0], death: filter_size });
226 for (&v, i) in buffer[1..].iter().zip(1..) {
227 if ring[0].death == i {
228 ring.pop_front().unwrap();
229 }
230
231 if f1(v, ring[0].val) {
232 ring[0] = Pair { val: v, death: filter_size + i };
233 while ring.len() > 1 {
234 ring.pop_back().unwrap();
235 }
236 } else {
237 while f2(ring.back().unwrap().val, v) {
238 ring.pop_back().unwrap();
239 }
240 ring.push_back(Pair { val: v, death: filter_size + i });
241 }
242 if i >= filter_size - 1 {
243 o[o_idx] = ring[0].val;
244 o_idx += 1;
245 }
246 }
247 ring.clear();
248 });
249}