Add threshold filter
This commit is contained in:
1 parent
cdcab41c73
commit
5b940c2192
4 files changed
+85
-64
No files matched your search
@@ -1,5 +1,8 @@
|
|||||||
pub mod canny;
|
pub mod canny;
|
||||||
pub mod sobel;
|
pub mod sobel;
|
||||||
|
pub mod threshold;
|
||||||
|
|
||||||
pub use canny::canny;
|
pub use canny::canny;
|
||||||
pub use sobel::sobel;
|
pub use sobel::sobel;
|
||||||
|
pub use threshold::threshold;
|
||||||
|
pub use threshold::threshold_auto;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::image::*;
|
use crate::image::*;
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
pub enum Candidate {
|
pub enum Candidate {
|
||||||
@@ -14,72 +15,16 @@ impl Default for Candidate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn double_threshold(img: Image<f32>) -> Image<Candidate> {
|
pub fn double_threshold(img: Image<f32>) -> Image<Candidate> {
|
||||||
let t = otsu::<20>(&img.pixels);
|
let t = filter::threshold::otsu::<20, _>(
|
||||||
let mut result = Image::<Candidate>::with_extent(img.extent);
|
(&img.pixels).into_iter().map(|p| *p),
|
||||||
result.for_each(|x, y, p| {
|
);
|
||||||
let value = img.at(x, y);
|
img.map(|p| {
|
||||||
*p = if value < t / 2.0 {
|
if p < t / 2.0 {
|
||||||
Candidate::None
|
Candidate::None
|
||||||
} else if value < t {
|
} else if p < t {
|
||||||
Candidate::Weak
|
Candidate::Weak
|
||||||
} else {
|
} else {
|
||||||
Candidate::Strong
|
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
|
|
||||||
}
|
}
|
||||||
@@ -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
@@ -1,3 +1,3 @@
|
|||||||
|
pub mod filter;
|
||||||
pub mod image;
|
pub mod image;
|
||||||
pub mod kernel;
|
pub mod kernel;
|
||||||
pub mod filter;
|
|
||||||
Reference in new issue
Block a user