pico_detect/detect/
multiscale.rs1use imageproc::rect::Rect;
2use thiserror::Error;
3
4use crate::geometry::Square;
5
6#[derive(Copy, Clone, Debug, PartialEq)]
8pub struct Multiscaler {
9 min_size: u32,
10 max_size: u32,
11 shift_factor: f32,
12 scale_factor: f32,
13}
14
15#[derive(Debug, Error)]
16pub enum MultiscalerError {
17 #[error("`min_size` should be non zero")]
18 MinSizeIsZero,
19 #[error("`max_size` should be greater than `min_size`")]
20 MaxSizeLessThanMinSize,
21 #[error("`shift_factor` should be in `(0, 1]` range")]
22 ShiftFactorOutOfRange,
23 #[error("`scale_factor` should be greater than 1")]
24 ScaleFactorLessThanOne,
25}
26
27impl Multiscaler {
28 #[inline]
37 pub fn new(
38 min_size: u32,
39 max_size: u32,
40 shift_factor: f32,
41 scale_factor: f32,
42 ) -> Result<Self, MultiscalerError> {
43 if min_size == 0 {
44 return Err(MultiscalerError::MinSizeIsZero);
45 }
46
47 if min_size > max_size {
48 return Err(MultiscalerError::MaxSizeLessThanMinSize);
49 }
50
51 if !(0.0..=1.0).contains(&shift_factor) {
52 return Err(MultiscalerError::ShiftFactorOutOfRange);
53 }
54
55 if scale_factor < 1.0 {
56 return Err(MultiscalerError::ScaleFactorLessThanOne);
57 }
58
59 Ok(Self {
60 min_size,
61 max_size,
62 shift_factor,
63 scale_factor,
64 })
65 }
66
67 pub fn min_size(&self) -> u32 {
69 self.min_size
70 }
71
72 pub fn max_size(&self) -> u32 {
74 self.max_size
75 }
76
77 pub fn shift_factor(&self) -> f32 {
79 self.shift_factor
80 }
81
82 pub fn scale_factor(&self) -> f32 {
84 self.scale_factor
85 }
86
87 #[inline]
94 pub fn run<F>(&self, rect: Rect, f: F)
95 where
96 F: FnMut(Square),
97 {
98 multiscale(
99 self.min_size,
100 self.max_size,
101 self.shift_factor,
102 self.scale_factor,
103 rect,
104 f,
105 )
106 }
107
108 #[inline]
111 pub fn count(&self, rect: Rect) -> usize {
112 let mut count = 0;
113 self.run(rect, |_| count += 1);
114 count
115 }
116
117 #[inline]
120 pub fn collect(&self, rect: Rect) -> Vec<Square> {
121 let mut result = Vec::with_capacity(self.count(rect));
122 self.run(rect, |s| result.push(s));
123 result
124 }
125}
126
127#[inline]
138pub fn multiscale<F>(
139 min_size: u32,
140 max_size: u32,
141 shift_factor: f32,
142 scale_factor: f32,
143 rect: Rect,
144 mut f: F,
145) where
146 F: FnMut(Square),
147{
148 let mut size = min_size;
149
150 let start_x = rect.left();
151 let start_y = rect.top();
152
153 let right = start_x + rect.width() as i32;
154 let bottom = start_y + rect.height() as i32;
155
156 while size <= max_size {
157 let sizef = size as f32;
158 let step: usize = 1.max((sizef * shift_factor) as usize);
159
160 let end_x = right - size as i32;
161 let end_y = bottom - size as i32;
162
163 for y in (start_y..=end_y).step_by(step) {
164 for x in (start_x..=end_x).step_by(step) {
165 f(Square::new(x, y, size))
166 }
167 }
168 size = (sizef * scale_factor) as u32;
169 }
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175
176 #[test]
177 fn test_multiscale_run() {
178 let ms = Multiscaler::new(1, 4, 1.0, 2.0).unwrap();
179 ms.run(Rect::at(0, 0).of_size(4, 4), |s| println!("{:?}", s));
180 }
181}