1use std::f64;
2use std::ops;
3
4use crate::*;
5
6#[derive(Debug, Clone, PartialEq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub struct Kernel {
10 rows: usize,
11 cols: usize,
12 data: Vec<Vec<f64>>,
13}
14
15impl From<Vec<Vec<f64>>> for Kernel {
16 fn from(data: Vec<Vec<f64>>) -> Kernel {
17 let rows = data.len();
18 let cols = data[0].len();
19 Kernel { data, rows, cols }
20 }
21}
22
23impl<'a> From<&'a [&'a [f64]]> for Kernel {
24 fn from(data: &'a [&'a [f64]]) -> Kernel {
25 let rows = data.len();
26 let cols = data[0].len();
27 let mut v = Vec::new();
28 for d in data {
29 v.push(Vec::from(*d))
30 }
31 Kernel {
32 data: v,
33 rows,
34 cols,
35 }
36 }
37}
38
39impl<const N: usize> From<[[f64; N]; N]> for Kernel {
40 fn from(data: [[f64; N]; N]) -> Kernel {
41 let data = data.iter().map(|d| d.to_vec()).collect();
42 Kernel {
43 data,
44 rows: N,
45 cols: N,
46 }
47 }
48}
49
50impl<T: Type, C: Color, U: Type, D: Color> Filter<T, C, U, D> for Kernel {
51 fn schedule(&self) -> Schedule {
52 Schedule::Image
53 }
54
55 fn compute_at(&self, pt: Point, input: &Input<T, C>, dest: &mut DataMut<U, D>) {
56 let r2 = (self.rows / 2) as isize;
57 let c2 = (self.cols / 2) as isize;
58 let mut f = input.new_pixel();
59 let mut x: f64;
60 for ky in -r2..=r2 {
61 let kr = &self.data[(ky + r2) as usize];
62 let pty = (pt.y as isize + ky) as usize;
63 for kx in -c2..=c2 {
64 let krc = kr[(kx + c2) as usize];
65 for c in 0..f.len() {
66 x = input.get_f(((pt.x as isize + kx) as usize, pty), c, Some(0));
67 f[c] += x * krc;
68 }
69 }
70 }
71 f.copy_to_slice(dest);
72 }
73}
74
75impl Kernel {
76 pub fn new(rows: usize, cols: usize) -> Kernel {
78 let data = vec![vec![0.0; cols]; rows];
79 Kernel { data, rows, cols }
80 }
81
82 pub fn square(x: usize) -> Kernel {
84 Self::new(x, x)
85 }
86
87 pub fn normalize(&mut self) {
89 let sum: f64 = self.data.iter().map(|x| -> f64 { x.iter().sum() }).sum();
90 if sum == 0.0 {
91 return;
92 }
93
94 for j in 0..self.rows {
95 for i in 0..self.cols {
96 self.data[j][i] /= sum
97 }
98 }
99 }
100
101 pub fn create<F: Fn(usize, usize) -> f64>(rows: usize, cols: usize, f: F) -> Kernel {
103 let mut k = Self::new(rows, cols);
104 for j in 0..rows {
105 let d = &mut k.data[j];
106 for (i, item) in d.iter_mut().enumerate() {
107 *item = f(i, j);
108 }
109 }
110 k
111 }
112
113 pub fn gaussian(n: usize, std: f64) -> Kernel {
115 assert!(n % 2 != 0);
116 let std2 = std * std;
117 let a = 1.0 / (2.0 * f64::consts::PI * std2);
118 let mut k = Kernel::create(n, n, |i, j| {
119 let x = (i * i + j * j) as f64 / (2.0 * std2);
120 a * f64::consts::E.powf(-1.0 * x)
121 });
122 k.normalize();
123 k
124 }
125
126 pub fn gaussian_3x3() -> Kernel {
128 Self::gaussian(3, 1.4)
129 }
130
131 pub fn gaussian_5x5() -> Kernel {
133 Self::gaussian(5, 1.4)
134 }
135
136 pub fn gaussian_7x7() -> Kernel {
138 Self::gaussian(7, 1.4)
139 }
140
141 pub fn gaussian_9x9() -> Kernel {
143 Self::gaussian(9, 1.4)
144 }
145
146 pub fn sobel_x() -> Kernel {
148 Kernel {
149 rows: 3,
150 cols: 3,
151 data: vec![
152 vec![1.0, 0.0, -1.0],
153 vec![2.0, 0.0, -2.0],
154 vec![1.0, 0.0, -1.0],
155 ],
156 }
157 }
158
159 pub fn sobel_y() -> Kernel {
161 Kernel {
162 rows: 3,
163 cols: 3,
164 data: vec![
165 vec![1.0, 2.0, 1.0],
166 vec![0.0, 0.0, 0.0],
167 vec![-1.0, -2.0, -1.0],
168 ],
169 }
170 }
171
172 pub fn laplacian() -> Kernel {
174 Kernel::from([[0., -1., 0.], [-1., 4., -1.], [0., -1., 0.]])
175 }
176
177 pub fn sobel() -> Kernel {
179 Kernel::sobel_x() + Kernel::sobel_y()
180 }
181}
182
183impl ops::Add for Kernel {
184 type Output = Kernel;
185
186 fn add(mut self, other: Kernel) -> Kernel {
187 for i in 0..self.rows {
188 for j in 0..self.cols {
189 self.data[i][j] += other.data[i][j];
190 }
191 }
192 self
193 }
194}
195
196impl ops::Sub for Kernel {
197 type Output = Kernel;
198
199 fn sub(mut self, other: Kernel) -> Kernel {
200 for i in 0..self.rows {
201 for j in 0..self.cols {
202 self.data[i][j] -= other.data[i][j];
203 }
204 }
205 self
206 }
207}
208
209impl ops::Mul for Kernel {
210 type Output = Kernel;
211
212 fn mul(mut self, other: Kernel) -> Kernel {
213 for i in 0..self.rows {
214 for j in 0..self.cols {
215 self.data[i][j] *= other.data[i][j];
216 }
217 }
218 self
219 }
220}
221
222impl ops::Div for Kernel {
223 type Output = Kernel;
224
225 fn div(mut self, other: Kernel) -> Kernel {
226 for i in 0..self.rows {
227 for j in 0..self.cols {
228 self.data[i][j] /= other.data[i][j];
229 }
230 }
231 self
232 }
233}