1use aksr::Builder;
2use anyhow::Result;
3use image::GrayImage;
4use rayon::prelude::*;
5
6use crate::{InstanceMeta, MaskStyle, Polygon};
7
8#[derive(Builder, Default, Clone)]
10pub struct Mask {
11 mask: GrayImage,
13 meta: InstanceMeta,
15 style: Option<MaskStyle>,
17}
18
19impl std::fmt::Debug for Mask {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 let mut f = f.debug_struct("Mask");
25 f.field("dimensions", &self.dimensions());
26 if let Some(id) = &self.meta.id() {
27 f.field("id", id);
28 }
29 if let Some(name) = &self.meta.name() {
30 f.field("name", name);
31 }
32 if let Some(confidence) = &self.meta.confidence() {
33 f.field("confidence", confidence);
34 }
35 if let Some(track_id) = &self.meta.track_id() {
36 f.field("track_id", track_id);
37 }
38 f.finish()
39 }
40}
41
42impl PartialEq for Mask {
43 fn eq(&self, other: &Self) -> bool {
44 self.mask == other.mask
45 }
46}
47
48impl Mask {
49 impl_meta_methods!();
50 pub fn new(u8s: &[u8], width: u32, height: u32) -> Result<Self> {
51 let mask: image::ImageBuffer<image::Luma<_>, Vec<_>> =
52 image::ImageBuffer::from_raw(width, height, u8s.to_vec())
53 .ok_or(anyhow::anyhow!("Failed to build ImageBuffer."))?;
54
55 Ok(Self {
56 mask,
57 ..Default::default()
58 })
59 }
60
61 pub fn to_vec(&self) -> Vec<u8> {
62 self.mask.to_vec()
63 }
64
65 pub fn height(&self) -> u32 {
66 self.mask.height()
67 }
68
69 pub fn width(&self) -> u32 {
70 self.mask.width()
71 }
72
73 pub fn dimensions(&self) -> (u32, u32) {
74 self.mask.dimensions()
75 }
76
77 pub fn polygon(&self) -> Option<Polygon> {
78 let polygons = self.polygons();
79 if polygons.is_empty() {
80 return None;
81 }
82
83 polygons.into_iter().max_by(|x, y| {
84 x.area()
85 .partial_cmp(&y.area())
86 .unwrap_or(std::cmp::Ordering::Equal)
87 })
88 }
89
90 pub fn polygons(&self) -> Vec<Polygon> {
91 let contours: Vec<imageproc::contours::Contour<i32>> =
92 imageproc::contours::find_contours_with_threshold(self.mask(), 0);
93 let polygons: Vec<Polygon> = contours
94 .into_par_iter()
95 .filter_map(|contour| {
96 if contour.border_type == imageproc::contours::BorderType::Hole
97 && contour.points.len() <= 2
98 {
99 return None;
100 }
101 let coords: Vec<[f32; 2]> = contour
102 .points
103 .iter()
104 .map(|p| [p.x as f32, p.y as f32])
105 .collect();
106
107 let mut polygon = match Polygon::try_from(coords) {
108 Ok(p) => p.verify(),
109 Err(_) => return None,
110 };
111 if let Some(x) = self.name() {
112 polygon = polygon.with_name(x);
113 }
114 if let Some(x) = self.id() {
115 polygon = polygon.with_id(x);
116 }
117 if let Some(x) = self.confidence() {
118 polygon = polygon.with_confidence(x);
119 }
120 Some(polygon)
121 })
122 .collect();
123
124 polygons
125 }
126}