fn main() {
use fovea::image::{Image, ImageView, ImageViewMut, Neighborhood};
use fovea::pixel::Mono8;
use fovea::border::Clamp;
use fovea::transform::{FoldItem, FoldOp, fold_neighborhood};
struct WeightedAverage;
impl FoldOp<Mono8, f32> for WeightedAverage {
type Accumulator = (f32, f32);
type Output = Mono8;
fn init(&self) -> Self::Accumulator {
(0.0_f32, 0.0_f32) }
#[inline(always)]
fn accumulate(&self, acc: &mut Self::Accumulator, item: FoldItem<Mono8, f32>) {
acc.0 += item.pixel.value() as f32 * item.weight;
acc.1 += item.weight;
}
fn finalize(&mut self, acc: Self::Accumulator) -> Self::Output {
let (sum, weight_sum) = acc;
let avg = if weight_sum > 0.0 {
sum / weight_sum
} else {
0.0
};
Mono8::new(avg.round().clamp(0.0, 255.0) as u8)
}
}
let mut img = Image::<Mono8>::zero(8, 8);
*img.pixel_at_mut(4, 4) = Mono8::new(255);
println!("Input: 8×8 black image with a bright spot at (4,4)");
println!(" pixel(4,4) = {}", img.pixel_at(4, 4).value()); println!(" pixel(3,4) = {}", img.pixel_at(3, 4).value()); println!(" pixel(0,0) = {}", img.pixel_at(0, 0).value());
let kernel = Neighborhood::<f32, 3, 3>::new([
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, ]);
let result = fold_neighborhood(
&img, kernel.weights(), kernel.anchor(), &Clamp, WeightedAverage, );
let center = result.pixel_at(4, 4).value();
let neighbor = result.pixel_at(3, 4).value();
let far = result.pixel_at(0, 0).value();
println!("\nOutput after 3×3 weighted-average filter:");
println!(" pixel(4,4) = {} (was 255)", center);
println!(" pixel(3,4) = {} (was 0)", neighbor);
println!(" pixel(0,0) = {} (was 0)", far);
assert!(
center > 0 && center < 255,
"center should be dimmed by averaging with its dark neighbors"
);
assert!(
neighbor > 0,
"immediate neighbor should be non-zero after averaging"
);
assert_eq!(
far, 0,
"pixels far from the bright spot should remain black"
);
assert_eq!(
center, 28,
"255 averaged over 9 equal-weight cells should round to 28"
);
assert_eq!(
neighbor, 28,
"neighbor's 3×3 window also contains exactly one bright pixel"
);
println!("\nCustom filter verified — the bright spot was spread by the 3×3 weighted average!");
println!("Implementing FoldOp lets you plug arbitrary per-pixel logic");
println!("into the same optimized interior/boundary engine that the");
println!("built-in convolution and morphology operations use.");
}