ndarray_vision/morphology/
mod.rs

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}