///|
/// Connected-component labeling on a thresholded image. Foreground pixels
/// (luma strictly greater than the threshold) are grouped by 4-connectivity
/// with an explicit-stack flood fill, giving each blob a positive label.
///|
/// Labels 4-connected foreground components. Returns `(labels, count)`
/// where `labels` has one entry per pixel — `0` for background, `1..count`
/// for each component — in row-major order.
pub fn Image::label_components(
self : Image,
threshold : Int,
) -> (Array[Int], Int) {
let w = self.width
let h = self.height
let n = w * h
// Foreground mask from luma.
let fg : Array[Bool] = Array::make(n, false)
for p in 0.. threshold
}
let labels : Array[Int] = Array::make(n, 0)
let stack : Array[Int] = []
let mut count = 0
for start in 0.. 0 {
let p = stack.unsafe_pop()
let px = p % w
let py = p / w
// 4-neighborhood.
if px > 0 && fg[p - 1] && labels[p - 1] == 0 {
labels[p - 1] = count
stack.push(p - 1)
}
if px + 1 < w && fg[p + 1] && labels[p + 1] == 0 {
labels[p + 1] = count
stack.push(p + 1)
}
if py > 0 && fg[p - w] && labels[p - w] == 0 {
labels[p - w] = count
stack.push(p - w)
}
if py + 1 < h && fg[p + w] && labels[p + w] == 0 {
labels[p + w] = count
stack.push(p + w)
}
}
}
(labels, count)
}
///|
/// Counts the 4-connected foreground blobs (luma > `threshold`).
pub fn Image::count_components(self : Image, threshold : Int) -> Int {
self.label_components(threshold).1
}