image_convolution/
kernels.rs

1use crate::Real;
2
3/// Square shaped convolution kernel
4pub struct Kernel {
5    pub data: Vec<Real>, // data length is sizeƗsize
6    pub size: u32,
7}
8
9impl std::ops::Index<(u32, u32)> for Kernel {
10    type Output = Real;
11
12    #[inline]
13    fn index(&self, (x, y): (u32, u32)) -> &Self::Output {
14        let idx = (y * self.size + x) as usize;
15        &self.data[idx]
16    }
17}
18
19/// compute gaussian kernel
20pub fn gaussian(sigma: Real) -> Kernel {
21    /*
22      The size of the kernel is selected to guarantee that the first discarded
23      term is at least 10^prec times smaller than the central value. For that,
24      the half size of the kernel must be larger than x, with
25        e^(-x^2/2sigma^2) = 1/10^prec
26      Then,
27        x = sigma * sqrt( 2 * prec * ln(10) )
28    */
29    let prec = 3.0;
30    let radius = (sigma * (2.0 * prec * (10.0 as Real).ln()).sqrt()).ceil() as i32;
31    let size = 1 + 2 * radius; /* kernel size */
32    let mut data = Vec::with_capacity((size * size) as usize);
33    for y in -radius..=radius {
34        for x in -radius..=radius {
35            let dist2 = x.pow(2) + y.pow(2);
36            // proximate a circle region
37            let value = if dist2 <= radius * radius {
38                (-0.5 * (dist2 as Real) / sigma.powi(2)).exp()
39            } else {
40                0.0
41            };
42            data.push(value);
43        }
44    }
45
46    //normalization
47    let sum: Real = data.iter().sum();
48    if sum > 0.0 {
49        for v in data.iter_mut() {
50            *v /= sum;
51        }
52    }
53
54    Kernel {
55        data,
56        size: size as u32,
57    }
58}
59
60pub fn roberts_operator() -> (Kernel, Kernel) {
61    let kx = Kernel {
62        data: vec![1.0, 0.0, 0.0, -1.0],
63        size: 2,
64    };
65    let ky = Kernel {
66        data: vec![0.0, 1.0, -1.0, 0.0],
67        size: 2,
68    };
69    (kx, ky)
70}
71
72pub fn desolneux_operator() -> (Kernel, Kernel) {
73    let kx = Kernel {
74        data: vec![-0.5, 0.5, -0.5, 0.5],
75        size: 2,
76    };
77    let ky = Kernel {
78        data: vec![-0.5, -0.5, 0.5, 0.5],
79        size: 2,
80    };
81    (kx, ky)
82}
83
84pub fn sobel_operator() -> (Kernel, Kernel) {
85    let kx = Kernel {
86        data: vec![-1.0, 0.0, 1.0, -2.0, 0.0, 2.0, -1.0, 0.0, 1.0],
87        size: 3,
88    };
89    let ky = Kernel {
90        data: vec![-1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0],
91        size: 3,
92    };
93    (kx, ky)
94}
95
96pub fn freichen_operator() -> (Kernel, Kernel) {
97    let sqrt_2 = (2.0 as Real).sqrt();
98    let kx = Kernel {
99        data: vec![-1.0, 0.0, 1.0, -sqrt_2, 0.0, sqrt_2, -1.0, 0.0, 1.0],
100        size: 3,
101    };
102    let ky = Kernel {
103        data: vec![-1.0, -sqrt_2, -1.0, 0.0, 0.0, 0.0, 1.0, sqrt_2, 1.0],
104        size: 3,
105    };
106    (kx, ky)
107}