| 1 | 
– | 
/* Copyright (c) 1997 Regents of the University of California */ | 
| 2 | 
– | 
 | 
| 1 | 
  | 
#ifndef lint | 
| 2 | 
< | 
static char SCCSid[] = "$SunId$ LBL"; | 
| 2 | 
> | 
static const char       RCSid[] = "$Id$"; | 
| 3 | 
  | 
#endif | 
| 6 | 
– | 
 | 
| 4 | 
  | 
/* | 
| 5 | 
  | 
 * Calibrate a scanned MacBeth Color Checker Chart | 
| 6 | 
  | 
 * | 
| 7 | 
< | 
 * Produce a .cal file suitable for use with pcomb. | 
| 7 | 
> | 
 * Produce a .cal file suitable for use with pcomb, | 
| 8 | 
> | 
 * or .cwp file suitable for use with pcwarp. | 
| 9 | 
> | 
 * | 
| 10 | 
> | 
 * Warping code depends on conformance of COLOR and W3VEC types. | 
| 11 | 
  | 
 */ | 
| 12 | 
  | 
 | 
| 13 | 
  | 
#include <stdio.h> | 
| 14 | 
< | 
#ifdef MSDOS | 
| 15 | 
< | 
#include <fcntl.h> | 
| 16 | 
< | 
#endif | 
| 14 | 
> | 
#include <math.h> | 
| 15 | 
> | 
#include <time.h> | 
| 16 | 
> | 
 | 
| 17 | 
> | 
#include "platform.h" | 
| 18 | 
  | 
#include "color.h" | 
| 19 | 
  | 
#include "resolu.h" | 
| 20 | 
  | 
#include "pmap.h" | 
| 21 | 
+ | 
#include "warp3d.h" | 
| 22 | 
  | 
 | 
| 23 | 
  | 
                                /* MacBeth colors */ | 
| 24 | 
  | 
#define DarkSkin        0 | 
| 97 | 
  | 
#define  RG_ORIG        02      /* original color region */ | 
| 98 | 
  | 
#define  RG_CORR        04      /* corrected color region */ | 
| 99 | 
  | 
 | 
| 100 | 
+ | 
#ifndef  DISPCOM | 
| 101 | 
+ | 
#define  DISPCOM        "ximage -op %s" | 
| 102 | 
+ | 
#endif | 
| 103 | 
+ | 
 | 
| 104 | 
  | 
int     scanning = 1;           /* scanned input (or recorded output)? */ | 
| 105 | 
+ | 
double  irrad = 1.0;            /* irradiance multiplication factor */ | 
| 106 | 
+ | 
int     rawmap = 0;             /* put out raw color mapping? */ | 
| 107 | 
  | 
 | 
| 108 | 
  | 
int     xmax, ymax;             /* input image dimensions */ | 
| 109 | 
  | 
int     bounds[4][2];           /* image coordinates of chart corners */ | 
| 117 | 
  | 
COLORMAT        solmat;         /* color mapping matrix */ | 
| 118 | 
  | 
COLOR   colmin, colmax;         /* gamut limits */ | 
| 119 | 
  | 
 | 
| 120 | 
+ | 
WARP3D  *wcor = NULL;           /* color space warp */ | 
| 121 | 
+ | 
 | 
| 122 | 
  | 
FILE    *debugfp = NULL;        /* debug output picture */ | 
| 123 | 
  | 
char    *progname; | 
| 124 | 
  | 
 | 
| 115 | 
– | 
extern char     *malloc(); | 
| 125 | 
  | 
 | 
| 117 | 
– | 
 | 
| 126 | 
  | 
main(argc, argv) | 
| 127 | 
  | 
int     argc; | 
| 128 | 
  | 
char    **argv; | 
| 140 | 
  | 
                                perror(argv[i]); | 
| 141 | 
  | 
                                exit(1); | 
| 142 | 
  | 
                        } | 
| 143 | 
< | 
#ifdef MSDOS | 
| 136 | 
< | 
                        setmode(fileno(debugfp), O_BINARY); | 
| 137 | 
< | 
#endif | 
| 143 | 
> | 
                        SET_FILE_BINARY(debugfp); | 
| 144 | 
  | 
                        newheader("RADIANCE", debugfp);         /* start */ | 
| 145 | 
  | 
                        printargs(argc, argv, debugfp);         /* header */ | 
| 146 | 
  | 
                        break; | 
| 157 | 
  | 
                        bounds[3][1] = atoi(argv[++i]); | 
| 158 | 
  | 
                        scanning = 2; | 
| 159 | 
  | 
                        break; | 
| 160 | 
+ | 
                case 'P':                               /* pick position */ | 
| 161 | 
+ | 
                        scanning = 3; | 
| 162 | 
+ | 
                        break; | 
| 163 | 
+ | 
                case 'i':                               /* irradiance factor */ | 
| 164 | 
+ | 
                        i++; | 
| 165 | 
+ | 
                        if (badarg(argc-i, argv+i, "f")) | 
| 166 | 
+ | 
                                goto userr; | 
| 167 | 
+ | 
                        irrad = atof(argv[i]); | 
| 168 | 
+ | 
                        break; | 
| 169 | 
+ | 
                case 'm':                               /* raw map output */ | 
| 170 | 
+ | 
                        rawmap = 1; | 
| 171 | 
+ | 
                        break; | 
| 172 | 
  | 
                case 'c':                               /* color input */ | 
| 173 | 
  | 
                        scanning = 0; | 
| 174 | 
  | 
                        break; | 
| 185 | 
  | 
                exit(1); | 
| 186 | 
  | 
        } | 
| 187 | 
  | 
        if (scanning) {                 /* load input picture header */ | 
| 188 | 
< | 
#ifdef MSDOS | 
| 171 | 
< | 
                setmode(fileno(stdin), O_BINARY); | 
| 172 | 
< | 
#endif | 
| 188 | 
> | 
                SET_FILE_BINARY(stdin); | 
| 189 | 
  | 
                if (checkheader(stdin, COLRFMT, NULL) < 0 || | 
| 190 | 
  | 
                                fgetresolu(&xmax, &ymax, stdin) < 0) { | 
| 191 | 
  | 
                        fprintf(stderr, "%s: bad input picture\n", progname); | 
| 192 | 
  | 
                        exit(1); | 
| 193 | 
  | 
                } | 
| 194 | 
+ | 
                if (scanning == 3) { | 
| 195 | 
+ | 
                        if (i >= argc) | 
| 196 | 
+ | 
                                goto userr; | 
| 197 | 
+ | 
                        pickchartpos(argv[i]); | 
| 198 | 
+ | 
                        scanning = 2; | 
| 199 | 
+ | 
                } | 
| 200 | 
  | 
        } else {                        /* else set default xmax and ymax */ | 
| 201 | 
  | 
                xmax = 512; | 
| 202 | 
  | 
                ymax = 2*512/3; | 
| 213 | 
  | 
        else | 
| 214 | 
  | 
                getcolors(); | 
| 215 | 
  | 
        compute();                      /* compute color mapping */ | 
| 216 | 
< | 
                                        /* print comment */ | 
| 217 | 
< | 
        printf("{\n\tColor correction file computed by:\n\t\t"); | 
| 218 | 
< | 
        printargs(argc, argv, stdout); | 
| 219 | 
< | 
        printf("\n\tUsage: pcomb -f %s uncorrected.pic > corrected.pic\n", | 
| 220 | 
< | 
                        i+1 < argc ? argv[i+1] : "{this_file}"); | 
| 221 | 
< | 
        if (!scanning) | 
| 200 | 
< | 
                printf("\t   Or: pcond [options] -f %s orig.pic > output.pic\n", | 
| 216 | 
> | 
        if (rawmap) {                   /* print out raw correspondence */ | 
| 217 | 
> | 
                register int    j; | 
| 218 | 
> | 
 | 
| 219 | 
> | 
                printf("# Color correspondence produced by:\n#\t\t"); | 
| 220 | 
> | 
                printargs(argc, argv, stdout); | 
| 221 | 
> | 
                printf("#\tUsage: pcwarp %s uncorrected.pic > corrected.pic\n", | 
| 222 | 
  | 
                                i+1 < argc ? argv[i+1] : "{this_file}"); | 
| 223 | 
< | 
        printf("}\n"); | 
| 224 | 
< | 
        putmapping();                   /* put out color mapping */ | 
| 223 | 
> | 
                printf("#\t   Or: pcond [options] -m %s orig.pic > output.pic\n", | 
| 224 | 
> | 
                                i+1 < argc ? argv[i+1] : "{this_file}"); | 
| 225 | 
> | 
                for (j = 0; j < 24; j++) | 
| 226 | 
> | 
                        printf("%f %f %f    %f %f %f\n", | 
| 227 | 
> | 
                                colval(inpRGB[j],RED), colval(inpRGB[j],GRN), | 
| 228 | 
> | 
                                colval(inpRGB[j],BLU), colval(mbRGB[j],RED), | 
| 229 | 
> | 
                                colval(mbRGB[j],GRN), colval(mbRGB[j],BLU)); | 
| 230 | 
> | 
                if (scanning && debugfp != NULL) | 
| 231 | 
> | 
                        cwarp();                /* color warp for debugging */ | 
| 232 | 
> | 
        } else {                        /* print color mapping */ | 
| 233 | 
> | 
                                                /* print header */ | 
| 234 | 
> | 
                printf("{\n\tColor correction file computed by:\n\t\t"); | 
| 235 | 
> | 
                printargs(argc, argv, stdout); | 
| 236 | 
> | 
                printf("\n\tUsage: pcomb -f %s uncorrected.pic > corrected.pic\n", | 
| 237 | 
> | 
                                i+1 < argc ? argv[i+1] : "{this_file}"); | 
| 238 | 
> | 
                if (!scanning) | 
| 239 | 
> | 
                        printf("\t   Or: pcond [options] -f %s orig.pic > output.pic\n", | 
| 240 | 
> | 
                                        i+1 < argc ? argv[i+1] : "{this_file}"); | 
| 241 | 
> | 
                printf("}\n"); | 
| 242 | 
> | 
                putmapping();                   /* put out color mapping */ | 
| 243 | 
> | 
        } | 
| 244 | 
  | 
        if (debugfp != NULL)            /* put out debug picture */ | 
| 245 | 
  | 
                if (scanning) | 
| 246 | 
  | 
                        picdebug(); | 
| 249 | 
  | 
        exit(0); | 
| 250 | 
  | 
userr: | 
| 251 | 
  | 
        fprintf(stderr, | 
| 252 | 
< | 
"Usage: %s [-d dbg.pic][-p xul yul xur yur xll yll xlr ylr] input.pic [output.cal]\n", | 
| 252 | 
> | 
"Usage: %s [-d dbg.pic][-P | -p xul yul xur yur xll yll xlr ylr][-i irrad][-m] input.pic [output.{cal|cwp}]\n", | 
| 253 | 
  | 
                        progname); | 
| 254 | 
< | 
        fprintf(stderr, "   or: %s [-d dbg.pic] -c [xyY.dat [output.cal]]\n", | 
| 254 | 
> | 
        fprintf(stderr, "   or: %s [-d dbg.pic][-i irrad][-m] -c [xyY.dat [output.{cal|cwp}]]\n", | 
| 255 | 
  | 
                        progname); | 
| 256 | 
  | 
        exit(1); | 
| 257 | 
  | 
} | 
| 276 | 
  | 
                exit(1); | 
| 277 | 
  | 
        } | 
| 278 | 
  | 
                                        /* map MacBeth colors to RGB space */ | 
| 279 | 
< | 
        for (i = 0; i < 24; i++) | 
| 279 | 
> | 
        for (i = 0; i < 24; i++) { | 
| 280 | 
  | 
                xyY2RGB(mbRGB[i], mbxyY[i]); | 
| 281 | 
+ | 
                scalecolor(mbRGB[i], irrad); | 
| 282 | 
+ | 
        } | 
| 283 | 
  | 
} | 
| 284 | 
  | 
 | 
| 285 | 
  | 
 | 
| 353 | 
  | 
                scalecolor(inpRGB[i], d); | 
| 354 | 
  | 
                inpflags |= 1L<<i; | 
| 355 | 
  | 
        } | 
| 356 | 
< | 
        free((char *)scanln); | 
| 356 | 
> | 
        free((void *)scanln); | 
| 357 | 
  | 
} | 
| 358 | 
  | 
 | 
| 359 | 
  | 
 | 
| 444 | 
  | 
        if (scanning) { | 
| 445 | 
  | 
                copycolor(colmin, cblack); | 
| 446 | 
  | 
                copycolor(colmax, cwhite); | 
| 447 | 
+ | 
                scalecolor(colmax, irrad); | 
| 448 | 
  | 
        } else | 
| 449 | 
  | 
                for (i = 0; i < 3; i++) { | 
| 450 | 
  | 
                        colval(colmin,i) = colval(bramp[0][0],i) - | 
| 469 | 
  | 
                                n++; | 
| 470 | 
  | 
                        } | 
| 471 | 
  | 
                compsoln(clrin, clrout, n); | 
| 472 | 
< | 
                                                /* check out-of-gamut colors */ | 
| 473 | 
< | 
                for (i = 0; i < 24; i++) | 
| 474 | 
< | 
                        if (cflags & 1L<<i && cvtcolor(ctmp, mbRGB[i])) | 
| 475 | 
< | 
                                gmtflags |= 1L<<i; | 
| 472 | 
> | 
                if (irrad > 0.99 && irrad < 1.01)       /* check gamut */ | 
| 473 | 
> | 
                        for (i = 0; i < 24; i++) | 
| 474 | 
> | 
                                if (cflags & 1L<<i && cvtcolor(ctmp, mbRGB[i])) | 
| 475 | 
> | 
                                        gmtflags |= 1L<<i; | 
| 476 | 
  | 
        } while (cflags & gmtflags); | 
| 477 | 
  | 
        if (gmtflags & MODFLGS) | 
| 478 | 
  | 
                fprintf(stderr, | 
| 481 | 
  | 
} | 
| 482 | 
  | 
 | 
| 483 | 
  | 
 | 
| 484 | 
< | 
putmapping()                    /* put out color mapping for pcomb -f */ | 
| 484 | 
> | 
putmapping()                    /* put out color mapping */ | 
| 485 | 
  | 
{ | 
| 486 | 
  | 
        static char     cchar[3] = {'r', 'g', 'b'}; | 
| 487 | 
  | 
        register int    i, j; | 
| 589 | 
  | 
} | 
| 590 | 
  | 
 | 
| 591 | 
  | 
 | 
| 592 | 
+ | 
cwarp()                         /* compute color warp map */ | 
| 593 | 
+ | 
{ | 
| 594 | 
+ | 
        register int    i; | 
| 595 | 
+ | 
 | 
| 596 | 
+ | 
        if ((wcor = new3dw(W3EXACT)) == NULL) | 
| 597 | 
+ | 
                goto memerr; | 
| 598 | 
+ | 
        for (i = 0; i < 24; i++) | 
| 599 | 
+ | 
                if (!add3dpt(wcor, inpRGB[i], mbRGB[i])) | 
| 600 | 
+ | 
                        goto memerr; | 
| 601 | 
+ | 
        return; | 
| 602 | 
+ | 
memerr: | 
| 603 | 
+ | 
        perror(progname); | 
| 604 | 
+ | 
        exit(1); | 
| 605 | 
+ | 
} | 
| 606 | 
+ | 
 | 
| 607 | 
+ | 
 | 
| 608 | 
  | 
int | 
| 609 | 
  | 
cvtcolor(cout, cin)             /* convert color according to our mapping */ | 
| 610 | 
  | 
COLOR   cout, cin; | 
| 612 | 
  | 
        COLOR   ctmp; | 
| 613 | 
  | 
        int     clipped; | 
| 614 | 
  | 
 | 
| 615 | 
< | 
        if (scanning) { | 
| 615 | 
> | 
        if (wcor != NULL) { | 
| 616 | 
> | 
                clipped = warp3d(cout, cin, wcor); | 
| 617 | 
> | 
                clipped |= clipgamut(cout,bright(cout),CGAMUT,colmin,colmax); | 
| 618 | 
> | 
        } else if (scanning) { | 
| 619 | 
  | 
                bresp(ctmp, cin); | 
| 620 | 
  | 
                clipped = cresp(cout, ctmp); | 
| 621 | 
  | 
        } else { | 
| 687 | 
  | 
                                if (!(1L<<i & gmtflags) || (x+y)&07) { | 
| 688 | 
  | 
                                        copycolor(scan[x], mbRGB[i]); | 
| 689 | 
  | 
                                        clipgamut(scan[x], bright(scan[x]), | 
| 690 | 
< | 
                                                CGAMUT, cblack, cwhite); | 
| 690 | 
> | 
                                                CGAMUT, colmin, colmax); | 
| 691 | 
  | 
                                } else | 
| 692 | 
  | 
                                        copycolor(scan[x], blkcol); | 
| 693 | 
  | 
                        } else if (rg == RG_CORR) | 
| 703 | 
  | 
        } | 
| 704 | 
  | 
                                                /* clean up */ | 
| 705 | 
  | 
        fclose(debugfp); | 
| 706 | 
< | 
        free((char *)scan); | 
| 706 | 
> | 
        free((void *)scan); | 
| 707 | 
  | 
} | 
| 708 | 
  | 
 | 
| 709 | 
  | 
 | 
| 726 | 
  | 
                        clipgamut(ctmp, bright(ctmp), CGAMUT, cblack, cwhite); | 
| 727 | 
  | 
                        setcolr(orclr[i], colval(ctmp,RED), | 
| 728 | 
  | 
                                        colval(ctmp,GRN), colval(ctmp,BLU)); | 
| 729 | 
< | 
                        bresp(ctmp, inpRGB[i]); | 
| 730 | 
< | 
                        colortrans(ct2, solmat, ctmp); | 
| 731 | 
< | 
                        clipgamut(ct2, bright(ct2), CGAMUT, cblack, cwhite); | 
| 732 | 
< | 
                        setcolr(cvclr[i], colval(ct2,RED), | 
| 733 | 
< | 
                                        colval(ct2,GRN), colval(ct2,BLU)); | 
| 729 | 
> | 
                        if (rawmap) | 
| 730 | 
> | 
                                copycolr(cvclr[i], mbclr[i]); | 
| 731 | 
> | 
                        else { | 
| 732 | 
> | 
                                bresp(ctmp, inpRGB[i]); | 
| 733 | 
> | 
                                colortrans(ct2, solmat, ctmp); | 
| 734 | 
> | 
                                clipgamut(ct2, bright(ct2), CGAMUT, | 
| 735 | 
> | 
                                                cblack, cwhite); | 
| 736 | 
> | 
                                setcolr(cvclr[i], colval(ct2,RED), | 
| 737 | 
> | 
                                                colval(ct2,GRN), | 
| 738 | 
> | 
                                                colval(ct2,BLU)); | 
| 739 | 
> | 
                        } | 
| 740 | 
  | 
                } | 
| 741 | 
  | 
        } | 
| 742 | 
  | 
                                                /* allocate scanline */ | 
| 773 | 
  | 
        } | 
| 774 | 
  | 
                                                /* clean up */ | 
| 775 | 
  | 
        fclose(debugfp); | 
| 776 | 
< | 
        free((char *)scan); | 
| 776 | 
> | 
        free((void *)scan); | 
| 777 | 
> | 
} | 
| 778 | 
> | 
 | 
| 779 | 
> | 
 | 
| 780 | 
> | 
getpos(name, bnds, fp)          /* get boundary position */ | 
| 781 | 
> | 
char    *name; | 
| 782 | 
> | 
int     bnds[2]; | 
| 783 | 
> | 
FILE    *fp; | 
| 784 | 
> | 
{ | 
| 785 | 
> | 
        char    buf[64]; | 
| 786 | 
> | 
 | 
| 787 | 
> | 
        fprintf(stderr, "\tSelect corner: %s\n", name); | 
| 788 | 
> | 
        if (fgets(buf, sizeof(buf), fp) == NULL || | 
| 789 | 
> | 
                        sscanf(buf, "%d %d", &bnds[0], &bnds[1]) != 2) { | 
| 790 | 
> | 
                fprintf(stderr, "%s: read error from display process\n", | 
| 791 | 
> | 
                                progname); | 
| 792 | 
> | 
                exit(1); | 
| 793 | 
> | 
        } | 
| 794 | 
> | 
} | 
| 795 | 
> | 
 | 
| 796 | 
> | 
 | 
| 797 | 
> | 
pickchartpos(pfn)               /* display picture and pick chart location */ | 
| 798 | 
> | 
char    *pfn; | 
| 799 | 
> | 
{ | 
| 800 | 
> | 
        char    combuf[512]; | 
| 801 | 
> | 
        FILE    *pfp; | 
| 802 | 
> | 
 | 
| 803 | 
> | 
        sprintf(combuf, DISPCOM, pfn); | 
| 804 | 
> | 
        if ((pfp = popen(combuf, "r")) == NULL) { | 
| 805 | 
> | 
                perror(combuf); | 
| 806 | 
> | 
                exit(1); | 
| 807 | 
> | 
        } | 
| 808 | 
> | 
        fputs("Use middle mouse button to select chart corners:\n", stderr); | 
| 809 | 
> | 
        getpos("upper left (dark skin)", bounds[0], pfp); | 
| 810 | 
> | 
        getpos("upper right (bluish green)", bounds[1], pfp); | 
| 811 | 
> | 
        getpos("lower left (white)", bounds[2], pfp); | 
| 812 | 
> | 
        getpos("lower right (black)", bounds[3], pfp); | 
| 813 | 
> | 
        fputs("Got it -- quit display program.\n", stderr); | 
| 814 | 
> | 
        pclose(pfp); | 
| 815 | 
  | 
} |