use std::ffi::c_int;
pub struct Kernel {
pub width: c_int,
pub height: c_int,
pub data: Vec<f32>,
}
impl Kernel {
pub fn new(width: c_int, height: c_int, data: Vec<f32>) -> Self {
if data.len() != (width * height) as usize {
panic!("Kernel data length does not match specified width and height");
}
Kernel {
width,
height,
data,
}
}
}
pub enum KernelType {
GaussianBlur3x3,
Sharpen3x3,
EdgeDetectionSobel,
GaussianBlurNxN(c_int),
SharpenNxN(c_int),
}
pub fn get_kernel(kernel_type: KernelType) -> Kernel {
match kernel_type {
KernelType::GaussianBlur3x3 => Kernel {
width: 3,
height: 3,
data: vec![
1.0 / 16.0,
2.0 / 16.0,
1.0 / 16.0,
2.0 / 16.0,
4.0 / 16.0,
2.0 / 16.0,
1.0 / 16.0,
2.0 / 16.0,
1.0 / 16.0,
],
},
KernelType::Sharpen3x3 => Kernel {
width: 3,
height: 3,
data: vec![0.0, -1.0, 0.0, -1.0, 5.0, -1.0, 0.0, -1.0, 0.0],
},
KernelType::EdgeDetectionSobel => Kernel {
width: 3,
height: 3,
data: vec![-1.0, 0.0, 1.0, -2.0, 0.0, 2.0, -1.0, 0.0, 1.0],
},
KernelType::GaussianBlurNxN(size) => {
let sigma = size as f32 / 6.0; generate_gaussian_kernel(size, sigma)
}
KernelType::SharpenNxN(size) => generate_sharpen_kernel(size),
}
}
fn generate_gaussian_kernel(size: c_int, sigma: f32) -> Kernel {
let mut kernel = vec![0.0; (size * size) as usize];
let mut sum = 0.0;
let center = size as f32 / 2.0;
for y in 0..size {
for x in 0..size {
let dx = x as f32 - center;
let dy = y as f32 - center;
let value = (-((dx * dx + dy * dy) / (2.0 * sigma * sigma))).exp();
kernel[(y * size + x) as usize] = value;
sum += value;
}
}
for k in &mut kernel {
*k /= sum;
}
Kernel {
width: size,
height: size,
data: kernel,
}
}
fn generate_sharpen_kernel(size: c_int) -> Kernel {
let mut kernel = vec![0.0; (size * size) as usize];
let center = (size * size / 2) as usize;
for i in 0..kernel.len() {
if i == center {
kernel[i] = (size * size) as f32 - 1.0; } else {
kernel[i] = -1.0 / (size * size) as f32; }
}
Kernel {
width: size,
height: size,
data: kernel,
}
}