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