use crate::{filter, error, util, convert};
use crate::image::{Image, BaseImage};
use crate::error::ImgProcResult;
use crate::util::constants::{K_PREWITT_1D_VERT, K_PREWITT_1D_HORZ, K_SOBEL_1D_VERT, K_SOBEL_1D_HORZ, K_LAPLACIAN};
pub fn derivative_mask(input: &Image<f64>, vert_kernel: &[f64], horz_kernel: &[f64]) -> ImgProcResult<Image<f64>> {
error::check_grayscale(input)?;
let img_x = filter::separable_filter(&input, &vert_kernel, &horz_kernel)?;
let img_y = filter::separable_filter(&input, &horz_kernel, &vert_kernel)?;
let mut output = Image::blank(input.info());
for i in 0..(output.info().full_size() as usize) {
output.set_pixel_indexed(i, &[(img_x[i][0].powf(2.0) + img_y[i][0].powf(2.0)).sqrt()]);
}
Ok(output)
}
pub fn prewitt(input: &Image<f64>) -> ImgProcResult<Image<f64>> {
Ok(derivative_mask(input, &K_PREWITT_1D_VERT, &K_PREWITT_1D_HORZ)?)
}
pub fn sobel(input: &Image<f64>) -> ImgProcResult<Image<f64>> {
Ok(derivative_mask(input, &K_SOBEL_1D_VERT, &K_SOBEL_1D_HORZ)?)
}
pub fn sobel_weighted(input: &Image<f64>, weight: u32) -> ImgProcResult<Image<f64>> {
let vert_kernel = vec![1.0, weight as f64, 1.0];
Ok(derivative_mask(input, &vert_kernel, &K_SOBEL_1D_HORZ)?)
}
pub fn laplacian(input: &Image<f64>) -> ImgProcResult<Image<f64>> {
Ok(filter::unseparable_filter(input, &K_LAPLACIAN)?)
}
pub fn laplacian_of_gaussian(input: &Image<f64>, size: u32, sigma: f64) -> ImgProcResult<Image<f64>> {
let kernel = util::generate_log_kernel(size, sigma)?;
Ok(filter::unseparable_filter(input, &kernel)?)
}
pub fn normalize_laplacian(input: &Image<f64>) -> ImgProcResult<Image<u8>> {
error::check_grayscale(input)?;
let min = *input.data().iter().min_by(|x, y| x.partial_cmp(y).unwrap()).unwrap();
let max = *input.data().iter().max_by(|x, y| x.partial_cmp(y).unwrap()).unwrap();
Ok(convert::scale_channels(&input, min, 0.0, max, 255.0)?.into())
}