/* Copyright (c) 1995 Regents of the University of California */ #ifndef lint static char SCCSid[] = "$SunId$ LBL"; #endif /* * Calibrate a scanned MacBeth Color Checker Chart * * Produce a .cal file suitable for use with pcomb. */ #include #ifdef MSDOS #include #endif #include "color.h" #include "resolu.h" #include "pmap.h" /* MacBeth colors */ #define DarkSkin 0 #define LightSkin 1 #define BlueSky 2 #define Foliage 3 #define BlueFlower 4 #define BluishGreen 5 #define Orange 6 #define PurplishBlue 7 #define ModerateRed 8 #define Purple 9 #define YellowGreen 10 #define OrangeYellow 11 #define Blue 12 #define Green 13 #define Red 14 #define Yellow 15 #define Magenta 16 #define Cyan 17 #define White 18 #define Neutral8 19 #define Neutral65 20 #define Neutral5 21 #define Neutral35 22 #define Black 23 /* computed from 5nm spectral measurements */ /* CIE 1931 2 degree obs, equal-energy white */ float mbxyY[24][3] = { {0.462, 0.3769, 0.0932961}, /* DarkSkin */ {0.4108, 0.3542, 0.410348}, /* LightSkin */ {0.2626, 0.267, 0.181554}, /* BlueSky */ {0.36, 0.4689, 0.108447}, /* Foliage */ {0.2977, 0.2602, 0.248407}, /* BlueFlower */ {0.2719, 0.3485, 0.401156}, /* BluishGreen */ {0.52, 0.4197, 0.357899}, /* Orange */ {0.229, 0.1866, 0.103911}, /* PurplishBlue */ {0.4909, 0.3262, 0.242615}, /* ModerateRed */ {0.3361, 0.2249, 0.0600102}, /* Purple */ {0.3855, 0.4874, 0.42963}, /* YellowGreen */ {0.4853, 0.4457, 0.476343}, /* OrangeYellow */ {0.2026, 0.1369, 0.0529249}, /* Blue */ {0.3007, 0.4822, 0.221226}, /* Green */ {0.5805, 0.3238, 0.162167}, /* Red */ {0.4617, 0.472, 0.64909}, /* Yellow */ {0.4178, 0.2625, 0.233662}, /* Magenta */ {0.2038, 0.2508, 0.167275}, /* Cyan */ {0.3358, 0.337, 0.916877}, /* White */ {0.3338, 0.3348, 0.604678}, /* Neutral.8 */ {0.3333, 0.3349, 0.364566}, /* Neutral.65 */ {0.3353, 0.3359, 0.200238}, /* Neutral.5 */ {0.3363, 0.336, 0.0878721}, /* Neutral.35 */ {0.3346, 0.3349, 0.0308383} /* Black */ }; COLOR mbRGB[24]; /* MacBeth RGB values */ #define NMBNEU 6 /* Number of MacBeth neutral colors */ short mbneu[NMBNEU] = {Black,Neutral35,Neutral5,Neutral65,Neutral8,White}; #define NMBMOD 16 /* Number of MacBeth unsaturated colors */ short mbmod[NMBMOD] = { DarkSkin,LightSkin,BlueSky,Foliage,BlueFlower,BluishGreen, PurplishBlue,ModerateRed,YellowGreen,OrangeYellow, Black,Neutral35,Neutral5,Neutral65,Neutral8,White }; #define NMBSAT 8 /* Number of MacBeth saturated colors */ short mbsat[NMBSAT] = { Red,Green,Blue,Magenta,Yellow,Cyan, Orange,Purple }; #define REQFLGS (1L<= 6. || cpos[1] < 0. || cpos[1] >= 4.) return(-1); ix = cpos[0]; iy = cpos[1]; fx = cpos[0] - ix; fy = cpos[1] - iy; cmin = .5*(1.-cvg); cmax = 1. - cmin; if (fx < cmin || fx >= cmax || fy < cmin || fy >= cmax) return(-1); return(iy*6 + ix); } getpicture() /* load in picture colors */ { COLR *scanln; COLOR pval; int ccount[24]; double d; int y; register int x, i; scanln = (COLR *)malloc(xmax*sizeof(COLR)); if (scanln == NULL) { perror(progname); exit(1); } for (i = 0; i < 24; i++) { setcolor(inpRGB[i], 0., 0., 0.); ccount[i] = 0; } for (y = ymax-1; y >= 0; y--) { if (freadcolrs(scanln, xmax, stdin) < 0) { fprintf(stderr, "%s: error reading input picture\n", progname); exit(1); } for (x = 0; x < xmax; x++) { i = chartndx(x, y, CENTCVG); if (i >= 0) { colr_color(pval, scanln[x]); addcolor(inpRGB[i], pval); ccount[i]++; } } } for (i = 0; i < 24; i++) { /* compute averages */ if (ccount[i] == 0) continue; d = 1./ccount[i]; scalecolor(inpRGB[i], d); inpflags |= 1L< 24 || fgetval(stdin, 'f', &xyYin[0]) != 1 || fgetval(stdin, 'f', &xyYin[1]) != 1 || fgetval(stdin, 'f', &xyYin[2]) != 1 || xyYin[0] < 0. | xyYin[0] > 1. | xyYin[1] < 0. | xyYin[1] > 1.) { fprintf(stderr, "%s: bad color input data\n", progname); exit(1); } if (n == 0) { /* calibration white */ xyY2RGB(whiteclr, xyYin); gotwhite++; } else { /* standard color */ n--; xyY2RGB(inpRGB[n], xyYin); inpflags |= 1L< NMBMOD) { fprintf(stderr, "%s: bad number of colors to match\n", progname); exit(1); } if (n == 3) for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) mat[i][j] = colval(cin[j],i); else { /* compute A^t A */ for (i = 0; i < 3; i++) for (j = i; j < 3; j++) { mat[i][j] = 0.; for (k = 0; k < n; k++) mat[i][j] += colval(cin[k],i) * colval(cin[k],j); } for (i = 1; i < 3; i++) /* using symmetry */ for (j = 0; j < i; j++) mat[i][j] = mat[j][i]; } det = mx3d_adjoint(mat, invmat); if (fabs(det) < 1e-4) { fprintf(stderr, "%s: cannot compute color mapping\n", progname); solmat[0][0] = solmat[1][1] = solmat[2][2] = 1.; solmat[0][1] = solmat[0][2] = solmat[1][0] = solmat[1][2] = solmat[2][0] = solmat[2][1] = 0.; return; } for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) invmat[i][j] /= det; for (i = 0; i < 3; i++) { if (n == 3) for (j = 0; j < 3; j++) colv[j] = colval(cout[j],i); else for (j = 0; j < 3; j++) { colv[j] = 0.; for (k = 0; k < n; k++) colv[j] += colval(cout[k],i) * colval(cin[k],j); } mx3d_transform(colv, invmat, rowv); for (j = 0; j < 3; j++) solmat[i][j] = rowv[j]; } } cvtcolor(cout, cin) /* convert color according to our mapping */ COLOR cout, cin; { double r, g, b; bresp(cout, cin); r = colval(cout,0)*solmat[0][0] + colval(cout,1)*solmat[0][1] + colval(cout,2)*solmat[0][2]; if (r < 0) r = 0; g = colval(cout,0)*solmat[1][0] + colval(cout,1)*solmat[1][1] + colval(cout,2)*solmat[1][2]; if (g < 0) g = 0; b = colval(cout,0)*solmat[2][0] + colval(cout,1)*solmat[2][1] + colval(cout,2)*solmat[2][2]; if (b < 0) b = 0; setcolor(cout, r, g, b); } xyY2RGB(rgbout, xyYin) /* convert xyY to RGB */ COLOR rgbout; register float xyYin[3]; { COLOR ctmp; double d; d = xyYin[2] / xyYin[1]; ctmp[0] = xyYin[0] * d; ctmp[1] = xyYin[2]; ctmp[2] = (1. - xyYin[0] - xyYin[1]) * d; cie_rgb(rgbout, ctmp); } picdebug() /* put out debugging picture */ { COLOR *scan; int y; register int x, i; if (fseek(stdin, 0L, 0) == EOF) { fprintf(stderr, "%s: cannot seek on input picture\n", progname); exit(1); } getheader(stdin, NULL, NULL); /* skip input header */ fgetresolu(&xmax, &ymax, stdin); /* allocate scanline */ scan = (COLOR *)malloc(xmax*sizeof(COLOR)); if (scan == NULL) { perror(progname); exit(1); } /* finish debug header */ fputformat(COLRFMT, debugfp); putc('\n', debugfp); fprtresolu(xmax, ymax, debugfp); /* write debug picture */ for (y = ymax-1; y >= 0; y--) { if (freadscan(scan, xmax, stdin) < 0) { fprintf(stderr, "%s: error rereading input picture\n", progname); exit(1); } for (x = 0; x < xmax; x++) { i = chartndx(x, y, CENTCVG); if (i < 0) cvtcolor(scan[x], scan[x]); else copycolor(scan[x], mbRGB[i]); } if (fwritescan(scan, xmax, debugfp) < 0) { fprintf(stderr, "%s: error writing debugging picture\n", progname); exit(1); } } /* clean up */ fclose(debugfp); free((char *)scan); } clrdebug() /* put out debug picture from color input */ { static COLR blkclr = BLKCOLR; COLR mbclr[24], cvclr[24]; COLR *scan; COLOR ctmp; int y; register int i, x; /* convert colors */ for (i = 0; i < 24; i++) { setcolr(mbclr[i], colval(mbRGB[i],RED), colval(mbRGB[i],GRN), colval(mbRGB[i],BLU)); if (inpflags & 1L<= 0; y--) { for (x = 0; x < xmax; x++) if ((i = chartndx(x, y, CENTCVG)) >= 0) copycolr(scan[x], mbclr[i]); else if ((i = chartndx(x, y, FULLCVG)) >= 0 && inpflags & 1L<