Modify contour finding to return path vertices instead of trace

This commit is contained in:
cdo committed 2026-10-29 13:13:22 +00:00
1 parent d550a7e71e
commit a7372d05c2
2 files changed
+72 -53

No files matched your search

+9 -6
View File
@@ -21,12 +21,15 @@ fn main() -> std::process::ExitCode {
let thresholded = filter::threshold_auto(greyscale); let thresholded = filter::threshold_auto(greyscale);
let contours = contour::find(thresholded); let contours = contour::find(thresholded);
for contour in contours { for contour in contours {
for (x, y) in contour.trace { let n = contour.vertices.len();
*img.at_mut(x, y) = match contour.kind { for i in 0..n {
contour::Kind::Inner => INNER, let (x0, y0) = contour.vertices[i];
contour::Kind::Outer => OUTER, let (x1, y1) = contour.vertices[(i + 1) % n];
}; draw::line(x0, y0, x1, y1, &mut img, match contour.kind {
} contour::Kind::Outer => OUTER,
contour::Kind::Inner => INNER,
});
}
} }
img img
}) })
+63 -47
View File
@@ -8,7 +8,7 @@ pub enum Kind {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Contour { pub struct Contour {
pub trace: Vec<(usize, usize)>, pub vertices: Vec<(usize, usize)>,
pub children: Vec<usize>, pub children: Vec<usize>,
pub parent: Option<usize>, pub parent: Option<usize>,
pub kind: Kind, pub kind: Kind,
@@ -58,66 +58,73 @@ pub fn find(img: image::Image<image::Luminance>) -> Vec<Contour> {
let mut parent = None; let mut parent = None;
for x in 0..map.extent.x { for x in 0..map.extent.x {
let q = (x, y); let q = (x, y);
if foreground(&map, q) { if foreground(&map, q) && background(&map, q.prev_x()) {
let prev_bg = background(&map, q.prev_x()); add(q, Kind::Outer, parent, &mut contours, &mut map);
let next_bg = background(&map, q.next_x()); } else if foreground(&map, q) && background(&map, q.next_x()) {
if prev_bg || next_bg { add(q, Kind::Inner, parent, &mut contours, &mut map);
let (dir, kind) = if prev_bg {
(Dir::W, Kind::Outer)
} else {
(Dir::E, Kind::Inner)
};
let label = contours.len();
let trace = trace(&mut map, q, dir, label);
contours.push(Contour::new(parent, kind, trace));
if let Some(index) = parent {
contours[index].add_child(label);
}
}
} else if let Some(label) = traced(&map, q) { } else if let Some(label) = traced(&map, q) {
if background(&map, q.prev_x()) { if background(&map, q.prev_x()) {
parent = Some(label); parent = Some(label);
} else if background(&map, q.next_x()) { } else if background(&map, q.next_x()) {
parent = contours[label].parent; parent = contours[label].parent;
} }
} }
} }
} }
contours contours
} }
fn add(
start: (usize, usize),
kind: Kind,
parent: Option<usize>,
contours: &mut Vec<Contour>,
map: &mut image::Image<Pixel>,
) {
let label = contours.len();
let vertices = trace(map, start, kind.start_dir(), label);
contours.push(Contour::new(parent, kind, vertices));
if let Some(index) = parent {
contours[index].add_child(label);
}
}
fn trace( fn trace(
img: &mut image::Image<Pixel>, img: &mut image::Image<Pixel>,
start_q: (usize, usize), start_q: (usize, usize),
mut dir: Dir, start_dir: Dir,
label: usize, label: usize,
) -> Vec<(usize, usize)> { ) -> Vec<(usize, usize)> {
let mut q = start_q; let mut q = start_q;
dir = dir.next(); let mut dir = start_dir;
while background(img, dir.from(q)) {
dir.next();
}
let mut path = Vec::new(); let mut vertices = Vec::new();
'outer: loop { loop {
if !q.in_bounds(img.extent) {
break;
}
q.set(img, Pixel::Traced(label)); q.set(img, Pixel::Traced(label));
path.push(q);
let start = dir; let prev_dir = dir;
while background(img, dir.from(q)) {
dir = dir.next();
if dir == start {
break 'outer;
}
}
q = dir.from(q);
dir = dir.flip().next(); dir = dir.flip().next();
q = loop {
let qp = dir.from(q);
if !background(img, qp) {
if dir != prev_dir {
vertices.push(q)
}
break qp;
}
dir = dir.next();
};
if q == start_q { if q == start_q || !q.in_bounds(img.extent) {
break; if dir != start_dir {
vertices.push(q);
}
break vertices;
} }
} }
path
} }
fn foreground(img: &image::Image<Pixel>, q: (usize, usize)) -> bool { fn foreground(img: &image::Image<Pixel>, q: (usize, usize)) -> bool {
@@ -141,6 +148,15 @@ fn traced(img: &image::Image<Pixel>, q: (usize, usize)) -> Option<usize> {
} }
} }
impl Kind {
fn start_dir(self) -> Dir {
match self {
Kind::Outer => Dir::E,
Kind::Inner => Dir::W,
}
}
}
impl Dir { impl Dir {
fn next(self) -> Self { fn next(self) -> Self {
match self { match self {
@@ -222,19 +238,19 @@ impl Contour {
fn new( fn new(
parent: Option<usize>, parent: Option<usize>,
kind: Kind, kind: Kind,
trace: Vec<(usize, usize)>, vertices: Vec<(usize, usize)>,
) -> Self { ) -> Self {
Self { Self {
trace, vertices,
children: Vec::new(), children: Vec::new(),
parent, parent,
kind, kind,
} }
} }
fn add_child(&mut self, child: usize) { fn add_child(&mut self, child: usize) {
self.children.push(child); self.children.push(child);
} }
} }
impl Default for Pixel { impl Default for Pixel {