Fully handle inner/outer determination and nesting in contour tracing
This commit is contained in:
1 parent
a7372d05c2
commit
7f29c5abbb
2 files changed
+63
-22
No files matched your search
+17
-10
@@ -15,22 +15,29 @@ const INNER: image::SRGBA = image::SRGBA {
|
|||||||
a: 1.0,
|
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 {
|
fn main() -> std::process::ExitCode {
|
||||||
common::process_image(|mut img| {
|
common::process_image(|mut img| {
|
||||||
let greyscale = img.map(|p| image::Luminance::from(p));
|
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);
|
let contours = contour::find(thresholded);
|
||||||
for contour in contours {
|
for contour in contours {
|
||||||
let n = contour.vertices.len();
|
draw(&contour, &mut img);
|
||||||
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
|
img
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
+46
-12
@@ -18,7 +18,8 @@ pub struct Contour {
|
|||||||
enum Pixel {
|
enum Pixel {
|
||||||
Foreground,
|
Foreground,
|
||||||
Background,
|
Background,
|
||||||
Traced(usize),
|
TracedUp(usize),
|
||||||
|
TracedDown(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
@@ -60,14 +61,14 @@ pub fn find(img: image::Image<image::Luminance>) -> Vec<Contour> {
|
|||||||
let q = (x, y);
|
let q = (x, y);
|
||||||
if foreground(&map, q) && background(&map, q.prev_x()) {
|
if foreground(&map, q) && background(&map, q.prev_x()) {
|
||||||
add(q, Kind::Outer, parent, &mut contours, &mut map);
|
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);
|
add(q, Kind::Inner, parent, &mut contours, &mut map);
|
||||||
} else if let Some(label) = traced(&map, q) {
|
} else if let Some(label) = traced_up(&map, q) {
|
||||||
if background(&map, q.prev_x()) {
|
parent = Some(label);
|
||||||
parent = Some(label);
|
} else if let Some(label) = traced_down(&map, q) {
|
||||||
} else if background(&map, q.next_x()) {
|
parent = contours[label].parent;
|
||||||
parent = contours[label].parent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,7 +104,9 @@ fn trace(
|
|||||||
|
|
||||||
let mut vertices = Vec::new();
|
let mut vertices = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
q.set(img, Pixel::Traced(label));
|
if foreground(img, q) {
|
||||||
|
q.set(img, Pixel::TracedUp(label));
|
||||||
|
}
|
||||||
|
|
||||||
let prev_dir = dir;
|
let prev_dir = dir;
|
||||||
dir = dir.flip().next();
|
dir = dir.flip().next();
|
||||||
@@ -115,6 +118,9 @@ fn trace(
|
|||||||
}
|
}
|
||||||
break qp;
|
break qp;
|
||||||
}
|
}
|
||||||
|
if dir == Dir::E {
|
||||||
|
q.set(img, Pixel::TracedDown(label));
|
||||||
|
}
|
||||||
dir = dir.next();
|
dir = dir.next();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -122,9 +128,27 @@ fn trace(
|
|||||||
if dir != start_dir {
|
if dir != start_dir {
|
||||||
vertices.push(q);
|
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 {
|
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) {
|
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,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user