///|
pub fn BinaryMask::BinaryMask(width~ : Int, height~ : Int) -> BinaryMask {
{
width: width.max(0),
height: height.max(0),
values: Array::make(width.max(0) * height.max(0), false),
}
}
///|
pub fn BinaryMask::inside(mask : BinaryMask, x : Int, y : Int) -> Bool {
x >= 0 && y >= 0 && x < mask.width && y < mask.height
}
///|
fn mask_index(mask : BinaryMask, x : Int, y : Int) -> Int {
y * mask.width + x
}
///|
pub fn BinaryMask::at(mask : BinaryMask, x : Int, y : Int) -> Bool {
if mask.inside(x, y) {
mask.values[mask_index(mask, x, y)]
} else {
false
}
}
///|
pub fn BinaryMask::set(
mask : BinaryMask,
x : Int,
y : Int,
value : Bool,
) -> Unit {
if mask.inside(x, y) {
mask.values[mask_index(mask, x, y)] = value
}
}
///|
pub fn BinaryMask::count(mask : BinaryMask) -> Int {
let mut result = 0
for value in mask.values {
if value {
result += 1
}
}
result
}
///|
pub fn BinaryMask::clear(mask : BinaryMask) -> Unit {
for i in 0.. Unit {
for i in 0.. BinaryMask {
let result = BinaryMask(width=mask.width, height=mask.height)
for i in 0.. BinaryMask {
let result = BinaryMask(width=mask.width, height=mask.height)
for i in 0.. BinaryMask {
let width = a.width.min(b.width)
let height = a.height.min(b.height)
let result = BinaryMask(width~, height~)
for y in 0.. BinaryMask {
let width = a.width.min(b.width)
let height = a.height.min(b.height)
let result = BinaryMask(width~, height~)
for y in 0.. BinaryMask {
let result = a.clone()
for y in 0.. Bounds {
let mut min_x = mask.width
let mut min_y = mask.height
let mut max_x = -1
let mut max_y = -1
for y in 0.. Array[Int] {
let result = Array::make(mask.height, 0)
for y in 0.. Array[Int] {
let result = Array::make(mask.width, 0)
for y in 0.. BinaryMask {
let result = BinaryMask(width=mask.width, height=mask.height)
let safe_radius = radius.max(0)
for y in 0.. BinaryMask {
let result = BinaryMask(width=mask.width, height=mask.height)
let safe_radius = radius.max(0)
for y in 0.. BinaryMask {
mask.erode(radius).dilate(radius)
}
///|
pub fn BinaryMask::closing(mask : BinaryMask, radius : Int) -> BinaryMask {
mask.dilate(radius).erode(radius)
}
///|
pub fn BinaryMask::boundary(mask : BinaryMask) -> BinaryMask {
mask.difference(mask.erode(1))
}
///|
pub fn has_true_neighbor(
mask : BinaryMask,
x : Int,
y : Int,
radius : Int,
) -> Bool {
let safe_radius = radius.max(0)
for dy in -safe_radius..<=safe_radius {
for dx in -safe_radius..<=safe_radius {
if (dx != 0 || dy != 0) && mask.at(x + dx, y + dy) {
return true
}
}
}
false
}
///|
pub fn mask_to_image(
mask : BinaryMask,
foreground : Double,
background : Double,
) -> GrayImage {
let image = GrayImage(width=mask.width, height=mask.height, fill=background)
for y in 0.. BinaryMask {
threshold_image(image, threshold)
}
///|
pub fn fill_mask_holes(mask : BinaryMask) -> BinaryMask {
let outside = BinaryMask(width=mask.width, height=mask.height)
let queue : Array[Point] = []
for x in 0.. 1 && !mask.at(x, mask.height - 1) {
outside.set(x, mask.height - 1, true)
queue.push(
Point(x=Double::from_int(x), y=Double::from_int(mask.height - 1)),
)
}
}
for y in 0.. 1 && !mask.at(mask.width - 1, y) {
outside.set(mask.width - 1, y, true)
queue.push(
Point(x=Double::from_int(mask.width - 1), y=Double::from_int(y)),
)
}
}
let mut cursor = 0
while cursor < queue.length() {
let point = queue[cursor]
cursor += 1
for
neighbor in [
Point(x=point.x + 1.0, y=point.y),
Point(x=point.x - 1.0, y=point.y),
Point(x=point.x, y=point.y + 1.0),
Point(x=point.x, y=point.y - 1.0),
] {
let nx = neighbor.x.to_int()
let ny = neighbor.y.to_int()
if outside.inside(nx, ny) && !mask.at(nx, ny) && !outside.at(nx, ny) {
outside.set(nx, ny, true)
queue.push(neighbor)
}
}
}
let result = mask.clone()
for y in 0..