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