diff --git a/src/hough.rs b/src/hough.rs new file mode 100644 index 0000000..4d31519 --- /dev/null +++ b/src/hough.rs @@ -0,0 +1,87 @@ +use crate::*; + +const THETA_N: usize = 200; + +#[derive(Clone, Copy, Debug)] +pub struct Line { + pub theta: f32, + pub rho: f32, + pub significance: f32, +} + +pub fn transform(img: image::Image) -> image::Image { + let diag = ((img.extent.x.pow(2) + img.extent.y.pow(2)) as f32).sqrt(); + let mut res = image::Image::::with_extent(image::Extent { + x: THETA_N, + y: diag as usize, + }); + for y in 0..img.extent.y { + for x in 0..img.extent.x { + if img.at(x, y).y != 1.0 { + continue; + } + for a in 0..THETA_N { + let theta = theta_from(a); + let rho = x as f32 * theta.cos() + y as f32 * theta.sin(); + if rho < 0.0 { + continue; + } + + *res.at_mut(a, rho as usize) += 1.0; + } + } + } + res +} + +pub fn lines( + min_significance: f32, + img: image::Image, +) -> Vec { + let hough = transform(img); + + let mu = mean((&hough.pixels).into_iter().map(|p| *p)); + let sigma = stddev((&hough.pixels).into_iter().map(|p| *p), mu); + + let mut lines = Vec::::new(); + for y in 0..hough.extent.y { + for x in 0..hough.extent.x { + let value = hough.at(x, y); + let significance = (value - mu) / sigma; + if significance >= min_significance { + let theta = theta_from(x); + let rho = y as f32; + lines.push(Line { + theta, + rho, + significance, + }); + } + } + } + lines +} + +fn theta_from(x: usize) -> f32 { + x as f32 * std::f32::consts::PI / THETA_N as f32 +} + +fn mean(xs: impl Iterator) -> f32 { + let mut n = 0; + let mut sum = 0.0; + for x in xs { + sum += x; + n += 1; + } + sum / n as f32 +} + +fn stddev(xs: impl Iterator, mean: f32) -> f32 { + let mut n = 0; + let mut sum = 0.0; + for x in xs { + sum += (x - mean).powf(2.0); + n += 1; + } + (sum / (n - 1) as f32).sqrt() +} diff --git a/src/lib.rs b/src/lib.rs index 8e343a3..b75f47b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ pub mod filter; +pub mod hough; pub mod image; pub mod kernel;