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
134
135
136
137
138
139
/// Represents subregion of image.
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum Region {
#[default]
Full,
Rectangle {
x: usize,
y: usize,
width: usize,
height: usize,
},
}
impl Region {
/// Create new [`Region`] that covers the whole image.
#[inline]
pub fn full() -> Self {
Region::Full
}
/// Create new partial [`Region`] with normalized width and height.
///
/// If the `width` or `height` is less than 2, it will be set to 2 to produce a region that
/// is valid when used with the NPP API.
///
/// # Arguments
///
/// * `topleft` - Coordinates of top left corner of the region.
/// * `dims` - Dimensions of the region.
#[inline]
pub fn rectangle_normalized(topleft: (usize, usize), dims: (usize, usize)) -> Self {
let (x, y) = topleft;
let (width, height) = dims;
Self::Rectangle {
x,
y,
width: width.max(2),
height: height.max(2),
}
}
/// Resolve the actual values for `x`, `y`, `width` and `height` of the box, even if when it is
/// `Region::Full`. To compute these, the outer `width` and `height` are required.
///
/// # Arguments
///
/// * `width` - Outer width.
/// * `height` - Outer height.
///
/// # Return value
///
/// Region coordinates `x`, `y`, `width` and `height`.
pub fn resolve_to_xywh(&self, width: usize, height: usize) -> (usize, usize, usize, usize) {
match self {
Region::Full => (0, 0, width, height),
Region::Rectangle {
x,
y,
width,
height,
} => (*x, *y, *width, *height),
}
}
/// Whether or not the region is of type `Region::Full`.
pub fn is_full(&self) -> bool {
matches!(self, Region::Full)
}
}
impl std::fmt::Display for Region {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Region::Full => write!(f, "[full]"),
// This formats to something like this:
//
// ```
// [x: 10, y: 10, width: 80, height: 40]
// ```
Region::Rectangle {
x,
y,
width,
height,
} => write!(f, "[x: {x}, y: {y}, width: {width}, height: {height}]",),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_full() {
assert_eq!(Region::full(), Region::Full);
assert!(Region::full().is_full());
}
#[test]
fn test_new_rectangle_normalized() {
assert_eq!(
Region::rectangle_normalized((1, 2), (3, 4)),
Region::Rectangle {
x: 1,
y: 2,
width: 3,
height: 4
}
);
assert_eq!(
Region::rectangle_normalized((1, 2), (0, 1)),
Region::Rectangle {
x: 1,
y: 2,
width: 2,
height: 2
}
);
assert!(!Region::rectangle_normalized((1, 2), (3, 4)).is_full());
}
#[test]
fn test_resolve_region() {
let region = Region::Rectangle {
x: 8,
y: 10,
width: 12,
height: 16,
};
assert_eq!(region.resolve_to_xywh(20, 20), (8, 10, 12, 16));
}
#[test]
fn test_resolve_full() {
let region = Region::Full;
assert_eq!(region.resolve_to_xywh(10, 20), (0, 0, 10, 20));
}
}