diff --git a/src/noise.rs b/src/noise.rs index 613211ad..5ebcb04e 100644 --- a/src/noise.rs +++ b/src/noise.rs @@ -33,6 +33,68 @@ where } } +/// Adds multiplicative speckle noise to an image with the given mean and standard deviation. +/// Noise is added per pixel for realistic sensor noise simulation. +pub fn speckle_noise

(image: &Image

, mean: f64, stddev: f64, seed: u64) -> Image

+where + P: Pixel, + P::Subpixel: Into + Clamp, +{ + let mut out = image.clone(); + speckle_noise_mut(&mut out, mean, stddev, seed); + out +} + +#[doc=generate_mut_doc_comment!("speckle_noise")] +pub fn speckle_noise_mut

(image: &mut Image

, mean: f64, stddev: f64, seed: u64) +where + P: Pixel, + P::Subpixel: Into + Clamp, +{ + let mut rng: StdRng = SeedableRng::seed_from_u64(seed); + let normal = Normal::new(mean, stddev).unwrap(); + + // Use the same noise pattern for each channel + for p in image.pixels_mut() { + let noise = normal.sample(&mut rng); + p.apply(|c| { + let original = c.into(); + P::Subpixel::clamp(original + original * noise) + }); + } +} + +/// Adds multiplicative speckle noise to an image with the given mean and standard deviation. +/// Noise is added independently per channel for data augmentation. +pub fn speckle_noise_per_channel

(image: &Image

, mean: f64, stddev: f64, seed: u64) -> Image

+where + P: Pixel, + P::Subpixel: Into + Clamp, +{ + let mut out = image.clone(); + speckle_noise_per_channel_mut(&mut out, mean, stddev, seed); + out +} + +#[doc=generate_mut_doc_comment!("speckle_noise_per_channel")] +pub fn speckle_noise_per_channel_mut

(image: &mut Image

, mean: f64, stddev: f64, seed: u64) +where + P: Pixel, + P::Subpixel: Into + Clamp, +{ + let mut rng: StdRng = SeedableRng::seed_from_u64(seed); + let normal = Normal::new(mean, stddev).unwrap(); + + // Add sampled noise per channel in each pixel + for p in image.pixels_mut() { + p.apply(|c| { + let noise = normal.sample(&mut rng); + let original = c.into(); + P::Subpixel::clamp(original + original * noise) + }); + } +} + /// Converts pixels to black or white at the given `rate` (between 0.0 and 1.0). /// Black and white occur with equal probability. pub fn salt_and_pepper_noise

(image: &Image

, rate: f64, seed: u64) -> Image

@@ -84,4 +146,22 @@ mod benches { }); black_box(image); } + + #[bench] + fn bench_speckle_noise_mut(b: &mut Bencher) { + let mut image = GrayImage::new(100, 100); + b.iter(|| { + speckle_noise_mut(&mut image, 0.0, 0.4, 1); + }); + black_box(image); + } + + #[bench] + fn bench_speckle_noise_per_channel_mut(b: &mut Bencher) { + let mut image = GrayImage::new(100, 100); + b.iter(|| { + speckle_noise_per_channel_mut(&mut image, 0.0, 0.4, 1); + }); + black_box(image); + } }