diff --git a/src/kernel.rs b/src/kernel.rs index 20c1b7e..396fa5e 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -1,29 +1,20 @@ use crate::*; +pub mod gaussian; +pub use gaussian::*; + pub trait Kernel { fn convolve

(&self, img: &image::Image

) -> image::Image

where P: image::Pixel; } -fn sum(kernel: &[[f32; N]; N]) -> f32 { - let mut x = 0.0; - for i in 0..N { - for j in 0..N { - x += kernel[j][i]; - } - } - x -} - impl Kernel for [[f32; N]; N] { fn convolve

(&self, img: &image::Image

) -> image::Image

where P: image::Pixel, { let l = N / 2; - let mag = sum(self); - let extent = image::Extent { x: img.extent.x - 2 * l, y: img.extent.y - 2 * l, @@ -32,10 +23,9 @@ impl Kernel for [[f32; N]; N] { result.for_each(|x, y, p| { for i in 0..N { for j in 0..N { - *p += img.at(x + i, y + j) * self[j][i]; + *p += img.at(x + j, y + i) * self[i][j]; } } - *p /= mag; }); result } @@ -83,24 +73,22 @@ mod tests { let input = image::Image { extent: image::Extent { x: 5, y: 5 }, pixels: vec![ - 10.0, 10.0, 10.0, 10.0, 10.0, - 10.0, p1, p2, p3, 10.0, - 10.0, p4, p5, p6, 10.0, - 10.0, p7, p8, p9, 10.0, - 10.0, 10.0, 10.0, 10.0, 10.0, - ], + 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, p1, p2, p3, 10.0, + 10.0, p4, p5, p6, 10.0, + 10.0, p7, p8, p9, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, + ], }; let kernel = [[k1, k2, k3], [k4, k5, k6], [k7, k8, k9]]; let output = kernel.convolve(&input); prop_assert_eq!(output.extent.x, 3); prop_assert_eq!(output.extent.y, 3); - let mag = k1 + k2 + k3 + k4 + k5 + k6 + k7 + k8 + k9; - let sum = p1 * k1 + p2 * k2 + p3 * k3 - + p4 * k4 + p5 * k5 + p6 * k6 - + p7 * k7 + p8 * k8 + p9 * k9; - let exp = sum / mag; - prop_assert!((output.at(1, 1) - exp).abs() < 1e-6); + let exp = p1 * k1 + p2 * k2 + p3 * k3 + + p4 * k4 + p5 * k5 + p6 * k6 + + p7 * k7 + p8 * k8 + p9 * k9; + prop_assert!((output.at(1, 1) - exp).abs() < 1e-6); } } } diff --git a/src/kernel/gaussian.rs b/src/kernel/gaussian.rs new file mode 100644 index 0000000..06f9e85 --- /dev/null +++ b/src/kernel/gaussian.rs @@ -0,0 +1,25 @@ +pub fn gaussian(sigma: f32) -> [[f32; N]; N] { + let mut kernel = [[0.0; N]; N]; + + let midpoint = (N / 2 + 1) as f32; + let v = sigma * sigma; + let k = 1.0 / (2.0 * std::f32::consts::PI * v).sqrt(); + let mut sum = 0.0; + for y in 0..N { + for x in 0..N { + let dx = x as f32 - midpoint; + let dy = y as f32 - midpoint; + let s = (dx * dx + dy * dy).sqrt(); + kernel[y][x] = k * (- s / (2.0 * v)).exp(); + sum += kernel[y][x]; + } + } + + for y in 0..N { + for x in 0..N { + kernel[y][x] /= sum; + } + } + + kernel +}