ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/macbethcal.c
Revision: 2.1
Committed: Wed Oct 11 10:40:13 1995 UTC (28 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

File Contents

# Content
1 /* Copyright (c) 1995 Regents of the University of California */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ LBL";
5 #endif
6
7 /*
8 * Calibrate a scanned MacBeth Color Checker Chart
9 *
10 * Produce a .cal file suitable for use with pcomb.
11 */
12
13 #include <stdio.h>
14 #ifdef MSDOS
15 #include <fcntl.h>
16 #endif
17 #include "color.h"
18 #include "resolu.h"
19 #include "pmap.h"
20
21 /* MacBeth colors (CIE 1931, absolute white) */
22 /* computed from spectral measurements */
23 float mbxyY[24][3] = {
24 {0.462, 0.3769, 0.0932961}, /* DarkSkin */
25 {0.4108, 0.3542, 0.410348}, /* LightSkin */
26 {0.2626, 0.267, 0.181554}, /* BlueSky */
27 {0.36, 0.4689, 0.108447}, /* Foliage */
28 {0.2977, 0.2602, 0.248407}, /* BlueFlower */
29 {0.2719, 0.3485, 0.401156}, /* BluishGreen */
30 {0.52, 0.4197, 0.357899}, /* Orange */
31 {0.229, 0.1866, 0.103911}, /* PurplishBlue */
32 {0.4909, 0.3262, 0.242615}, /* ModerateRed */
33 {0.3361, 0.2249, 0.0600102}, /* Purple */
34 {0.3855, 0.4874, 0.42963}, /* YellowGreen */
35 {0.4853, 0.4457, 0.476343}, /* OrangeYellow */
36 {0.2026, 0.1369, 0.0529249}, /* Blue */
37 {0.3007, 0.4822, 0.221226}, /* Green */
38 {0.5805, 0.3238, 0.162167}, /* Red */
39 {0.4617, 0.472, 0.64909}, /* Yellow */
40 {0.4178, 0.2625, 0.233662}, /* Magenta */
41 {0.2038, 0.2508, 0.167275}, /* Cyan */
42 {0.3358, 0.337, 0.916877}, /* White */
43 {0.3338, 0.3348, 0.604678}, /* Neutral.8 */
44 {0.3333, 0.3349, 0.364566}, /* Neutral.65 */
45 {0.3353, 0.3359, 0.200238}, /* Neutral.5 */
46 {0.3363, 0.336, 0.0878721}, /* Neutral.35 */
47 {0.3346, 0.3349, 0.0308383} /* Black */
48 };
49
50 COLOR mbRGB[24]; /* MacBeth RGB values */
51
52 #define NMBNEU 6 /* Number of MacBeth neutral colors */
53 short mbneu[NMBNEU] = {23,22,21,20,19,18};
54 #define NMBMOD 3 /* Number of MacBeth moderate colors */
55 short mbmod[NMBMOD] = {1,3,2};
56 #define NMBSAT 6 /* Number of MacBeth saturated colors */
57 short mbsat[NMBSAT] = {14,12,13,15,16,17};
58
59 int xmax, ymax; /* input image dimensions */
60 int bounds[4][2]; /* image coordinates of chart corners */
61 double imgxfm[3][3]; /* coordinate transformation matrix */
62
63 COLOR picRGB[24]; /* picture colors */
64
65 double bramp[NMBNEU][2]; /* brightness ramp */
66 double solmat[3][3]; /* color mapping matrix */
67
68 FILE *debugfp = NULL;
69 char *progname;
70
71 extern char *malloc();
72
73
74 main(argc, argv)
75 int argc;
76 char **argv;
77 {
78 int i;
79
80 progname = argv[0];
81 if (argc > 2 && !strcmp(argv[1], "-d")) { /* debug output */
82 if ((debugfp = fopen(argv[2], "w")) == NULL) {
83 perror(argv[2]);
84 exit(1);
85 }
86 #ifdef MSDOS
87 setmode(fileno(debugfp), O_BINARY);
88 #endif
89 newheader("RADIANCE", debugfp);
90 printargs(argc, argv, debugfp);
91 argv += 2;
92 argc -= 2;
93 }
94 if (argc != 3 && argc != 11)
95 goto userr;
96 if (strcmp(argv[1], "-") && freopen(argv[1], "r", stdin) == NULL) {
97 perror(argv[1]);
98 exit(1);
99 }
100 if (strcmp(argv[2], "-") && freopen(argv[2], "w", stdout) == NULL) {
101 perror(argv[2]);
102 exit(1);
103 }
104 #ifdef MSDOS
105 setmode(fileno(stdin), O_BINARY);
106 #endif
107 if (checkheader(stdin, COLRFMT, NULL) < 0 ||
108 fgetresolu(&xmax, &ymax, stdin) < 0) {
109 fprintf(stderr, "%s: bad input picture\n", progname);
110 exit(1);
111 }
112 /* get chart boundaries */
113 if (argc == 11) {
114 for (i = 0; i < 4; i++) {
115 if (!isint(argv[2*i+3]) | !isint(argv[2*i+4]))
116 goto userr;
117 bounds[i][0] = atoi(argv[2*i+3]);
118 bounds[i][1] = atoi(argv[2*i+4]);
119 }
120 } else {
121 bounds[0][0] = bounds[2][0] = .029*xmax + .5;
122 bounds[0][1] = bounds[1][1] = .956*ymax + .5;
123 bounds[1][0] = bounds[3][0] = .971*xmax + .5;
124 bounds[2][1] = bounds[3][1] = .056*ymax + .5;
125 }
126 init(); /* initialize */
127 getcolors(); /* get picture colors */
128 putmapping(); /* put out color mapping */
129 putdebug(); /* put out debug picture */
130 exit(0);
131 userr:
132 fprintf(stderr, "Usage: %s [-d dbg.pic] input.pic output.cal [xul yul xur yur xll yll xlr ylr]\n",
133 progname);
134 exit(1);
135 }
136
137
138 init() /* initialize */
139 {
140 double quad[4][2];
141 COLOR ctmp;
142 double d;
143 int i;
144 /* make coordinate transformation */
145 quad[0][0] = bounds[0][0];
146 quad[0][1] = bounds[0][1];
147 quad[1][0] = bounds[1][0];
148 quad[1][1] = bounds[1][1];
149 quad[2][0] = bounds[3][0];
150 quad[2][1] = bounds[3][1];
151 quad[3][0] = bounds[2][0];
152 quad[3][1] = bounds[2][1];
153
154 if (pmap_quad_rect(0., 0., 6., 4., quad, imgxfm) == PMAP_BAD) {
155 fprintf(stderr, "%s: bad chart boundaries\n", progname);
156 exit(1);
157 }
158 /* map MacBeth colors to RGB space */
159 for (i = 0; i < 24; i++) {
160 d = mbxyY[i][2] / mbxyY[i][1];
161 ctmp[0] = mbxyY[i][0] * d;
162 ctmp[1] = mbxyY[i][2];
163 ctmp[2] = (1. - mbxyY[i][0] - mbxyY[i][1]) * d;
164 cie_rgb(mbRGB[i], ctmp);
165 }
166 }
167
168
169 int
170 chartndx(x, y) /* find color number for position */
171 int x, y;
172 {
173 double ipos[3], cpos[3];
174 int ix, iy;
175 double fx, fy;
176
177 ipos[0] = x;
178 ipos[1] = y;
179 ipos[2] = 1;
180 mx3d_transform(ipos, imgxfm, cpos);
181 cpos[0] /= cpos[2];
182 cpos[1] /= cpos[2];
183 if (cpos[0] < 0. || cpos[0] >= 6. || cpos[1] < 0. || cpos[1] >= 4.)
184 return(-1);
185 ix = cpos[0];
186 iy = cpos[1];
187 fx = cpos[0] - ix;
188 fy = cpos[1] - iy;
189 if (fx < .35 || fx >= .65 || fy < .35 || fy >= .65)
190 return(-1);
191 return(iy*6 + ix);
192 }
193
194
195 getcolors() /* load in picture colors */
196 {
197 COLR *scanln;
198 COLOR pval;
199 int ccount[24];
200 double d;
201 int y;
202 register int x, i;
203
204 scanln = (COLR *)malloc(xmax*sizeof(COLR));
205 if (scanln == NULL) {
206 perror(progname);
207 exit(1);
208 }
209 for (i = 0; i < 24; i++) {
210 setcolor(picRGB[i], 0., 0., 0.);
211 ccount[i] = 0;
212 }
213 for (y = ymax-1; y >= 0; y--) {
214 if (freadcolrs(scanln, xmax, stdin) < 0) {
215 fprintf(stderr, "%s: error reading input picture\n",
216 progname);
217 exit(1);
218 }
219 for (x = 0; x < xmax; x++) {
220 i = chartndx(x, y);
221 if (i >= 0) {
222 colr_color(pval, scanln[x]);
223 addcolor(picRGB[i], pval);
224 ccount[i]++;
225 }
226 }
227 }
228 for (i = 0; i < 24; i++) {
229 if (ccount[i] == 0) {
230 fprintf(stderr, "%s: bad chart boundaries\n",
231 progname);
232 exit(1);
233 }
234 d = 1.0/ccount[i];
235 scalecolor(picRGB[i], d);
236 }
237 free((char *)scanln);
238 }
239
240
241 double
242 bresp(x) /* piecewise linear interpolation of brightness */
243 double x;
244 {
245 register int n = NMBNEU;
246
247 while (n > 0 && x < bramp[--n][0])
248 ;
249 return( ((bramp[n+1][0] - x)*bramp[n][1] +
250 (x - bramp[n][0])*bramp[n+1][1]) /
251 (bramp[n+1][0] - bramp[n][0]) );
252 }
253
254
255 putmapping() /* compute and print mapping for pcomb -f */
256 {
257 float clrin[NMBMOD][3], clrout[NMBMOD][3];
258 register int i, j;
259 /* compute piecewise luminance curve */
260 for (i = 0; i < NMBNEU; i++) {
261 bramp[i][0] = bright(picRGB[mbneu[i]]);
262 bramp[i][1] = bright(mbRGB[mbneu[i]]);
263 }
264 /* compute color matrix */
265 for (i = 0; i < NMBMOD; i++)
266 for (j = 0; j < 3; j++) {
267 clrin[i][j] = bresp(picRGB[mbmod[i]][j]);
268 clrout[i][j] = mbRGB[mbmod[i]][j];
269 }
270 compsoln(clrin, clrout, NMBMOD);
271 /* print brightness mapping */
272 printf("xval(i) : select(i, 0");
273 for (i = 0; i < NMBNEU; i++)
274 printf(", %g", bramp[i][0]);
275 printf(");\n");
276 printf("yval(i) : select(i, 0");
277 for (i = 0; i < NMBNEU; i++)
278 printf(", %g", bramp[i][1]);
279 printf(");\n");
280 printf("ifind(x,f,n) : if(1.5-n, 1, if(x-f(n), n, ifind(x,f,n-1)));\n");
281 printf("binterp(i,x) : ((xval(i+1)-x)*yval(i) + (x-xval(i))*yval(i+1))/\n");
282 printf("\t\t(xval(i+1) - xval(i));\n");
283 printf("bresp(x) : binterp(ifind(x,xval,xval(0)-1), x);\n");
284 printf("nred = bresp(ri(1));\n");
285 printf("ngrn = bresp(gi(1));\n");
286 printf("nblu = bresp(bi(1));\n");
287 /* print color mapping */
288 printf("ro = %g*nred + %g*ngrn + %g*nblu\n",
289 solmat[0][0], solmat[1][0], solmat[2][0]);
290 printf("go = %g*nred + %g*ngrn + %g*nblu\n",
291 solmat[0][1], solmat[1][1], solmat[2][1]);
292 printf("bo = %g*nred + %g*ngrn + %g*nblu\n",
293 solmat[0][2], solmat[1][2], solmat[2][2]);
294 }
295
296
297 compsoln(cin, cout, n) /* solve 3x3 system */
298 float cin[][3], cout[][3];
299 int n;
300 {
301 extern double mx3d_adjoint(), fabs();
302 double mat[3][3], invmat[3][3];
303 double det;
304 double colv[3], rowv[3];
305 register int i, j;
306
307 if (n != 3) {
308 fprintf(stderr, "%s: inconsistent code!\n", progname);
309 exit(1);
310 }
311 for (i = 0; i < 3; i++)
312 for (j = 0; j < 3; j++)
313 mat[i][j] = cin[j][i];
314 det = mx3d_adjoint(mat, invmat);
315 if (fabs(det) < 1e-4) {
316 fprintf(stderr, "%s: cannot compute color mapping\n",
317 progname);
318 solmat[0][0] = solmat[1][1] = solmat[2][2] = 1.;
319 solmat[0][1] = solmat[0][2] = solmat[1][0] =
320 solmat[1][2] = solmat[2][0] = solmat[2][1] = 0.;
321 return;
322 }
323 for (i = 0; i < 3; i++)
324 for (j = 0; j < 3; j++)
325 invmat[i][j] /= det;
326 for (i = 0; i < 3; i++) {
327 for (j = 0; j < 3; j++)
328 rowv[j] = cout[j][i];
329 mx3d_transform(rowv, invmat, colv);
330 for (j = 0; j < 3; j++)
331 solmat[j][i] = colv[j];
332 }
333 }
334
335
336 cvtcolor(cout, cin) /* convert color according to our mapping */
337 COLOR cout, cin;
338 {
339 double r, g, b;
340 double r1, g1, b1;
341
342 r = bresp(colval(cin,RED));
343 g = bresp(colval(cin,GRN));
344 b = bresp(colval(cin,BLU));
345 r1 = r*solmat[0][0] + g*solmat[1][0] + b*solmat[2][0];
346 if (r1 < 0) r1 = 0;
347 g1 = r*solmat[0][1] + g*solmat[1][1] + b*solmat[2][1];
348 if (g1 < 0) g1 = 0;
349 b1 = r*solmat[0][2] + g*solmat[1][2] + b*solmat[2][2];
350 if (b1 < 0) b1 = 0;
351 setcolor(cout, r1, g1, b1);
352 }
353
354
355 putdebug() /* put out debugging picture */
356 {
357 COLOR *scan;
358 int y;
359 register int x, i;
360
361 if (debugfp == NULL)
362 return;
363 if (fseek(stdin, 0L, 0) == EOF) {
364 fprintf(stderr, "%s: cannot seek on input picture\n", progname);
365 exit(1);
366 }
367 getheader(stdin, NULL, NULL); /* skip input header */
368 fgetresolu(&xmax, &ymax, stdin);
369 /* allocate scanline */
370 scan = (COLOR *)malloc(xmax*sizeof(COLOR));
371 if (scan == NULL) {
372 perror(progname);
373 exit(1);
374 }
375 /* finish debug header */
376 putc('\n', debugfp);
377 fprtresolu(xmax, ymax, debugfp);
378 for (y = ymax-1; y >= 0; y--) {
379 if (freadscan(scan, xmax, stdin) < 0) {
380 fprintf(stderr, "%s: error rereading input picture\n",
381 progname);
382 exit(1);
383 }
384 for (x = 0; x < xmax; x++) {
385 i = chartndx(x, y);
386 if (i < 0)
387 cvtcolor(scan[x], scan[x]);
388 else
389 copycolor(scan[x], mbRGB[i]);
390 }
391 if (fwritescan(scan, xmax, debugfp) < 0) {
392 fprintf(stderr, "%s: error writing debugging picture\n",
393 progname);
394 exit(1);
395 }
396 }
397 free((char *)scan);
398 }