1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use std::cmp;
use image::{GenericImageView, Luma};
use nalgebra::Point2;
use super::detection::Detection;
use super::detector::Detector;
use super::geometry::ISimilarity2;
#[derive(Copy, Clone, Debug)]
pub struct MultiScale {
min_size: u32,
max_size: u32,
shift_factor: f32,
scale_factor: f32,
pad_x: (i32, i32),
pad_y: (i32, i32),
}
impl Default for MultiScale {
fn default() -> Self {
Self {
min_size: 100,
max_size: 1000,
shift_factor: 0.1,
scale_factor: 1.1,
pad_x: (0, 0),
pad_y: (0, 0),
}
}
}
impl MultiScale {
pub fn with_padding(mut self, x: (i32, i32), y: (i32, i32)) -> Self {
self.pad_x = x;
self.pad_y = y;
self
}
pub fn with_size_range(mut self, min_size: u32, max_size: u32) -> Self {
assert!(
max_size > min_size,
"Max size should be greater than min size"
);
self.min_size = min_size;
self.max_size = max_size;
self
}
pub fn with_shift_factor(mut self, factor: f32) -> Self {
assert!(factor > 0.0, "Shift factor should be positive");
assert!(factor < 1.0, "Shift factor should less 1.0");
self.shift_factor = factor;
self
}
pub fn with_scale_factor(mut self, factor: f32) -> Self {
assert!(factor > 1.0, "Shift factor should be greater than 1");
self.scale_factor = factor;
self
}
#[inline]
fn sliding_window_bbox(
&self,
width: u32,
height: u32,
offset: i32,
) -> (Point2<i32>, Point2<i32>) {
let start_x = self.pad_x.0 + offset;
let end_x = (width as i32) - self.pad_x.1 - offset;
let start_y = self.pad_y.0 + offset;
let end_y = (height as i32) - self.pad_y.1 - offset;
(Point2::new(start_x, start_y), Point2::new(end_x, end_y))
}
#[inline]
pub fn run_mut<I>(&self, detector: &Detector, image: &I, detections: &mut Vec<Detection>) -> usize
where
I: GenericImageView<Pixel = Luma<u8>>,
{
let (width, height) = (image.width(), image.height());
let mut size = self.min_size;
let mut new_detections = 0;
while size <= self.max_size {
let sizef = size as f32;
let step = cmp::max((sizef * self.shift_factor) as usize, 1);
let offset = (size / 2 + 1) as i32;
let (start, end) = self.sliding_window_bbox(width, height, offset);
for y in (start.y..end.y).step_by(step) {
for x in (start.x..end.x).step_by(step) {
if let Some(score) =
detector.classify(image, ISimilarity2::from_components(x, y, size))
{
detections
.push(Detection::from_components(x as f32, y as f32, sizef, score));
new_detections += 1;
}
}
}
size = (sizef * self.scale_factor) as u32;
}
new_detections
}
pub fn run<I>(&self, detector: &Detector, image: &I) -> Vec<Detection>
where
I: GenericImageView<Pixel = Luma<u8>>,
{
let mut detections = Vec::new();
self.run_mut(detector, image, &mut detections);
detections
}
}