use image::DynamicImage;
pub fn remove_moire(img: &mut DynamicImage) {
let blurred = img.blur(1.0);
*img = blurred.unsharpen(0.5, 1);
}
#[cfg(test)]
mod tests {
use super::*;
use image::{DynamicImage, GrayImage, RgbImage};
#[test]
fn test_remove_moire_grayscale() {
let mut gray = GrayImage::new(64, 64);
for y in 0..64 {
for x in 0..64 {
let val = if (x + y) % 2 == 0 { 200u8 } else { 50u8 };
gray.put_pixel(x, y, image::Luma([val]));
}
}
let mut img = DynamicImage::ImageLuma8(gray);
remove_moire(&mut img);
assert_eq!(img.width(), 64);
assert_eq!(img.height(), 64);
let output_gray = img.to_luma8();
let center = output_gray.get_pixel(32, 32)[0];
let neighbor = output_gray.get_pixel(33, 32)[0];
let original_diff: i32 = 150; let filtered_diff = (center as i32 - neighbor as i32).abs();
assert!(
filtered_diff < original_diff,
"Moire filter should reduce high-frequency contrast: original diff={}, filtered diff={}",
original_diff,
filtered_diff,
);
println!(" \u{2713} Grayscale moire: contrast diff {} -> {}", original_diff, filtered_diff);
}
#[test]
fn test_remove_moire_rgb() {
let rgb = RgbImage::new(32, 32);
let mut img = DynamicImage::ImageRgb8(rgb);
remove_moire(&mut img);
assert_eq!(img.width(), 32);
assert_eq!(img.height(), 32);
println!(" \u{2713} RGB 32x32 moire filter ran without error");
}
#[test]
fn test_remove_moire_preserves_dimensions() {
for &(w, h) in &[(1, 1), (3, 3), (100, 200), (1072, 1448)] {
let gray = GrayImage::new(w, h);
let mut img = DynamicImage::ImageLuma8(gray);
remove_moire(&mut img);
assert_eq!(img.width(), w);
assert_eq!(img.height(), h);
}
println!(" \u{2713} All 4 sizes preserved dimensions after moire filter");
}
}