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