ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/pcond.c
Revision: 3.33
Committed: Wed Sep 11 18:56:11 2024 UTC (6 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 3.32: +16 -5 lines
Log Message:
feat(pcond,pvalue): Added hyperspectral input handling

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: pcond.c,v 3.32 2023/10/27 16:35:02 greg Exp $";
3 #endif
4 /*
5 * Condition Radiance picture for display/output
6 * Added white-balance adjustment 10/01 (GW).
7 */
8
9 #include "platform.h"
10 #include "paths.h"
11 #include "pcond.h"
12
13
14 #define LDMAX 100 /* default max. display luminance */
15 #define LDDYN 100 /* default dynamic range */
16
17 int what2do = 0; /* desired adjustments */
18
19 double ldmax = LDMAX; /* maximum output luminance */
20 double lddyn = LDDYN; /* display dynamic range */
21 double Bldmin, Bldmax; /* Bl(ldmax/lddyn) and Bl(ldmax) */
22
23 char *progname; /* global argv[0] */
24
25 char *infn; /* input file name */
26 FILE *infp; /* input stream */
27 FILE *mapfp = NULL; /* tone-mapping function stream */
28 VIEW ourview = STDVIEW; /* picture view */
29 int gotview = 0; /* picture has view */
30 double pixaspect = 1.0; /* pixel aspect ratio */
31 double fixfrac = 0.; /* histogram share due to fixations */
32 RESOLU inpres; /* input picture resolution */
33
34 COLOR *fovimg; /* foveal (1 degree) averaged image */
35 int fvxr, fvyr; /* foveal image resolution */
36 float *crfimg; /* contrast reduction factors */
37 short (*fixlst)[2]; /* fixation history list */
38 int nfixations; /* number of fixation points */
39 double bwhist[HISTRES]; /* luminance histogram */
40 double histot; /* total count of histogram */
41 double bwmin, bwmax; /* histogram limits */
42 double bwavg; /* mean brightness */
43
44 double scalef = 0.; /* linear scaling factor */
45
46 static gethfunc headline;
47 static void getahead(void);
48 static void mapimage(void);
49 static void getfovimg(void);
50 static void check2do(void);
51
52
53
54 int
55 main(
56 int argc,
57 char *argv[]
58 )
59 {
60 static RGBPRIMS outprimS;
61 int i;
62 #define check_bool(flg) switch (argv[i][2]) { \
63 case '\0': what2do ^= flg; break; \
64 case 'y': case 'Y': case 't': case 'T': \
65 case '+': case '1': what2do |= flg; break; \
66 case 'n': case 'N': case 'f': case 'F': \
67 case '-': case '0': what2do &= ~(flg); break; \
68 default: goto userr; }
69
70 progname = argv[0];
71
72 for (i = 1; i < argc && argv[i][0] == '-'; i++)
73 switch (argv[i][1]) {
74 case 'h':
75 check_bool(DO_HUMAN);
76 break;
77 case 'a':
78 check_bool(DO_ACUITY);
79 break;
80 case 'v':
81 check_bool(DO_VEIL);
82 break;
83 case 's':
84 check_bool(DO_HSENS);
85 break;
86 case 'c':
87 check_bool(DO_COLOR);
88 break;
89 case 'w':
90 check_bool(DO_CWEIGHT);
91 break;
92 case 'i':
93 if (i+1 >= argc) goto userr;
94 fixfrac = atof(argv[++i]);
95 if (fixfrac > FTINY) what2do |= DO_FIXHIST;
96 else what2do &= ~DO_FIXHIST;
97 break;
98 case 'I':
99 check_bool(DO_PREHIST);
100 break;
101 case 'l':
102 check_bool(DO_LINEAR);
103 break;
104 case 'p':
105 if (i+8 >= argc) goto userr;
106 outprimS[RED][CIEX] = atof(argv[++i]);
107 outprimS[RED][CIEY] = atof(argv[++i]);
108 outprimS[GRN][CIEX] = atof(argv[++i]);
109 outprimS[GRN][CIEY] = atof(argv[++i]);
110 outprimS[BLU][CIEX] = atof(argv[++i]);
111 outprimS[BLU][CIEY] = atof(argv[++i]);
112 outprimS[WHT][CIEX] = atof(argv[++i]);
113 outprimS[WHT][CIEY] = atof(argv[++i]);
114 outprims = outprimS;
115 break;
116 case 'e':
117 if (i+1 >= argc) goto userr;
118 scalef = atof(argv[++i]);
119 if ((argv[i][0] == '+') | (argv[i][0] == '-'))
120 scalef = pow(2.0, scalef);
121 what2do |= DO_LINEAR;
122 break;
123 case 'f':
124 if (i+1 >= argc) goto userr;
125 mbcalfile = argv[++i];
126 break;
127 case 'm':
128 if (i+1 >= argc) goto userr;
129 cwarpfile = argv[++i];
130 break;
131 case 'u':
132 if (i+1 >= argc) goto userr;
133 ldmax = atof(argv[++i]);
134 if (ldmax <= FTINY)
135 goto userr;
136 break;
137 case 'd':
138 if (i+1 >= argc) goto userr;
139 lddyn = atof(argv[++i]);
140 break;
141 case 'x':
142 if (i+1 >= argc) goto userr;
143 if ((mapfp = fopen(argv[++i], "w")) == NULL) {
144 fprintf(stderr,
145 "%s: cannot open for writing\n",
146 argv[i]);
147 exit(1);
148 }
149 break;
150 default:
151 goto userr;
152 }
153 if ((what2do & (DO_FIXHIST|DO_PREHIST)) == (DO_FIXHIST|DO_PREHIST)) {
154 fprintf(stderr, "%s: only one of -i or -I option\n", progname);
155 exit(1);
156 }
157 if ((mbcalfile != NULL) + (cwarpfile != NULL) +
158 (outprims != stdprims) > 1) {
159 fprintf(stderr,
160 "%s: only one of -p, -m or -f option supported\n",
161 progname);
162 exit(1);
163 }
164 if ((outprims == stdprims) & (inprims != stdprims))
165 outprims = inprims;
166 Bldmin = Bl(ldmax/lddyn);
167 Bldmax = Bl(ldmax);
168 if (i >= argc || i+2 < argc)
169 goto userr;
170 /* open input file */
171 if ((infp = fopen(infn=argv[i], "r")) == NULL)
172 syserror(infn);
173 /* open output file */
174 if (i+2 == argc && freopen(argv[i+1], "w", stdout) == NULL)
175 syserror(argv[i+1]);
176 SET_FILE_BINARY(infp);
177 SET_FILE_BINARY(stdout);
178 getahead(); /* load input header */
179 printargs(argc, argv, stdout); /* add to output header */
180 if ((mbcalfile == NULL) & (outprims != stdprims))
181 fputprims(outprims, stdout);
182 if ((what2do & (DO_PREHIST|DO_VEIL|DO_ACUITY)) != DO_PREHIST)
183 getfovimg(); /* get foveal sample image? */
184 if (what2do&DO_PREHIST) /* get histogram? */
185 gethisto(stdin);
186 else if (what2do&DO_FIXHIST) /* get fixation history? */
187 getfixations(stdin);
188 mapimage(); /* map the picture */
189 if (mapfp != NULL) /* write out basic mapping */
190 putmapping(mapfp);
191 exit(0);
192 userr:
193 fprintf(stderr, "Usage: %s [-{h|a|v|s|c|l|w}[+-]][-I|-i ffrac][-e ev][-p xr yr xg yg xb yb xw yw|-f mbf.cal|-m rgb.cwp][-u Ldmax][-d Lddyn][-x mapfile] inpic [outpic]\n",
194 progname);
195 exit(1);
196 return 1; /* pro forma return */
197 #undef check_bool
198 }
199
200
201 void
202 syserror( /* report system error and exit */
203 char *s
204 )
205 {
206 fprintf(stderr, "%s: ", progname);
207 perror(s);
208 exit(2);
209 }
210
211
212 static int
213 headline( /* process header line */
214 char *s,
215 void *p
216 )
217 {
218 static RGBPRIMS inprimS;
219 char fmt[MAXFMTLEN];
220
221 if (formatval(fmt, s)) { /* check if format string */
222 if (!strcmp(fmt,COLRFMT) || !strcmp(fmt,SPECFMT))
223 lumf = rgblum;
224 else if (!strcmp(fmt,CIEFMT))
225 lumf = cielum;
226 else
227 lumf = NULL;
228 return(0); /* don't echo */
229 }
230 if (isncomp(s)) {
231 NCSAMP = ncompval(s);
232 return(0);
233 }
234 if (iswlsplit(s)) {
235 wlsplitval(WLPART, s);
236 return(0);
237 }
238 /* get input primaries */
239 if (isprims(s) && primsval(inprimS, s)) {
240 inprims = inprimS;
241 return(0); /* don't echo */
242 }
243 if (isexpos(s)) { /* picture exposure */
244 inpexp *= exposval(s);
245 return(0); /* don't echo */
246 }
247 if (isaspect(s)) /* pixel aspect ratio */
248 pixaspect *= aspectval(s);
249 if (isview(s)) /* image view */
250 gotview += sscanview(&ourview, s);
251 return(fputs(s, stdout));
252 }
253
254
255 static void
256 getahead(void) /* load picture header */
257 {
258 char *err;
259
260 getheader(infp, headline, NULL);
261 if (lumf == NULL || !fgetsresolu(&inpres, infp)) {
262 fprintf(stderr, "%s: %s: not a Radiance picture\n",
263 progname, infn);
264 exit(1);
265 }
266 if (lumf == rgblum)
267 comprgb2xyzWBmat(inrgb2xyz, inprims);
268 else if (mbcalfile != NULL) {
269 fprintf(stderr, "%s: macbethcal only works with RGB pictures\n",
270 progname);
271 exit(1);
272 }
273 if (!gotview || ourview.type == VT_PAR ||
274 (ourview.horiz <= 5.) | (ourview.vert <= 5.)) {
275 ourview = stdview;
276 ourview.type = VT_PER;
277 if (pixaspect*inpres.yr < inpres.xr) {
278 ourview.horiz = 40.0;
279 ourview.vert = 2.*180./PI *
280 atan(.3639702*pixaspect*inpres.yr/inpres.xr);
281 } else {
282 ourview.vert = 40.0;
283 ourview.horiz = 2.*180./PI *
284 atan(.3639702*inpres.xr/pixaspect/inpres.yr);
285 }
286 }
287 if ((err = setview(&ourview)) != NULL) {
288 fprintf(stderr, "%s: view error in picture \"%s\": %s\n",
289 progname, infn, err);
290 exit(1);
291 }
292 }
293
294
295 static void
296 mapimage(void) /* map picture and send to stdout */
297 {
298 COLOR *scan;
299
300 comphist(); /* generate adaptation histogram */
301 check2do(); /* modify what2do flags */
302 if (what2do&DO_VEIL)
303 compveil(); /* compute veil image */
304 if (!(what2do&DO_LINEAR))
305 if (mkbrmap() < 0) /* make tone map */
306 what2do |= DO_LINEAR; /* failed! -- use linear */
307 #if ADJ_VEIL
308 else if (what2do&DO_VEIL)
309 adjveil(); /* else adjust veil image */
310 #endif
311 if (what2do&DO_LINEAR) {
312 if (scalef <= FTINY) {
313 if (what2do&DO_HSENS)
314 scalef = htcontrs(Lb(0.5*(Bldmax+Bldmin))) /
315 htcontrs(Lb(bwavg));
316 else
317 scalef = Lb(0.5*(Bldmax+Bldmin)) / Lb(bwavg);
318 scalef *= WHTEFFICACY/(inpexp*ldmax);
319 }
320 fputexpos(inpexp*scalef, stdout); /* record exposure */
321 if (lumf == cielum) scalef /= WHTEFFICACY;
322 }
323 fputformat(COLRFMT, stdout); /* complete header */
324 putchar('\n');
325 fputsresolu(&inpres, stdout); /* resolution doesn't change */
326 /* condition our image */
327 for (scan = firstscan(); scan != NULL; scan = nextscan())
328 if (fwritescan(scan, scanlen(&inpres), stdout) < 0) {
329 fprintf(stderr, "%s: scanline write error\n",
330 progname);
331 exit(1);
332 }
333 }
334
335
336 static void
337 getfovimg(void) /* load foveal sampled image */
338 {
339 char combuf[PATH_MAX];
340 FILE *fp;
341 int x, y;
342 /* compute image size */
343 fvxr = sqrt(ourview.hn2)/FOVDIA + 0.5;
344 if (fvxr < 2) fvxr = 2;
345 fvyr = sqrt(ourview.vn2)/FOVDIA + 0.5;
346 if (fvyr < 2) fvyr = 2;
347 if (!(inpres.rt & YMAJOR)) { /* picture is rotated? */
348 y = fvyr;
349 fvyr = fvxr;
350 fvxr = y;
351 }
352 if ((fovimg = (COLOR *)malloc(fvxr*fvyr*sizeof(COLOR))) == NULL)
353 syserror("malloc");
354 sprintf(combuf, "pfilt -1 -b -pa 0 -x %d -y %d \"%s\"", fvxr, fvyr, infn);
355 if ((fp = popen(combuf, "r")) == NULL)
356 syserror("popen");
357 SET_FILE_BINARY(fp);
358 getheader(fp, NULL, NULL); /* skip header */
359 if (fgetresolu(&x, &y, fp) < 0 || (x != fvxr) | (y != fvyr))
360 goto readerr;
361 for (y = 0; y < fvyr; y++)
362 if (fread2scan(fovscan(y), fvxr, fp, NCSAMP, WLPART) < 0)
363 goto readerr;
364 pclose(fp);
365 return;
366 readerr:
367 fprintf(stderr, "%s: error reading from pfilt process in fovimage\n",
368 progname);
369 exit(1);
370 }
371
372
373 static void
374 check2do(void) /* check histogram to see what isn't worth doing */
375 {
376 double sum;
377 double b, l;
378 int i;
379
380 /* check for within display range */
381 if (bwmax - bwmin <= Bldmax - Bldmin)
382 what2do |= DO_LINEAR;
383 /* determine if veiling significant */
384 if (bwmax - bwmin < 4.5) /* heuristic */
385 what2do &= ~DO_VEIL;
386
387 if (!(what2do & (DO_ACUITY|DO_COLOR)))
388 return;
389 /* find 5th percentile */
390 sum = histot*0.05;
391 for (i = 0; i < HISTRES; i++)
392 if ((sum -= bwhist[i]) <= 0)
393 break;
394 b = (i+.5)*(bwmax-bwmin)/HISTRES + bwmin;
395 l = Lb(b);
396 /* determine if acuity adj. useful */
397 if (what2do&DO_ACUITY &&
398 hacuity(l) >= (inpres.xr/sqrt(ourview.hn2) +
399 inpres.yr/sqrt(ourview.vn2))/(2.*180./PI))
400 what2do &= ~DO_ACUITY;
401 /* color sensitivity loss? */
402 if (l >= TopMesopic)
403 what2do &= ~DO_COLOR;
404 }