Add threshold filter

This commit is contained in:
cdo committed 2026-10-28 19:40:11 +00:00
1 parent cdcab41c73
commit 5b940c2192
4 files changed
+85 -64

No files matched your search

+3
View File
@@ -1,5 +1,8 @@
pub mod canny;
pub mod sobel;
pub mod threshold;
pub use canny::canny;
pub use sobel::sobel;
pub use threshold::threshold;
pub use threshold::threshold_auto;
+8 -63
View File
@@ -1,4 +1,5 @@
use crate::image::*;
use crate::*;
#[derive(Clone, Copy, PartialEq)]
pub enum Candidate {
@@ -14,72 +15,16 @@ impl Default for Candidate {
}
pub fn double_threshold(img: Image<f32>) -> Image<Candidate> {
let t = otsu::<20>(&img.pixels);
let mut result = Image::<Candidate>::with_extent(img.extent);
result.for_each(|x, y, p| {
let value = img.at(x, y);
*p = if value < t / 2.0 {
let t = filter::threshold::otsu::<20, _>(
(&img.pixels).into_iter().map(|p| *p),
);
img.map(|p| {
if p < t / 2.0 {
Candidate::None
} else if value < t {
} else if p < t {
Candidate::Weak
} else {
Candidate::Strong
}
});
result
}
fn otsu<const N: usize>(values: &Vec<f32>) -> f32 {
let mut hist = [0.0; N];
for x in values {
let bin = std::cmp::min(N - 1, (*x * (N as f32)) as usize);
hist[bin] += 1.0;
}
for i in 0..N {
hist[i] /= values.len() as f32;
}
let mut max = 0.0;
let mut res = 0;
for t in 0..N {
let var = variance(t, hist);
if var > max {
res = t;
max = var;
}
}
res as f32 / N as f32
}
fn variance<const N: usize>(t: usize, hist: [f32; N]) -> f32 {
let omega_0 = omega(0, t, hist);
let omega_1 = omega(t, N, hist);
let mu_0 = mu(0, t, hist, omega_0);
let mu_1 = mu(t, N, hist, omega_1);
omega_0 * omega_1 * (mu_0 - mu_1).powf(2.0)
}
fn omega<const N: usize>(from: usize, to: usize, hist: [f32; N]) -> f32 {
let mut sum = 0.0;
for i in from..to {
sum += hist[i];
}
sum
}
fn mu<const N: usize>(
from: usize,
to: usize,
hist: [f32; N],
omega: f32,
) -> f32 {
let mut sum = 0.0;
for i in from..to {
let bin_centre = (i as f32 + 0.5) / N as f32;
sum += bin_centre * hist[i];
}
sum / omega
})
}
+73
View File
@@ -0,0 +1,73 @@
use crate::image::*;
pub fn threshold_auto(img: Image<Luminance>) -> Image<Luminance> {
let t = otsu::<20, _>((&img.pixels).into_iter().map(|p| p.y));
threshold(t, img)
}
pub fn threshold(t: f32, mut img: Image<Luminance>) -> Image<Luminance> {
img.for_each(|_, _, p| {
p.y = if p.y >= t { 1.0 } else { 0.0 };
});
img
}
pub fn otsu<const N: usize, I>(values: I) -> f32
where
I: Iterator<Item = f32>,
{
let mut hist = [0.0; N];
let mut n = 0;
for x in values {
let bin = std::cmp::min(N - 1, (x * (N as f32)) as usize);
hist[bin] += 1.0;
n += 1;
}
for i in 0..N {
hist[i] /= n as f32;
}
let mut max = 0.0;
let mut res = 0;
for t in 0..N {
let var = variance(t, hist);
if var > max {
res = t;
max = var;
}
}
res as f32 / N as f32
}
fn variance<const N: usize>(t: usize, hist: [f32; N]) -> f32 {
let omega_0 = omega(0, t, hist);
let omega_1 = omega(t, N, hist);
let mu_0 = mu(0, t, hist, omega_0);
let mu_1 = mu(t, N, hist, omega_1);
omega_0 * omega_1 * (mu_0 - mu_1).powf(2.0)
}
fn omega<const N: usize>(from: usize, to: usize, hist: [f32; N]) -> f32 {
let mut sum = 0.0;
for i in from..to {
sum += hist[i];
}
sum
}
fn mu<const N: usize>(
from: usize,
to: usize,
hist: [f32; N],
omega: f32,
) -> f32 {
let mut sum = 0.0;
for i in from..to {
let bin_centre = (i as f32 + 0.5) / N as f32;
sum += bin_centre * hist[i];
}
sum / omega
}
+1 -1
View File
@@ -1,3 +1,3 @@
pub mod filter;
pub mod image;
pub mod kernel;
pub mod filter;