1use crate::core::types::Size;
2use crate::error::Result;
3use crate::image::Image;
4use burn::tensor::backend::Backend;
5
6#[derive(Clone, Copy, Debug, PartialEq)]
8pub enum MorphOp {
9 Opening,
10 Closing,
11 Gradient,
12 TopHat,
13 BlackHat,
14}
15
16#[derive(Clone, Copy, Debug, PartialEq)]
18pub enum MorphShape {
19 Rect,
20 Cross,
21 Ellipse,
22}
23
24impl<B: Backend> Image<B> {
25 pub fn morphology_ex(&self, op: MorphOp, kernel_size: usize) -> Result<Self> {
27 match op {
28 MorphOp::Opening => self.clone().morph_open(kernel_size),
29 MorphOp::Closing => self.clone().morph_close(kernel_size),
30 MorphOp::Gradient => {
31 let dilated = self.clone().dilate(kernel_size)?;
32 let eroded = self.clone().erode(kernel_size)?;
33 dilated.subtract(&eroded)
34 }
35 MorphOp::TopHat => {
36 let opened = self.clone().morph_open(kernel_size)?;
37 self.subtract(&opened)
38 }
39 MorphOp::BlackHat => {
40 let closed = self.clone().morph_close(kernel_size)?;
41 closed.subtract(self)
42 }
43 }
44 }
45}
46
47pub struct Morphology;
48
49impl Morphology {
50 #[must_use]
52 pub fn get_structuring_element(shape: MorphShape, ksize: Size<usize>) -> Vec<Vec<u8>> {
53 let w = ksize.width;
54 let h = ksize.height;
55 let mut element = vec![vec![0; w]; h];
56
57 let xc = (w / 2) as f64;
58 let yc = (h / 2) as f64;
59
60 for (y, row) in element.iter_mut().enumerate() {
61 for (x, val) in row.iter_mut().enumerate() {
62 *val = match shape {
63 MorphShape::Rect => 1,
64 MorphShape::Cross => u8::from(x == w / 2 || y == h / 2),
65 MorphShape::Ellipse => {
66 let dx = x as f64 - xc;
67 let dy = y as f64 - yc;
68 let r_x = w as f64 / 2.0;
69 let r_y = h as f64 / 2.0;
70
71 if r_x > 0.0 && r_y > 0.0 {
72 let term = (dx * dx) / (r_x * r_x) + (dy * dy) / (r_y * r_y);
73 u8::from(term <= 1.05)
74 } else {
75 1
76 }
77 }
78 };
79 }
80 }
81
82 element
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_structuring_elements() {
92 let size = Size::new(5, 5);
93 let rect = Morphology::get_structuring_element(MorphShape::Rect, size);
94 assert_eq!(rect[0][0], 1);
95
96 let cross = Morphology::get_structuring_element(MorphShape::Cross, size);
97 assert_eq!(cross[0][0], 0);
98 assert_eq!(cross[2][2], 1);
99
100 let ellipse = Morphology::get_structuring_element(MorphShape::Ellipse, size);
101 assert_eq!(ellipse[0][0], 0);
102 }
103}