| 18 | 
  | 
#include "resolu.h" | 
| 19 | 
  | 
#include "pmap.h" | 
| 20 | 
  | 
 | 
| 21 | 
< | 
                                /* MacBeth colors (CIE 1931, absolute white) */ | 
| 22 | 
< | 
                                /* computed from spectral measurements */ | 
| 21 | 
> | 
                                /* MacBeth colors */ | 
| 22 | 
> | 
#define DarkSkin        0 | 
| 23 | 
> | 
#define LightSkin       1 | 
| 24 | 
> | 
#define BlueSky         2 | 
| 25 | 
> | 
#define Foliage         3 | 
| 26 | 
> | 
#define BlueFlower      4 | 
| 27 | 
> | 
#define BluishGreen     5 | 
| 28 | 
> | 
#define Orange          6 | 
| 29 | 
> | 
#define PurplishBlue    7 | 
| 30 | 
> | 
#define ModerateRed     8 | 
| 31 | 
> | 
#define Purple          9 | 
| 32 | 
> | 
#define YellowGreen     10 | 
| 33 | 
> | 
#define OrangeYellow    11 | 
| 34 | 
> | 
#define Blue            12 | 
| 35 | 
> | 
#define Green           13 | 
| 36 | 
> | 
#define Red             14 | 
| 37 | 
> | 
#define Yellow          15 | 
| 38 | 
> | 
#define Magenta         16 | 
| 39 | 
> | 
#define Cyan            17 | 
| 40 | 
> | 
#define White           18 | 
| 41 | 
> | 
#define Neutral8        19 | 
| 42 | 
> | 
#define Neutral65       20 | 
| 43 | 
> | 
#define Neutral5        21 | 
| 44 | 
> | 
#define Neutral35       22 | 
| 45 | 
> | 
#define Black           23 | 
| 46 | 
> | 
                                /* computed from 5nm spectral measurements */ | 
| 47 | 
> | 
                                /* CIE 1931 2 degree obs, equal-energy white */ | 
| 48 | 
  | 
float   mbxyY[24][3] = { | 
| 49 | 
  | 
                {0.462, 0.3769, 0.0932961},     /* DarkSkin */ | 
| 50 | 
  | 
                {0.4108, 0.3542, 0.410348},     /* LightSkin */ | 
| 75 | 
  | 
COLOR   mbRGB[24];              /* MacBeth RGB values */ | 
| 76 | 
  | 
 | 
| 77 | 
  | 
#define NMBNEU          6       /* Number of MacBeth neutral colors */ | 
| 78 | 
< | 
short   mbneu[NMBNEU] = {23,22,21,20,19,18}; | 
| 54 | 
< | 
#define NMBMOD          16      /* Number of MacBeth unsaturated colors */ | 
| 55 | 
< | 
short   mbmod[NMBMOD] = {0,1,2,3,4,5,6,7,8,9,10,11,19,20,21,22}; | 
| 56 | 
< | 
#define NMBSAT          6       /* Number of MacBeth saturated colors */ | 
| 57 | 
< | 
short   mbsat[NMBSAT] = {14,12,13,15,16,17}; | 
| 78 | 
> | 
short   mbneu[NMBNEU] = {Black,Neutral35,Neutral5,Neutral65,Neutral8,White}; | 
| 79 | 
  | 
 | 
| 80 | 
+ | 
#define NMBMOD          17      /* Number of MacBeth unsaturated colors */ | 
| 81 | 
+ | 
short   mbmod[NMBMOD] = { | 
| 82 | 
+ | 
                DarkSkin,LightSkin,BlueSky,Foliage,BlueFlower,BluishGreen, | 
| 83 | 
+ | 
                Orange,PurplishBlue,ModerateRed,Purple,YellowGreen, | 
| 84 | 
+ | 
                Black,Neutral35,Neutral5,Neutral65,Neutral8,White | 
| 85 | 
+ | 
        }; | 
| 86 | 
+ | 
 | 
| 87 | 
+ | 
#define NMBSAT          8       /* Number of MacBeth saturated colors */ | 
| 88 | 
+ | 
short   mbsat[NMBSAT] = { | 
| 89 | 
+ | 
                Red,Green,Blue,Magenta,Yellow,Cyan, | 
| 90 | 
+ | 
                Orange,OrangeYellow | 
| 91 | 
+ | 
        }; | 
| 92 | 
+ | 
 | 
| 93 | 
  | 
int     xmax, ymax;             /* input image dimensions */ | 
| 94 | 
  | 
int     bounds[4][2];           /* image coordinates of chart corners */ | 
| 95 | 
  | 
double  imgxfm[3][3];           /* coordinate transformation matrix */ | 
| 99 | 
  | 
COLOR   bramp[NMBNEU][2];       /* brightness ramp (per primary) */ | 
| 100 | 
  | 
double  solmat[3][3];           /* color mapping matrix */ | 
| 101 | 
  | 
 | 
| 102 | 
< | 
FILE    *debugfp = NULL; | 
| 102 | 
> | 
FILE    *debugfp = NULL;        /* debug output picture */ | 
| 103 | 
  | 
char    *progname; | 
| 104 | 
  | 
 | 
| 105 | 
  | 
extern char     *malloc(); | 
| 160 | 
  | 
        init();                         /* initialize */ | 
| 161 | 
  | 
        getcolors();                    /* get picture colors */ | 
| 162 | 
  | 
        compute();                      /* compute color mapping */ | 
| 163 | 
+ | 
                                        /* print comment */ | 
| 164 | 
+ | 
        printf("{ Color correction file computed by %s }\n", progname); | 
| 165 | 
+ | 
        printf("{ from scanned MacBetch color chart %s }\n", argv[1]); | 
| 166 | 
  | 
        putmapping();                   /* put out color mapping */ | 
| 167 | 
  | 
        putdebug();                     /* put out debug picture */ | 
| 168 | 
  | 
        exit(0); | 
| 352 | 
  | 
} | 
| 353 | 
  | 
 | 
| 354 | 
  | 
 | 
| 355 | 
< | 
#if NMBMOD == 3 | 
| 319 | 
< | 
compsoln(cin, cout, n)          /* solve 3x3 system */ | 
| 355 | 
> | 
compsoln(cin, cout, n)          /* solve 3xN system using least-squares */ | 
| 356 | 
  | 
COLOR   cin[], cout[]; | 
| 357 | 
  | 
int     n; | 
| 358 | 
  | 
{ | 
| 360 | 
  | 
        double  mat[3][3], invmat[3][3]; | 
| 361 | 
  | 
        double  det; | 
| 362 | 
  | 
        double  colv[3], rowv[3]; | 
| 363 | 
< | 
        register int    i, j; | 
| 363 | 
> | 
        register int    i, j, k; | 
| 364 | 
  | 
 | 
| 365 | 
< | 
        if (n != 3) { | 
| 365 | 
> | 
        if (n < 3 | n > NMBMOD) { | 
| 366 | 
  | 
                fprintf(stderr, "%s: inconsistent code!\n", progname); | 
| 367 | 
  | 
                exit(1); | 
| 368 | 
  | 
        } | 
| 369 | 
< | 
        for (i = 0; i < 3; i++) | 
| 370 | 
< | 
                for (j = 0; j < 3; j++) | 
| 371 | 
< | 
                        mat[i][j] = colval(cin[j],i); | 
| 369 | 
> | 
        if (n == 3) | 
| 370 | 
> | 
                for (i = 0; i < 3; i++) | 
| 371 | 
> | 
                        for (j = 0; j < 3; j++) | 
| 372 | 
> | 
                                mat[i][j] = colval(cin[j],i); | 
| 373 | 
> | 
        else {                          /* compute A^t A */ | 
| 374 | 
> | 
                for (i = 0; i < 3; i++) | 
| 375 | 
> | 
                        for (j = i; j < 3; j++) { | 
| 376 | 
> | 
                                mat[i][j] = 0.; | 
| 377 | 
> | 
                                for (k = 0; k < n; k++) | 
| 378 | 
> | 
                                        mat[i][j] += colval(cin[k],i) * | 
| 379 | 
> | 
                                                        colval(cin[k],j); | 
| 380 | 
> | 
                        } | 
| 381 | 
> | 
                for (i = 1; i < 3; i++)         /* using symmetry */ | 
| 382 | 
> | 
                        for (j = 0; j < i; j++) | 
| 383 | 
> | 
                                mat[i][j] = mat[j][i]; | 
| 384 | 
> | 
        } | 
| 385 | 
  | 
        det = mx3d_adjoint(mat, invmat); | 
| 386 | 
  | 
        if (fabs(det) < 1e-4) { | 
| 387 | 
  | 
                fprintf(stderr, "%s: cannot compute color mapping\n", | 
| 395 | 
  | 
                for (j = 0; j < 3; j++) | 
| 396 | 
  | 
                        invmat[i][j] /= det; | 
| 397 | 
  | 
        for (i = 0; i < 3; i++) { | 
| 398 | 
< | 
                for (j = 0; j < 3; j++) | 
| 399 | 
< | 
                        colv[j] = colval(cout[j],i); | 
| 398 | 
> | 
                if (n == 3) | 
| 399 | 
> | 
                        for (j = 0; j < 3; j++) | 
| 400 | 
> | 
                                colv[j] = colval(cout[j],i); | 
| 401 | 
> | 
                else | 
| 402 | 
> | 
                        for (j = 0; j < 3; j++) { | 
| 403 | 
> | 
                                colv[j] = 0.; | 
| 404 | 
> | 
                                for (k = 0; k < n; k++) | 
| 405 | 
> | 
                                        colv[j] += colval(cout[k],i) * | 
| 406 | 
> | 
                                                        colval(cin[k],j); | 
| 407 | 
> | 
                        } | 
| 408 | 
  | 
                mx3d_transform(colv, invmat, rowv); | 
| 409 | 
  | 
                for (j = 0; j < 3; j++) | 
| 410 | 
  | 
                        solmat[i][j] = rowv[j]; | 
| 411 | 
  | 
        } | 
| 412 | 
  | 
} | 
| 356 | 
– | 
#else | 
| 357 | 
– | 
compsoln(cin, cout, n)          /* solve 3xN system (N > 3) */ | 
| 358 | 
– | 
COLOR   cin[], cout[]; | 
| 359 | 
– | 
int     n; | 
| 360 | 
– | 
{ | 
| 361 | 
– | 
        double  *au[NMBMOD], *v[3], vv[3][3], auv[NMBMOD][3], w[3]; | 
| 362 | 
– | 
        double  b[NMBMOD]; | 
| 363 | 
– | 
        register int    i, j; | 
| 364 | 
– | 
 | 
| 365 | 
– | 
        if (n > NMBMOD) { | 
| 366 | 
– | 
                fprintf(stderr, "%s: inconsistent code!\n", progname); | 
| 367 | 
– | 
                exit(1); | 
| 368 | 
– | 
        } | 
| 369 | 
– | 
        for (i = 0; i < n; i++)         /* assign rectangular matrix A */ | 
| 370 | 
– | 
                for (j = 0; j < 3; j++) | 
| 371 | 
– | 
                        auv[i][j] = colval(cin[i],j); | 
| 372 | 
– | 
                                /* svdcmp indexing requires pointer offsets */ | 
| 373 | 
– | 
        for (j = 0; j < 3; j++) | 
| 374 | 
– | 
                v[j] = vv[j] - 1; | 
| 375 | 
– | 
        for (i = 0; i < n; i++) | 
| 376 | 
– | 
                au[i] = auv[i] - 1; | 
| 377 | 
– | 
                                /* compute singular value decomposition */ | 
| 378 | 
– | 
fprintf(stderr, "A:\n"); | 
| 379 | 
– | 
for (i = 1; i <= n; i++) | 
| 380 | 
– | 
fprintf(stderr, "%g %g %g\n", (au-1)[i][1], (au-1)[i][2], (au-1)[i][3]); | 
| 381 | 
– | 
        svdcmp(au-1, n, 3, w-1, v-1); | 
| 382 | 
– | 
fprintf(stderr, "U:\n"); | 
| 383 | 
– | 
for (i = 0; i < n; i++) | 
| 384 | 
– | 
fprintf(stderr, "%g %g %g\n", auv[i][0], auv[i][1], auv[i][2]); | 
| 385 | 
– | 
fprintf(stderr, "V:\n"); | 
| 386 | 
– | 
for (i = 0; i < 3; i++) | 
| 387 | 
– | 
fprintf(stderr, "%g %g %g\n", vv[i][0], vv[i][1], vv[i][2]); | 
| 388 | 
– | 
fprintf(stderr, "W: %g %g %g\n", w[0], w[1], w[2]); | 
| 389 | 
– | 
                                /* zero out small weights */ | 
| 390 | 
– | 
        for (j = 0; j < 3; j++) | 
| 391 | 
– | 
                if (w[j] < 1e-4) | 
| 392 | 
– | 
                        w[j] = 0.; | 
| 393 | 
– | 
                                /* back substitution for each row vector */ | 
| 394 | 
– | 
        for (j = 0; j < 3; j++) { | 
| 395 | 
– | 
                for (i = 0; i < n; i++) | 
| 396 | 
– | 
                        b[i] = colval(cout[i],j); | 
| 397 | 
– | 
                svbksb(au-1, w-1, v-1, n, 3, b-1, solmat[j]-1); | 
| 398 | 
– | 
        } | 
| 399 | 
– | 
} | 
| 400 | 
– | 
#endif | 
| 413 | 
  | 
 | 
| 414 | 
  | 
 | 
| 415 | 
  | 
cvtcolor(cout, cin)             /* convert color according to our mapping */ |