1use crate::core::*;
2use ndarray::{prelude::*, DataMut, Zip};
3
4pub trait MorphologyExt {
5 type Output;
6
7 fn erode(&self, kernel: ArrayView2<bool>) -> Self::Output;
8
9 fn erode_inplace(&mut self, kernel: ArrayView2<bool>);
10
11 fn dilate(&self, kernel: ArrayView2<bool>) -> Self::Output;
12
13 fn dilate_inplace(&mut self, kernel: ArrayView2<bool>);
14
15 fn union(&self, other: &Self) -> Self::Output;
16
17 fn union_inplace(&mut self, other: &Self);
18
19 fn intersection(&self, other: &Self) -> Self::Output;
20
21 fn intersection_inplace(&mut self, other: &Self);
22}
23
24impl<U> MorphologyExt for ArrayBase<U, Ix3>
25where
26 U: DataMut<Elem = bool>,
27{
28 type Output = Array<bool, Ix3>;
29
30 fn erode(&self, kernel: ArrayView2<bool>) -> Self::Output {
31 let sh = kernel.shape();
32 let (ro, co) = kernel_centre(sh[0], sh[1]);
33 let mut result = Self::Output::from_elem(self.dim(), false);
34 if self.shape()[0] >= sh[0] && self.shape()[1] >= sh[1] {
35 Zip::indexed(self.slice(s![.., .., 0]).windows(kernel.dim())).for_each(
36 |(i, j), window| {
37 result[[i + ro, j + co, 0]] = (&kernel & &window) == kernel;
38 },
39 );
40 }
41 result
42 }
43
44 fn erode_inplace(&mut self, kernel: ArrayView2<bool>) {
45 self.assign(&self.erode(kernel));
46 }
47
48 fn dilate(&self, kernel: ArrayView2<bool>) -> Self::Output {
49 let sh = kernel.shape();
50 let (ro, co) = kernel_centre(sh[0], sh[1]);
51 let mut result = Self::Output::from_elem(self.dim(), false);
52 if self.shape()[0] >= sh[0] && self.shape()[1] >= sh[1] {
53 Zip::indexed(self.slice(s![.., .., 0]).windows(kernel.dim())).for_each(
54 |(i, j), window| {
55 result[[i + ro, j + co, 0]] = (&kernel & &window).iter().any(|x| *x);
56 },
57 );
58 }
59 result
60 }
61
62 fn dilate_inplace(&mut self, kernel: ArrayView2<bool>) {
63 self.assign(&self.dilate(kernel));
64 }
65
66 fn union(&self, other: &Self) -> Self::Output {
67 self | other
68 }
69
70 fn union_inplace(&mut self, other: &Self) {
71 *self |= other;
72 }
73
74 fn intersection(&self, other: &Self) -> Self::Output {
75 self & other
76 }
77
78 fn intersection_inplace(&mut self, other: &Self) {
79 *self &= other;
80 }
81}
82
83impl<U, C> MorphologyExt for ImageBase<U, C>
84where
85 U: DataMut<Elem = bool>,
86 C: ColourModel,
87{
88 type Output = Image<bool, C>;
89
90 fn erode(&self, kernel: ArrayView2<bool>) -> Self::Output {
91 Self::Output::from_data(self.data.erode(kernel))
92 }
93
94 fn erode_inplace(&mut self, kernel: ArrayView2<bool>) {
95 self.data.erode_inplace(kernel);
96 }
97
98 fn dilate(&self, kernel: ArrayView2<bool>) -> Self::Output {
99 Self::Output::from_data(self.data.dilate(kernel))
100 }
101
102 fn dilate_inplace(&mut self, kernel: ArrayView2<bool>) {
103 self.data.dilate_inplace(kernel);
104 }
105
106 fn union(&self, other: &Self) -> Self::Output {
107 Self::Output::from_data(self.data.union(&other.data))
108 }
109
110 fn union_inplace(&mut self, other: &Self) {
111 self.data.union_inplace(&other.data);
112 }
113
114 fn intersection(&self, other: &Self) -> Self::Output {
115 Self::Output::from_data(self.data.intersection(&other.data))
116 }
117
118 fn intersection_inplace(&mut self, other: &Self) {
119 self.data.intersection_inplace(&other.data);
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126 use ndarray::arr2;
127
128 #[test]
129 fn simple_dilation() {
130 let pix_in = vec![
131 false, false, false, false, false, false, false, false, false, false, false, false,
132 true, false, false, false, false, false, false, false, false, false, false, false,
133 false,
134 ];
135 let pix_out = vec![
136 false, false, false, false, false, false, true, true, true, false, false, true, true,
137 true, false, false, true, true, true, false, false, false, false, false, false,
138 ];
139
140 let kern = arr2(&[[true, true, true], [true, true, true], [true, true, true]]);
141
142 let mut input = Image::<bool, Gray>::from_shape_data(5, 5, pix_in);
143 let expected = Image::<bool, Gray>::from_shape_data(5, 5, pix_out);
144 let actual = input.dilate(kern.view());
145 assert_eq!(actual, expected);
146 input.dilate_inplace(kern.view());
147 assert_eq!(input, expected);
148 }
149
150 #[test]
151 fn simple_erosion() {
152 let pix_out = vec![
153 false, false, false, false, false, false, false, false, false, false, false, false,
154 true, false, false, false, false, false, false, false, false, false, false, false,
155 false,
156 ];
157 let pix_in = vec![
158 false, false, false, false, false, false, true, true, true, false, false, true, true,
159 true, false, false, true, true, true, false, false, false, false, false, false,
160 ];
161
162 let kern = arr2(&[[true, true, true], [true, true, true], [true, true, true]]);
163
164 let mut input = Image::<bool, Gray>::from_shape_data(5, 5, pix_in);
165 let expected = Image::<bool, Gray>::from_shape_data(5, 5, pix_out);
166 let actual = input.erode(kern.view());
167 assert_eq!(actual, expected);
168 input.erode_inplace(kern.view());
169 assert_eq!(input, expected);
170 }
171
172 #[test]
173 fn simple_intersect() {
174 let a = vec![false, false, false, true, true, true, false, false, false];
175 let b = vec![false, true, false, false, true, false, false, true, false];
176 let mut a = Image::<bool, Gray>::from_shape_data(3, 3, a);
177 let b = Image::<bool, Gray>::from_shape_data(3, 3, b);
178
179 let exp = vec![false, false, false, false, true, false, false, false, false];
180 let expected = Image::<bool, Gray>::from_shape_data(3, 3, exp);
181 let c = a.intersection(&b);
182
183 assert_eq!(c, expected);
184 assert_eq!(a.intersection(&b), b.intersection(&a));
185
186 a.intersection_inplace(&b);
187 assert_eq!(a, c);
188 }
189
190 #[test]
191 fn simple_union() {
192 let a = vec![false, false, false, true, true, true, false, false, false];
193 let b = vec![false, true, false, false, true, false, false, true, false];
194 let mut a = Image::<bool, Gray>::from_shape_data(3, 3, a);
195 let b = Image::<bool, Gray>::from_shape_data(3, 3, b);
196
197 let exp = vec![false, true, false, true, true, true, false, true, false];
198 let expected = Image::<bool, Gray>::from_shape_data(3, 3, exp);
199 let c = a.union(&b);
200
201 assert_eq!(c, expected);
202 assert_eq!(a.union(&b), b.union(&a));
203
204 a.union_inplace(&b);
205 assert_eq!(a, c);
206 }
207}