use crate::dynmatrix::DynMatrix;
use crate::traits::FloatScalar;
use super::integral::{integral_image, integral_rect_sum};
pub fn local_mean<T: FloatScalar>(src: &DynMatrix<T>, radius: usize) -> DynMatrix<T> {
let h = src.nrows();
let w = src.ncols();
if h == 0 || w == 0 {
return DynMatrix::<T>::zeros(h, w);
}
let sat = integral_image(src);
let mut out = DynMatrix::<T>::zeros(h, w);
let r = radius;
for j in 0..w {
let c0 = j.saturating_sub(r);
let c1 = (j + r + 1).min(w);
for i in 0..h {
let r0 = i.saturating_sub(r);
let r1 = (i + r + 1).min(h);
let count = T::from((r1 - r0) * (c1 - c0)).unwrap();
let sum = integral_rect_sum(&sat, r0, c0, r1, c1);
out[(i, j)] = sum / count;
}
}
out
}
pub fn local_variance<T: FloatScalar>(src: &DynMatrix<T>, radius: usize) -> DynMatrix<T> {
let h = src.nrows();
let w = src.ncols();
if h == 0 || w == 0 {
return DynMatrix::<T>::zeros(h, w);
}
let sat = integral_image(src);
let squared = DynMatrix::from_fn(h, w, |i, j| {
let v = src[(i, j)];
v * v
});
let sat2 = integral_image(&squared);
let mut out = DynMatrix::<T>::zeros(h, w);
let zero = T::zero();
for j in 0..w {
let c0 = j.saturating_sub(radius);
let c1 = (j + radius + 1).min(w);
for i in 0..h {
let r0 = i.saturating_sub(radius);
let r1 = (i + radius + 1).min(h);
let count = T::from((r1 - r0) * (c1 - c0)).unwrap();
let s1 = integral_rect_sum(&sat, r0, c0, r1, c1);
let s2 = integral_rect_sum(&sat2, r0, c0, r1, c1);
let mean = s1 / count;
let var = s2 / count - mean * mean;
out[(i, j)] = if var < zero { zero } else { var };
}
}
out
}
pub fn local_stddev<T: FloatScalar>(src: &DynMatrix<T>, radius: usize) -> DynMatrix<T> {
let var = local_variance(src, radius);
let h = var.nrows();
let w = var.ncols();
let mut out = DynMatrix::<T>::zeros(h, w);
for j in 0..w {
for i in 0..h {
out[(i, j)] = var[(i, j)].sqrt();
}
}
out
}