1use pixtra::canvas::{Canvas, Island};
2use pixtra::pixels::{Pixel, PixelBuilder};
3use pixtra::utility::{to_grey_lumiosity, count_colors, counted_colors_to_html};
4use std::path::Path;
5
6fn gaussian_filter(canvas: &Canvas, x: u32, y: u32) -> Pixel {
7 let kernel = vec![0.06, 0.13, 0.06, 0.13, 0.24, 0.13, 0.06, 0.13, 0.06];
10 let coords = vec![
11 (-1, -1),
12 (0, -1),
13 (1, -1),
14 (-1, 0),
15 (0, 0),
16 (1, 0),
17 (-1, 1),
18 (0, 1),
19 (1, 1),
20 ];
21 let canvas_size = canvas.dimensions();
23 if x > 0 && y > 0 && x < canvas_size.width - 1 && y < canvas_size.height - 1 {
24 let pixel = apply_filter(canvas, (x, y), &kernel, &coords);
25 return pixel;
26 }
27 canvas.get_pixel(x, y)
28}
29
30fn lap_of_gaussian_filter(canvas: &Canvas, x: u32, y: u32) -> Pixel {
31 let kernel = vec![
34 0, 1, 1, 2, 2, 2, 1, 1, 0,
35 1, 2, 4, 5, 5, 5, 4, 2, 1,
36 1, 4, 5, 3, 0, 3, 5, 4, 1,
37 2, 5, 3, -12, -24, -12, 3, 5, 2,
38 2, 5, 0, -24, -40, -24, 0, 5, 2,
39 2, 5, 3, -12, -24, -12, 3, 5, 2,
40 1, 4, 5, 3, 0, 3, 5, 4, 1,
41 1, 2, 4, 5, 5, 5, 4, 2, 1,
42 0, 1, 1, 2, 2, 2, 1, 1, 0];
43 let kernel = kernel.iter().map(|&x| x as f32).collect();
44 let mut coords = vec![];
45 for y in -4..5 {
46 for x in -4..5 {
47 coords.push((x, y));
48 }
49 }
50 let canvas_size = canvas.dimensions();
52 if x > 3 && y > 3 && x < canvas_size.width - 4 && y < canvas_size.height - 4 {
53 let pixel = apply_filter(canvas, (x, y), &kernel, &coords);
54 return pixel;
55 }
56 canvas.get_pixel(x, y)
57}
58
59fn grey_scale_filter(canvas: &Canvas, x: u32, y: u32) -> Pixel {
60 to_grey_lumiosity(&canvas.get_pixel(x, y))
61}
62
63fn black_or_white_filter(canvas: &Canvas, x: u32, y: u32) -> Pixel {
64 let pixel = canvas.get_pixel(x, y);
65 if pixel.r < 128 {
66 Pixel::new(0, 0, 0, 255)
67 } else {
68 Pixel::new(255, 255, 255, 255)
69 }
70}
71
72
73
74fn apply_filter(
75 canvas: &Canvas,
76 center: (u32, u32),
77 kernel: &Vec<f32>,
78 coords: &Vec<(i32, i32)>,
79) -> Pixel {
80 let scales = kernel
81 .iter()
82 .zip(coords.iter())
83 .fold(Pixel::builder(), |acc, (scale, (x, y))| {
84 let pixel =
85 canvas.get_pixel((center.0 as i32 + *x) as u32, (center.1 as i32 + *y) as u32);
86 acc + PixelBuilder::from(
87 pixel.r as f32 * scale,
88 pixel.g as f32 * scale,
89 pixel.b as f32 * scale,
90 pixel.a as f32,
91 )
92 });
93 scales.build()
94}
95
96fn lap_edge_detection_filter(canvas: &Canvas, x: u32, y: u32) -> Pixel {
97 let kernel = vec![0.5, 1.0, 0.5, 1.0, -6.0, 1.0, 0.5, 1.0, 0.5];
100 let coords = vec![
101 (-1, -1),
102 (0, -1),
103 (1, -1),
104 (-1, 0),
105 (0, 0),
106 (1, 0),
107 (-1, 1),
108 (0, 1),
109 (1, 1),
110 ];
111 let canvas_size = canvas.dimensions();
113 if x > 0 && y > 0 && x < canvas_size.width - 1 && y < canvas_size.height - 1 {
114 let pixel = apply_filter(canvas, (x, y), &kernel, &coords);
115 return pixel;
116 }
117 canvas.get_pixel(x, y)
118}
119
120fn prewitt_edge_detection_filter(canvas: &Canvas, x: u32, y: u32) -> Pixel {
121 let kernel_one: Vec<f32> = vec![1f32, 0f32, -1f32, 1f32, 0f32, -1f32, 1f32, 0f32, -1f32];
122 let kernel_two: Vec<f32> = vec![1f32, 1f32, 1f32, 0f32, 0f32, 0f32, -1f32, -1f32, -1f32];
123 let coords = vec![
124 (-1, -1),
125 (0, -1),
126 (1, -1),
127 (-1, 0),
128 (0, 0),
129 (1, 0),
130 (-1, 1),
131 (0, 1),
132 (1, 1),
133 ];
134
135 let canvas_size = canvas.dimensions();
136 if x > 0 && y > 0 && x < canvas_size.width - 1 && y < canvas_size.height - 1 {
137 let pixel_one = apply_filter(canvas, (x, y), &kernel_one, &coords);
138 let pixel_two = apply_filter(canvas, (x, y), &kernel_two, &coords);
139
140 let pixel = PixelBuilder::from(
141 ((pixel_one.r as u32 * pixel_one.r as u32 + pixel_two.r as u32 * pixel_two.r as u32)
142 as f64)
143 .sqrt() as f32,
144 ((pixel_one.g as u32 * pixel_one.g as u32 + pixel_two.g as u32 * pixel_two.g as u32)
145 as f64)
146 .sqrt() as f32,
147 ((pixel_one.b as u32 * pixel_one.b as u32 + pixel_two.b as u32 * pixel_two.b as u32)
148 as f64)
149 .sqrt() as f32,
150 255f32,
151 );
152 return pixel.build();
153 }
154 canvas.get_pixel(x, y)
155}
156
157fn inverse(pixel: Pixel) -> Pixel {
158 Pixel {
159 r: u8::max_value() - pixel.r,
160 g: u8::max_value() - pixel.g,
161 b: u8::max_value() - pixel.b,
162 a: pixel.a,
163 }
164}
165
166fn inverse_filter(canvas: &Canvas, x: u32, y: u32) -> Pixel {
167 inverse(canvas.get_pixel(x, y))
168}
169
170fn main() {
171 let canvas = Canvas::load(Path::new("assets/lena.png")).unwrap();
173 let test_image = Canvas::load(Path::new("assets/IMG_0771.JPG")).unwrap();
174 let gaussian_canvas = canvas.filter(gaussian_filter);
175 let _ = gaussian_canvas
176 .save(Path::new("gaussian_canvas.png"))
177 .unwrap();
178 let gaussian_canvas = gaussian_canvas.filter(gaussian_filter);
179 let gaussian_canvas = gaussian_canvas.filter(gaussian_filter);
180 let gaussian_canvas = gaussian_canvas.filter(gaussian_filter);
181 let gaussian_canvas = gaussian_canvas.filter(gaussian_filter);
182 let _ = gaussian_canvas
183 .save(Path::new("very_gaussian_canvas.png"))
184 .unwrap();
185
186 let inverse_gaussian_canvas = canvas.filter(inverse_filter).filter(gaussian_filter);
188 let _ = inverse_gaussian_canvas
189 .save(Path::new("inverse_gaussian_canvas.png"))
190 .unwrap();
191
192 let lap_edge_detection_canvas = canvas.filter(lap_edge_detection_filter);
193 let _ = lap_edge_detection_canvas
194 .save(Path::new("lap_edge_detection_filter.png"))
195 .unwrap();
196
197 let prewitt_edge_detection_canvas = canvas.filter(prewitt_edge_detection_filter);
198 let _ = prewitt_edge_detection_canvas
199 .save(Path::new("prewitt_edge_detection_filter.png"))
200 .unwrap();
201
202 let lap_of_gaussian_filter_canvas = test_image.filter(grey_scale_filter).filter(lap_of_gaussian_filter);
203 let _ = lap_of_gaussian_filter_canvas
206 .save(Path::new("lap_of_gaussian_edge_detection_filter.png"))
207 .unwrap();
208 let filtered_canvas = lap_of_gaussian_filter_canvas.filter(black_or_white_filter);
209 let _ = filtered_canvas
210 .save(Path::new("filtered_canvas.png"))
211 .unwrap();
212
213 let islands = filtered_canvas.find_islands(&Pixel::new(255, 255, 255, 255));
214 let islands_with_size: Vec<Island> = islands.iter().filter(|x| x.points.len() > 40000).map(|x| x.clone()).collect();
215 }