use std::cmp::{max, min};
pub fn binarize(img: &[u8], width: usize, height: usize) -> Vec<u8> {
if width == 0 || height == 0 {
return Vec::new();
}
let mut mask = vec![0u8; width * height];
let mut logwindw = 4;
while logwindw < 8 && (1 << logwindw) < ((width + 7) >> 3) {
logwindw += 1;
}
let mut logwindh = 4;
while logwindh < 8 && (1 << logwindh) < ((height + 7) >> 3) {
logwindh += 1;
}
let windw = 1 << logwindw;
let windh = 1 << logwindh;
let mut col_sums = vec![0u32; width];
for x in 0..width {
let g = img[x] as u32;
col_sums[x] = (g << (logwindh - 1)) + g;
}
for y in 1..(windh >> 1) {
let y1offs = min(y, height - 1) * width;
for x in 0..width {
let g = img[y1offs + x] as u32;
col_sums[x] += g;
}
}
for y in 0..height {
let mut m = (col_sums[0] << (logwindw - 1)) + col_sums[0];
for x in 1..(windw >> 1) {
let x1 = min(x, width - 1);
m += col_sums[x1];
}
for x in 0..width {
let g = img[y * width + x] as u32;
mask[y * width + x] = if ((g + 3) << (logwindw + logwindh)) < m {
0xFF
} else {
0x00
};
if x + 1 < width {
let x0 = max(0, x as i32 - (windw as i32 >> 1)) as usize;
let x1 = min(x + (windw >> 1), width - 1);
m += col_sums[x1];
m -= col_sums[x0];
}
}
if y + 1 < height {
let y0offs = max(0, y as i32 - (windh as i32 >> 1)) as usize * width;
let y1offs = min(y + (windh >> 1), height - 1) * width;
for x in 0..width {
col_sums[x] -= img[y0offs + x] as u32;
col_sums[x] += img[y1offs + x] as u32;
}
}
}
mask
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_binarize_empty() {
let img = vec![0u8; 0];
let mask = binarize(&img, 0, 0);
assert_eq!(mask.len(), 0);
}
#[test]
fn test_binarize_uniform() {
let img = vec![128u8; 100 * 100];
let mask = binarize(&img, 100, 100);
assert_eq!(mask.len(), 100 * 100);
let first = mask[0];
assert!(mask.iter().all(|&p| p == first));
}
#[test]
fn test_binarize_simple_pattern() {
let width = 50;
let height = 50;
let mut img = vec![255u8; width * height];
for y in 20..30 {
for x in 20..30 {
img[y * width + x] = 0;
}
}
let mask = binarize(&img, width, height);
assert_eq!(mask.len(), width * height);
assert_eq!(mask[25 * width + 25], 0xFF);
}
#[test]
fn test_binarize_gradient() {
let width = 64;
let height = 64;
let mut img = vec![0u8; width * height];
for y in 0..height {
for x in 0..width {
img[y * width + x] = ((x * 255) / (width - 1)) as u8;
}
}
let mask = binarize(&img, width, height);
assert_eq!(mask.len(), width * height);
assert_eq!(mask[32 * width], 0xFF); assert_eq!(mask[32 * width + 63], 0x00); }
#[test]
fn test_binarize_small_image() {
let img = vec![0, 255, 255, 0]; let mask = binarize(&img, 2, 2);
assert_eq!(mask.len(), 4);
}
}