Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
src/develop/noise_generator.h
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2020 Aurélien PIERRE.
4 Copyright (C) 2021 Ralf Brown.
5 Copyright (C) 2022 Martin Bařinka.
6
7 darktable is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 darktable is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with darktable. If not, see <http://www.gnu.org/licenses/>.
19*/
20
22
23
25{
26 DT_NOISE_UNIFORM = 0, // $DESCRIPTION: "uniform"
27 DT_NOISE_GAUSSIAN = 1, // $DESCRIPTION: "gaussian"
28 DT_NOISE_POISSONIAN = 2 // $DESCRIPTION: "poissonian"
30
31
33static inline uint32_t splitmix32(const uint64_t seed)
34{
35 // fast random number generator
36 // reference : http://prng.di.unimi.it/splitmix64.c
37 uint64_t result = (seed ^ (seed >> 33)) * 0x62a9d9ed799705f5ul;
38 result = (result ^ (result >> 28)) * 0xcb24d0a5c88c35b3ul;
39 return (uint32_t)(result >> 32);
40}
41
42
43__OMP_DECLARE_SIMD__(uniform(k))
44static inline uint32_t rol32(const uint32_t x, const int k)
45{
46 return (x << k) | (x >> (32 - k));
47}
48
49
50__OMP_DECLARE_SIMD__(aligned(state:64))
51static inline float xoshiro128plus(uint32_t state[4])
52{
53 // fast random number generator
54 // reference : http://prng.di.unimi.it/
55 const unsigned int result = state[0] + state[3];
56 const unsigned int t = state[1] << 9;
57
58 state[2] ^= state[0];
59 state[3] ^= state[1];
60 state[1] ^= state[2];
61 state[0] ^= state[3];
62
63 state[2] ^= t;
64 state[3] = rol32(state[3], 11);
65
66 return (float)(result >> 8) * 0x1.0p-24f; // take the first 24 bits and put them in mantissa
67}
68
69
70__OMP_DECLARE_SIMD__(uniform(sigma) aligned(state:64))
71static inline float uniform_noise(const float mu, const float sigma, uint32_t state[4])
72{
73 return mu + 2.0f * (xoshiro128plus(state) - 0.5f) * sigma;
74}
75
76
77__OMP_DECLARE_SIMD__(uniform(sigma) aligned(state:64))
78static inline float gaussian_noise(const float mu, const float sigma, const int flip, uint32_t state[4])
79{
80 // Create gaussian noise centered in mu of standard deviation sigma
81 // state should be initialized with xoshiro256_init() before calling and private in thread
82 // flip needs to be flipped every next iteration
83 // reference : https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
84
85 const float u1 = fmaxf(xoshiro128plus(state), FLT_MIN);
86 const float u2 = xoshiro128plus(state);
87 const float noise = (flip) ? sqrtf(-2.0f * logf(u1)) * cosf(2.f * M_PI * u2) :
88 sqrtf(-2.0f * logf(u1)) * sinf(2.f * M_PI * u2);
89 return noise * sigma + mu;
90}
91
92
93__OMP_DECLARE_SIMD__(uniform(sigma) aligned(state:64))
94static inline float poisson_noise(const float mu, const float sigma, const int flip, uint32_t state[4])
95{
96 // create poisson noise - It's just gaussian noise with Anscombe transform applied
97 const float u1 = fmaxf(xoshiro128plus(state), FLT_MIN);
98 const float u2 = xoshiro128plus(state);
99 const float noise = (flip) ? sqrtf(-2.0f * logf(u1)) * cosf(2.f * M_PI * u2) :
100 sqrtf(-2.0f * logf(u1)) * sinf(2.f * M_PI * u2);
101 const float r = noise * sigma + 2.0f * sqrtf(fmaxf(mu + 3.f / 8.f, 0.0f));
102 return (r * r - sigma * sigma) / 4.f - 3.f / 8.f;
103}
104
105
106__OMP_DECLARE_SIMD__(uniform(distribution, param) aligned(state:64))
107static inline float dt_noise_generator(const dt_noise_distribution_t distribution,
108 const float mu, const float param, const int flip, uint32_t state[4])
109{
110 // scalar version
111
112 switch(distribution)
113 {
114 case(DT_NOISE_UNIFORM):
115 default:
116 return uniform_noise(mu, param, state);
117
118 case(DT_NOISE_GAUSSIAN):
119 return gaussian_noise(mu, param, flip, state);
120
122 return poisson_noise(mu, param, flip, state);
123 }
124}
125
126__OMP_DECLARE_SIMD__(uniform(sigma) aligned(state:64) aligned(mu, sigma, out:16))
128 uint32_t state[4], dt_aligned_pixel_t out)
129{
131
133 out[c] = mu[c] + 2.0f * (noise[c] - 0.5f) * sigma[c];
134}
135
136
137__OMP_DECLARE_SIMD__(uniform(sigma) aligned(state:64) aligned(mu, sigma, flip, out:16))
139 const int flip[4], uint32_t state[4], dt_aligned_pixel_t out)
140{
141 // Create gaussian noise centered in mu of standard deviation sigma
142 // state should be initialized with xoshiro256_init() before calling and private in thread
143 // flip needs to be flipped every next iteration
144 // reference : https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
145
146 dt_aligned_pixel_t u1 = { 0.f };
147 dt_aligned_pixel_t u2 = { 0.f };
148
149
150 for(size_t c = 0; c < 3; c++)
151 u1[c] = fmaxf(xoshiro128plus(state), FLT_MIN);
152
153
154 for(size_t c = 0; c < 3; c++)
155 u2[c] = xoshiro128plus(state);
156
157 dt_aligned_pixel_t noise = { 0.f };
158
160 {
161 noise[c] = (flip[c]) ? sqrtf(-2.0f * logf(u1[c])) * cosf(2.f * M_PI * u2[c]) :
162 sqrtf(-2.0f * logf(u1[c])) * sinf(2.f * M_PI * u2[c]);
163 }
164
166 out[c] = noise[c] * sigma[c] + mu[c];
167}
168
169
170__OMP_DECLARE_SIMD__(uniform(sigma) aligned(state:64) aligned(mu, sigma, flip, out:16))
171static inline void poisson_noise_simd(const dt_aligned_pixel_t mu, const dt_aligned_pixel_t sigma, const int flip[4],
172 uint32_t state[4], dt_aligned_pixel_t out)
173{
174 // create poissonian noise - It's just gaussian noise with Anscombe transform applied
175 dt_aligned_pixel_t u1 = { 0.f };
176 dt_aligned_pixel_t u2 = { 0.f };
177
178 for(size_t c = 0; c < 3; c++)
179 {
180 u1[c] = fmaxf(xoshiro128plus(state), FLT_MIN);
182 }
183
184 dt_aligned_pixel_t noise = { 0.f };
185
187 {
188 noise[c] = (flip[c]) ? sqrtf(-2.0f * logf(u1[c])) * cosf(2.f * M_PI * u2[c]) :
189 sqrtf(-2.0f * logf(u1[c])) * sinf(2.f * M_PI * u2[c]);
190 }
191
192 // now we have gaussian noise, then apply Anscombe transform to get poissonian one
193 dt_aligned_pixel_t r = { 0.f };
194
196 {
197 r[c] = noise[c] * sigma[c] + 2.0f * sqrtf(fmaxf(mu[c] + 3.f / 8.f, 0.0f));
198 out[c] = (r[c] * r[c] - sigma[c] * sigma[c]) / 4.f - 3.f / 8.f;
199 }
200}
201
202
203__OMP_DECLARE_SIMD__(uniform(distribution, param) aligned(state:64) aligned(mu, param, flip, out:16))
204static inline void dt_noise_generator_simd(const dt_noise_distribution_t distribution,
206 const int flip[4], uint32_t state[4], dt_aligned_pixel_t out)
207{
208 // vector version
209
210 switch(distribution)
211 {
212 case(DT_NOISE_UNIFORM):
213 default:
214 {
216 break;
217 }
218
219 case(DT_NOISE_GAUSSIAN):
220 {
222 break;
223 }
224
226 {
228 break;
229 }
230 }
231}
232// clang-format off
233// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
234// vim: shiftwidth=2 expandtab tabstop=2 cindent
235// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
236// clang-format on
237
const dt_colormatrix_t dt_aligned_pixel_t out
Definition colorspaces_inline_conversions.h:42
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
#define for_each_channel(_var,...)
Definition darktable.h:662
#define __OMP_DECLARE_SIMD__(...)
Definition darktable.h:263
dt_noise_distribution_t
Definition data/kernels/noise_generator.h:25
static float4 dt_noise_generator_simd(const dt_noise_distribution_t distribution, const float4 mu, const float4 param, uint state[4])
Definition data/kernels/noise_generator.h:132
static float4 uniform_noise_simd(const float4 mu, const float4 sigma, uint state[4])
Definition data/kernels/noise_generator.h:68
static float4 poisson_noise_simd(const float4 mu, const float4 sigma, uint state[4])
Definition data/kernels/noise_generator.h:104
static float4 gaussian_noise_simd(const float4 mu, const float4 sigma, uint state[4])
Definition data/kernels/noise_generator.h:75
static const float x
Definition iop_profile.h:235
const int t
Definition iop_profile.h:225
float *const restrict const size_t k
Definition luminance_mask.h:78
#define M_PI
Definition math.h:45
c
Definition derive_filmic_v6_gamut_mapping.py:35
float dt_aligned_pixel_t[4]
Definition noiseprofile.c:28
const float uint32_t state[4]
Definition src/develop/noise_generator.h:72
dt_noise_distribution_t
Definition src/develop/noise_generator.h:25
@ DT_NOISE_GAUSSIAN
Definition src/develop/noise_generator.h:27
@ DT_NOISE_POISSONIAN
Definition src/develop/noise_generator.h:28
@ DT_NOISE_UNIFORM
Definition src/develop/noise_generator.h:26
const float sigma
Definition src/develop/noise_generator.h:71
const float const float param
Definition src/develop/noise_generator.h:108
return noise *sigma mu
Definition src/develop/noise_generator.h:89
const float u2
Definition src/develop/noise_generator.h:86
const float r
Definition src/develop/noise_generator.h:101
const float const int flip
Definition src/develop/noise_generator.h:78
const float noise
Definition src/develop/noise_generator.h:87
static uint32_t rol32(const uint32_t x, const int k)
Definition src/develop/noise_generator.h:44
static float xoshiro128plus(uint32_t state[4])
Definition src/develop/noise_generator.h:51
static uint32_t splitmix32(const uint64_t seed)
Definition src/develop/noise_generator.h:33
unsigned __int64 uint64_t
Definition strptime.c:75