1use crate::definitions::{Clamp, HasBlack, HasWhite, Image};
4use crate::math::cast;
5use conv::ValueInto;
6use image::Pixel;
7use rand::{rngs::StdRng, SeedableRng};
8use rand_distr::{Distribution, Normal, Uniform};
9
10pub fn gaussian_noise<P>(image: &Image<P>, mean: f64, stddev: f64, seed: u64) -> Image<P>
13where
14 P: Pixel,
15 P::Subpixel: ValueInto<f64> + Clamp<f64>,
16{
17 let mut out = image.clone();
18 gaussian_noise_mut(&mut out, mean, stddev, seed);
19 out
20}
21
22pub fn gaussian_noise_mut<P>(image: &mut Image<P>, mean: f64, stddev: f64, seed: u64)
25where
26 P: Pixel,
27 P::Subpixel: ValueInto<f64> + Clamp<f64>,
28{
29 let mut rng: StdRng = SeedableRng::seed_from_u64(seed);
30 let normal = Normal::new(mean, stddev).unwrap();
31
32 for p in image.pixels_mut() {
33 for c in p.channels_mut() {
34 let noise = normal.sample(&mut rng);
35 *c = P::Subpixel::clamp(cast(*c) + noise);
36 }
37 }
38}
39
40pub fn salt_and_pepper_noise<P>(image: &Image<P>, rate: f64, seed: u64) -> Image<P>
43where
44 P: Pixel + HasBlack + HasWhite,
45{
46 let mut out = image.clone();
47 salt_and_pepper_noise_mut(&mut out, rate, seed);
48 out
49}
50
51pub fn salt_and_pepper_noise_mut<P>(image: &mut Image<P>, rate: f64, seed: u64)
54where
55 P: Pixel + HasBlack + HasWhite,
56{
57 let mut rng: StdRng = SeedableRng::seed_from_u64(seed);
58 let uniform = Uniform::new(0.0, 1.0);
59
60 for p in image.pixels_mut() {
61 if uniform.sample(&mut rng) > rate {
62 continue;
63 }
64 let r = uniform.sample(&mut rng);
65 *p = if r >= 0.5 { P::white() } else { P::black() };
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use image::GrayImage;
73 use test::{black_box, Bencher};
74
75 #[bench]
76 fn bench_gaussian_noise_mut(b: &mut Bencher) {
77 let mut image = GrayImage::new(100, 100);
78 b.iter(|| {
79 gaussian_noise_mut(&mut image, 30.0, 40.0, 1);
80 });
81 black_box(image);
82 }
83
84 #[bench]
85 fn bench_salt_and_pepper_noise_mut(b: &mut Bencher) {
86 let mut image = GrayImage::new(100, 100);
87 b.iter(|| {
88 salt_and_pepper_noise_mut(&mut image, 0.3, 1);
89 });
90 black_box(image);
91 }
92}