diff options
Diffstat (limited to 'profile/colverify.c')
-rw-r--r-- | profile/colverify.c | 425 |
1 files changed, 361 insertions, 64 deletions
diff --git a/profile/colverify.c b/profile/colverify.c index ba09366..e84fa6a 100644 --- a/profile/colverify.c +++ b/profile/colverify.c @@ -22,7 +22,7 @@ * TTBD: */ -#undef DEBUG +#define DEBUG #define verbo stdout @@ -37,9 +37,20 @@ #include "vrml.h" #include "cgats.h" #include "xicc.h" -#include "ccmx.h" #include "insttypes.h" +#include "disptechs.h" +#include "ccmx.h" #include "sort.h" +#include "plot.h" +#include "ui.h" + +#ifdef DEBUG +#undef DBG +#define DBG(xxx) printf xxx ; +#else +#undef DBG +#define DBG(xxx) +#endif void usage(void) { @@ -50,13 +61,17 @@ usage(void) { fprintf(stderr," -n Normalise each files reading to its white Y\n"); fprintf(stderr," -N Normalise each files reading to its white XYZ\n"); fprintf(stderr," -m Normalise each files reading to its white X+Y+Z\n"); + fprintf(stderr," -M Normalise both files reading to mean white XYZ\n"); fprintf(stderr," -D Use D50 100.0 as L*a*b* white reference\n"); fprintf(stderr," -c Show CIE94 delta E values\n"); fprintf(stderr," -k Show CIEDE2000 delta E values\n"); + fprintf(stderr," -h Plot a histogram of delta E's\n"); fprintf(stderr," -s Sort patch values by error\n"); - fprintf(stderr," -w create VRML vector visualisation (measured.wrl)\n"); - fprintf(stderr," -W create VRML marker visualisation (measured.wrl)\n"); - fprintf(stderr," -x Use VRML axes\n"); + fprintf(stderr," -w create PCS %s vector visualisation (measured%s)\n",vrml_format(), vrml_ext()); + fprintf(stderr," -W create PCS %s marker visualisation (measured%s)\n",vrml_format(),vrml_ext()); + fprintf(stderr," -d create Device RGB %s marker visualisation (measured%s)\n",vrml_format(),vrml_ext()); +// fprintf(stderr," -d y create Device YCbCr %s marker visualisation (measured%s)\n",vrml_format(),vrml_ext()); + fprintf(stderr," -x Use %s axes\n",vrml_format()); fprintf(stderr," -f [illum] Use Fluorescent Whitening Agent compensation [opt. simulated inst. illum.:\n"); fprintf(stderr," M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]\n"); fprintf(stderr," -i illum Choose illuminant for computation of CIE XYZ from spectral data & FWA:\n"); @@ -74,6 +89,8 @@ usage(void) { typedef struct { char sid[50]; /* sample id */ char loc[100]; /* sample location (empty if none) */ + double rgb[3]; /* RGB value if RGB device space present, or YCbCr if dovrml==4 */ + double ycc[3]; /* YCbCr if RGB and dovrml==4 */ int og; /* Out of gamut flag */ double xyz[3]; /* XYZ value */ double v[3]; /* Lab value */ @@ -82,17 +99,25 @@ typedef struct { double ide[3]; /* Lab Component DE */ } pval; +/* Histogram bin type */ +typedef struct { + int count; /* Raw count */ + double val; /* Normalized value */ + double min, max; /* Bin range */ +} hbin; + int main(int argc, char *argv[]) { int fa,nfa,mfa; /* current argument we're looking at */ int verb = 0; /* Verbose level */ int norm = 0; /* 1 = norm to White Y, 2 = norm to White XYZ */ - /* 3 = norm to White X+Y+Z */ + /* 3 = norm to White X+Y+Z, 4 = norm to average XYZ */ int usestdd50 = 0; /* Use standard D50 instead of avg white as reference */ int cie94 = 0; int cie2k = 0; - int dovrml = 0; + int dovrml = 0; /* 1 = PCS vector, 2 = PCS marker, 3 = RGB, 4 - YCbCr */ int doaxes = 0; + int dohisto = 0; /* Plot histogram of delta E's */ int dosort = 0; char ccmxname[MAXNAMEL+1] = "\000"; /* Colorimeter Correction Matrix name */ ccmx *cmx = NULL; /* Colorimeter Correction Matrix */ @@ -106,6 +131,7 @@ int main(int argc, char *argv[]) char name[MAXNAMEL+1]; /* Patch filename */ int isdisp; /* nz if display */ int isdnormed; /* Has display data been normalised to 100 ? */ + int isrgb; /* Is RGB device space ? */ int npat; /* Number of patches */ int nig; /* Number of patches in gamut */ double w[3]; /* XYZ of "white" */ @@ -125,16 +151,11 @@ int main(int argc, char *argv[]) icmXYZNumber labw = icmD50; /* The Lab white reference */ - char out_name[MAXNAMEL+4+1]; /* VRML name */ + char out_name[MAXNAMEL+4+1]; /* VRML/X3D name */ vrml *wrl = NULL; int i, j, n; -#if defined(__IBMC__) - _control87(EM_UNDERFLOW, EM_UNDERFLOW); - _control87(EM_OVERFLOW, EM_OVERFLOW); -#endif - if (argc <= 1) usage(); @@ -182,15 +203,31 @@ int main(int argc, char *argv[]) norm = 3; } + else if (argv[fa][1] == 'M') { + norm = 4; + } + else if (argv[fa][1] == 'D') usestdd50 = 1; - /* VRML */ + /* VRML/X3D */ else if (argv[fa][1] == 'w') dovrml = 1; + else if (argv[fa][1] == 'W') dovrml = 2; + else if (argv[fa][1] == 'd') { + dovrml = 3; + if (na != NULL) { /* Argument is present - RGB or YCbCr. */ + fa = nfa; + if (strcmp(na, "y") == 0) + dovrml = 4; + else + usage(); + } + } + /* Axes */ else if (argv[fa][1] == 'x') doaxes = 1; @@ -206,6 +243,10 @@ int main(int argc, char *argv[]) cie2k = 1; } + /* Plot histogram */ + else if (argv[fa][1] == 'h') + dohisto = 1; + /* Sort */ else if (argv[fa][1] == 's') dosort = 1; @@ -337,13 +378,13 @@ int main(int argc, char *argv[]) if (fa >= argc || argv[fa][0] == '-') usage(); strncpy(cg[1].name,argv[fa],MAXNAMEL); cg[1].name[MAXNAMEL] = '\000'; - /* Create VRML name */ + /* Create VRML/X3D base name */ { char *xl; strcpy(out_name, cg[1].name); if ((xl = strrchr(out_name, '.')) == NULL) /* Figure where extention is */ xl = out_name + strlen(out_name); - strcpy(xl,".wrl"); + xl[0] = '\000'; /* Remove extension */ } if (fwacomp && spec == 0) @@ -396,11 +437,14 @@ int main(int argc, char *argv[]) int sidx; /* Sample ID index */ int sldx = -1; /* Sample location index, < 0 if invalid */ int xix, yix, zix; + int rgbix[3]; /* RGB field indexes (if rgb ) */ /* Open CIE target values */ cgf = new_cgats(); /* Create a CGATS structure */ cgf->add_other(cgf, ""); /* Allow any signature file */ + DBG(("Opening file '%s'\n",cg[n].name)) + if (cgf->read_name(cgf, cg[n].name)) error("CGATS file '%s' read error : %s",cg[n].name,cgf->err); @@ -438,34 +482,50 @@ int main(int argc, char *argv[]) cg[n].isdnormed = 0; cg[n].w[0] = cg[n].w[1] = cg[n].w[2] = 0.0; - if ((ti = cgf->find_kword(cgf, 0, "DEVICE_CLASS")) < 0) - error ("Input file '%s' doesn't contain keyword DEVICE_CLASS",cg[n].name); - - if (strcmp(cgf->t[0].kdata[ti],"DISPLAY") == 0) { - cg[n].isdisp = 1; - cg[n].isdnormed = 1; /* Assume display type is normalised to 100 */ - illum = icxIT_none; /* Displays are assumed to be self luminous */ - /* ?? What if two files are different ?? */ - } - - if (cg[n].isdisp) { + if ((ti = cgf->find_kword(cgf, 0, "DEVICE_CLASS")) < 0) { + warning("Input file '%s' doesn't contain keyword DEVICE_CLASS",cg[n].name); - if ((ti = cgf->find_kword(cgf, 0, "LUMINANCE_XYZ_CDM2")) >= 0) { - if (sscanf(cgf->t[0].kdata[ti], " %lf %lf %lf ",&cg[n].w[0], &cg[n].w[1], &cg[n].w[2]) != 3) - cg[n].w[0] = cg[n].w[1] = cg[n].w[2] = 0.0; + } else { + if (strcmp(cgf->t[0].kdata[ti],"DISPLAY") == 0) { + cg[n].isdisp = 1; + cg[n].isdnormed = 1; /* Assume display type is normalised to 100 */ + illum = icxIT_none; /* Displays are assumed to be self luminous */ + /* ?? What if two files are different ?? */ } - - /* See if there is an explicit tag indicating data has been normalised to Y = 100 */ - if ((ti = cgf->find_kword(cgf, 0, "NORMALIZED_TO_Y_100")) >= 0) { - if (strcmp(cgf->t[0].kdata[ti],"NO") == 0) { - cg[n].isdnormed = 0; - } else { - cg[n].isdnormed = 1; + + if (cg[n].isdisp) { + + if ((ti = cgf->find_kword(cgf, 0, "LUMINANCE_XYZ_CDM2")) >= 0) { + if (sscanf(cgf->t[0].kdata[ti], " %lf %lf %lf ",&cg[n].w[0], &cg[n].w[1], &cg[n].w[2]) != 3) + cg[n].w[0] = cg[n].w[1] = cg[n].w[2] = 0.0; + } + + /* See if there is an explicit tag indicating data has been normalised to Y = 100 */ + if ((ti = cgf->find_kword(cgf, 0, "NORMALIZED_TO_Y_100")) >= 0) { + if (strcmp(cgf->t[0].kdata[ti],"NO") == 0) { + cg[n].isdnormed = 0; + } else { + cg[n].isdnormed = 1; + } } } } } + /* See if it has RGB device space (for -d option) */ + if ((rgbix[0] = cgf->find_field(cgf, 0, "RGB_R")) >= 0 + && cgf->t[0].ftype[rgbix[0]] == r_t + + && (rgbix[1] = cgf->find_field(cgf, 0, "RGB_G")) >= 0 + && cgf->t[0].ftype[rgbix[1]] == r_t + + && (rgbix[2] = cgf->find_field(cgf, 0, "RGB_B")) >= 0 + && cgf->t[0].ftype[rgbix[2]] == r_t) { + cg[n].isrgb = 1; + } else { + cg[n].isrgb = 0; + } + /* Read all the target patches */ if (cg[n].npat <= 0) error("No sets of data in file '%s'",cg[n].name); @@ -535,14 +595,14 @@ int main(int argc, char *argv[]) cg[n].pat[i].xyz[1] = *((double *)cgf->t[0].fdata[i][yix]); cg[n].pat[i].xyz[2] = *((double *)cgf->t[0].fdata[i][zix]); - if (isLab) { /* Convert to XYZ */ + if (isLab) { /* Convert Lab to XYZ */ icmLab2XYZ(&icmD50, cg[n].pat[i].xyz, cg[n].pat[i].xyz); } //printf("~1 file %d patch %d = XYZ %f %f %f\n", n,i,cg[n].pat[i].xyz[0],cg[n].pat[i].xyz[1],cg[n].pat[i].xyz[2]); /* restore normalised display values to absolute */ if (cg[n].isdnormed) { - if (cg[n].w[1] > 0.0) { + if (cg[n].w[1] > 0.0) { // Found absoluute display white tag cg[n].pat[i].xyz[0] *= cg[n].w[1]/100.0; cg[n].pat[i].xyz[1] *= cg[n].w[1]/100.0; cg[n].pat[i].xyz[2] *= cg[n].w[1]/100.0; @@ -560,6 +620,16 @@ int main(int argc, char *argv[]) if (n == 1 && cmx != NULL) { cmx->xform(cmx, cg[n].pat[i].xyz, cg[n].pat[i].xyz); } + + if ((dovrml == 3 || dovrml == 4) && cg[n].isrgb) { + cg[n].pat[i].rgb[0] = 0.01 * *((double *)cgf->t[0].fdata[i][rgbix[0]]); + cg[n].pat[i].rgb[1] = 0.01 * *((double *)cgf->t[0].fdata[i][rgbix[1]]); + cg[n].pat[i].rgb[2] = 0.01 * *((double *)cgf->t[0].fdata[i][rgbix[2]]); + + if (dovrml == 4) { + icmRec709_RGBd_2_YPbPr(cg[n].pat[i].ycc, cg[n].pat[i].rgb); + } + } } } else { /* Using spectral data */ @@ -677,7 +747,7 @@ int main(int argc, char *argv[]) /* restore normalised display values to absolute */ if (cg[n].isdnormed) { - if (cg[n].w[1] > 0.0) { + if (cg[n].w[1] > 0.0) { // Found absoluute display white tag cg[n].pat[i].xyz[0] *= cg[n].w[1]; cg[n].pat[i].xyz[1] *= cg[n].w[1]; cg[n].pat[i].xyz[2] *= cg[n].w[1]; @@ -697,10 +767,11 @@ int main(int argc, char *argv[]) /* Locate the patch with maximum Y, a possible white patch */ - if (norm) { + /* in case we need it latter. */ + { int ii; - if (cg[n].w[1] == 0.0) { /* No white patch */ + if (cg[n].w[1] == 0.0) { /* No display white patch tag */ /* Locate patch with biggest Y, assume it is white... */ for (i = 0; i < cg[n].npat; i++) { @@ -709,15 +780,25 @@ int main(int argc, char *argv[]) ii = i; } } - if (verb) printf("File %d Chose patch %d as white, xyz %f %f %f\n", + if (verb) printf("File %d Chose patch %d as white, XYZ %f %f %f\n", n, ii+1,cg[n].w[0],cg[n].w[1],cg[n].w[2]); } else { - if (verb) printf("File %d White is from display luminance ref. xyz %f %f %f\n", + if (verb) printf("File %d White is from display luminance ref. XYZ %f %f %f\n", n, cg[n].w[0],cg[n].w[1],cg[n].w[2]); } icmCpy3(cg[n].nw, cg[n].w); } + cgf->del(cgf); /* Clean up */ + } /* Next file */ + if (norm == 4) { /* Normalise to average of white XYZ of the two files */ + icmBlend3(cg[0].w, cg[0].w, cg[1].w, 0.5); + icmCpy3(cg[1].w, cg[0].w); +// if (verb) printf("Average White XYZ %f %f %f\n",cg[0].w[0],cg[0].w[1],cg[0].w[2]); + } + + /* For both files */ + for (n = 0; n < 2; n++) { /* Normalise this file to white = 1.0 or D50 */ if (norm) { @@ -725,7 +806,9 @@ int main(int argc, char *argv[]) double chmat[3][3]; /* Chromatic adapation matrix */ - if (norm == 2) { /* Norm to white XYZ */ + DBG(("Normalizng '%s' to white\n",cg[n].name)) + + if (norm == 2 || norm == 4) { /* Norm to white XYZ */ icmXYZNumber s_wp; icmAry2XYZ(s_wp, cg[n].w); icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, s_wp, chmat); @@ -736,7 +819,7 @@ int main(int argc, char *argv[]) cg[n].pat[i].xyz[0] *= 100.0 / cg[n].w[1]; cg[n].pat[i].xyz[1] *= 100.0 / cg[n].w[1]; cg[n].pat[i].xyz[2] *= 100.0 / cg[n].w[1]; - } else if (norm == 2) { + } else if (norm == 2 || norm == 4) { icmMulBy3x3(cg[n].pat[i].xyz, chmat, cg[n].pat[i].xyz); } else { cg[n].pat[i].xyz[0] *= 100.0 / (cg[n].w[0] + cg[n].w[1] + cg[n].w[2]); @@ -750,7 +833,7 @@ int main(int argc, char *argv[]) cg[n].nw[0] *= 100.0 / cg[n].w[1]; cg[n].nw[1] *= 100.0 / cg[n].w[1]; cg[n].nw[2] *= 100.0 / cg[n].w[1]; - } else if (norm == 2) { + } else if (norm == 2 || norm == 4) { icmMulBy3x3(cg[n].nw, chmat, cg[n].w); } else { cg[n].nw[0] *= 100.0 / (cg[n].w[0] + cg[n].w[1] + cg[n].w[2]); @@ -759,8 +842,8 @@ int main(int argc, char *argv[]) } //printf("~1 file %d norm white XYZ %f %f %f\n", n,cg[n].nw[0], cg[n].nw[1], cg[n].nw[2]); } - cgf->del(cgf); /* Clean up */ - } + } /* Next file */ + if (cmx != NULL) cmx->del(cmx); cmx = NULL; @@ -791,12 +874,24 @@ int main(int argc, char *argv[]) icmXYZNumber s_wp; int rv; + DBG(("Figuring out of gamut patches\n")) + /* Convert sample PCS to relative */ - icmAry2XYZ(s_wp, cg[0].nw); +//printf(" cg[0].w %f %f %f\n", cg[0].w[0], cg[0].w[1], cg[0].w[2]); + icmAry2XYZ(s_wp, cg[0].w); + s_wp.X /= s_wp.Y; // Normalise the white to 1.0 + s_wp.Y /= s_wp.Y; // so that matrix doesn't change magnitude + s_wp.Z /= s_wp.Y; +//printf(" s_wp %f %f %f\n", s_wp.X, s_wp.Y, s_wp.Z); icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, s_wp, chmat); +//printf("~1 matrix = \n"); +//printf(" %f %f %f\n", chmat[0][0], chmat[0][1], chmat[0][2]); +//printf(" %f %f %f\n", chmat[1][0], chmat[1][1], chmat[1][2]); +//printf(" %f %f %f\n", chmat[2][0], chmat[2][1], chmat[2][2]); for (i = 0; i < cg[0].npat; i++) { icmMulBy3x3(in, chmat, cg[0].pat[i].xyz); + //printf("~1 %d: xyz %f %f %f, rel %f %f %f\n", i+1, cg[0].pat[i].xyz[0], cg[0].pat[i].xyz[1], cg[0].pat[i].xyz[2], in[0], in[1], in[2]); if ((rv = luo->inv_lookup(luo, out, in)) > 0 || 1) { @@ -816,7 +911,13 @@ int main(int argc, char *argv[]) } } if (verb) - fprintf(verbo,"No of test patches in gamut = %d/%d\n",cg[0].npat - cg[0].nig,cg[0].npat); + fprintf(verbo,"No of test patches in gamut = %d/%d\n",cg[0].nig,cg[0].npat); + } + + if (cg[0].nig <= 0) { + if (verb) + fprintf(verbo,"No test patches in gamut - givig up\n"); + return 0; } /* Adjust the Lab reference white to be the mean of the white of the two files */ @@ -829,6 +930,8 @@ int main(int argc, char *argv[]) printf("L*a*b* white reference = XYZ %f %f %f\n",labw.X,labw.Y,labw.Z); } + /* labw defaults to D50 */ + /* Convert XYZ to Lab */ for (n = 0; n < 2; n++) { for (i = 0; i < cg[n].npat; i++) { @@ -837,11 +940,9 @@ int main(int argc, char *argv[]) } /* Compute the delta E's */ + DBG(("Computing the delta E's\n")) for (i = 0; i < cg[0].npat; i++) { - if (cg[0].pat[i].og) /* Skip out of gamut patches */ - continue; - cg[0].pat[i].ixde[0] = fabs(cg[0].pat[i].xyz[0] - cg[1].pat[match[i]].xyz[0]); cg[0].pat[i].ixde[1] = fabs(cg[0].pat[i].xyz[1] - cg[1].pat[match[i]].xyz[1]); cg[0].pat[i].ixde[2] = fabs(cg[0].pat[i].xyz[2] - cg[1].pat[match[i]].xyz[2]); @@ -869,6 +970,111 @@ int main(int argc, char *argv[]) #undef HEAP_COMPARE /* - - - - - - - - - - */ + /* Plot a dE histogram */ + if (dohisto) { + double demax = -1e6, demin = 1e6; + int maxbins = 50; /* Maximum bins */ + int minbins = 20; /* Target minimum bins (depends on distribution) */ + int mincount = 10; /* Minimum number of points in a bin */ + double mbwidth; + int nbins = 0; + hbin *bins = NULL; + pval **stpat; /* Pointers to sorted cg[0].pat[] */ + double tval; + double *x, *y; + + DBG(("Plotting histogram\n")) + + /* Figure out the range of dE's */ + for (i = 0; i < cg[0].npat; i++) { + double de = cg[0].pat[i].de; + + if (de > demax) + demax = de; + if (de < demin) + demin = de; + } + + if (demax < 1e-6) + error("histogram: dE range is too small to plot"); + + /* Bin width that gives maxbins */ + mbwidth = demax / maxbins; + + /* Reduce mincount if needed to get minbins */ + if (cg[0].npat/minbins < mincount) + mincount = cg[0].npat/minbins; + + if ((bins = (hbin *)calloc(maxbins, sizeof(hbin))) == NULL) + error("malloc of histogram bins failed"); + + if ((stpat = (pval **)malloc(sizeof(pval *) * cg[0].npat)) == NULL) + error("Malloc failed - stpat[]"); + + for (i = 0; i < cg[0].npat; i++) + stpat[i] = &cg[0].pat[i]; + + /* Sort the dE's */ +#define HEAP_COMPARE(A,B) (A->de < B->de) + HEAPSORT(pval *, stpat, cg[0].npat); +#undef HEAP_COMPARE + + /* Create bins and add points */ + bins[0].min = 0.0; + for (nbins = i = 0; i < cg[0].npat && nbins < maxbins; i++) { + double de = stpat[i]->de; + + /* Move on to next bin ? */ + if (bins[nbins].count >= mincount + && (de - bins[nbins].min) >= mbwidth) { + if (i > 0) + bins[nbins].max = 0.5 * (de + stpat[i-1]->de); + else + bins[nbins].max = de; + nbins++; + bins[nbins].min = bins[nbins-1].max; + } + bins[nbins].count++; + bins[nbins].max = de; + } + if (bins[nbins].count != 0) + nbins++; + + /* Compute value */ + tval = 0.0; + for (i = 0; i < nbins; i++) { + bins[i].val = bins[i].count/(bins[i].max - bins[i].min); + tval += bins[i].val; + } + + tval /= 100.0; /* Make it % */ + for (i = 0; i < nbins; i++) { + bins[i].val /= tval; + if (verb) fprintf(verbo,"Bin %d, %f - %f, % 2.4f%%, count %d\n", + i,bins[i].min,bins[i].max,bins[i].val,bins[i].count); + } + + /* Plot it */ + if ((x = (double *)calloc(nbins+1, sizeof(double))) == NULL) + error("malloc of histogram x array"); + if ((y = (double *)calloc(nbins+1, sizeof(double))) == NULL) + error("malloc of histogram y array"); + + for (i = 0; i < nbins; i++) { + x[i] = 0.5 * (bins[i].min + bins[i].max); + y[i] = bins[i].val; + } + x[i] = demax; + y[i] = 0.0; + do_plot(x, y, NULL, NULL, nbins+1); + + free(y); + free(x); + free(bins); + free(stpat); + } + + /* - - - - - - - - - - */ /* Figure out the report */ { double merr = 0.0, aerr = 0.0; @@ -879,13 +1085,60 @@ int main(int argc, char *argv[]) double rad; double aierr[3] = { 0.0, 0.0, 0.0 }; double aixerr[3] = { 0.0, 0.0, 0.0 }; + double red[3] = { 1.0, 0.2, 0.2 }; + double green[3] = { 0.2, 1.0, 0.2 }; + double min[3], max[3]; + double col[3]; if (dovrml) { - wrl = new_vrml(out_name, doaxes, 0); + double vol; + int k; + + wrl = new_vrml(out_name, doaxes, (dovrml == 3 || dovrml == 4) ? vrml_rgb : vrml_lab); wrl->start_line_set(wrl, 0); - /* Fudge sphere diameter */ - rad = 10.0/pow(cg[0].npat, 1.0/3.0); + for (j = 0; j < 3; j++) { + min[j] = 1e6; + max[j] = -1e6; + } + + /* Get bounding box */ + for (i = 0; i < cg[0].npat; i++) { + for (k = 0; k < 2; k++) { + for (j = 0; j < 3; j++) { + if (dovrml == 3 || dovrml == 4) { /* RGB or YCC device plot */ + if (cg[k].pat[i].rgb[j] > max[j]) + max[j] = cg[k].pat[i].rgb[j]; + if (cg[k].pat[i].rgb[j] < min[j]) + min[j] = cg[k].pat[i].rgb[j]; + } else { + if (cg[k].pat[i].v[j] > max[j]) + max[j] = cg[k].pat[i].v[j]; + if (cg[k].pat[i].v[j] < min[j]) + min[j] = cg[k].pat[i].v[j]; + } + } + } + } + + for (vol = 1.0, j = 0; j < 3; j++) { +//printf("~1 size[%d] = %f\n",j, max[j] - min[j]); + vol *= (max[j] - min[j]); + } + vol = sqrt(vol); +//printf("~1 vol = %f\n",vol); + rad = 0.02 * vol/pow(cg[0].npat, 1.0/3.0); +//printf("~1 rad = %f\n",rad); + + if (dovrml == 3) // Hack + rad = 0.02; + else if (dovrml == 4) // Hack + rad = 0.015; + } + + if (dovrml && (dovrml == 3 || dovrml == 4)) { /* RGB/YCC device plot */ + if (!cg[0].isrgb || !cg[1].isrgb) + error("Both files must have RGB devices space for -d option"); } /* Do overall results */ @@ -932,13 +1185,45 @@ int main(int argc, char *argv[]) merr = de; if (dovrml) { - if (de > 1e-6) { - wrl->add_vertex(wrl, 0, cg[0].pat[j].v); - wrl->add_vertex(wrl, 0, cg[1].pat[j].v); - } - if (dovrml == 2) { - wrl->add_marker(wrl, cg[0].pat[j].v, NULL, rad); - wrl->add_marker(wrl, cg[1].pat[j].v, NULL, rad); + if ((dovrml == 3 || dovrml == 4)) { /* RGB/YCC device plot */ + double *val1, *val2; + int k; + + if (dovrml == 3) { + val1 = cg[0].pat[i].rgb; + val2 = cg[1].pat[match[i]].rgb; + } else { + val1 = cg[0].pat[i].ycc; + val2 = cg[1].pat[match[i]].ycc; + } + + de = icmNorm33(val1, val2); + + if (de > 1e-6) { + wrl->add_vertex(wrl, 0, val1); + wrl->add_vertex(wrl, 0, val2); + } + +#ifdef NEVER // Green target + wrl->add_marker(wrl, val1, green, rad); + +#else // Natural color + for (k = 0; k < 3; k++) + col[k] = 0.3 + 0.7 * (cg[0].pat[i].rgb[k] - min[k])/(max[k] - min[k]); + wrl->add_marker(wrl, val1, col, rad); +#endif + + wrl->add_marker_trans(wrl, val2, red, 0.3, rad * 0.99); + + } else { /* PCS */ + if (de > 1e-6) { + wrl->add_vertex(wrl, 0, cg[0].pat[i].v); + wrl->add_vertex(wrl, 0, cg[1].pat[match[i]].v); + } + if (dovrml == 2) { + wrl->add_marker(wrl, cg[0].pat[i].v, green, rad); + wrl->add_marker(wrl, cg[1].pat[match[i]].v, red, rad); + } } } @@ -997,6 +1282,18 @@ int main(int argc, char *argv[]) fprintf(verbo,"No of test patches in best 90%% are = %d\n",n90); } printf("Verify results:\n"); + if (norm == 4) + printf(" L*a*b* ref. = average XYZ %f %f %f\n",cg[0].w[0],cg[0].w[1],cg[0].w[2]); + else if (norm == 1) { + printf(" File 1 L* ref. Y %f\n", cg[0].w[1]); + printf(" File 2 L* ref. Y %f\n", cg[1].w[1]); + } else if (norm == 2) { + printf(" File 1 L*a*b* ref. XYZ %f %f %f\n", cg[0].w[0],cg[0].w[1],cg[0].w[2]); + printf(" File 2 L*a*b* ref. XYZ %f %f %f\n", cg[1].w[0],cg[1].w[1],cg[1].w[2]); + } else if (norm == 3) { + printf(" File 1 L* ref. X+Y+Z %f %f %f\n", cg[0].w[0],cg[0].w[1],cg[0].w[2]); + printf(" File 2 L* ref. X+Y+Z %f %f %f\n", cg[1].w[0],cg[1].w[1],cg[1].w[2]); + } printf(" Total errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr, aerr); printf(" Worst 10%% errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr10, aerr10); printf(" Best 90%% errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr90, aerr90); |