1pub use self::bilateral::*;
4pub use self::edge::*;
5pub use self::median::*;
6
7mod median;
8mod bilateral;
9mod edge;
10
11use crate::{error, util};
12use crate::enums::Thresh;
13use crate::error::ImgProcResult;
14use crate::image::{BaseImage, Image, Number};
15use crate::util::constants::{K_SHARPEN, K_UNSHARP_MASKING};
16
17#[cfg(feature = "rayon")]
18use rayon::prelude::*;
19
20#[cfg(not(feature = "rayon"))]
27pub fn filter_1d(input: &Image<f32>, kernel: &[f32], is_vert: bool) -> ImgProcResult<Image<f32>> {
28 error::check_odd(kernel.len(), "kernel length")?;
29
30 let (width, height, channels) = input.info().whc();
31 let mut output = Image::blank(input.info());
32 let mut p_out = Vec::with_capacity(channels as usize);
33
34 for y in 0..height {
35 for x in 0..width {
36 util::apply_1d_kernel(&input.get_neighborhood_1d(x, y, kernel.len() as u32, is_vert),
37 &mut p_out, kernel)?;
38 output.set_pixel(x, y, &p_out);
39 }
40 }
41
42 Ok(output)
43}
44
45#[cfg(feature = "rayon")]
48pub fn filter_1d(input: &Image<f32>, kernel: &[f32], is_vert: bool) -> ImgProcResult<Image<f32>> {
49 error::check_odd(kernel.len(), "kernel length")?;
50
51 let (width, height, channels, alpha) = input.info().whca();
52
53 let data: Vec<Vec<f32>> = (0..input.info().size())
54 .into_par_iter()
55 .map(|i| {
56 let (x, y) = util::get_2d_coords(i, width);
57 util::apply_1d_kernel(&input.get_neighborhood_1d(x, y,kernel.len() as u32, is_vert), kernel).unwrap()
58 })
59 .collect();
60
61 Ok(Image::from_vec_of_vec(width, height, channels, alpha, data))
62}
63
64pub fn separable_filter(input: &Image<f32>, vert_kernel: &[f32], horz_kernel: &[f32]) -> ImgProcResult<Image<f32>> {
66 error::check_odd(vert_kernel.len(), "vert_kernel length")?;
67 error::check_odd(horz_kernel.len(), "horz_kernel length")?;
68 error::check_equal(vert_kernel.len(), horz_kernel.len(), "kernel lengths")?;
69
70 let vertical = filter_1d(input, vert_kernel, true)?;
71 Ok(filter_1d(&vertical, horz_kernel, false)?)
72}
73
74#[cfg(not(feature = "rayon"))]
76pub fn unseparable_filter(input: &Image<f32>, kernel: &[f32]) -> ImgProcResult<Image<f32>> {
77 error::check_odd(kernel.len(), "kernel length")?;
78 error::check_square(kernel.len() as f32, "kernel length")?;
79
80 let size = (kernel.len() as f32).sqrt() as u32;
81 let (width, height, channels) = input.info().whc();
82 let mut output = Image::blank(input.info());
83 let mut p_out = Vec::with_capacity(channels as usize);
84
85 for y in 0..height {
86 for x in 0..width {
87 util::apply_2d_kernel(&input.get_neighborhood_2d(x, y, size), &mut p_out, kernel)?;
88 output.set_pixel(x, y, &p_out);
89 }
90 }
91
92 Ok(output)
93}
94
95#[cfg(feature = "rayon")]
97pub fn unseparable_filter(input: &Image<f32>, kernel: &[f32]) -> ImgProcResult<Image<f32>> {
98 error::check_odd(kernel.len(), "kernel length")?;
99 error::check_square(kernel.len() as f32, "kernel length")?;
100
101 let size = (kernel.len() as f32).sqrt() as u32;
102 let (width, height, channels, alpha) = input.info().whca();
103
104 let data: Vec<Vec<f32>> = (0..input.info().size())
105 .into_par_iter()
106 .map(|i| {
107 let (x, y) = util::get_2d_coords(i, width);
108 util::apply_2d_kernel(&input.get_neighborhood_2d(x, y, size), kernel).unwrap()
109 })
110 .collect();
111
112 Ok(Image::from_vec_of_vec(width, height, channels, alpha, data))
113}
114
115pub fn linear_filter(input: &Image<f32>, kernel: &[f32]) -> ImgProcResult<Image<f32>> {
117 error::check_odd(kernel.len(), "kernel length")?;
118 error::check_square(kernel.len() as f32, "kernel length")?;
119
120 let separable = util::separate_kernel(kernel);
121 match separable {
122 Some((vert, horz)) => Ok(separable_filter(input, &vert, &horz)?),
123 None => Ok(unseparable_filter(input, &kernel)?)
124 }
125}
126
127pub fn box_filter(input: &Image<f32>, size: u32) -> ImgProcResult<Image<f32>> {
133 error::check_odd(size, "size")?;
134
135 let len = (size * size) as usize;
136 let kernel = vec![1.0 / ((size * size) as f32); len];
137
138 Ok(separable_filter(input, &kernel, &kernel)?)
139}
140
141pub fn weighted_avg_filter(input: &Image<f32>, size: u32, weight: u32) -> ImgProcResult<Image<f32>> {
143 error::check_odd(size, "size")?;
144
145 let sum = (size * size) - 1 + weight;
146 let center = (size / 2) * size + (size / 2);
147 let mut kernel = vec![1.0 / (sum as f32); (size * size) as usize];
148 kernel[center as usize] = (weight as f32) / (sum as f32);
149
150 Ok(unseparable_filter(input, &kernel)?)
151}
152
153pub fn gaussian_blur(input: &Image<f32>, size: u32, sigma: f32) -> ImgProcResult<Image<f32>> {
155 let kernel = util::generate_gaussian_kernel(size, sigma)?;
156 Ok(linear_filter(input, &kernel)?)
157}
158
159pub fn sharpen(input: &Image<f32>) -> ImgProcResult<Image<f32>> {
165 Ok(unseparable_filter(input, &K_SHARPEN)?)
166}
167
168pub fn unsharp_masking(input: &Image<f32>) -> ImgProcResult<Image<f32>> {
170 Ok(unseparable_filter(input, &K_UNSHARP_MASKING)?)
171}
172
173pub fn threshold(input: &Image<f32>, threshold: f32, max: f32, method: Thresh) -> ImgProcResult<Image<f32>> {
179 error::check_grayscale(input)?;
180
181 match method {
182 Thresh::Binary => {
183 Ok(input.map_channels_if_alpha(|channel| {
184 if channel > threshold {
185 max
186 } else {
187 0.0
188 }
189 }, |a| a))
190 },
191 Thresh::BinaryInv => {
192 Ok(input.map_channels_if_alpha(|channel| {
193 if channel > threshold {
194 0.0
195 } else {
196 max
197 }
198 }, |a| a))
199 },
200 Thresh::Trunc => {
201 Ok(input.map_channels_if_alpha(|channel| {
202 if channel > threshold {
203 threshold
204 } else {
205 channel
206 }
207 }, |a| a))
208 },
209 Thresh::ToZero => {
210 Ok(input.map_channels_if_alpha(|channel| {
211 if channel > threshold {
212 channel
213 } else {
214 0.0
215 }
216 }, |a| a))
217 },
218 Thresh::ToZeroInv => {
219 Ok(input.map_channels_if_alpha(|channel| {
220 if channel > threshold {
221 0.0
222 } else {
223 channel
224 }
225 }, |a| a))
226 },
227 }
228}
229
230pub fn residual<T: Number>(original: &Image<T>, filtered: &Image<T>) -> ImgProcResult<Image<T>> {
236 error::check_equal(original.info(), filtered.info(), "image dimensions")?;
237
238 let (width, height, channels, alpha) = original.info().whca();
239 let mut data = Vec::new();
240
241 for y in 0..height {
242 for x in 0..width {
243 let p_1 = original.get_pixel(x, y);
244 let p_2 = filtered.get_pixel(x, y);
245
246 for c in 0..(channels as usize) {
247 data.push(p_1[c] - p_2[c]);
248 }
249 }
250 }
251
252 Ok(Image::from_slice(width, height, channels, alpha, &data))
253}