Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
noiseprofile.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2012, 2016 johannes hanika.
4 Copyright (C) 2020 Hubert Kowalski.
5 Copyright (C) 2021 Pascal Obry.
6 Copyright (C) 2021 Ralf Brown.
7
8 darktable is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 darktable is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with darktable. If not, see <http://www.gnu.org/licenses/>.
20*/
21#include <math.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <assert.h>
25#include <string.h>
26#include <glib/gstdio.h>
27
28typedef float dt_aligned_pixel_t[4];
29
30typedef float elem_type;
31#define ELEM_SWAP(a,b) { elem_type t=(a);(a)=(b);(b)=t; }
32
33/*---------------------------------------------------------------------------
34Function : kth_smallest()
35In : array of elements, # of elements in the array, rank k
36Out : one element
37Job : find the kth smallest element in the array
38Notice : use the median() macro defined below to get the median.
39
40Reference:
41
42Author: Wirth, Niklaus
43Title: Algorithms + data structures = programs
44Publisher: Englewood Cliffs: Prentice-Hall, 1976
45Physical description: 366 p.
46Series: Prentice-Hall Series in Automatic Computation
47
48---------------------------------------------------------------------------*/
49
50static elem_type
51kth_smallest(elem_type a[], int n, int k)
52{
53 int i,j,l,m ;
54 elem_type x ;
55
56 l=0 ; m=n-1 ;
57 while (l<m) {
58 x=a[2*k+1] ;
59 i=l ;
60 j=m ;
61 do {
62 while (a[2*i+1]<x) i++ ;
63 while (x<a[2*j+1]) j-- ;
64 if (i<=j) {
65 ELEM_SWAP(a[2*i+1],a[2*j+1]) ;
66 i++ ; j-- ;
67 }
68 } while (i<=j) ;
69 if (j<k) l=i ;
70 if (k<i) m=j ;
71 }
72 return a[2*k+1] ;
73}
74
75#define median(a,n) kth_smallest(a,n,(((n)&1)?((n)/2):(((n)/2)-1)))
76
77
78
79static float*
80read_pfm(const char *filename, int *wd, int*ht)
81{
82 FILE *f = g_fopen(filename, "rb");
83 if(!f) return 0;
84 fscanf(f, "PF\n%d %d\n%*[^\n]", wd, ht);
85 fgetc(f); // eat only one newline
86
87 float *p = (float *)malloc(sizeof(float)*3*(*wd)*(*ht));
88 fread(p, sizeof(float)*3, (*wd)*(*ht), f);
89 for(int k=0;k<3*(*wd)*(*ht);k++) p[k] = fmaxf(0.0f, p[k]);
90 fclose(f);
91 return p;
92}
93
94static float*
95read_histogram(const char *filename, int *bins)
96{
97 *bins = 0;
98 FILE *f = g_fopen(filename, "rb");
99 if(!f) return 0;
100
101 while(!feof(f))
102 {
103 fscanf(f, "%*f %*f %*f %*f %*f %*f %*f %*f %*f %*f\n");
104 (*bins) ++;
105 }
106 fseek(f, 0, SEEK_SET);
107 // second round, alloc and read
108 float *hist = (float *)malloc(sizeof(float) * 3 * (*bins));
109 int k=0;
110 while(!feof(f))
111 {
112 fscanf(f, "%*f %*f %*f %*f %*f %*f %*f %f %f %f\n", hist + 3*k, hist+3*k+1, hist+3*k+2);
113 k++;
114 }
115
116 fclose(f);
117 return hist;
118}
119
120static void
122 const float *const hist,
123 float *const inv_hist,
124 const int bins)
125{
126 // invert non-normalised accumulated hist
127 for(int c=0;c<3;c++)
128 {
129 int last = 0;
130 for(int i=last+1; i<bins; i++)
131 {
132 for(int k=last; k<bins; k++)
133 {
134 if(hist[3*k+c] >= i/(float)bins)
135 {
136 last = k;
137 inv_hist[3*i+c] = k/(float)bins;
138 break;
139 }
140 }
141 }
142 }
143}
144
145#if 0
146static void
147write_pfm(const char *filename, float *buf, int wd, int ht)
148{
149 FILE *f = g_fopen(filename, "wb");
150 if(!f) return;
151 fprintf(f, "PF\n%d %d\n-1.0\n", wd, ht);
152 fwrite(buf, sizeof(float)*3, wd*ht, f);
153 fclose(f);
154}
155#endif
156
157
158#define N 300
159
160static inline float
161clamp(float f, float m, float M)
162{
163 return fmaxf(fminf(f, M), m);
164}
165
166int compare_llhh(const void *a, const void *b)
167{
168 return (int)clamp(((float *)a)[0]*N, 0, N-1) - (int)clamp(((float *)b)[0]*N, 0, N-1);
169}
170
171int main(int argc, char *arg[])
172{
173 if(argc < 2)
174 {
175 fprintf(stderr, "usage: %s input.pfm [-c a1 b1]\n", arg[0]);
176 exit(1);
177 }
178 int wd, ht;
179 float *input = read_pfm(arg[1], &wd, &ht);
180 float max = 0.0f;
181 // sanity checks:
182 // for(int k=0;k<3*wd*ht;k++) input[k] = clamp(input[k], 0.0f, 1.0f);
183
184 // correction requested?
185 if(argc >= 9 && !strcmp(arg[2], "-c"))
186 {
187 const dt_aligned_pixel_t a = { atof(arg[3]), atof(arg[4]), atof(arg[5]) };
188 const dt_aligned_pixel_t b = { atof(arg[6]), atof(arg[7]), atof(arg[8]) };
189 // const float m[3] = {1, 1, 1};
190 // 2.0f*sqrt(a[0]*1.0f+b[0])/a[0],
191 // 2.0f*sqrt(a[1]*1.0f+b[1])/a[1],
192 // 2.0f*sqrt(a[2]*1.0f+b[2])/a[2]};
193#if 1
194 // dump curves:
195 for(int k=0;k<N;k++)
196 {
197 for(int c=0;c<3;c++)
198 {
199 // const float y = k/(N-1.0f);
200 // const float x = m[c]*m[c]*a[c]*y*y/4.0f - b[c]/a[c];
201 float x = k/(N-1.0f)/a[c];
202 const float d = fmaxf(0.0f, x + 3./8. + (b[c]/a[c])*(b[c]/a[c]));
203 x = 2.0f*sqrtf(d);
204 fprintf(stderr, "%f ", x);
205 }
206 fprintf(stderr, "\n");
207 }
208#endif
209 for(int k=0;k<wd*ht;k++)
210 {
211 for(int c=0;c<3;c++)
212 {
213 // input[3*k+c] = 2.0f*sqrtf(a[c]*input[3*k+c]+b[c])/(a[c]*m[c]);
214 input[3*k+c] = input[3*k+c] / a[c];
215 const float d = fmaxf(0.0f, input[3*k+c] + 3./8. + (b[c]/a[c])*(b[c]/a[c]));
216 input[3*k+c] = 2.0f*sqrtf(d);
217 max = fmaxf(max, input[3*k+c]);
218 }
219 }
220 for(int k=0;k<3*wd*ht;k++) input[k] /= max;
221 }
222 else if(argc >= 4 && !strcmp(arg[2], "-h"))
223 {
224 int bins = 0;
225 float *hist = read_histogram(arg[3], &bins);
226 float *inv_hist = (float *)malloc(sizeof(float) * 3 * bins);
227 invert_histogram(hist, inv_hist, bins);
228#if 1
229 // output curves and their inverse:
230 for(int k=0;k<bins;k++)
231 // fprintf(stderr, "%f %f %f %f %f %f %f\n", k/(float)bins, hist[3*k], hist[3*k+1], hist[3*k+2], inv_hist[3*k], inv_hist[3*k+1], inv_hist[3*k+2]);
232 fprintf(stderr, "%f %f %f\n", inv_hist[3*k], inv_hist[3*k+1], inv_hist[3*k+2]);
233 // fprintf(stderr,"scanned %d bins\n", bins);
234#endif
235 for(int k=0;k<wd*ht;k++)
236 {
237 for(int c=0;c<3;c++)
238 {
239 float f = clamp(input[3*k+c]*bins, 0, bins-2);
240 const int bin = (int)f;
241 f -= bin;
242 input[3*k+c] = (1.0f-f)*inv_hist[3*bin+c] + f*inv_hist[3*(bin+1)+c];
243 }
244 }
245 }
246
247 float std[N][3] = {{0.0f}};
248 float cnt[N][3] = {{0.0f}};
249
250 // one level haar decomposition, separable, decimated, lifting scheme
251 for(int j=0;j<ht;j++)
252 {
253 for(int i=0;i<wd-1;i+=2)
254 {
255 float *buf = input + 3*(wd*j + i);
256 for(int c=0;c<3;c++)
257 {
258 buf[c] += buf[3+c];
259 buf[c] *= .5f;
260 buf[3+c] -= buf[c];
261 }
262 // buf += 3;
263 }
264 }
265 for(int i=0;i<wd;i++)
266 {
267 for(int j=0;j<ht-1;j+=2)
268 {
269 float *buf = input + 3*(wd*j + i);
270 for(int c=0;c<3;c++)
271 {
272 buf[c] += buf[3*wd+c];
273 buf[c] *= .5f;
274 buf[3*wd+c] -= buf[c];
275 }
276 // buf += 3*wd;
277 }
278 }
279
280#if 0
281 // debug: write full wavelet transform:
282 write_pfm("wt.pfm", input, wd, ht);
283 // debug: write LL
284 float *out = (float *)malloc(sizeof(float)*3*wd/2*ht/2);
285 for(int j=0;j<ht-1;j+=2)
286 {
287 for(int i=0;i<wd-1;i+=2)
288 {
289 for(int c=0;c<3;c++)
290 {
291 out[3*((wd/2)*(j/2)+(i/2))+c] = input[3*(wd*j+i)+c];
292 }
293 }
294 }
295 write_pfm("LL.pfm", out, wd/2, ht/2);
296 free(out);
297#endif
298
299 // sort pairs (LL,HH) for each color channel:
300 float *llhh = (float *)malloc(sizeof(float)*wd*ht/2);
301 for(int c=0;c<3;c++)
302 {
303 int k = 0;
304 for(int j=0;j<ht-1;j+=2)
305 {
306 for(int i=0;i<wd-1;i+=2)
307 {
308 llhh[2*k] = input[3*(wd*j+i)+c];
309 llhh[2*k+1] = fabsf(input[3*(wd*(j+1)+(i+1))+c]);
310 k++;
311 }
312 }
313 qsort(llhh, k, 2*sizeof(float), compare_llhh);
314 // estimate std deviation for every bin we've got:
315 for(int begin=0;begin<k;)
316 {
317 // LL is used to estimate brightness:
318 const int bin = (int)clamp(llhh[2*begin]*N, 0, N-1);
319 int end = begin+1;
320 while((end < k) && ((int)clamp(llhh[2*end]*N, 0, N-1) == bin))
321 end++;
322 assert(end >= k || bin <= (int)clamp(llhh[2*end]*N, 0, N-1));
323 // fprintf(stderr, "from %d (%d) -- %d (%d)\n", begin, bin, end, (int)clamp(llhh[2*end]*N, 0, N-1));
324
325 // estimate noise by robust statistic (assumes zero mean of HH band):
326 // MAD: median(|Y - med(Y)|) = 0.6745 sigma
327 // if(end - begin > 10)
328 // fprintf(stdout, "%d %f %d\n", bin, median(llhh+2*begin, end-begin)/0.6745, end - begin);
329 std[bin][c] += median(llhh+2*begin, end-begin)/0.6745;
330 cnt[bin][c] = end - begin;
331
332 begin = end;
333 }
334 }
335
336#if 0
337 // recover noise curve:
338 for(int k=0;k<wd*ht;k++)
339 {
340 for(int c=0;c<3;c++)
341 {
342 const int i = clamp(ref[3*k+c]*N, 0, N-1);
343 cnt[i][c] ++;
344 const float diff = input[3*k+c] - ref[3*k+c];
345 // assume zero mean:
346 var[i][c] += diff*diff; // - E(X^2)
347 }
348 }
349#endif
350#if 0
351
352 // normalize
353 for(int i=0;i<N;i++)
354 for(int c=0;c<3;c++)
355 if(cnt[i][c] > 0.0f)
356 std[i][c] /= cnt[i][c];
357 else
358 std[i][c] = 0.0f;
359#endif
360
361 // scale back in case we needed to bin it down:
362 if(max > 0.0f)
363 for(int i=0;i<N;i++)
364 for(int k=0;k<3;k++) std[i][k] *= max;
365 // output variance per brightness level:
366 // fprintf(stdout, "# bin std_r std_g std_b hist_r hist_g hist_b cdf_r cdf_g cdf_b\n");
367 dt_aligned_pixel_t sum = { 0.0f };
368 for(int i=0;i<N;i++)
369 for(int k=0;k<3;k++) sum[k] += std[i][k];
370 dt_aligned_pixel_t cdf = { 0.0f };
371 for(int i=0;i<N;i++)
372 {
373 fprintf(stdout, "%f %f %f %f %f %f %f %f %f %f\n", i/(float)N, std[i][0], std[i][1], std[i][2],
374 cnt[i][0], cnt[i][1], cnt[i][2],
375 cdf[0]/sum[0], cdf[1]/sum[1], cdf[2]/sum[2]);
376 // cdf[0], cdf[1], cdf[2]);
377 for(int k=0;k<3;k++) cdf[k] += std[i][k];
378 }
379
380 free(llhh);
381 free(input);
382 exit(0);
383}
#define m
Definition basecurve.c:278
void write_pfm(const char *filename, int width, int height, float *data)
Definition chart/pfm.c:135
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
const dt_aligned_pixel_t f
const float max
const dt_colormatrix_t dt_aligned_pixel_t out
static const dt_colormatrix_t M
static const float x
float *const restrict const size_t k
#define N
static float * read_histogram(const char *filename, int *bins)
int compare_llhh(const void *a, const void *b)
static float clamp(float f, float m, float M)
float dt_aligned_pixel_t[4]
static elem_type kth_smallest(elem_type a[], int n, int k)
#define ELEM_SWAP(a, b)
static float * read_pfm(const char *filename, int *wd, int *ht)
float elem_type
#define median(a, n)
static void invert_histogram(const float *const hist, float *const inv_hist, const int bins)
int main()
Definition prova.c:47