ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/pcond3.c
Revision: 3.19
Committed: Tue Apr 13 02:56:42 2021 UTC (3 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, HEAD
Changes since 3.18: +2 -2 lines
Log Message:
perf(pcond): more aggressive trim criterion for tone curve

File Contents

# User Rev Content
1 greg 3.1 #ifndef lint
2 greg 3.19 static const char RCSid[] = "$Id: pcond3.c,v 3.18 2020/06/27 03:37:24 greg Exp $";
3 greg 3.1 #endif
4     /*
5     * Routines for computing and applying brightness mapping.
6     */
7    
8 schorsch 3.14 #include <string.h>
9    
10 greg 3.1 #include "pcond.h"
11 greg 3.18 #include "random.h"
12 greg 3.1
13    
14 greg 3.5 #define CVRATIO 0.025 /* fraction of samples allowed > env. */
15 greg 3.1
16 gwlarson 3.10 #define LN_10 2.30258509299404568402
17     #define exp10(x) exp(LN_10*(x))
18 greg 3.1
19 greg 3.11 double modhist[HISTRES]; /* modified histogram */
20 greg 3.5 double mhistot; /* modified histogram total */
21 greg 3.11 double cumf[HISTRES+1]; /* cumulative distribution function */
22 greg 3.1
23 greg 3.18 static double centprob(int x, int y);
24 schorsch 3.15 static void mkcumf(void);
25 greg 3.18 static double cf(double b);
26     static double BLw(double Lw);
27     static float *getlumsamp(int n);
28 schorsch 3.15 #if ADJ_VEIL
29     static void mkcrfimage(void);
30     #endif
31    
32    
33 greg 3.1
34 greg 3.16 void
35 schorsch 3.15 getfixations( /* load fixation history list */
36     FILE *fp
37     )
38 greg 3.8 {
39     #define FIXHUNK 128
40     RESOLU fvres;
41     int pos[2];
42 greg 3.16 int px, py, i;
43 greg 3.8 /* initialize our resolution struct */
44 greg 3.11 if ((fvres.rt=inpres.rt)&YMAJOR) {
45 greg 3.8 fvres.xr = fvxr;
46     fvres.yr = fvyr;
47     } else {
48     fvres.xr = fvyr;
49     fvres.yr = fvxr;
50     }
51     /* read each picture position */
52     while (fscanf(fp, "%d %d", &pos[0], &pos[1]) == 2) {
53     /* convert to closest index in foveal image */
54     loc2pix(pos, &fvres,
55     (pos[0]+.5)/inpres.xr, (pos[1]+.5)/inpres.yr);
56     /* include nine neighborhood samples */
57     for (px = pos[0]-1; px <= pos[0]+1; px++) {
58     if (px < 0 || px >= fvxr)
59     continue;
60     for (py = pos[1]-1; py <= pos[1]+1; py++) {
61     if (py < 0 || py >= fvyr)
62     continue;
63     for (i = nfixations; i-- > 0; )
64     if (fixlst[i][0] == px &&
65     fixlst[i][1] == py)
66     break;
67     if (i >= 0)
68     continue; /* already there */
69     if (nfixations % FIXHUNK == 0) {
70     if (nfixations)
71     fixlst = (short (*)[2])
72 greg 3.12 realloc((void *)fixlst,
73 greg 3.8 (nfixations+FIXHUNK)*
74     2*sizeof(short));
75     else
76     fixlst = (short (*)[2])malloc(
77     FIXHUNK*2*sizeof(short)
78     );
79     if (fixlst == NULL)
80     syserror("malloc");
81     }
82     fixlst[nfixations][0] = px;
83     fixlst[nfixations][1] = py;
84     nfixations++;
85     }
86     }
87     }
88     if (!feof(fp)) {
89     fprintf(stderr, "%s: format error reading fixation data\n",
90     progname);
91     exit(1);
92     }
93     #undef FIXHUNK
94     }
95    
96    
97 greg 3.16 void
98 schorsch 3.15 gethisto( /* load precomputed luminance histogram */
99     FILE *fp
100     )
101 gwlarson 3.10 {
102 greg 3.11 double histo[MAXPREHIST];
103 gwlarson 3.10 double histart, histep;
104 schorsch 3.15 double b, lastb, w;
105 gwlarson 3.10 int n;
106 greg 3.16 int i;
107 gwlarson 3.10 /* load data */
108     for (i = 0; i < MAXPREHIST &&
109 greg 3.11 fscanf(fp, "%lf %lf", &b, &histo[i]) == 2; i++) {
110     if (i > 1 && fabs(b - lastb - histep) > .001) {
111 gwlarson 3.10 fprintf(stderr,
112     "%s: uneven step size in histogram data\n",
113     progname);
114     exit(1);
115     }
116     if (i == 1)
117 greg 3.11 if ((histep = b - (histart = lastb)) <= FTINY) {
118     fprintf(stderr,
119     "%s: illegal step in histogram data\n",
120     progname);
121     exit(1);
122     }
123 gwlarson 3.10 lastb = b;
124     }
125     if (i < 2 || !feof(fp)) {
126     fprintf(stderr,
127     "%s: format/length error loading histogram (log10L %f at %d)\n",
128     progname, b, i);
129     exit(1);
130     }
131     n = i;
132     histart *= LN_10;
133     histep *= LN_10;
134     /* find extrema */
135     for (i = 0; i < n && histo[i] <= FTINY; i++)
136     ;
137 greg 3.11 bwmin = histart + (i-.001)*histep;
138 gwlarson 3.10 for (i = n; i-- && histo[i] <= FTINY; )
139     ;
140 greg 3.11 bwmax = histart + (i+1.001)*histep;
141 gwlarson 3.10 if (bwmax > Bl(LMAX))
142     bwmax = Bl(LMAX);
143     if (bwmin < Bl(LMIN))
144     bwmin = Bl(LMIN);
145     else /* duplicate bottom bin */
146     bwmin = bwmax - (bwmax-bwmin)*HISTRES/(HISTRES-1);
147     /* convert histogram */
148     bwavg = 0.; histot = 0.;
149     for (i = 0; i < HISTRES; i++)
150     bwhist[i] = 0.;
151     for (i = 0, b = histart; i < n; i++, b += histep) {
152 greg 3.11 if (b < bwmin+FTINY) continue;
153     if (b >= bwmax-FTINY) break;
154 gwlarson 3.10 w = histo[i];
155     bwavg += w*b;
156     bwhist[bwhi(b)] += w;
157     histot += w;
158     }
159     bwavg /= histot;
160     if (bwmin > Bl(LMIN)+FTINY) { /* add false samples at bottom */
161     bwhist[1] *= 0.5;
162     bwhist[0] += bwhist[1];
163     }
164     }
165    
166    
167 schorsch 3.15 static double
168     centprob( /* center-weighting probability function */
169     int x,
170     int y
171     )
172 greg 3.8 {
173     double xr, yr, p;
174     /* paraboloid, 0 at 90 degrees from center */
175     xr = (x - .5*(fvxr-1))/90.; /* 180 degree fisheye has fv?r == 90 */
176     yr = (y - .5*(fvyr-1))/90.;
177     p = 1. - xr*xr - yr*yr;
178     return(p < 0. ? 0. : p);
179     }
180    
181    
182 greg 3.18 static float *
183     getlumsamp(int n) /* get set of random point sample luminances */
184     {
185     float *ls = (float *)malloc(n*sizeof(float));
186     COLR *cscan = (COLR *)malloc(scanlen(&inpres)*sizeof(COLR));
187     long startpos = ftell(infp);
188     long npleft = (long)inpres.xr*inpres.yr;
189     int x;
190    
191     if ((ls == NULL) | (cscan == NULL))
192     syserror("malloc");
193     x = 0; /* read/convert samples */
194     while (n > 0) {
195     COLOR col;
196     int sv = 0;
197     double rval, cumprob = 0;
198    
199     if (x <= 0 && freadcolrs(cscan, x=scanlen(&inpres), infp) < 0) {
200     fprintf(stderr, "%s: %s: scanline read error\n",
201     progname, infn);
202     exit(1);
203     }
204     rval = frandom(); /* random distance to next sample */
205     while ((cumprob += (1.-cumprob)*n/(npleft-sv)) < rval)
206     sv++;
207     if (x < ++sv) { /* out of pixels in this scanline */
208     npleft -= x;
209     x = 0;
210     continue;
211     }
212     x -= sv;
213     colr_color(col, cscan[x]);
214     ls[--n] = plum(col);
215     npleft -= sv;
216     }
217     free(cscan); /* clean up and reset file pointer */
218     if (fseek(infp, startpos, SEEK_SET) < 0)
219     syserror("fseek");
220     return(ls);
221     }
222    
223    
224 greg 3.16 void
225 schorsch 3.15 comphist(void) /* create foveal sampling histogram */
226 greg 3.8 {
227     double l, b, w, lwmin, lwmax;
228 greg 3.18 float *lumsamp;
229     int nlumsamp;
230 greg 3.16 int x, y;
231 gwlarson 3.10 /* check for precalculated histogram */
232     if (what2do&DO_PREHIST)
233     return;
234 greg 3.8 lwmin = 1e10; /* find extrema */
235     lwmax = 0.;
236     for (y = 0; y < fvyr; y++)
237     for (x = 0; x < fvxr; x++) {
238     l = plum(fovscan(y)[x]);
239 greg 3.17 if (l < lwmin) lwmin = l;
240     if (l > lwmax) lwmax = l;
241 greg 3.8 }
242 greg 3.18 /* sample luminance pixels */
243     nlumsamp = fvxr*fvyr*16;
244     if (nlumsamp > inpres.xr*inpres.yr)
245     nlumsamp = inpres.xr*inpres.yr;
246     lumsamp = getlumsamp(nlumsamp);
247     for (x = nlumsamp; x--; ) {
248     l = lumsamp[x];
249     if (l < lwmin) lwmin = l;
250     if (l > lwmax) lwmax = l;
251     }
252 greg 3.9 lwmax *= 1.01;
253     if (lwmax > LMAX)
254     lwmax = LMAX;
255 greg 3.8 bwmax = Bl(lwmax);
256 greg 3.9 if (lwmin < LMIN) {
257     lwmin = LMIN;
258     bwmin = Bl(LMIN);
259     } else { /* duplicate bottom bin */
260     bwmin = bwmax - (bwmax-Bl(lwmin))*HISTRES/(HISTRES-1);
261     lwmin = Lb(bwmin);
262     }
263 greg 3.8 /* (re)compute histogram */
264     bwavg = 0.;
265     histot = 0.;
266 greg 3.18 memset(bwhist, 0, sizeof(bwhist));
267 greg 3.8 /* global average */
268 greg 3.18 if (!(what2do&DO_FIXHIST) || fixfrac < 1.-FTINY) {
269 greg 3.8 for (y = 0; y < fvyr; y++)
270     for (x = 0; x < fvxr; x++) {
271     l = plum(fovscan(y)[x]);
272 greg 3.11 if (l < lwmin+FTINY) continue;
273     if (l >= lwmax-FTINY) continue;
274 greg 3.8 b = Bl(l);
275     w = what2do&DO_CWEIGHT ? centprob(x,y) : 1.;
276 gwlarson 3.10 bwavg += w*b;
277 greg 3.8 bwhist[bwhi(b)] += w;
278     histot += w;
279     }
280 greg 3.18 /* weight for point luminances */
281     w = 1. * histot / nlumsamp;
282     for (x = nlumsamp; x--; ) {
283     l = lumsamp[x];
284     if (l < lwmin+FTINY) continue;
285     if (l >= lwmax-FTINY) continue;
286     b = Bl(l);
287     bwavg += w*b;
288     bwhist[bwhi(b)] += w;
289     histot += w;
290     }
291     }
292 greg 3.8 /* average fixation points */
293     if (what2do&DO_FIXHIST && nfixations > 0) {
294     if (histot > FTINY)
295     w = fixfrac/(1.-fixfrac)*histot/nfixations;
296     else
297     w = 1.;
298     for (x = 0; x < nfixations; x++) {
299     l = plum(fovscan(fixlst[x][1])[fixlst[x][0]]);
300 greg 3.11 if (l < lwmin+FTINY) continue;
301     if (l >= lwmax-FTINY) continue;
302 greg 3.8 b = Bl(l);
303 gwlarson 3.10 bwavg += w*b;
304 greg 3.8 bwhist[bwhi(b)] += w;
305     histot += w;
306     }
307     }
308     bwavg /= histot;
309 greg 3.9 if (lwmin > LMIN+FTINY) { /* add false samples at bottom */
310     bwhist[1] *= 0.5;
311     bwhist[0] += bwhist[1];
312     }
313 greg 3.18 free(lumsamp);
314 greg 3.8 }
315    
316    
317 schorsch 3.15 static void
318     mkcumf(void) /* make cumulative distribution function */
319 greg 3.1 {
320 greg 3.16 int i;
321     double sum;
322 greg 3.1
323 greg 3.5 mhistot = 0.; /* compute modified total */
324     for (i = 0; i < HISTRES; i++)
325     mhistot += modhist[i];
326    
327     sum = 0.; /* compute cumulative function */
328     for (i = 0; i < HISTRES; i++) {
329     cumf[i] = sum/mhistot;
330 greg 3.1 sum += modhist[i];
331     }
332     cumf[HISTRES] = 1.;
333     }
334    
335    
336 schorsch 3.15 static double
337     cf( /* return cumulative function at b */
338     double b
339     )
340 greg 3.1 {
341     double x;
342 greg 3.16 int i;
343 greg 3.1
344     i = x = HISTRES*(b - bwmin)/(bwmax - bwmin);
345     x -= (double)i;
346     return(cumf[i]*(1.-x) + cumf[i+1]*x);
347     }
348    
349    
350 schorsch 3.15 static double
351     BLw( /* map world luminance to display brightness */
352     double Lw
353     )
354 greg 3.1 {
355     double b;
356    
357     if (Lw <= LMIN || (b = Bl(Lw)) <= bwmin+FTINY)
358     return(Bldmin);
359     if (b >= bwmax-FTINY)
360     return(Bldmax);
361 greg 3.4 return(Bldmin + cf(b)*(Bldmax-Bldmin));
362 greg 3.1 }
363    
364    
365 greg 3.16 double
366 schorsch 3.15 htcontrs( /* human threshold contrast sensitivity, dL(La) */
367     double La
368     )
369 greg 3.1 {
370     double l10La, l10dL;
371     /* formula taken from Ferwerda et al. [SG96] */
372     if (La < 1.148e-4)
373     return(1.38e-3);
374     l10La = log10(La);
375     if (l10La < -1.44) /* rod response regime */
376     l10dL = pow(.405*l10La + 1.6, 2.18) - 2.86;
377     else if (l10La < -.0184)
378     l10dL = l10La - .395;
379     else if (l10La < 1.9) /* cone response regime */
380     l10dL = pow(.249*l10La + .65, 2.7) - .72;
381     else
382     l10dL = l10La - 1.255;
383    
384     return(exp10(l10dL));
385     }
386    
387    
388 greg 3.16 double
389 schorsch 3.15 clampf( /* histogram clamping function */
390     double Lw
391     )
392 greg 3.1 {
393     double bLw, ratio;
394    
395     bLw = BLw(Lw); /* apply current brightness map */
396     ratio = what2do&DO_HSENS ? htcontrs(Lb(bLw))/htcontrs(Lw) : Lb(bLw)/Lw;
397     return(ratio/(Lb1(bLw)*(Bldmax-Bldmin)*Bl1(Lw)));
398     }
399    
400 greg 3.16 double
401 schorsch 3.15 crfactor( /* contrast reduction factor */
402     double Lw
403     )
404 greg 3.11 {
405     int i = HISTRES*(Bl(Lw) - bwmin)/(bwmax - bwmin);
406     double bLw, ratio, Tdb;
407    
408     if (i <= 0)
409     return(1.0);
410     if (i >= HISTRES)
411     return(1.0);
412     bLw = BLw(Lw);
413     ratio = what2do&DO_HSENS ? htcontrs(Lb(bLw))/htcontrs(Lw) : Lb(bLw)/Lw;
414     Tdb = mhistot * (bwmax - bwmin) / HISTRES;
415     return(modhist[i]*Lb1(bLw)*(Bldmax-Bldmin)*Bl1(Lw)/(Tdb*ratio));
416     }
417    
418    
419     #if ADJ_VEIL
420 schorsch 3.15 static void
421     mkcrfimage(void) /* compute contrast reduction factor image */
422 greg 3.11 {
423     int i;
424     float *crfptr;
425     COLOR *fovptr;
426    
427     if (crfimg == NULL)
428     crfimg = (float *)malloc(fvxr*fvyr*sizeof(float));
429     if (crfimg == NULL)
430     syserror("malloc");
431     crfptr = crfimg;
432     fovptr = fovimg;
433     for (i = fvxr*fvyr; i--; crfptr++, fovptr++)
434     crfptr[0] = crfactor(plum(fovptr[0]));
435     }
436     #endif
437    
438 greg 3.1
439 greg 3.16 int
440 schorsch 3.15 mkbrmap(void) /* make dynamic range map */
441 greg 3.1 {
442 greg 3.11 double Tdb, b, s;
443 greg 3.5 double ceiling, trimmings;
444 greg 3.16 int i;
445 greg 3.1 /* copy initial histogram */
446 schorsch 3.14 memcpy((void *)modhist, (void *)bwhist, sizeof(modhist));
447 greg 3.11 s = (bwmax - bwmin)/HISTRES; /* s is delta b */
448 greg 3.1 /* loop until satisfactory */
449 greg 3.5 do {
450     mkcumf(); /* sync brightness mapping */
451     if (mhistot <= histot*CVRATIO)
452     return(-1); /* no compression needed! */
453 greg 3.11 Tdb = mhistot * s;
454 greg 3.5 trimmings = 0.; /* clip to envelope */
455 greg 3.1 for (i = 0, b = bwmin + .5*s; i < HISTRES; i++, b += s) {
456 greg 3.11 ceiling = Tdb*clampf(Lb(b));
457 greg 3.5 if (modhist[i] > ceiling) {
458     trimmings += modhist[i] - ceiling;
459     modhist[i] = ceiling;
460     }
461 greg 3.1 }
462 greg 3.19 } while (trimmings > mhistot*CVRATIO);
463 greg 3.5
464 greg 3.11 #if ADJ_VEIL
465     mkcrfimage(); /* contrast reduction image */
466     #endif
467    
468 greg 3.5 return(0); /* we got it */
469 greg 3.1 }
470    
471    
472 greg 3.16 void
473 schorsch 3.15 scotscan( /* apply scotopic color sensitivity loss */
474     COLOR *scan,
475     int xres
476     )
477 greg 3.1 {
478     COLOR ctmp;
479     double incolor, b, Lw;
480 greg 3.16 int i;
481 greg 3.1
482     for (i = 0; i < xres; i++) {
483     Lw = plum(scan[i]);
484     if (Lw >= TopMesopic)
485     incolor = 1.;
486     else if (Lw <= BotMesopic)
487     incolor = 0.;
488     else
489     incolor = (Lw - BotMesopic) /
490     (TopMesopic - BotMesopic);
491     if (incolor < 1.-FTINY) {
492 greg 3.2 b = (1.-incolor)*slum(scan[i])*inpexp/SWNORM;
493     if (lumf == rgblum) b /= WHTEFFICACY;
494     setcolor(ctmp, b, b, b);
495 greg 3.1 if (incolor <= FTINY)
496     setcolor(scan[i], 0., 0., 0.);
497     else
498     scalecolor(scan[i], incolor);
499     addcolor(scan[i], ctmp);
500     }
501     }
502     }
503    
504    
505 greg 3.16 void
506 schorsch 3.15 mapscan( /* apply tone mapping operator to scanline */
507     COLOR *scan,
508     int xres
509     )
510 greg 3.1 {
511     double mult, Lw, b;
512 greg 3.16 int x;
513 greg 3.1
514 greg 3.11 for (x = 0; x < xres; x++) {
515     Lw = plum(scan[x]);
516 greg 3.1 if (Lw < LMIN) {
517 greg 3.11 setcolor(scan[x], 0., 0., 0.);
518 greg 3.1 continue;
519     }
520 greg 3.11 b = BLw(Lw); /* apply brightness mapping */
521     mult = (Lb(b) - ldmin)/(ldmax - ldmin)/(Lw*inpexp);
522 greg 3.1 if (lumf == rgblum) mult *= WHTEFFICACY;
523 greg 3.11 scalecolor(scan[x], mult);
524 greg 3.4 }
525     }
526    
527    
528 greg 3.16 void
529 schorsch 3.15 putmapping( /* put out mapping function */
530     FILE *fp
531     )
532 greg 3.4 {
533     double b, s;
534 greg 3.16 int i;
535 greg 3.7 double wlum, sf, dlum;
536 greg 3.4
537     sf = scalef*inpexp;
538     if (lumf == cielum) sf *= WHTEFFICACY;
539     s = (bwmax - bwmin)/HISTRES;
540     for (i = 0, b = bwmin + .5*s; i < HISTRES; i++, b += s) {
541     wlum = Lb(b);
542 greg 3.7 if (what2do&DO_LINEAR) {
543     dlum = sf*wlum;
544     if (dlum > ldmax) dlum = ldmax;
545     else if (dlum < ldmin) dlum = ldmin;
546     fprintf(fp, "%e %e\n", wlum, dlum);
547     } else
548 greg 3.4 fprintf(fp, "%e %e\n", wlum, Lb(BLw(wlum)));
549 greg 3.1 }
550     }