diff --git a/src/filter.rs b/src/filter.rs new file mode 100644 index 0000000..5588ff0 --- /dev/null +++ b/src/filter.rs @@ -0,0 +1,3 @@ +pub mod sobel; + +pub use sobel::sobel; diff --git a/src/filter/sobel.rs b/src/filter/sobel.rs new file mode 100644 index 0000000..d8154fa --- /dev/null +++ b/src/filter/sobel.rs @@ -0,0 +1,55 @@ +use crate::image::*; +use crate::kernel::Kernel; +use crate::*; + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Vector { + pub magnitude: f32, + pub direction: f32, +} + +impl Default for Vector { + fn default() -> Self { + Vector { + magnitude: 0.0, + direction: 0.0, + } + } +} + +const KERNEL_X: [[f32; 3]; 3] = + [[-1.0, 0.0, 1.0], [-2.0, 0.0, 2.0], [-1.0, 0.0, 1.0]]; +const KERNEL_Y: [[f32; 3]; 3] = + [[-1.0, -2.0, -1.0], [0.0, 0.0, 0.0], [1.0, 2.0, 1.0]]; + +pub fn sobel(img: Image) -> Image { + let x_edges = KERNEL_X.convolve(&img); + let y_edges = KERNEL_Y.convolve(&img); + + let mut result = image::Image::::with_extent(x_edges.extent); + result.for_each(|x, y, p| { + let gx = x_edges.at(x, y).y; + let gy = y_edges.at(x, y).y; + p.magnitude = norm(gx, gy); + p.direction = gy.atan2(gx); + }); + + normalise_magnitude(&mut result); + result +} + +fn norm(x: f32, y: f32) -> f32 { + (x * x + y * y).sqrt() +} + +fn normalise_magnitude(img: &mut Image) { + let mut max = f32::NEG_INFINITY; + for p in &img.pixels { + if p.magnitude > max { + max = p.magnitude; + } + } + img.for_each(|_, _, p| { + p.magnitude /= max; + }); +} diff --git a/src/lib.rs b/src/lib.rs index 2ba1056..bd26a13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ pub mod image; pub mod kernel; +pub mod filter;