zune_imageprocs/
spatial_ops.rs1use std::fmt::Debug;
10use std::ops::{Add, Div, Sub};
11
12use crate::pad::{pad, PadMethod};
13use crate::spatial::spatial;
14use crate::traits::NumOps;
15
16#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
18pub enum SpatialOperations {
19 Contrast,
21 Maximum,
23 Gradient,
25 Minimum,
27 Mean
29}
30
31impl SpatialOperations {
32 pub fn from_string_result(input: &str) -> Result<Self, String> {
33 match input
34 {
35 "contrast" => Ok(Self::Contrast),
36 "maximum" | "max" => Ok(Self::Maximum),
37 "gradient" => Ok(Self::Gradient),
38 "minimum" | "min" => Ok(Self::Minimum),
39 "mean" | "avg" => Ok(Self::Mean),
40 _ => Err(
41 "Unknown statistic type,accepted values are contrast,(maximum|max),gradient,(minimum|min),mean"
42 .to_string()
43 )
44 }
45 }
46}
47
48fn find_min<T: PartialOrd + Default + Copy + NumOps<T>>(data: &[T]) -> T {
49 let mut minimum = T::max_val();
50
51 for datum in data {
52 if *datum < minimum {
53 minimum = *datum;
54 }
55 }
56 minimum
57}
58
59fn find_contrast<
60 T: PartialOrd + Default + Copy + NumOps<T> + Sub<Output = T> + Add<Output = T> + Div<Output = T>
61>(
62 data: &[T]
63) -> T {
64 let mut minimum = T::MAX_VAL;
65 let mut maximum = T::MIN_VAL;
66
67 for datum in data {
68 if *datum < minimum {
69 minimum = *datum;
70 }
71 if *datum > maximum {
72 maximum = *datum;
73 }
74 }
75 let num = maximum - minimum;
76 let div = (maximum + minimum).saturating_add(T::one()); num / div
79}
80
81fn find_gradient<
82 T: PartialOrd + Default + Copy + NumOps<T> + Sub<Output = T> + Add<Output = T> + Div<Output = T>
83>(
84 data: &[T]
85) -> T {
86 let mut minimum = T::max_val();
87 let mut maximum = T::min_val();
88
89 for datum in data {
90 if *datum < minimum {
91 minimum = *datum;
92 }
93 if *datum > maximum {
94 maximum = *datum;
95 }
96 }
97
98 maximum - minimum
99}
100
101#[inline(always)]
102fn find_max<T: PartialOrd + Copy + NumOps<T>>(data: &[T]) -> T {
103 let mut maximum = T::min_val();
104
105 for datum in data {
106 if *datum > maximum {
107 maximum = *datum;
108 }
109 }
110 maximum
111}
112
113#[allow(clippy::cast_possible_truncation)]
114fn find_mean<T>(data: &[T]) -> T
115where
116 T: Default + Copy + NumOps<T> + Add<Output = T> + Div<Output = T>,
117 u32: std::convert::From<T>
118{
119 let mut maximum = u32::default();
121 let len = data.len() as u32;
122
123 for datum in data {
124 maximum += u32::from(*datum);
125 }
126 T::from_u32(maximum / len)
127}
128
129pub fn spatial_ops<T>(
142 in_channel: &[T], out_channel: &mut [T], radius: usize, width: usize, height: usize,
143 operations: SpatialOperations
144) where
145 T: PartialOrd
146 + Default
147 + Copy
148 + NumOps<T>
149 + Sub<Output = T>
150 + Add<Output = T>
151 + Div<Output = T>,
152 u32: std::convert::From<T>
153{
154 let padded_input = pad(
156 in_channel,
157 width,
158 height,
159 radius,
160 radius,
161 PadMethod::Replicate
162 );
163
164 let ptr = match operations {
180 SpatialOperations::Contrast => find_contrast::<T>,
181 SpatialOperations::Maximum => find_max::<T>,
182 SpatialOperations::Gradient => find_gradient::<T>,
183 SpatialOperations::Minimum => find_min::<T>,
184 SpatialOperations::Mean => find_mean::<T>
185 };
186
187 spatial(&padded_input, out_channel, radius, width, height, ptr);
188}
189
190#[cfg(feature = "benchmarks")]
191#[cfg(test)]
192mod benchmarks {
193 extern crate test;
194
195 use crate::spatial_ops::{spatial_ops, SpatialOperations};
196
197 #[bench]
198 fn bench_spatial_mean(b: &mut test::Bencher) {
199 let width = 800;
200 let height = 800;
201 let dimensions = width * height;
202
203 let in_vec = vec![255_u16; dimensions];
204 let mut out_vec = vec![255_u16; dimensions];
205
206 let radius = 3;
207
208 b.iter(|| {
209 spatial_ops(
210 &in_vec,
211 &mut out_vec,
212 radius,
213 width,
214 height,
215 SpatialOperations::Mean
216 );
217 });
218 }
219
220 #[bench]
221 fn bench_spatial_min(b: &mut test::Bencher) {
222 let width = 800;
223 let height = 800;
224 let dimensions = width * height;
225
226 let in_vec = vec![255_u16; dimensions];
227 let mut out_vec = vec![255_u16; dimensions];
228
229 let radius = 3;
230
231 b.iter(|| {
232 spatial_ops(
233 &in_vec,
234 &mut out_vec,
235 radius,
236 width,
237 height,
238 SpatialOperations::Minimum
239 );
240 });
241 }
242}