1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file.
5 
6 #ifndef LIB_JXL_NOISE_DISTRIBUTIONS_H_
7 #define LIB_JXL_NOISE_DISTRIBUTIONS_H_
8 
9 // Noise distributions for testing partial_derivatives and robust_statistics.
10 
11 #include <stddef.h>
12 #include <stdint.h>
13 
14 #include <random>  // distributions
15 #include <string>
16 
17 #include "lib/jxl/common.h"
18 #include "lib/jxl/image.h"
19 
20 namespace jxl {
21 
22 // Unmodified input
23 struct NoiseNone {
NameNoiseNone24   std::string Name() const { return "None"; }
25 
26   template <class Random>
operatorNoiseNone27   float operator()(const float in, Random* rng) const {
28     return in;
29   }
30 };
31 
32 // Salt+pepper
33 class NoiseImpulse {
34  public:
NoiseImpulse(const uint32_t threshold)35   explicit NoiseImpulse(const uint32_t threshold) : threshold_(threshold) {}
Name()36   std::string Name() const { return "Impulse" + ToString(threshold_); }
37 
38   // Sets pixels to 0 if rand < threshold or 1 if rand > ~threshold.
39   template <class Random>
operator()40   float operator()(const float in, Random* rng) const {
41     const uint32_t rand = (*rng)();
42     float out = 0.0f;
43     if (rand > ~threshold_) {
44       out = 1.0f;
45     }
46     if (rand > threshold_) {
47       out = in;
48     }
49     return out;
50   }
51 
52  private:
53   const uint32_t threshold_;
54 };
55 
56 class NoiseUniform {
57  public:
NoiseUniform(const float min,const float max_exclusive)58   NoiseUniform(const float min, const float max_exclusive)
59       : dist_(min, max_exclusive) {}
Name()60   std::string Name() const { return "Uniform" + ToString(dist_.b()); }
61 
62   template <class Random>
operator()63   float operator()(const float in, Random* rng) const {
64     return in + dist_(*rng);
65   }
66 
67  private:
68   mutable std::uniform_real_distribution<float> dist_;
69 };
70 
71 // Additive, zero-mean Gaussian.
72 class NoiseGaussian {
73  public:
NoiseGaussian(const float stddev)74   explicit NoiseGaussian(const float stddev) : dist_(0.0f, stddev) {}
Name()75   std::string Name() const { return "Gaussian" + ToString(dist_.stddev()); }
76 
77   template <class Random>
operator()78   float operator()(const float in, Random* rng) const {
79     return in + dist_(*rng);
80   }
81 
82  private:
83   mutable std::normal_distribution<float> dist_;
84 };
85 
86 // Integer noise is scaled by 1E-3.
87 class NoisePoisson {
88  public:
NoisePoisson(const double mean)89   explicit NoisePoisson(const double mean) : dist_(mean) {}
Name()90   std::string Name() const { return "Poisson" + ToString(dist_.mean()); }
91 
92   template <class Random>
operator()93   float operator()(const float in, Random* rng) const {
94     return in + dist_(*rng) * 1E-3f;
95   }
96 
97  private:
98   mutable std::poisson_distribution<int> dist_;
99 };
100 
101 // Returns the result of applying the randomized "noise" function to each pixel.
102 template <class NoiseType, class Random>
AddNoise(const ImageF & in,const NoiseType & noise,Random * rng)103 ImageF AddNoise(const ImageF& in, const NoiseType& noise, Random* rng) {
104   const size_t xsize = in.xsize();
105   const size_t ysize = in.ysize();
106   ImageF out(xsize, ysize);
107   for (size_t y = 0; y < ysize; ++y) {
108     const float* JXL_RESTRICT in_row = in.ConstRow(y);
109     float* JXL_RESTRICT out_row = out.Row(y);
110     for (size_t x = 0; x < xsize; ++x) {
111       out_row[x] = noise(in_row[x], rng);
112     }
113   }
114   return out;
115 }
116 
117 template <class NoiseType, class Random>
AddNoise(const Image3F & in,const NoiseType & noise,Random * rng)118 Image3F AddNoise(const Image3F& in, const NoiseType& noise, Random* rng) {
119   const size_t xsize = in.xsize();
120   const size_t ysize = in.ysize();
121   Image3F out(xsize, ysize);
122   // noise_estimator_test requires this loop order.
123   for (size_t c = 0; c < 3; ++c) {
124     for (size_t y = 0; y < ysize; ++y) {
125       const float* JXL_RESTRICT in_row = in.ConstPlaneRow(c, y);
126       float* JXL_RESTRICT out_row = out.PlaneRow(c, y);
127 
128       for (size_t x = 0; x < xsize; ++x) {
129         out_row[x] = noise(in_row[x], rng);
130       }
131     }
132   }
133   return out;
134 }
135 
136 }  // namespace jxl
137 
138 #endif  // LIB_JXL_NOISE_DISTRIBUTIONS_H_
139