use crate::dynmatrix::DynMatrix;
use crate::traits::FloatScalar;
use super::border::BorderMode;
use super::convolve::{convolve2d, convolve2d_separable};
use super::kernels::{
box_kernel_1d, gaussian_kernel_1d, scharr_x_3x3, scharr_y_3x3, sobel_x_3x3, sobel_y_3x3,
};
pub fn gaussian_blur<T: FloatScalar>(
src: &DynMatrix<T>,
sigma: T,
border: BorderMode<T>,
) -> DynMatrix<T> {
if !sigma.is_finite() || sigma <= T::zero() {
return src.clone();
}
let three = T::from(3.0_f64).unwrap();
let kernel = match gaussian_kernel_1d(sigma, three) {
Ok(k) => k,
Err(_) => return src.clone(),
};
convolve2d_separable(src, &kernel, &kernel, border)
}
pub fn box_blur<T: FloatScalar>(
src: &DynMatrix<T>,
radius: usize,
border: BorderMode<T>,
) -> DynMatrix<T> {
if radius == 0 {
return src.clone();
}
let n = 2 * radius + 1;
let kernel = match box_kernel_1d::<T>(n) {
Ok(k) => k,
Err(_) => return src.clone(),
};
convolve2d_separable(src, &kernel, &kernel, border)
}
pub fn laplacian<T: FloatScalar>(src: &DynMatrix<T>, border: BorderMode<T>) -> DynMatrix<T> {
let k = super::kernels::laplacian_3x3::<T>();
convolve2d(src, &k, border)
}
pub fn laplacian_of_gaussian<T: FloatScalar>(
src: &DynMatrix<T>,
sigma: T,
border: BorderMode<T>,
) -> DynMatrix<T> {
let smoothed = gaussian_blur(src, sigma, border);
laplacian(&smoothed, border)
}
pub fn unsharp_mask<T: FloatScalar>(
src: &DynMatrix<T>,
sigma: T,
amount: T,
border: BorderMode<T>,
) -> DynMatrix<T> {
if !sigma.is_finite() || sigma <= T::zero() {
return src.clone();
}
let blurred = gaussian_blur(src, sigma, border);
let mut out = DynMatrix::<T>::zeros(src.nrows(), src.ncols());
for j in 0..src.ncols() {
for i in 0..src.nrows() {
let s = src[(i, j)];
let b = blurred[(i, j)];
out[(i, j)] = s + amount * (s - b);
}
}
out
}
pub fn scharr_gradients<T: FloatScalar>(
src: &DynMatrix<T>,
border: BorderMode<T>,
) -> (DynMatrix<T>, DynMatrix<T>) {
let kx = scharr_x_3x3::<T>();
let ky = scharr_y_3x3::<T>();
let gx = convolve2d(src, &kx, border);
let gy = convolve2d(src, &ky, border);
(gx, gy)
}
pub fn gradient_magnitude<T: FloatScalar>(
gx: &DynMatrix<T>,
gy: &DynMatrix<T>,
) -> DynMatrix<T> {
assert_eq!(
(gx.nrows(), gx.ncols()),
(gy.nrows(), gy.ncols()),
"gradient magnitude inputs must have the same shape",
);
let mut out = DynMatrix::<T>::zeros(gx.nrows(), gx.ncols());
for j in 0..gx.ncols() {
for i in 0..gx.nrows() {
let a = gx[(i, j)];
let b = gy[(i, j)];
out[(i, j)] = (a * a + b * b).sqrt();
}
}
out
}
pub fn sobel_gradients<T: FloatScalar>(
src: &DynMatrix<T>,
border: BorderMode<T>,
) -> (DynMatrix<T>, DynMatrix<T>) {
let kx = sobel_x_3x3::<T>();
let ky = sobel_y_3x3::<T>();
let gx = convolve2d(src, &kx, border);
let gy = convolve2d(src, &ky, border);
(gx, gy)
}