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
use image::GenericImageView;
use nalgebra::Point2;
#[inline(always)]
fn saturate_coordinate(value: u32, bound: u32) -> u32 {
if value < bound {
value
} else {
bound - 1
}
}
#[inline(always)]
pub fn saturating_get_pixel<I>(image: &I, x: i32, y: i32) -> I::Pixel
where
I: GenericImageView,
{
let x = if x.is_negative() {
0u32
} else {
saturate_coordinate(x as u32, image.width())
};
let y = if y.is_negative() {
0u32
} else {
saturate_coordinate(y as u32, image.height())
};
unsafe { image.unsafe_get_pixel(x, y) }
}
#[inline(always)]
pub fn get_pixel_with_fallback<I>(image: &I, x: i32, y: i32, fallback: I::Pixel) -> I::Pixel
where
I: GenericImageView,
{
if x.is_negative() || y.is_negative() {
fallback
} else {
let x = x as u32;
let y = y as u32;
if image.in_bounds(x, y) {
unsafe { image.unsafe_get_pixel(x, y) }
} else {
fallback
}
}
}
#[inline]
pub fn roi_to_bbox(point: Point2<f32>, size: f32) -> (Point2<f32>, Point2<f32>) {
let h = size / 2.0;
(
Point2::new(
point.x - h,
point.y - h
),
Point2::new(
point.x + h,
point.y + h
),
)
}
pub fn odd_median_mut(numbers: &mut[f32]) -> f32 {
numbers.sort_by(|a, b| a.partial_cmp(b).unwrap());
numbers[numbers.len() / 2]
}
#[cfg(test)]
mod tests {
use super::*;
use image::{GrayImage, Luma};
#[test]
fn check_get_pixel() {
let (width, height) = (64u32, 48u32);
let mut image = GrayImage::new(width, height);
image.put_pixel(0, 0, Luma::from([42u8]));
image.put_pixel(width - 1, height - 1, Luma::from([255u8]));
let test_coords = vec![
(0f32, 0f32),
(-10f32, -10f32),
((width as f32 - 1f32), (height as f32 - 1f32)),
(width as f32, height as f32),
];
let lum_values = vec![42u8, 42u8, 255u8, 255u8];
let fallbacks = vec![false, true, false, true];
for ((x, y), (lum_value, should_fallback)) in test_coords
.iter()
.zip(lum_values.iter().zip(fallbacks.iter()))
{
let x = *x as i32;
let y = *y as i32;
println!("x: {}, y: {}", x, y);
let lum = Luma::from([*lum_value]);
assert_eq!(saturating_get_pixel(&image, x, y), lum);
let fallback = Luma::from([0u8]);
assert_eq!(
get_pixel_with_fallback(&image, x, y, fallback.clone()),
if *should_fallback { fallback } else { lum }
);
}
}
}