///|
/// Structuring element shape for mathematical morphology operations.
pub(all) enum MorphShape {
Rect
Cross
Ellipse
} derive(Debug, Eq)
///|
/// Structuring element with 2D binary kernel.
pub(all) struct StructuringElement {
shape : MorphShape
radius : Int
width : Int
height : Int
data : Array[Bool]
} derive(Debug, Eq)
///|
/// Creates a structuring element of specified shape and radius.
pub fn StructuringElement::new(
shape : MorphShape,
radius : Int,
) -> StructuringElement {
let r = if radius < 1 { 1 } else { radius }
let size = 2 * r + 1
let data = Array::make(size * size, false)
for dy in -r..<=r {
for dx in -r..<=r {
let is_active = match shape {
Rect => true
Cross => dx == 0 || dy == 0
Ellipse =>
(dx * dx).to_double() / (r * r).to_double() +
(dy * dy).to_double() / (r * r).to_double() <=
1.0001
}
let idx = (dy + r) * size + (dx + r)
data[idx] = is_active
}
}
{ shape, radius: r, width: size, height: size, data }
}
///|
/// Morphological Dilation (local maximum operator).
pub fn morph_dilate(img : Image, element : StructuringElement) -> Image {
let w = img.width
let h = img.height
let res = Image::new(w, h)
let r = element.radius
let size = element.width
for y in 0..= 0 && px < w && py >= 0 && py < h {
let v = img.get(px, py)
if v > max_val {
max_val = v
}
}
}
}
}
res.set(x, y, max_val)
}
}
res
}
///|
/// Morphological Erosion (local minimum operator).
pub fn morph_erode(img : Image, element : StructuringElement) -> Image {
let w = img.width
let h = img.height
let res = Image::new(w, h)
let r = element.radius
let size = element.width
for y in 0..= 0 && px < w && py >= 0 && py < h {
let v = img.get(px, py)
if v < min_val {
min_val = v
}
} else {
min_val = 0
}
}
}
}
res.set(x, y, min_val)
}
}
res
}
///|
/// Morphological Opening: Erode followed by Dilate (removes small bright noise).
pub fn morph_open(img : Image, element : StructuringElement) -> Image {
let eroded = morph_erode(img, element)
morph_dilate(eroded, element)
}
///|
/// Morphological Closing: Dilate followed by Erode (fills small dark holes).
pub fn morph_close(img : Image, element : StructuringElement) -> Image {
let dilated = morph_dilate(img, element)
morph_erode(dilated, element)
}
///|
/// Morphological Gradient: Dilate minus Erode (highlights object boundaries).
pub fn morph_gradient(img : Image, element : StructuringElement) -> Image {
let dilated = morph_dilate(img, element)
let eroded = morph_erode(img, element)
let w = img.width
let h = img.height
let res = Image::new(w, h)
for y in 0.. Image {
let opened = morph_open(img, element)
let w = img.width
let h = img.height
let res = Image::new(w, h)
for y in 0.. Image {
let closed = morph_close(img, element)
let w = img.width
let h = img.height
let res = Image::new(w, h)
for y in 0.. Image {
let w = binary_img.width
let h = binary_img.height
let img = binary_img.clone()
let mut changed = true
let to_delete : Array[(Int, Int)] = []
while changed {
changed = false
// Step 1
to_delete.clear()
for y in 1..<(h - 1) {
for x in 1..<(w - 1) {
if img.get(x, y) > 0 {
let p2 = if img.get(x, y - 1) > 0 { 1 } else { 0 }
let p3 = if img.get(x + 1, y - 1) > 0 { 1 } else { 0 }
let p4 = if img.get(x + 1, y) > 0 { 1 } else { 0 }
let p5 = if img.get(x + 1, y + 1) > 0 { 1 } else { 0 }
let p6 = if img.get(x, y + 1) > 0 { 1 } else { 0 }
let p7 = if img.get(x - 1, y + 1) > 0 { 1 } else { 0 }
let p8 = if img.get(x - 1, y) > 0 { 1 } else { 0 }
let p9 = if img.get(x - 1, y - 1) > 0 { 1 } else { 0 }
let b = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9
if b >= 2 && b <= 6 {
let mut a = 0
if p2 == 0 && p3 == 1 {
a += 1
}
if p3 == 0 && p4 == 1 {
a += 1
}
if p4 == 0 && p5 == 1 {
a += 1
}
if p5 == 0 && p6 == 1 {
a += 1
}
if p6 == 0 && p7 == 1 {
a += 1
}
if p7 == 0 && p8 == 1 {
a += 1
}
if p8 == 0 && p9 == 1 {
a += 1
}
if p9 == 0 && p2 == 1 {
a += 1
}
if a == 1 && p2 * p4 * p6 == 0 && p4 * p6 * p8 == 0 {
to_delete.push((x, y))
}
}
}
}
}
if to_delete.length() > 0 {
changed = true
for pt in to_delete {
img.set(pt.0, pt.1, 0)
}
}
// Step 2
to_delete.clear()
for y in 1..<(h - 1) {
for x in 1..<(w - 1) {
if img.get(x, y) > 0 {
let p2 = if img.get(x, y - 1) > 0 { 1 } else { 0 }
let p3 = if img.get(x + 1, y - 1) > 0 { 1 } else { 0 }
let p4 = if img.get(x + 1, y) > 0 { 1 } else { 0 }
let p5 = if img.get(x + 1, y + 1) > 0 { 1 } else { 0 }
let p6 = if img.get(x, y + 1) > 0 { 1 } else { 0 }
let p7 = if img.get(x - 1, y + 1) > 0 { 1 } else { 0 }
let p8 = if img.get(x - 1, y) > 0 { 1 } else { 0 }
let p9 = if img.get(x - 1, y - 1) > 0 { 1 } else { 0 }
let b = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9
if b >= 2 && b <= 6 {
let mut a = 0
if p2 == 0 && p3 == 1 {
a += 1
}
if p3 == 0 && p4 == 1 {
a += 1
}
if p4 == 0 && p5 == 1 {
a += 1
}
if p5 == 0 && p6 == 1 {
a += 1
}
if p6 == 0 && p7 == 1 {
a += 1
}
if p7 == 0 && p8 == 1 {
a += 1
}
if p8 == 0 && p9 == 1 {
a += 1
}
if p9 == 0 && p2 == 1 {
a += 1
}
if a == 1 && p2 * p4 * p8 == 0 && p2 * p6 * p8 == 0 {
to_delete.push((x, y))
}
}
}
}
}
if to_delete.length() > 0 {
changed = true
for pt in to_delete {
img.set(pt.0, pt.1, 0)
}
}
}
img
}