Fully handle inner/outer determination and nesting in contour tracing

This commit is contained in:
cdo committed 2026-10-30 11:10:13 +00:00
1 parent a7372d05c2
commit 7f29c5abbb
2 files changed
+63 -22

No files matched your search

+17 -10
View File
@@ -15,22 +15,29 @@ const INNER: image::SRGBA = image::SRGBA {
a: 1.0,
};
fn draw(contour: &contour::Contour, img: &mut image::Image<image::SRGBA>) {
let n = contour.vertices.len();
for i in 0..n {
let (x0, y0) = contour.vertices[i];
let (x1, y1) = contour.vertices[(i + 1) % n];
let colour = match contour.kind {
contour::Kind::Outer => OUTER,
contour::Kind::Inner => INNER,
};
draw::line(x0, y0, x1, y1, img, colour);
}
}
fn main() -> std::process::ExitCode {
common::process_image(|mut img| {
let greyscale = img.map(|p| image::Luminance::from(p));
let thresholded = filter::threshold_auto(greyscale);
let thresholded = filter::threshold_auto(greyscale);
let contours = contour::find(thresholded);
for contour in contours {
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,
});
}
draw(&contour, &mut img);
}
img
})
}
+46 -12
View File
@@ -18,7 +18,8 @@ pub struct Contour {
enum Pixel {
Foreground,
Background,
Traced(usize),
TracedUp(usize),
TracedDown(usize),
}
#[derive(Clone, Copy, Debug, PartialEq)]
@@ -60,14 +61,14 @@ pub fn find(img: image::Image<image::Luminance>) -> Vec<Contour> {
let q = (x, y);
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()) {
} else if (foreground(&map, q) || traced_up(&map, q).is_some())
&& 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;
}
} else if let Some(label) = traced_up(&map, q) {
parent = Some(label);
} else if let Some(label) = traced_down(&map, q) {
parent = contours[label].parent;
}
}
}
@@ -103,7 +104,9 @@ fn trace(
let mut vertices = Vec::new();
loop {
q.set(img, Pixel::Traced(label));
if foreground(img, q) {
q.set(img, Pixel::TracedUp(label));
}
let prev_dir = dir;
dir = dir.flip().next();
@@ -115,6 +118,9 @@ fn trace(
}
break qp;
}
if dir == Dir::E {
q.set(img, Pixel::TracedDown(label));
}
dir = dir.next();
};
@@ -122,9 +128,27 @@ fn trace(
if dir != start_dir {
vertices.push(q);
}
break vertices;
break;
}
}
// println!();
// for y in 0..img.extent.y {
// for x in 0..img.extent.x {
// if let Some(label) = traced_up(img, (x, y)) {
// print!("{:1}", label);
// } else if let Some(label) = traced_down(img, (x, y)) {
// print!("-")
// } else if foreground(img, (x, y)) {
// print!(".");
// } else if background(img, (x, y)) {
// print!(" ");
// }
// }
// println!();
// }
vertices
}
fn foreground(img: &image::Image<Pixel>, q: (usize, usize)) -> bool {
@@ -141,9 +165,19 @@ fn background(img: &image::Image<Pixel>, q: (usize, usize)) -> bool {
}
}
fn traced(img: &image::Image<Pixel>, q: (usize, usize)) -> Option<usize> {
fn traced_up(img: &image::Image<Pixel>, q: (usize, usize)) -> Option<usize> {
match q.get(img) {
Some(Pixel::Traced(label)) => Some(label),
Some(Pixel::TracedUp(label)) => Some(label),
_ => None,
}
}
fn traced_down(
img: &image::Image<Pixel>,
q: (usize, usize),
) -> Option<usize> {
match q.get(img) {
Some(Pixel::TracedDown(label)) => Some(label),
_ => None,
}
}