1use crate::{BinaryImage, BoundingRect};
2
3pub struct Sampler {
5 pub image: BinaryImage,
6}
7
8impl Sampler {
9 pub fn new(image: &BinaryImage) -> Sampler {
10 let size = std::cmp::max(image.width, image.height);
11 Self::new_with_size(image, size)
12 }
13
14 pub fn new_with_size(image: &BinaryImage, sampler_size: usize) -> Sampler {
15 Self::new_with_size_crop(image, sampler_size, Default::default())
16 }
17
18 pub fn new_with_size_crop(
19 image: &BinaryImage,
20 sampler_size: usize,
21 crop: BoundingRect,
22 ) -> Sampler {
23 let new_image;
24 assert_eq!(crop.width(), crop.height());
25 if crop.is_empty() && image.width == image.height && image.width == sampler_size {
26 new_image = image.clone();
27 } else if !crop.is_empty()
28 && crop.width() as usize == sampler_size
29 && crop.height() as usize == sampler_size
30 {
31 new_image = image.crop_with_rect(crop);
32 } else {
33 new_image = Self::resample_square_image(&image, crop, sampler_size);
34 }
35 Sampler { image: new_image }
36 }
37
38 pub fn resample_square_image(
41 image: &BinaryImage,
42 crop: BoundingRect,
43 new_size: usize,
44 ) -> BinaryImage {
45 let mut new_image = BinaryImage::new_w_h(new_size, new_size);
46 let new_size = new_size as i32;
47 let crop = if !crop.is_empty() {
48 crop
49 } else {
50 BoundingRect::new_x_y_w_h(0, 0, image.width as i32, image.height as i32)
51 };
52 let image_size = std::cmp::max(crop.width(), crop.height()) as i32;
53 let ox = (image_size - crop.width() as i32) >> 1;
54 let oy = (image_size - crop.height() as i32) >> 1;
55 for y in 0..new_size {
56 for x in 0..new_size {
57 let xx = x * image_size / new_size - ox + crop.left;
58 let yy = y * image_size / new_size - oy + crop.top;
59 new_image.set_pixel(x as usize, y as usize, image.get_pixel_safe(xx, yy));
60 }
61 }
62 new_image
63 }
64
65 pub fn resample_image(image: &BinaryImage, new_width: usize, new_height: usize) -> BinaryImage {
66 Self::resample_image_with_crop(image, Default::default(), new_width, new_height)
67 }
68
69 pub fn resample_image_with_crop(
70 image: &BinaryImage,
71 crop: BoundingRect,
72 new_width: usize,
73 new_height: usize,
74 ) -> BinaryImage {
75 let mut new_image = BinaryImage::new_w_h(new_width, new_height);
76 Self::resample_image_with_crop_to_image(
77 image,
78 crop,
79 &mut new_image,
80 BoundingRect::new_x_y_w_h(0, 0, new_width as i32, new_height as i32),
81 );
82 new_image
83 }
84
85 pub fn resample_image_with_crop_to_image(
86 src: &BinaryImage,
87 src_rect: BoundingRect,
88 dst: &mut BinaryImage,
89 dst_rect: BoundingRect,
90 ) {
91 Self::resample_image_with_crop_to_image_overlay(src, src_rect, dst, dst_rect, false);
92 }
93
94 pub fn resample_image_with_crop_to_image_overlay(
95 src: &BinaryImage,
96 src_rect: BoundingRect,
97 dst: &mut BinaryImage,
98 dst_rect: BoundingRect,
99 overlay: bool,
100 ) {
101 let src_rect = if !src_rect.is_empty() {
102 src_rect
103 } else {
104 BoundingRect::new_x_y_w_h(0, 0, src.width as i32, src.height as i32)
105 };
106 for y in 0..dst_rect.height() {
107 for x in 0..dst_rect.width() {
108 let s = 1;
109 let xx =
110 s * x as i32 * src_rect.width() / dst_rect.width() as i32
111 + s * src_rect.left;
112 let yy =
113 s * y as i32 * src_rect.height() / dst_rect.height() as i32
114 + s * src_rect.top;
115 let pixel = src.get_pixel_safe(xx / s, yy / s);
116 if !overlay || pixel {
117 dst.set_pixel(
120 (dst_rect.left + x) as usize,
121 (dst_rect.top + y) as usize,
122 pixel,
123 );
124 }
125 }
126 }
127 }
128}
129
130impl Sampler {
131 pub fn size(&self) -> usize {
132 self.image.width
133 }
134
135 pub fn bounding_rect(&self) -> BoundingRect {
136 self.image.bounding_rect()
137 }
138
139 pub fn sample(&self, left: usize, top: usize, right: usize, bottom: usize) -> usize {
140 let mut count = 0;
141 for y in top..bottom {
142 for x in left..right {
143 if self.image.get_pixel(x, y) {
144 count += 1;
145 }
146 }
147 }
148 count
149 }
150}
151
152#[allow(dead_code)]
153fn is_pow_of_four(n: usize) -> bool {
154 (1 << (2 * pow_of_four(n))) == n
155}
156
157fn pow_of_four(mut n: usize) -> usize {
158 let mut pow_of_4 = 0;
159 while n > 3 {
160 n >>= 2;
161 pow_of_4 += 1;
162 }
163 pow_of_4
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn sampler_2() {
172 let size = 2;
173 let mut image = BinaryImage::new_w_h(size, size);
174 image.set_pixel(0, 0, true);
175 image.set_pixel(1, 1, true);
176 let sampler = Sampler::new_with_size(&image, size);
177 assert_eq!(sampler.sample(0, 0, 1, 1), 1);
178 assert_eq!(sampler.sample(0, 1, 1, 2), 0);
179 assert_eq!(sampler.sample(1, 0, 2, 1), 0);
180 assert_eq!(sampler.sample(1, 1, 2, 2), 1);
181 }
182
183 #[test]
184 fn sampler_crop() {
186 let size = 4;
187 let mut image = BinaryImage::new_w_h(size,size);
188 image.set_pixel(1,1,true);
189 image.set_pixel(2,2,true);
190 let sampler = Sampler::new_with_size_crop(&image, 2, BoundingRect {
191 left: 1, top: 1, right: 3, bottom: 3
192 });
193 assert_eq!(sampler.image.width, 2);
194 assert_eq!(sampler.size(), 2);
195 assert_eq!(sampler.sample(0, 0, 1, 1), 1);
196 assert_eq!(sampler.sample(0, 1, 1, 2), 0);
197 assert_eq!(sampler.sample(1, 0, 2, 1), 0);
198 assert_eq!(sampler.sample(1, 1, 2, 2), 1);
199 }
200
201 #[test]
202 fn sampler_4() {
203 let size = 4;
204 let mut image = BinaryImage::new_w_h(size, size);
205 image.set_pixel(0, 0, true);
206 image.set_pixel(1, 1, true);
207 let sampler = Sampler::new_with_size(&image, size);
208 assert_eq!(sampler.sample(0, 0, size, size), 2); assert_eq!(sampler.sample(0, 0, size / 2, size / 2), 2);
210 assert_eq!(sampler.sample(size / 2, size / 2, size, size), 0);
211 assert_eq!(sampler.sample(0,0,1,1), 1);
212 assert_eq!(sampler.sample(1,1,size/2,size/2), 1);
213 let rect = sampler.bounding_rect();
214 assert_eq!(rect, BoundingRect { left: 0, right: 2, top: 0, bottom: 2 });
215 assert_eq!(rect.width(), 2);
216 assert_eq!(rect.height(), 2);
217 }
218
219 #[test]
220 fn sampler_upsize() {
221 let mut image = BinaryImage::new_w_h(4, 4);
222 image.set_pixel(1, 1, true);
223 println!("image:\n{}", image.to_string());
224 let sampler = Sampler::new_with_size(&image, 8);
225 assert_eq!(sampler.image.width, 8);
226 println!("upsized:\n{}", sampler.image.to_string());
227 assert_eq!(sampler.sample(2, 2, 4, 4), 4);
228 assert_eq!(sampler.sample(0, 0, 8, 8), 4);
229 assert_eq!(sampler.sample(4, 4, 8, 8), 0);
230 }
231
232 #[test]
233 fn sampler_crop_upsize() {
234 let mut image = BinaryImage::new_w_h(8,8);
235 image.set_pixel(2,2,true);
236 println!("image:\n{}", image.to_string());
237 let sampler = Sampler::new_with_size_crop(&image, 8, BoundingRect {
238 left: 1, top: 1, right: 5, bottom: 5
239 });
240 assert_eq!(sampler.image.width, 8);
241 println!("cropped & upsized:\n{}", sampler.image.to_string());
242 assert_eq!(sampler.sample(2, 2, 4, 4), 4);
243 assert_eq!(sampler.sample(0, 0, 8, 8), 4);
244 assert_eq!(sampler.sample(4, 4, 8, 8), 0);
245 }
246
247 #[test]
248 fn sampler_upsize_non_exact() {
249 let mut image = BinaryImage::new_w_h(6, 6);
250 image.set_pixel(1, 1, true);
251 let sampler = Sampler::new_with_size(&image, 8);
252 assert_eq!(sampler.sample(0, 0, 8, 8), 1);
253 }
254
255 #[test]
256 fn resample_image_2x2_to_4x2() {
257 let image = BinaryImage::from_string(&(
258 "*-\n".to_owned()+
259 "-*\n"));
260 assert_eq!(
261 Sampler::resample_image(&image, 4, 2).to_string(),
262 BinaryImage::from_string(&(
263 "**--\n".to_owned()+
264 "--**\n")).to_string()
265 );
266 }
267
268 #[test]
269 fn resample_image_2x2_to_4x2_crop() {
270 let image = BinaryImage::from_string(&(
271 "--\n".to_owned()+
272 "*-\n"+
273 "-*\n"));
274 let mut new_image = BinaryImage::new_w_h(4, 4);
275 Sampler::resample_image_with_crop_to_image(
276 &image, BoundingRect::new_x_y_w_h(0, 1, 2, 2),
277 &mut new_image, BoundingRect::new_x_y_w_h(0, 1, 4, 2),
278 );
279 assert_eq!(
280 new_image.to_string(),
281 BinaryImage::from_string(&(
282 "----\n".to_owned()+
283 "**--\n"+
284 "--**\n"+
285 "----\n")).to_string()
286 );
287 }
288
289 #[test]
290 fn resample_image_2x2_to_3x2() {
291 let image = BinaryImage::from_string(&(
292 "*-\n".to_owned()+
293 "-*\n"));
294 assert_eq!(
295 Sampler::resample_image(&image, 3, 2).to_string(),
296 BinaryImage::from_string(&(
297 "**-\n".to_owned()+
298 "--*\n")).to_string()
299 )
300 }
301
302 #[test]
303 fn resample_image_3x3_to_2x2() {
304 let mut image = BinaryImage::new_w_h(3, 3);
305 image.set_pixel(1, 1, true);
306 image.set_pixel(2, 1, true);
307 image.set_pixel(1, 2, true);
308 image.set_pixel(2, 2, true);
309 let new_image = Sampler::resample_image(&image, 2, 2);
310 assert_eq!(new_image.width, 2);
311 assert_eq!(new_image.height, 2);
312 assert_eq!(new_image.get_pixel(0, 0), false);
313 assert_eq!(new_image.get_pixel(0, 1), false);
314 assert_eq!(new_image.get_pixel(1, 0), false);
315 assert_eq!(new_image.get_pixel(1, 1), true);
316 }
317}