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

# User Rev Content
1 greg 2.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     }