ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/pcond4.c
Revision: 3.16
Committed: Sat Feb 22 02:07:27 2003 UTC (21 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R5
Changes since 3.15: +132 -7 lines
Log Message:
Changes and check-in for 3.5 release
Includes new source files and modifications not recorded for many years
See ray/doc/notes/ReleaseNotes for notes between 3.1 and 3.5 release

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id$";
3 #endif
4 /*
5 * Routines for veiling glare and loss of acuity.
6 */
7
8 #include "pcond.h"
9
10 /************** VEILING STUFF *****************/
11
12 #define VADAPT 0.08 /* fraction of adaptation from veil */
13
14 static COLOR *veilimg = NULL; /* veiling image */
15
16 #define veilscan(y) (veilimg+(y)*fvxr)
17
18 static float (*raydir)[3] = NULL; /* ray direction for each pixel */
19
20 #define rdirscan(y) (raydir+(y)*fvxr)
21
22
23 compraydir() /* compute ray directions */
24 {
25 FVECT rorg, rdir;
26 double h, v;
27 register int x, y;
28
29 if (raydir != NULL) /* already done? */
30 return;
31 raydir = (float (*)[3])malloc(fvxr*fvyr*3*sizeof(float));
32 if (raydir == NULL)
33 syserror("malloc");
34
35 for (y = 0; y < fvyr; y++) {
36 switch (inpres.rt) {
37 case YMAJOR: case YMAJOR|XDECR:
38 v = (y+.5)/fvyr; break;
39 case YMAJOR|YDECR: case YMAJOR|YDECR|XDECR:
40 v = 1. - (y+.5)/fvyr; break;
41 case 0: case YDECR:
42 h = (y+.5)/fvyr; break;
43 case XDECR: case XDECR|YDECR:
44 h = 1. - (y+.5)/fvyr; break;
45 }
46 for (x = 0; x < fvxr; x++) {
47 switch (inpres.rt) {
48 case YMAJOR: case YMAJOR|YDECR:
49 h = (x+.5)/fvxr; break;
50 case YMAJOR|XDECR: case YMAJOR|XDECR|YDECR:
51 h = 1. - (x+.5)/fvxr; break;
52 case 0: case XDECR:
53 v = (x+.5)/fvxr; break;
54 case YDECR: case YDECR|XDECR:
55 v = 1. - (x+.5)/fvxr; break;
56 }
57 if (viewray(rorg, rdir, &ourview, h, v)
58 >= -FTINY) {
59 rdirscan(y)[x][0] = rdir[0];
60 rdirscan(y)[x][1] = rdir[1];
61 rdirscan(y)[x][2] = rdir[2];
62 } else {
63 rdirscan(y)[x][0] =
64 rdirscan(y)[x][1] =
65 rdirscan(y)[x][2] = 0.0;
66 }
67 }
68 }
69 }
70
71
72 compveil() /* compute veiling image */
73 {
74 double t2, t2sum;
75 COLOR ctmp, vsum;
76 int px, py;
77 register int x, y;
78
79 if (veilimg != NULL) /* already done? */
80 return;
81 /* compute ray directions */
82 compraydir();
83 /* compute veil image */
84 veilimg = (COLOR *)malloc(fvxr*fvyr*sizeof(COLOR));
85 if (veilimg == NULL)
86 syserror("malloc");
87 for (py = 0; py < fvyr; py++)
88 for (px = 0; px < fvxr; px++) {
89 t2sum = 0.;
90 setcolor(vsum, 0., 0., 0.);
91 for (y = 0; y < fvyr; y++)
92 for (x = 0; x < fvxr; x++) {
93 if (x == px && y == py) continue;
94 t2 = DOT(rdirscan(py)[px],
95 rdirscan(y)[x]);
96 if (t2 <= FTINY) continue;
97 /* use approximation instead
98 t3 = acos(t2);
99 t2 = t2/(t3*t3);
100 */
101 t2 *= .5 / (1. - t2);
102 copycolor(ctmp, fovscan(y)[x]);
103 scalecolor(ctmp, t2);
104 addcolor(vsum, ctmp);
105 t2sum += t2;
106 }
107 /* VADAPT of original is subtracted in addveil() */
108 if (t2sum > FTINY)
109 scalecolor(vsum, VADAPT/t2sum);
110 copycolor(veilscan(py)[px], vsum);
111 }
112 /* modify FOV sample image */
113 for (y = 0; y < fvyr; y++)
114 for (x = 0; x < fvxr; x++) {
115 scalecolor(fovscan(y)[x], 1.-VADAPT);
116 addcolor(fovscan(y)[x], veilscan(y)[x]);
117 }
118 comphist(); /* recompute histogram */
119 }
120
121
122 #if ADJ_VEIL
123 /*
124 * The following veil adjustment was added to compensate for
125 * the fact that contrast reduction gets confused with veil
126 * in the human visual system. Therefore, we reduce the
127 * veil in portions of the image where our mapping has
128 * already reduced contrast below the target value.
129 * This gets called after the intial veil has been computed
130 * and added to the foveal image, and the mapping has been
131 * determined.
132 */
133 adjveil() /* adjust veil image */
134 {
135 float *crfptr = crfimg;
136 COLOR *fovptr = fovimg;
137 COLOR *veilptr = veilimg;
138 double s2nits = 1./inpexp;
139 double vl, vl2, fovl, vlsum;
140 double deltavc[3];
141 int i, j;
142
143 if (lumf == rgblum)
144 s2nits *= WHTEFFICACY;
145
146 for (i = fvxr*fvyr; i--; crfptr++, fovptr++, veilptr++) {
147 if (crfptr[0] >= 0.95)
148 continue;
149 vl = plum(veilptr[0]);
150 fovl = (plum(fovptr[0]) - vl) * (1./(1.-VADAPT));
151 if (vl <= 0.05*fovl)
152 continue;
153 vlsum = vl;
154 for (j = 2; j < 11; j++) {
155 vlsum += crfptr[0]*vl - (1.0 - crfptr[0])*fovl;
156 vl2 = vlsum / (double)j;
157 if (vl2 < 0.0)
158 vl2 = 0.0;
159 crfptr[0] = crfactor(fovl + vl2);
160 }
161 /* desaturation code causes color fringes at this level */
162 for (j = 3; j--; ) {
163 double vc = colval(veilptr[0],j);
164 double fovc = (colval(fovptr[0],j) - vc) *
165 (1./(1.-VADAPT));
166 deltavc[j] = (1.-crfptr[0])*(fovl/s2nits - fovc);
167 if (vc + deltavc[j] < 0.0)
168 break;
169 }
170 if (j < 0)
171 addcolor(veilptr[0], deltavc);
172 else
173 scalecolor(veilptr[0], vl2/vl);
174 }
175 smoothveil(); /* smooth our result */
176 }
177
178
179 smoothveil() /* smooth veil image */
180 {
181 COLOR *nveilimg;
182 COLOR *ovptr, *nvptr;
183 int x, y, i;
184
185 nveilimg = (COLOR *)malloc(fvxr*fvyr*sizeof(COLOR));
186 if (nveilimg == NULL)
187 return;
188 for (y = 1; y < fvyr-1; y++) {
189 ovptr = veilimg + y*fvxr + 1;
190 nvptr = nveilimg + y*fvxr + 1;
191 for (x = 1; x < fvxr-1; x++, ovptr++, nvptr++)
192 for (i = 3; i--; )
193 nvptr[0][i] = 0.5 * ovptr[0][i]
194 + (1./12.) *
195 (ovptr[-1][i] + ovptr[-fvxr][i] +
196 ovptr[1][i] + ovptr[fvxr][i])
197 + (1./24.) *
198 (ovptr[-fvxr-1][i] + ovptr[-fvxr+1][i] +
199 ovptr[fvxr-1][i] + ovptr[fvxr+1][i]);
200 }
201 ovptr = veilimg + 1;
202 nvptr = nveilimg + 1;
203 for (x = 1; x < fvxr-1; x++, ovptr++, nvptr++)
204 for (i = 3; i--; )
205 nvptr[0][i] = 0.5 * ovptr[0][i]
206 + (1./9.) *
207 (ovptr[-1][i] + ovptr[1][i] + ovptr[fvxr][i])
208 + (1./12.) *
209 (ovptr[fvxr-1][i] + ovptr[fvxr+1][i]);
210 ovptr = veilimg + (fvyr-1)*fvxr + 1;
211 nvptr = nveilimg + (fvyr-1)*fvxr + 1;
212 for (x = 1; x < fvxr-1; x++, ovptr++, nvptr++)
213 for (i = 3; i--; )
214 nvptr[0][i] = 0.5 * ovptr[0][i]
215 + (1./9.) *
216 (ovptr[-1][i] + ovptr[1][i] + ovptr[-fvxr][i])
217 + (1./12.) *
218 (ovptr[-fvxr-1][i] + ovptr[-fvxr+1][i]);
219 ovptr = veilimg + fvxr;
220 nvptr = nveilimg + fvxr;
221 for (y = 1; y < fvyr-1; y++, ovptr += fvxr, nvptr += fvxr)
222 for (i = 3; i--; )
223 nvptr[0][i] = 0.5 * ovptr[0][i]
224 + (1./9.) *
225 (ovptr[-fvxr][i] + ovptr[1][i] + ovptr[fvxr][i])
226 + (1./12.) *
227 (ovptr[-fvxr+1][i] + ovptr[fvxr+1][i]);
228 ovptr = veilimg + fvxr - 1;
229 nvptr = nveilimg + fvxr - 1;
230 for (y = 1; y < fvyr-1; y++, ovptr += fvxr, nvptr += fvxr)
231 for (i = 3; i--; )
232 nvptr[0][i] = 0.5 * ovptr[0][i]
233 + (1./9.) *
234 (ovptr[-fvxr][i] + ovptr[-1][i] + ovptr[fvxr][i])
235 + (1./12.) *
236 (ovptr[-fvxr-1][i] + ovptr[fvxr-1][i]);
237 for (i = 3; i--; ) {
238 nveilimg[0][i] = veilimg[0][i];
239 nveilimg[fvxr-1][i] = veilimg[fvxr-1][i];
240 nveilimg[(fvyr-1)*fvxr][i] = veilimg[(fvyr-1)*fvxr][i];
241 nveilimg[fvyr*fvxr-1][i] = veilimg[fvyr*fvxr-1][i];
242 }
243 free((void *)veilimg);
244 veilimg = nveilimg;
245 }
246 #endif
247
248 addveil(sl, y) /* add veil to scanline */
249 COLOR *sl;
250 int y;
251 {
252 int vx, vy;
253 double dx, dy;
254 double lv, uv;
255 register int x, i;
256
257 vy = dy = (y+.5)/numscans(&inpres)*fvyr - .5;
258 while (vy >= fvyr-1) vy--;
259 dy -= (double)vy;
260 for (x = 0; x < scanlen(&inpres); x++) {
261 vx = dx = (x+.5)/scanlen(&inpres)*fvxr - .5;
262 while (vx >= fvxr-1) vx--;
263 dx -= (double)vx;
264 for (i = 0; i < 3; i++) {
265 lv = (1.-dy)*colval(veilscan(vy)[vx],i) +
266 dy*colval(veilscan(vy+1)[vx],i);
267 uv = (1.-dy)*colval(veilscan(vy)[vx+1],i) +
268 dy*colval(veilscan(vy+1)[vx+1],i);
269 colval(sl[x],i) = (1.-VADAPT)*colval(sl[x],i) +
270 (1.-dx)*lv + dx*uv;
271 }
272 }
273 }
274
275
276 /****************** ACUITY STUFF *******************/
277
278 typedef struct {
279 short sampe; /* sample area size (exponent of 2) */
280 short nscans; /* number of scanlines in this bar */
281 int len; /* individual scanline length */
282 int nread; /* number of scanlines loaded */
283 COLOR *sdata; /* scanbar data */
284 } SCANBAR;
285
286 #define bscan(sb,y) ((COLOR *)(sb)->sdata+((y)%(sb)->nscans)*(sb)->len)
287
288 SCANBAR *rootbar; /* root scan bar (lowest resolution) */
289
290 float *inpacuD; /* input acuity data (cycles/degree) */
291
292 #define tsampr(x,y) inpacuD[(y)*fvxr+(x)]
293
294
295 double
296 hacuity(La) /* return visual acuity in cycles/degree */
297 double La;
298 {
299 /* functional fit */
300 return(17.25*atan(1.4*log10(La) + 0.35) + 25.72);
301 }
302
303
304 COLOR *
305 getascan(sb, y) /* find/read scanline y for scanbar sb */
306 register SCANBAR *sb;
307 int y;
308 {
309 register COLOR *sl0, *sl1, *mysl;
310 register int i;
311
312 if (y < sb->nread - sb->nscans) /* too far back? */
313 return(NULL);
314 for ( ; y >= sb->nread; sb->nread++) { /* read as necessary */
315 mysl = bscan(sb, sb->nread);
316 if (sb->sampe == 0) {
317 if (freadscan(mysl, sb->len, infp) < 0) {
318 fprintf(stderr, "%s: %s: scanline read error\n",
319 progname, infn);
320 exit(1);
321 }
322 } else {
323 sl0 = getascan(sb+1, 2*y);
324 if (sl0 == NULL)
325 return(NULL);
326 sl1 = getascan(sb+1, 2*y+1);
327 for (i = 0; i < sb->len; i++) {
328 copycolor(mysl[i], sl0[2*i]);
329 addcolor(mysl[i], sl0[2*i+1]);
330 addcolor(mysl[i], sl1[2*i]);
331 addcolor(mysl[i], sl1[2*i+1]);
332 scalecolor(mysl[i], 0.25);
333 }
334 }
335 }
336 return(bscan(sb, y));
337 }
338
339
340 acuscan(scln, y) /* get acuity-sampled scanline */
341 COLOR *scln;
342 int y;
343 {
344 double sr;
345 double dx, dy;
346 int ix, iy;
347 register int x;
348 /* compute foveal y position */
349 iy = dy = (y+.5)/numscans(&inpres)*fvyr - .5;
350 while (iy >= fvyr-1) iy--;
351 dy -= (double)iy;
352 for (x = 0; x < scanlen(&inpres); x++) {
353 /* compute foveal x position */
354 ix = dx = (x+.5)/scanlen(&inpres)*fvxr - .5;
355 while (ix >= fvxr-1) ix--;
356 dx -= (double)ix;
357 /* interpolate sample rate */
358 sr = (1.-dy)*((1.-dx)*tsampr(ix,iy) + dx*tsampr(ix+1,iy)) +
359 dy*((1.-dx)*tsampr(ix,iy+1) + dx*tsampr(ix+1,iy+1));
360
361 acusample(scln[x], x, y, sr); /* compute sample */
362 }
363 }
364
365
366 acusample(col, x, y, sr) /* interpolate sample at (x,y) using rate sr */
367 COLOR col;
368 int x, y;
369 double sr;
370 {
371 COLOR c1;
372 double d;
373 register SCANBAR *sb0;
374
375 for (sb0 = rootbar; sb0->sampe != 0 && 1<<sb0[1].sampe > sr; sb0++)
376 ;
377 ascanval(col, x, y, sb0);
378 if (sb0->sampe == 0) /* don't extrapolate highest */
379 return;
380 ascanval(c1, x, y, sb0+1);
381 d = ((1<<sb0->sampe) - sr)/(1<<sb0[1].sampe);
382 scalecolor(col, 1.-d);
383 scalecolor(c1, d);
384 addcolor(col, c1);
385 }
386
387
388 ascanval(col, x, y, sb) /* interpolate scanbar at orig. coords (x,y) */
389 COLOR col;
390 int x, y;
391 SCANBAR *sb;
392 {
393 COLOR *sl0, *sl1, c1, c1y;
394 double dx, dy;
395 int ix, iy;
396
397 if (sb->sampe == 0) { /* no need to interpolate */
398 sl0 = getascan(sb, y);
399 copycolor(col, sl0[x]);
400 return;
401 }
402 /* compute coordinates for sb */
403 ix = dx = (x+.5)/(1<<sb->sampe) - .5;
404 while (ix >= sb->len-1) ix--;
405 dx -= (double)ix;
406 iy = dy = (y+.5)/(1<<sb->sampe) - .5;
407 while (iy >= (numscans(&inpres)>>sb->sampe)-1) iy--;
408 dy -= (double)iy;
409 /* get scanlines */
410 sl0 = getascan(sb, iy);
411 #ifdef DEBUG
412 if (sl0 == NULL)
413 error(INTERNAL, "cannot backspace in ascanval");
414 #endif
415 sl1 = getascan(sb, iy+1);
416 /* 2D linear interpolation */
417 copycolor(col, sl0[ix]);
418 scalecolor(col, 1.-dx);
419 copycolor(c1, sl0[ix+1]);
420 scalecolor(c1, dx);
421 addcolor(col, c1);
422 copycolor(c1y, sl1[ix]);
423 scalecolor(c1y, 1.-dx);
424 copycolor(c1, sl1[ix+1]);
425 scalecolor(c1, dx);
426 addcolor(c1y, c1);
427 scalecolor(col, 1.-dy);
428 scalecolor(c1y, dy);
429 addcolor(col, c1y);
430 for (ix = 0; ix < 3; ix++) /* make sure no negative */
431 if (colval(col,ix) < 0.)
432 colval(col,ix) = 0.;
433 }
434
435
436 SCANBAR *
437 sballoc(se, ns, sl) /* allocate scanbar */
438 int se; /* sampling rate exponent */
439 int ns; /* number of scanlines */
440 int sl; /* original scanline length */
441 {
442 SCANBAR *sbarr;
443 register SCANBAR *sb;
444
445 sbarr = sb = (SCANBAR *)malloc((se+1)*sizeof(SCANBAR));
446 if (sb == NULL)
447 syserror("malloc");
448 do {
449 sb->len = sl>>se;
450 if (sb->len <= 0)
451 continue;
452 sb->sampe = se;
453 sb->nscans = ns;
454 sb->sdata = (COLOR *)malloc(sb->len*ns*sizeof(COLOR));
455 if (sb->sdata == NULL)
456 syserror("malloc");
457 sb->nread = 0;
458 ns <<= 1;
459 sb++;
460 } while (--se >= 0);
461 return(sbarr);
462 }
463
464
465 initacuity() /* initialize variable acuity sampling */
466 {
467 FVECT diffx, diffy, cp;
468 double omega, maxsr;
469 register int x, y, i;
470
471 compraydir(); /* compute ray directions */
472
473 inpacuD = (float *)malloc(fvxr*fvyr*sizeof(float));
474 if (inpacuD == NULL)
475 syserror("malloc");
476 maxsr = 1.; /* compute internal sample rates */
477 for (y = 1; y < fvyr-1; y++)
478 for (x = 1; x < fvxr-1; x++) {
479 for (i = 0; i < 3; i++) {
480 diffx[i] = 0.5*fvxr/scanlen(&inpres) *
481 (rdirscan(y)[x+1][i] -
482 rdirscan(y)[x-1][i]);
483 diffy[i] = 0.5*fvyr/numscans(&inpres) *
484 (rdirscan(y+1)[x][i] -
485 rdirscan(y-1)[x][i]);
486 }
487 fcross(cp, diffx, diffy);
488 omega = 0.5 * sqrt(DOT(cp,cp));
489 if (omega <= FTINY*FTINY)
490 tsampr(x,y) = 1.;
491 else if ((tsampr(x,y) = PI/180. / sqrt(omega) /
492 hacuity(plum(fovscan(y)[x]))) > maxsr)
493 maxsr = tsampr(x,y);
494 }
495 /* copy perimeter (easier) */
496 for (x = 1; x < fvxr-1; x++) {
497 tsampr(x,0) = tsampr(x,1);
498 tsampr(x,fvyr-1) = tsampr(x,fvyr-2);
499 }
500 for (y = 0; y < fvyr; y++) {
501 tsampr(0,y) = tsampr(1,y);
502 tsampr(fvxr-1,y) = tsampr(fvxr-2,y);
503 }
504 /* initialize with next power of two */
505 rootbar = sballoc((int)(log(maxsr)/log(2.))+1, 2, scanlen(&inpres));
506 }