Files
argyllcms/xicc/cam02test.c
T
2026-08-20 20:28:40 +01:00

1365 lines
39 KiB
C

/*
* International Color Consortium color transform expanded support
*
* Author: Graeme W. Gill
* Date: 18/1/2004
* Version: 1.00
*
* Copyright 2000-2011 Graeme W. Gill
* All rights reserved.
* This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
* see the License.txt file for licencing details.
*
*/
/*
* This is some test code to test the CIECAM02 functionality.
* This isn't very useful when cam02.c has undef ENABLE_DECOMPR.
* The
*/
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#include "icc.h"
#include "xcam.h"
#include "cam02.h"
#include "numlib.h"
#include "cam02ref.h"
/* ** = usual tests */
#undef DIAG /* Print internal value diagnostics for each spot test conversion */
/* and print diagnostics for excessive errors, nans etc. */
#undef VERBOSE /* Print diagnostic values for every conversion */
#undef SPOTTEST /* ** Test known spot colors */
#undef TROUBLE /* Test trouble spot colors XYZ -> Jab -> XYZ */
#undef TROUBLE2 /* Test trouble spot colors Jab -> XYZ -> Jab */
#undef SPECIAL /* Special exploration code */
#undef LOCUSTEST /* [def] ** Test spectrum locus points */
#undef LOCUSRAND /* [def] ** Test random spectrum locus points */
#define INVTEST /* [def] ** -100 -> 100 XYZ cube to Jab to XYZ */
#undef INVTEST1 /* [undef] Single value */
#undef INVTEST2 /* [undef] Powell search for invers */
#define TESTINV /* [def] ** Jab cube to XYZ to Jab */
#undef TESTINV1 /* [undef] Single Jab value */
#undef TESTINV2 /* [undef] J = 0 test values */
//#define TRES 41 /* Grid resolution */
#define TRES 17 /* Grid resolution */
#define USE_HK 0 /* Use Helmholtz-Kohlraush in testing */
#undef EXIT_ON_ERROR /* and also trace */
//#define MAX_SPOT_ERR 0.05
//#define MAX_REF_ERR 0.1 /* Maximum permitted error to reference transform in delta Jab */
/* The blue fix throws this out */
#define MAX_SPOT_ERR 2.0
#define MAX_REF_ERR 3.7 /* Maximum permitted error to reference transform in delta Jab */
#ifndef _isnan
#define _isnan(x) ((x) != (x))
#define _finite(x) ((x) == 0.0 || (x) * 1.0000001 != (x))
#endif
#ifdef INVTEST1
static void
Lab2XYZ(double *out, double *in) {
double L = in[0], a = in[1], b = in[2];
double x,y,z,fx,fy,fz;
if (L > 8.0) {
fy = (L + 16.0)/116.0;
y = pow(fy,3.0);
} else {
y = L/903.2963058;
fy = 7.787036979 * y + 16.0/116.0;
}
fx = a/500.0 + fy;
if (fx > 24.0/116.0)
x = pow(fx,3.0);
else
x = (fx - 16.0/116.0)/7.787036979;
fz = fy - b/200.0;
if (fz > 24.0/116.0)
z = pow(fz,3.0);
else
z = (fz - 16.0/116.0)/7.787036979;
out[0] = x * 0.9642;
out[1] = y * 1.0000;
out[2] = z * 0.8249;
}
#endif /* INVTEST1 */
/* CIE XYZ to perceptual Lab */
static void
XYZ2Lab(double *out, double *in) {
double X = in[0], Y = in[1], Z = in[2];
double x,y,z,fx,fy,fz;
x = X/0.9642; /* D50 ? */
y = Y/1.0000;
z = Z/0.8249;
if (x > 0.008856451586)
fx = pow(x,1.0/3.0);
else
fx = 7.787036979 * x + 16.0/116.0;
if (y > 0.008856451586)
fy = pow(y,1.0/3.0);
else
fy = 7.787036979 * y + 16.0/116.0;
if (z > 0.008856451586)
fz = pow(z,1.0/3.0);
else
fz = 7.787036979 * z + 16.0/116.0;
out[0] = 116.0 * fy - 16.0;
out[1] = 500.0 * (fx - fy);
out[2] = 200.0 * (fy - fz);
}
/* Return maximum difference */
double maxdiff(double in1[3], double in2[3]) {
int i;
double tt, rv = 0.0;
/* Deal with the possibility that we have nan's */
for (i = 0; i < 3; i++) {
tt = fabs(in1[i] - in2[i]);
if (!_finite(tt))
return tt;
if (tt > rv)
rv = tt;
}
return rv;
}
/* Return absolute difference */
double absdiff(double in1[3], double in2[3]) {
double tt, rv = 0.0;
tt = in1[0] - in2[0];
rv += tt * tt;
tt = in1[1] - in2[1];
rv += tt * tt;
tt = in1[2] - in2[2];
rv += tt * tt;
return sqrt(rv);
}
/* Return maximum Lab difference of XYZ */
double maxxyzdiff(double i1[3], double i2[3]) {
int i;
double tt, rv = 0.0;
double in1[3], in2[3];
XYZ2Lab(in1, i1);
XYZ2Lab(in2, i2);
/* Deal with the possibility that we have nan's */
for (i = 0; i < 3; i++) {
tt = fabs(in1[i] - in2[i]);
if (!_finite(tt))
return tt;
if (tt > rv)
rv = tt;
}
return rv;
}
#ifdef INVTEST2
/* Powell callback function and struct */
typedef struct {
cam02 *cam;
double Jab[3];
} cntx;
static double opt1(void *fdata, double tp[]) {
cntx *x = (cntx *)fdata;
double Jab[3];
double tt, rv = 0.0;
x->cam->XYZ_to_cam(x->cam, Jab, tp);
tt = Jab[0] - x->Jab[0];
rv += tt * tt;
tt = Jab[1] - x->Jab[1];
rv += tt * tt;
tt = Jab[2] - x->Jab[2];
rv += tt * tt;
return rv;
}
#endif /* INVTEST2 */
/* 2 degree spectrum locus in xy coordinates */
/* nm, x, y, Y CMC */
double sl[65][4] = {
{ 380, 0.1741, 0.0050, 0.000039097450 },
{ 385, 0.1740, 0.0050, 0.000065464490 },
{ 390, 0.1738, 0.0049, 0.000121224052 },
{ 395, 0.1736, 0.0049, 0.000221434140 },
{ 400, 0.1733, 0.0048, 0.000395705080 },
{ 405, 0.1730, 0.0048, 0.000656030940 },
{ 410, 0.1726, 0.0048, 0.001222776600 },
{ 415, 0.1721, 0.0048, 0.002210898200 },
{ 420, 0.1714, 0.0051, 0.004069952000 },
{ 425, 0.1703, 0.0058, 0.007334133400 },
{ 430, 0.1689, 0.0069, 0.011637600000 },
{ 435, 0.1669, 0.0086, 0.016881322000 },
{ 440, 0.1644, 0.0109, 0.023015402000 },
{ 445, 0.1611, 0.0138, 0.029860866000 },
{ 450, 0.1566, 0.0177, 0.038072300000 },
{ 455, 0.1510, 0.0227, 0.048085078000 },
{ 460, 0.1440, 0.0297, 0.060063754000 },
{ 465, 0.1355, 0.0399, 0.074027114000 },
{ 470, 0.1241, 0.0578, 0.091168598000 },
{ 475, 0.1096, 0.0868, 0.112811680000 },
{ 480, 0.0913, 0.1327, 0.139122260000 },
{ 485, 0.0686, 0.2007, 0.169656160000 },
{ 490, 0.0454, 0.2950, 0.208513180000 },
{ 495, 0.0235, 0.4127, 0.259083420000 },
{ 500, 0.0082, 0.5384, 0.323943280000 },
{ 505, 0.0039, 0.6548, 0.407645120000 },
{ 510, 0.0139, 0.7502, 0.503483040000 },
{ 515, 0.0389, 0.8120, 0.608101540000 },
{ 520, 0.0743, 0.8338, 0.709073280000 },
{ 525, 0.1142, 0.8262, 0.792722560000 },
{ 530, 0.1547, 0.8059, 0.861314320000 },
{ 535, 0.1929, 0.7816, 0.914322820000 },
{ 540, 0.2296, 0.7543, 0.953482260000 },
{ 545, 0.2658, 0.7243, 0.979818740000 },
{ 550, 0.3016, 0.6923, 0.994576720000 },
{ 555, 0.3373, 0.6589, 0.999604300000 },
{ 560, 0.3731, 0.6245, 0.994513460000 },
{ 565, 0.4087, 0.5896, 0.978204680000 },
{ 570, 0.4441, 0.5547, 0.951588260000 },
{ 575, 0.4788, 0.5202, 0.915060800000 },
{ 580, 0.5125, 0.4866, 0.869647940000 },
{ 585, 0.5448, 0.4544, 0.816076000000 },
{ 590, 0.5752, 0.4242, 0.756904640000 },
{ 595, 0.6029, 0.3965, 0.694818180000 },
{ 600, 0.6270, 0.3725, 0.630997820000 },
{ 605, 0.6482, 0.3514, 0.566802360000 },
{ 610, 0.6658, 0.3340, 0.503096860000 },
{ 615, 0.6801, 0.3197, 0.441279360000 },
{ 620, 0.6915, 0.3083, 0.380961920000 },
{ 625, 0.7006, 0.2993, 0.321156580000 },
{ 630, 0.7079, 0.2920, 0.265374180000 },
{ 635, 0.7140, 0.2859, 0.217219520000 },
{ 640, 0.7190, 0.2809, 0.175199900000 },
{ 645, 0.7230, 0.2770, 0.138425720000 },
{ 650, 0.7260, 0.2740, 0.107242628000 },
{ 655, 0.7283, 0.2717, 0.081786794000 },
{ 660, 0.7300, 0.2700, 0.061166218000 },
{ 665, 0.7311, 0.2689, 0.044729418000 },
{ 670, 0.7320, 0.2680, 0.032160714000 },
{ 675, 0.7327, 0.2673, 0.023307860000 },
{ 680, 0.7334, 0.2666, 0.017028548000 },
{ 685, 0.7340, 0.2660, 0.011981432000 },
{ 690, 0.7344, 0.2656, 0.008259734600 },
{ 695, 0.7346, 0.2654, 0.005758363200 },
{ 700, 0.7347, 0.2653, 0.004117206200 }
};
int
main(void) {
int ok = 1;
#define NO_WHITES 9
double white[9][3] = {
{ 0.964242, 1.000000, 0.825124 }, /* 0: D50 */
{ 1.098494, 1.000000, 0.355908 }, /* 1: A */
{ 0.908731, 1.000000, 0.987233 }, /* 2: F5 */
{ 1.128981, 1.000000, 0.305862 }, /* 3: D25 */
{ 0.950471, 1.000000, 1.088828 }, /* 4: D65 */
{ 0.949662, 1.000000, 1.160438 }, /* 5: D80 */
{ 0.949662, 1.000000, 1.160438 }, /* 6: D80 */
{ 0.951297, 1.000000, 1.338196 }, /* 7: D85 */
{ 0.952480, 1.000000, 1.386693 } /* 8: D90 */
};
#define NO_LAS 6
double La[6] = { 10.0, 31.83, 100.0, 318.31, 1000.83, 3183.1 };
#define NO_VCS 4
ViewingCondition Vc[4] = {
vc_average,
vc_dark,
vc_dim,
vc_cut_sheet
};
#ifdef SPOTTEST
#define NO_SPOTS 5
double sp_white[6][3] = {
{ 0.9505, 1.000, 1.0888 },
{ 0.9505, 1.000, 1.0888 },
{ 1.0985, 1.000, 0.3558 },
{ 1.0985, 1.000, 0.3558 },
{ 0.9505, 1.000, 1.0888 },
{ 0.9642, 1.000, 0.8249 } /* D50 for inversion tests */
};
double sp_La[6] = { 318.31, 31.83, 318.31, 31.83, 318.31, 150.0 };
double sample[5][3] = {
{ 0.1901, 0.2000, 0.2178 },
{ 0.5706, 0.4306, 0.3196 },
{ 0.0353, 0.0656, 0.0214 },
{ 0.1901, 0.2000, 0.2178 },
{ 0.9505, 1.000, 1.0888 } /* Check white */
};
/* Reference values (NOT correct anymore, as HK params have changed!!!) */
#if USE_HK == 1
double correct[5][4] = { /* Hue range is last two */
{ 41.75, 0.10, 217.0, 219.0 },
{ 69.11, 48.60, 19.9, 19.91 },
{ 30.22, 46.94, 177.1, 177.2 },
{ 52.64, 53.07, 249.5, 249.6 },
{ 100.00, 0.14, 0.0, 360.0 }
};
#else
double correct[5][4] = { /* Hue range is last two */
{ 41.73, 0.10, 217.0, 219.0 },
{ 65.94, 48.60, 19.90, 19.91 },
{ 21.79, 46.94, 177.1, 177.2 },
{ 42.66, 53.07, 249.5, 249.6 },
{ 100.0, 0.14, 0.0, 360.0 } /* Check white */
};
#endif /* USE_HK */
// Original values
//#if USE_HK == 1
// double correct[5][4] = { /* Hue range is last two */
// { 41.75, 0.10, 217.0, 219.0 },
// { 69.13, 48.57, 19.56, 19.56 },
// { 30.22, 46.94, 177.1, 177.1 },
// { 52.31, 51.92, 248.9, 248.9 },
// { 100.00, 0.14, 0.0, 360.0 }
// };
#//else
// double correct[5][4] = { /* Hue range is last two */
// { 41.73, 0.10, 217.0, 219.0 },
// { 65.96, 48.57, 19.6, 19.6 },
// { 21.79, 46.94, 177.1, 177.1 },
// { 42.53, 51.92, 248.9, 248.9 },
// { 100.0, 0.14, 0.0, 360.0 } /* Check white */
// };
//#endif /* USE_HK */
#endif /* SPOTTEST */
#if defined(TROUBLE) || defined(TROUBLE2) || defined(SPECIAL)
#define NO_TROUBLE 1
double twhite[3][3] = {
{ 0.9642, 1.000, 0.8249 }, /* D50 */
{ 0.949662, 1.000000, 1.160438 }, /* 5: D80 */
{ 0.9642, 1.000, 0.8249 } /* D50 */
};
ViewingCondition tVc[3] = { vc_average, vc_average, vc_average };
double tLa[3] = { 10.0, 3183.1, 50.0 };
double tFlair[3] = { 0.00, 0.01, 0.01 };
double tsample[4][3] = {
{ -1.0, -1.0, -1.0 }, /* Inv Problem */
{ 34.485160, 0.982246, 164.621489 }, /* Inv Problem */
{ 0.031339, 0.000000, 0.824895 }, /* ProPhoto Blue - OK */
{ 0.041795, 0.006211, 0.652597 } /* ProPhoto nearly Blue - fails */
};
double tsample2[1][3] = {
{ 3.625000, -121.600000, -64.000000, } /* Inv Problem */
};
#endif /* TROUBLE || TROUBLE2 */
cam02ref *camr;
cam02 *cam;
int c, d, e;
cam = new_cam02();
camr = new_cam02ref();
camr->range = 1; /* Return on range error */
#ifdef VERBOSE
cam->trace = 1;
camr->trace = 1;
#endif
/* ================= Trouble colors ===================== */
#if defined(TROUBLE) || defined(TROUBLE2) || defined(SPECIAL)
for (c = 0; c < NO_TROUBLE; c++) {
#ifdef DIAG
printf("Case %d:\n",c);
#endif /* DIAG */
camr->set_view(
camr,
tVc[c], /* Enumerated Viewing Condition */
twhite[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
tLa[c], /* Adapting/Surround Luminance cd/m^2 */
0.20, /* Relative Luminance of Background to reference white */
0.0, /* Luminance of white in image - not used */
tFlair[c], /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.00, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
twhite[c], /* The Flare color coordinates (typically the Ambient color) */
USE_HK, /* use Helmholtz-Kohlraush flag */
1.0,
0.0,
NULL
);
cam->set_view(
cam,
tVc[c], /* Enumerated Viewing Condition */
twhite[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
tLa[c], /* Adapting/Surround Luminance cd/m^2 */
0.20, /* Relative Luminance of Background to reference white */
0.0, /* Luminance of white in image - not used */
tFlair[c], /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.00, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
twhite[c], /* The Flare color coordinates (typically the Ambient color) */
USE_HK, /* use Helmholtz-Kohlraush flag */
1.0,
0.0,
NULL
);
camr->nldlimit = cam->nldlimit;
camr->jlimit = cam->jlimit;
#ifdef DIAG
printf("\n");
#endif /* DIAG */
#ifdef SPECIAL
/* See what happens as we approach a neutral color */
{
double j1[3] = { 50, +0.1, +0.1 }, x1[3];
double j2[3] = { 0, +0.1, +0.1 }, x2[3];
double Jab[3], xyz[3];
double rr = 1.0;
int i;
/* Establish the XYZ */
cam->cam_to_XYZ(cam, x1, j1);
cam->cam_to_XYZ(cam, x2, j2);
cam->trace = 1;
/* Approach it by halves */
for (i = 0; i < 100; i++, rr *= 0.5) {
xyz[0] = rr * x1[0] + (1.0 - rr) * x2[0];
xyz[1] = rr * x1[1] + (1.0 - rr) * x2[1];
xyz[2] = rr * x1[2] + (1.0 - rr) * x2[2];
cam->XYZ_to_cam(cam, Jab, xyz);
printf("XYZ %f %f %f -> Jab is %f %f %f\n",
xyz[0], xyz[1], xyz[2],
Jab[0], Jab[1], Jab[2]);
}
exit(0);
}
#endif /* SPECIAL */
#ifdef TROUBLE
{
double Jab[3], jabr[3], xyz[3];
cam->XYZ_to_cam(cam, Jab, tsample[c]);
if (camr->XYZ_to_cam(camr, jabr, tsample[c])) {
#ifdef DIAG
printf("Reference XYZ2Jab returned error from XYZ %f %f %f\n",tsample[c][0],tsample[c][1],tsample[c][2]);
#endif /* DIAG */
} else if (maxdiff(Jab, jabr) > MAX_REF_ERR) {
printf("Spottest: Excessive error to reference for %f %f %f\n",tsample[c][0],tsample[c][1],tsample[c][2]);
printf("Spottest: Error %f, Got %f %f %f\n expected %f %f %f\n", maxdiff(Jab, jabr), Jab[0], Jab[1], Jab[2], jabr[0], jabr[1], jabr[2]);
ok = 0;
#ifdef EXIT_ON_ERROR
fflush(stdout);
exit(-1);
#endif /* EXIT_ON_ERROR */
}
#ifdef DIAG
printf("XYZ %f %f %f -> Jab is %f %f %f\n",
tsample[c][0], tsample[c][1], tsample[c][2],
Jab[0], Jab[1], Jab[2]);
#endif /* DIAG */
cam->cam_to_XYZ(cam, xyz, Jab);
#ifdef DIAG
printf("XYZ %f %f %f -> Jab is %f %f %f\n",
Jab[0], Jab[1], Jab[2],
xyz[0], xyz[1], xyz[2]);
#endif /* DIAG */
if (maxdiff(tsample[c], xyz) > 1e-5) {
printf("Spottest trouble 1: Excessive error in inversion %f\n",maxdiff(tsample[c], xyz));
printf("Is %f %f %f\n",xyz[0],xyz[1],xyz[2]);
printf("Should be %f %f %f\n",tsample[c][0],tsample[c][1],tsample[c][2]);
ok = 0;
#ifdef EXIT_ON_ERROR
fflush(stdout);
exit(-1);
#endif /* EXIT_ON_ERROR */
}
}
#endif /* TROUBLE */
#ifdef TROUBLE2
{
double Jab[3], xyz[3];
cam->cam_to_XYZ(cam, xyz, tsample2[c]);
#ifdef DIAG
printf("Lab %f %f %f -> XYZ is %f %f %f\n",
tsample2[c][0], tsample2[c][1], tsample2[c][2],
xyz[0], xyz[1], xyz[2]);
#endif /* DIAG */
cam->XYZ_to_cam(cam, Jab, xyz);
#ifdef DIAG
printf("XYZ %f %f %f -> Jab is %f %f %f\n",
xyz[0], xyz[1], xyz[2],
Jab[0], Jab[1], Jab[2]);
#endif /* DIAG */
if (maxdiff(tsample2[c], Jab) > 1e-3) {
printf("Spottest trouble2: Excessive error in inversion %f\n",maxdiff(tsample2[c], Jab));
printf("Is %f %f %f\n",Jab[0],Jab[1],Jab[2]);
printf("Should be %f %f %f\n",tsample2[c][0],tsample2[c][1],tsample2[c][2]);
ok = 0;
#ifdef EXIT_ON_ERROR
fflush(stdout);
exit(-1);
#endif /* EXIT_ON_ERROR */
}
}
#endif /* TROUBLE2 */
}
#endif /* TROUBLE || TROUBLE 2 */
/* =============================================== */
/* ================= SpotTest ===================== */
#ifdef SPOTTEST
{
double mrerr = 0.0, mxerr = 0.0;
for (c = 0; c < NO_SPOTS; c++) {
#ifdef DIAG
printf("Case %d:\n",c);
#endif /* DIAG */
camr->set_view(
camr,
vc_average, /* Enumerated Viewing Condition */
sp_white[c],/* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
sp_La[c], /* Adapting/Surround Luminance cd/m^2 */
0.20, /* Relative Luminance of Background to reference white */
0.0, /* Luminance of white in image - not used */
0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.00, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
sp_white[c],/* The Glare color coordinates (typically the Ambient color) */
USE_HK, /* use Helmholtz-Kohlraush flag */
1.0, /* Normal Helmholtz-Kohlraush scale */
0.0, /* No mid-tone hack */
NULL
);
cam->set_view(
cam,
vc_average, /* Enumerated Viewing Condition */
sp_white[c],/* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
sp_La[c], /* Adapting/Surround Luminance cd/m^2 */
0.20, /* Relative Luminance of Background to reference white */
0.0, /* Luminance of white in image - not used */
0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.00, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
sp_white[c],/* The Glare color coordinates (typically the Ambient color) */
USE_HK, /* use Helmholtz-Kohlraush flag */
1.0, /* Normal Helmholtz-Kohlraush scale */
0.0, /* No mid-tone hack */
NULL
);
camr->nldlimit = cam->nldlimit;
camr->jlimit = cam->jlimit;
#ifdef DIAG
printf("\n");
#endif /* DIAG */
{
double Jab[3], JCh[3], jabr[3], res[3], target[3];
double mde;
cam->XYZ_to_cam(cam, Jab, sample[c]);
if (camr->XYZ_to_cam(camr, jabr, sample[c]))
printf("Reference XYZ2Jab returned error\n");
else if ((mde = maxdiff(Jab, jabr)) > MAX_REF_ERR) {
printf("Spottest: Excessive error to reference for %f %f %f\n",sample[c][0],sample[c][1],sample[c][2]);
printf("Spottest: Error %f, Got %f %f %f\n expected %f %f %f\n",maxdiff(Jab, jabr),
Jab[0], Jab[1], Jab[2], jabr[0], jabr[1], jabr[2]);
ok = 0;
#ifdef EXIT_ON_ERROR
camr->trace = 1;
camr->XYZ_to_cam(camr, jabr, sample[c]);
camr->trace = 0;
cam->trace = 1;
cam->XYZ_to_cam(cam, Jab, sample[c]);
cam->trace = 0;
fflush(stdout);
fflush(stdout);
exit(-1);
#endif /* EXIT_ON_ERROR */
}
if (mde > mrerr)
mrerr = mde;
/* Convert to JCh for checking */
JCh[0] = Jab[0];
/* Compute hue angle */
JCh[2] = (180.0/3.14159265359) * atan2(Jab[2], Jab[1]);
JCh[2] = (JCh[2] < 0.0) ? JCh[2] + 360.0 : JCh[2];
/* Compute chroma value */
JCh[1] = sqrt(Jab[1] * Jab[1] + Jab[2] * Jab[2]);
target[0] = correct[c][0];
target[1] = correct[c][1];
if (JCh[2] >= correct[c][2] && JCh[2] <= correct[c][3]) {
target[2] = JCh[2];
} else {
if (fabs(JCh[2] - correct[c][2]) < fabs(JCh[2] - correct[c][3]))
target[2] = correct[c][2];
else
target[2] = correct[c][3];
}
if ((mde = maxdiff(JCh, target)) > MAX_SPOT_ERR) {
printf("Spottest: Excessive error for %f %f %f\n",sample[c][0],sample[c][1],sample[c][2]);
printf("Spottest: Excessive error in conversion to CAM %f\n",maxdiff(JCh, target));
printf("Jab is %f %f %f\nJch is %f %f %f\n",
Jab[0], Jab[1], Jab[2],
JCh[0], JCh[1], JCh[2]);
printf("JCh should be %f %f %f - %f\n",
correct[c][0], correct[c][1], correct[c][2], correct[c][3]);
ok = 0;
#ifdef EXIT_ON_ERROR
fflush(stdout);
exit(-1);
#endif /* EXIT_ON_ERROR */
}
if (mde > mxerr)
mxerr = mde;
cam->cam_to_XYZ(cam, res, Jab);
if (maxdiff(sample[c], res) > 1e-5) {
printf("Spottest: Excessive error in inversion %f\n",maxdiff(sample[c], res));
ok = 0;
#ifdef EXIT_ON_ERROR
cam->trace = 1;
cam->XYZ_to_cam(cam, Jab, sample[c]);
cam->cam_to_XYZ(cam, res, Jab);
cam->trace = 0;
fflush(stdout);
exit(-1);
#endif /* EXIT_ON_ERROR */
}
#ifdef DIAG
printf("Jab is %f %f %f\nJch is %f %f %f\n",
Jab[0], Jab[1], Jab[2],
JCh[0], JCh[1], JCh[2]);
printf("JCh should be %f %f %f - %f\n",
correct[c][0], correct[c][1], correct[c][2], correct[c][3]);
printf("XYZ is %f %f %f\n",res[0], res[1], res[2]);
printf("Inversion error = %f\n",maxdiff(sample[c], res));
printf("\n\n");
#endif /* DIAG */
}
}
if (ok == 0) {
printf("Spottest testing FAILED\n");
} else {
printf("Spottest testing OK\n");
printf("Spottest maximum DE to ref = %f, to expected = %f\n",mrerr,mxerr);
}
}
#endif /* SPOTTEST */
/* =============================================== */
/* ================= LocusTest ===================== */
#ifdef LOCUSTEST
#define LT_YRES 30
{
double mxlocde = -100.0; /* maximum locus test delta E */
for (c = 0; c < NO_WHITES; c++) {
printf("Locus: next white reference\n");
for (d = 0; d < NO_LAS; d++) {
for (e = 0; e < NO_VCS; e++) {
int i, j;
double Yxy[3], xyz[3], Jab[3], jabr[3], checkxyz[3];
double mxd; /* Maximum delta of Lab any component */
double ltde; /* Locus test delta E */
camr->set_view(
camr,
Vc[e], /* Enumerated Viewing Condition */
white[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) = D50 */
La[d], /* Adapting/Surround Luminance cd/m^2 */
0.20, /* Relative Luminance of Background to reference white */
0.0, /* Luminance of white in image - not used */
0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.00, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
white[c], /* The Glare color coordinates (typically the Ambient color) */
USE_HK, /* use Helmholtz-Kohlraush flag */
1.0, /* Normal Helmholtz-Kohlraush scale */
0.0, /* No mid-tone hack */
NULL
);
cam->set_view(
cam,
Vc[e], /* Enumerated Viewing Condition */
white[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) = D50 */
La[d], /* Adapting/Surround Luminance cd/m^2 */
0.20, /* Relative Luminance of Background to reference white */
0.0, /* Luminance of white in image - not used */
0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.00, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
white[c], /* The Glare color coordinates (typically the Ambient color) */
USE_HK, /* use Helmholtz-Kohlraush flag */
1.0, /* Normal Helmholtz-Kohlraush scale */
0.0, /* No mid-tone hack */
NULL
);
/* Make reference return error where it's going to disagree with implementation */
camr->nldlimit = cam->nldlimit;
camr->jlimit = cam->jlimit;
/* The monochromic boundary with a unit energy monochromic source */
for (j = 0; j < LT_YRES; j++) {
double Y = j/(LT_YRES - 1.0);
Y = Y * Y * 0.999 + 0.001;
for (i = 0; i < 65; i++) {
Yxy[0] = Y * sl[i][3];
Yxy[1] = sl[i][1];
Yxy[2] = sl[i][2];
icmYxy2XYZ(xyz, Yxy);
cam->XYZ_to_cam(cam, Jab, xyz);
if (camr->XYZ_to_cam(camr, jabr, xyz)) {
#ifdef DIAG
printf("Reference XYZ2Jab returned error from XYZ %f %f %f\n",xyz[0],xyz[1],xyz[2]);
#endif /* DIAG */
} else if (maxdiff(Jab, jabr) > MAX_REF_ERR) {
printf("Locustest1: Excessive error to reference for %f %f %f\n",xyz[0],xyz[1],xyz[2]);
printf("Locustest1: Error %f, Got %f %f %f\n expected %f %f %f\n",maxdiff(Jab, jabr),
Jab[0], Jab[1], Jab[2], jabr[0], jabr[1], jabr[2]);
ok = 0;
#ifdef EXIT_ON_ERROR
fflush(stdout);
exit(-1);
#endif /* EXIT_ON_ERROR */
}
cam->cam_to_XYZ(cam, checkxyz, Jab);
#ifdef DIAG
printf("Inversion error = %f\n",maxdiff(checkxyz, xyz));
#endif /* DIAG */
/* Check the result */
ltde = icmXYZLabDE(&icmD50, checkxyz, xyz);
if (ltde > mxlocde)
mxlocde = ltde;
mxd = maxxyzdiff(checkxyz, xyz);
if (mxd > 0.05) {
printf("XYZ %f %f %f\n ->",xyz[0],xyz[1],xyz[2]);
printf("Jab %f %f %f\n ->",Jab[0],Jab[1],Jab[2]);
printf("XYZ %f %f %f\n",checkxyz[0],checkxyz[1],checkxyz[2]);
printf("Locustest1: Excessive roundtrip error %f\n",mxd);
printf("c = %d, d = %d, e = %d\n",c,d,e);
ok = 0;
#ifdef EXIT_ON_ERROR
fflush(stdout);
exit(-1);
#endif /* EXIT_ON_ERROR */
}
}
/* Do the purple line */
for (i = 0; i < 20; i++) {
double b = i/(20 - 1.0);
Yxy[0] = (b * sl[0][3] + (1.0 - b) * sl[64][3]) * Y;
Yxy[1] = b * sl[0][1] + (1.0 - b) * sl[64][1];
Yxy[2] = b * sl[0][2] + (1.0 - b) * sl[64][2];
icmYxy2XYZ(xyz, Yxy);
cam->XYZ_to_cam(cam, Jab, xyz);
if (camr->XYZ_to_cam(camr, jabr, xyz)) {
#ifdef DIAG
printf("Reference XYZ2Jab returned error from XYZ %f %f %f\n",xyz[0],xyz[1],xyz[2]);
#endif /* DIAG */
} else if (maxdiff(Jab, jabr) > MAX_REF_ERR) {
printf("Locustest2: Excessive error to reference for %f %f %f\n",xyz[0],xyz[1],xyz[2]);
printf("Locustest2: Error %f, Got %f %f %f,\n expected %f %f %f\n",maxdiff(Jab, jabr),
Jab[0], Jab[1], Jab[2], jabr[0], jabr[1], jabr[2]);
ok = 0;
#ifdef EXIT_ON_ERROR
fflush(stdout);
exit(-1);
#endif /* EXIT_ON_ERROR */
}
cam->cam_to_XYZ(cam, checkxyz, Jab);
#ifdef DIAG
printf("Inversion error = %f\n",maxdiff(checkxyz, xyz));
#endif /* DIAG */
/* Check the result */
ltde = icmXYZLabDE(&icmD50, checkxyz, xyz);
if (ltde > mxlocde)
mxlocde = ltde;
mxd = maxxyzdiff(checkxyz, xyz);
if (mxd > 0.05) {
printf("XYZ %f %f %f\n ->",xyz[0],xyz[1],xyz[2]);
printf("Jab %f %f %f\n ->",Jab[0],Jab[1],Jab[2]);
printf("XYZ %f %f %f\n",checkxyz[0],checkxyz[1],checkxyz[2]);
printf("Locustest2: Excessive roundtrip error %f\n",mxd);
printf("c = %d, d = %d, e = %d\n",c,d,e);
ok = 0;
#ifdef EXIT_ON_ERROR
fflush(stdout);
exit(-1);
#endif /* EXIT_ON_ERROR */
}
}
}
#ifdef LOCUSRAND
for (i = 0; i < 20000 ; i++) {
// for (i = 0; i < 1000000 ; i++) {
int i1, i2, i3;
double Y, bb1, bb2, bb3;
i1 = i_rand(0, 64);
i2 = i_rand(0, 64);
i3 = i_rand(0, 64);
bb1 = d_rand(0.0, 1.0);
bb2 = d_rand(0.0, 1.0 - bb1);
bb3 = 1.0 - bb1 - bb2;
Y = d_rand(0.001, 1.0);
//printf("~1 i1 = %d, i2 = %d, i3 = %d\n",i1,i2,i3);
//printf("~1 bb1 = %f, bb2 = %f, bb3 = %f\n",bb1,bb2,bb3);
//printf("~1 Y = %f\n",Y);
Yxy[0] = bb1 * sl[i1][3] + bb2 * sl[i2][3] + bb3 * sl[i3][3];
Yxy[1] = bb1 * sl[i1][1] + bb2 * sl[i2][1] + bb3 * sl[i3][1];
Yxy[2] = bb1 * sl[i1][2] + bb2 * sl[i2][2] + bb3 * sl[i3][2];
Yxy[0] = Y; /* ??? */
icmYxy2XYZ(xyz, Yxy);
Yxy[0] = (bb1 * sl[i1][3] + bb2 * sl[i2][3] + bb3 * sl[i3][3]) * Y;
//printf("~1 xyz = %f %f %f\n", xyz[0], xyz[1], xyz[2]);
cam->XYZ_to_cam(cam, Jab, xyz);
if (camr->XYZ_to_cam(camr, jabr, xyz)) {
#ifdef DIAG
printf("Reference XYZ2Jab returned error from XYZ %f %f %f\n",xyz[0],xyz[1],xyz[2]);
#endif /* DIAG */
} else if (maxdiff(Jab, jabr) > MAX_REF_ERR) {
printf("Locustest3: Excessive error to reference for %f %f %f\n",xyz[0],xyz[1],xyz[2]);
printf("Locustest3: Error %f, Got %f %f %f, expected %f %f %f\n",maxdiff(Jab, jabr),
Jab[0], Jab[1], Jab[2], jabr[0], jabr[1], jabr[2]);
printf("c = %d, d = %d, e = %d\n",c,d,e);
ok = 0;
#ifdef EXIT_ON_ERROR
fflush(stdout);
exit(-1);
#endif /* EXIT_ON_ERROR */
}
cam->cam_to_XYZ(cam, checkxyz, Jab);
#ifdef DIAG
printf("Inversion error = %f\n",maxdiff(checkxyz, xyz));
#endif /* DIAG */
/* Check the result */
ltde = icmXYZLabDE(&icmD50, checkxyz, xyz);
if (ltde > mxlocde)
mxlocde = ltde;
mxd = maxxyzdiff(checkxyz, xyz);
if (mxd > 0.05) {
printf("XYZ %f %f %f\n ->",xyz[0],xyz[1],xyz[2]);
printf("Jab %f %f %f\n ->",Jab[0],Jab[1],Jab[2]);
printf("XYZ %f %f %f\n",checkxyz[0],checkxyz[1],checkxyz[2]);
printf("Locustest3: Excessive roundtrip error %f\n",mxd);
printf("c = %d, d = %d, e = %d\n",c,d,e);
ok = 0;
#ifdef EXIT_ON_ERROR
fflush(stdout);
exit(-1);
#endif /* EXIT_ON_ERROR */
}
}
#endif
} /* Viewing condition */
} /* Luninence */
} /* Whites */
if (ok == 0) {
printf("Locustest FAILED\n");
} else {
printf("Locustest OK, max DE = %e\n",mxlocde);
}
}
#endif /* LOCUSTEST */
/* =============================================== */
/* ================= XYZ->Jab->XYZ ================== */
#if defined(INVTEST) || defined(INVTEST1) || defined(INVTEST2)
{
/* Get the range of Jab values */
double xmin[3] = { 1e38, 1e38, 1e38 };
double xmax[3] = { -1e38, -1e38, -1e38 };
double jmin[3] = { 1e38, 1e38, 1e38 };
double jmax[3] = { -1e38, -1e38, -1e38 };
double merr = 0.0;
int ntests = 0;
for (c = 0; c < 6; c++) {
int co0, co1, co2; /* (using co[3] triggers compiler bug) */
double xyz[3], Lab[3], Jab[3], checkxyz[3];
double mxd;
cam->set_view(
cam,
vc_average, /* Enumerated Viewing Condition */
white[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) = D50 */
34.0, /* Adapting/Surround Luminance cd/m^2 */
0.20, /* Relative Luminance of Background to reference white */
0.0, /* Luminance of white in image - not used */
0.0, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.0, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
white[c], /* The Glare color coordinates (typically the Ambient color) */
USE_HK, /* use Helmholtz-Kohlraush flag */
1.0, /* Normal Helmholtz-Kohlraush scale */
0.0, /* No mid-tone hack */
NULL
);
#ifdef INVTEST1
/* Test case */
Lab[0] = 0.0; Lab[1] = -128.0; Lab[2] = 36.571429;
Lab2XYZ(xyz, Lab);
cam->XYZ_to_cam(cam, Jab, xyz);
cam->cam_to_XYZ(cam, checkxyz, Jab);
/* Check the result */
mxd = maxxyzdiff(checkxyz, xyz);
if (_finite(merr) && (!_finite(mxd) || mxd > merr))
merr = mxd;
#ifdef DIAG
#ifndef VERBOSE
if (!_finite(mxd) || mxd > 0.1)
#endif /* VERBOSE */
{
printf("\n");
printf("c = %d, #### Lab = %f %f %f\n",c, Lab[0], Lab[1], Lab[2]);
printf("%f %f %f -> %f %f %f -> %f %f %f [%f]\n",
xyz[0],xyz[1],xyz[2],Jab[0],Jab[1],Jab[2],
checkxyz[0],checkxyz[1],checkxyz[2],
maxxyzdiff(checkxyz, xyz));
#ifdef EXIT_ON_ERROR
if (!_finite(mxd) || mxd > 0.1) {
fflush(stdout);
exit(-1);
}
#endif /* EXIT_ON_ERROR */
}
#endif /* DIAG */
#endif /* INVTEST1 */
#ifdef INVTEST2
{
int rv;
cntx x;
double xyz[3], ss[3], Jab[3];
x.cam = cam;
x.Jab[0] = 0.0;
x.Jab[1] = -50.0;
x.Jab[2] = -50.0;
xyz[0] = -0.3;
xyz[1] = -0.3;
xyz[2] = -0.3;
ss[0] = 0.3;
ss[1] = 0.3;
ss[2] = 0.3;
rv = powell(NULL, 3, xyz, ss, 1e-12, 10000, opt1, (void *)&x);
if (rv)
printf("Powell failed\n");
else {
printf("XYZ %f %f %f\n",xyz[0], xyz[1], xyz[2]);
}
cam->cam_to_XYZ(cam, xyz, x.Jab);
printf("Inverted XYZ %f %f %f\n",xyz[0], xyz[1], xyz[2]);
cam->XYZ_to_cam(cam, Jab, xyz);
printf("Check Jab %f %f %f\n",Jab[0], Jab[1], Jab[2]);
c = 6;
}
#endif /* INVTEST2 */
#ifdef INVTEST
/* itterate through -20 to +120 XYZ cube space */
for (co0 = 0; co0 < TRES; co0++) {
xyz[0] = co0/(TRES-1.0);
xyz[0] = xyz[0] * 1.4 - 0.2;
for (co1 = 0; co1 < TRES; co1++) {
xyz[1] = co1/(TRES-1.0);
xyz[1] = xyz[1] * 1.4 - 0.2;
for (co2 = 0; co2 < TRES; co2++) {
int i;
xyz[2] = co2/(TRES-1.0);
xyz[2] = xyz[2] * 1.4 - 0.2;
for (i = 0; i < 3; i++) {
if (xyz[i] < xmin[i])
xmin[i] = xyz[i];
if (xyz[i] > xmax[i])
xmax[i] = xyz[i];
}
cam->XYZ_to_cam(cam, Jab, xyz);
for (i = 0; i < 3; i++) {
if (Jab[i] < jmin[i])
jmin[i] = Jab[i];
if (Jab[i] > jmax[i])
jmax[i] = Jab[i];
}
cam->cam_to_XYZ(cam, checkxyz, Jab);
ntests++;
/* Check the result */
mxd = maxxyzdiff(checkxyz, xyz);
if (_finite(merr) && (!_finite(mxd) || mxd > merr))
merr = mxd;
#if defined(DIAG) || defined(VERBOSE) || defined(EXIT_ON_ERROR)
#if defined(DIAG) || defined(EXIT_ON_ERROR)
if (!_finite(mxd) || mxd > 0.5) /* Delta E */
#endif /* DIAG || EXIT_ON_ERROR */
{
double oLab[3];
printf("\n");
printf("#### XYZ = %f %f %f -> %f %f %f\n",
xyz[0], xyz[1], xyz[2], checkxyz[0], checkxyz[1], checkxyz[2]);
printf("%f %f %f -> %f %f %f -> %f %f %f [%f]\n",
xyz[0],xyz[1],xyz[2],Jab[0],Jab[1],Jab[2],
checkxyz[0],checkxyz[1],checkxyz[2],
maxxyzdiff(checkxyz, xyz));
printf("c = %d\n",c);
#ifdef EXIT_ON_ERROR
if (!_finite(mxd) || mxd > 0.1) {
cam->trace = 1;
cam->XYZ_to_cam(cam, Jab, xyz);
cam->cam_to_XYZ(cam, checkxyz, Jab);
cam->trace = 0;
fflush(stdout);
exit(-1);
}
#endif /* EXIT_ON_ERROR */
}
#endif /* DIAG || VERBOSE || EXIT_ON_ERROR */
}
}
}
#endif /* INVTEST */
}
if (!_finite(merr) || merr > 3.7) {
printf("INVTEST: Excessive error in roundtrip check %f DE (max allowd 3.7)\n",merr);
ok = 0;
}
printf("\n");
printf("XYZ -> Jab -> XYZ\n");
printf("Inversion of %d points check complete, peak error = %e DE\n",ntests, merr);
printf("Range of XYZ values was:\n");
printf("X: %f -> %f\n", xmin[0], xmax[0]);
printf("Y: %f -> %f\n", xmin[1], xmax[1]);
printf("Z: %f -> %f\n", xmin[2], xmax[2]);
printf("Range of Jab values was:\n");
printf("J: %f -> %f\n", jmin[0], jmax[0]);
printf("a: %f -> %f\n", jmin[1], jmax[1]);
printf("b: %f -> %f\n", jmin[2], jmax[2]);
}
#endif /* INVTEST || INVTEST1 || INVTEST2 */
/* =============================================== */
/* ===================Jab->XYX->Jab ============================ */
/* Note that this is expected to fail if BLUECOMPR is enabled */
#if defined(TESTINV) || defined(TESTINV1) || defined(TESTINV2)
{
/* Get the range of XYZ values */
double xmin[3] = { 1e38, 1e38, 1e38 };
double xmax[3] = { -1e38, -1e38, -1e38 };
double jmin[3] = { 1e38, 1e38, 1e38 };
double jmax[3] = { -1e38, -1e38, -1e38 };
double merr = 0.0;
int ntests = 0;
for (c = 0; c < 6; c++) {
int i, j;
int co0, co1, co2; /* (using co[3] triggers compiler bug) */
double xyz[3], Jab[3], checkJab[3];
double mxd;
cam->set_view(
cam,
vc_average, /* Enumerated Viewing Condition */
white[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) = D50 */
34.0, /* Adapting/Surround Luminance cd/m^2 */
0.20, /* Relative Luminance of Background to reference white */
0.0, /* Luminance of white in image - not used */
0.0, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.0, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
white[c], /* The Glare color coordinates (typically the Ambient color) */
USE_HK, /* use Helmholtz-Kohlraush flag */
1.0, /* Normal Helmholtz-Kohlraush scale */
0.0, /* No mid-tone hack */
NULL
);
#ifdef TESTINV1
/* Double sample test case */
for (j = 0; j < 2; j++) {
if (j == 0) {
// Jab[0] = -2.5; Jab[1] = 128.0; Jab[2] = 128.0;
Jab[0] = 0.0; Jab[1] = -7.683075; Jab[2] = -7.683075;
} else {
// Jab[0] = -2.5; Jab[1] = -128.0; Jab[2] = -128.0;
Jab[0] = 0.0; Jab[1] = -128.0; Jab[2] = -128.0;
}
// Jab[0] = 21.25; Jab[1] = 0.0; Jab[2] = -64.0;
// Jab[0] = 1.05; Jab[1] = 0.0; Jab[2] = -64.0;
// Jab[0] = 0.0; Jab[1] = -128.0; Jab[2] = -128.0;
for (i = 0; i < 3; i++) {
if (Jab[i] < jmin[i])
jmin[i] = Jab[i];
if (Jab[i] > jmax[i])
jmax[i] = Jab[i];
}
cam->cam_to_XYZ(cam, xyz, Jab);
for (i = 0; i < 3; i++) {
if (xyz[i] < xmin[i])
xmin[i] = xyz[i];
if (xyz[i] > xmax[i])
xmax[i] = xyz[i];
}
cam->XYZ_to_cam(cam, checkJab, xyz);
/* Check the result */
mxd = maxdiff(checkJab, Jab);
if (_finite(merr) && (!_finite(mxd) || mxd > merr))
merr = mxd;
#ifdef DIAG
#ifndef VERBOSE
if (!_finite(mxd) || mxd > 0.1)
#endif /* VERBOSE */
{
printf("\n");
printf("#### Jab = %f %f %f\n",Jab[0], Jab[1], Jab[2]);
printf("%f %f %f -> %f %f %f -> %f %f %f [%f]\n",
Jab[0],Jab[1],Jab[2], xyz[0],xyz[1],xyz[2],
checkJab[0],checkJab[1],checkJab[2],
maxdiff(checkJab, Jab));
printf("c = %d\n",c);
#ifdef EXIT_ON_ERROR
if (!_finite(mxd) || mxd > 0.1) {
fflush(stdout);
exit(-1);
}
#endif /* EXIT_ON_ERROR */
}
#endif /* DIAG */
}
#endif /* TESTINV1 */
#ifdef TESTINV2
{ /* J = 0 test cases */
int i;
for (i = 1; i < 128; i++) {
Jab[0] = 0.0;
Jab[1] = (double)i/2;
Jab[2] = (double)i;
cam->cam_to_XYZ(cam, xyz, Jab);
Jab[0] = 0.0;
Jab[1] = (double)-i/2;
Jab[2] = (double)i;
cam->cam_to_XYZ(cam, xyz, Jab);
Jab[0] = 0.0;
Jab[1] = (double)i/2;
Jab[2] = (double)-i;
cam->cam_to_XYZ(cam, xyz, Jab);
Jab[0] = 0.0;
Jab[1] = (double)-i/2;
Jab[2] = (double)-i;
cam->cam_to_XYZ(cam, xyz, Jab);
Jab[0] = 0.0;
Jab[1] = (double)i;
Jab[2] = (double)i/2;
cam->cam_to_XYZ(cam, xyz, Jab);
Jab[0] = 0.0;
Jab[1] = (double)-i;
Jab[2] = (double)i/2;
cam->cam_to_XYZ(cam, xyz, Jab);
Jab[0] = 0.0;
Jab[1] = (double)i;
Jab[2] = (double)-i/2;
cam->cam_to_XYZ(cam, xyz, Jab);
Jab[0] = 0.0;
Jab[1] = (double)-i;
Jab[2] = (double)-i/2;
cam->cam_to_XYZ(cam, xyz, Jab);
}
}
#endif /* TESTINV2 */
#ifdef TESTINV
/* itterate through Jab space */
for (co0 = 0; co0 < TRES; co0++) {
Jab[0] = co0/(TRES-1.0);
Jab[0] = -50.0 + Jab[0] * 165.0;
for (co1 = 0; co1 < TRES; co1++) {
Jab[1] = co1/(TRES-1.0);
Jab[1] = (Jab[1] - 0.5) * 256.0;
for (co2 = 0; co2 < TRES; co2++) {
int i;
Jab[2] = co2/(TRES-1.0);
Jab[2] = (Jab[2] - 0.5) * 256.0;
for (i = 0; i < 3; i++) {
if (Jab[i] < jmin[i])
jmin[i] = Jab[i];
if (Jab[i] > jmax[i])
jmax[i] = Jab[i];
}
cam->cam_to_XYZ(cam, xyz, Jab);
for (i = 0; i < 3; i++) {
if (xyz[i] < xmin[i])
xmin[i] = xyz[i];
if (xyz[i] > xmax[i])
xmax[i] = xyz[i];
}
cam->XYZ_to_cam(cam, checkJab, xyz);
ntests++;
/* Check the result */
mxd = maxdiff(checkJab, Jab);
if (_finite(merr) && (!_finite(mxd) || mxd > merr))
merr = mxd;
#if defined(DIAG) || defined(VERBOSE) || defined(EXIT_ON_ERROR)
#if defined(DIAG) || defined(EXIT_ON_ERROR)
if (!_finite(mxd) || mxd > 0.1)
#endif /* DIAG || EXIT_ON_ERROR */
{
printf("\n");
printf("#### Jab = %f %f %f\n",Jab[0], Jab[1], Jab[2]);
printf("%f %f %f -> %f %f %f -> %f %f %f [%f]\n",
Jab[0],Jab[1],Jab[2], xyz[0],xyz[1],xyz[2],
checkJab[0],checkJab[1],checkJab[2],
maxdiff(checkJab, Jab));
printf("c = %d\n",c);
#ifdef EXIT_ON_ERROR
if (!_finite(mxd) || mxd > 0.1) {
cam->trace = 1;
cam->cam_to_XYZ(cam, xyz, Jab);
cam->XYZ_to_cam(cam, checkJab, xyz);
cam->trace = 0;
fflush(stdout);
exit(-1);
}
#endif /* EXIT_ON_ERROR */
}
#endif /* DIAG || VERBOSE || EXIT_ON_ERROR */
}
}
}
#endif /* TESTINV */
}
if (!_finite(merr) || merr > 3.7) {
printf("TESTINV: Excessive error in roundtrip check %f (max allowed 3.7)\n",merr);
ok = 0;
}
printf("\n");
printf("Jab -> XYX -> Jab\n");
printf("Inversion check 2 of %d points complete, peak error = %e DE Jab\n",ntests,merr);
printf("Range of Jab values was:\n");
printf("J: %f -> %f\n", jmin[0], jmax[0]);
printf("a: %f -> %f\n", jmin[1], jmax[1]);
printf("b: %f -> %f\n", jmin[2], jmax[2]);
printf("Range of XYZ values was:\n");
printf("X: %f -> %f\n", xmin[0], xmax[0]);
printf("Y: %f -> %f\n", xmin[1], xmax[1]);
printf("Z: %f -> %f\n", xmin[2], xmax[2]);
}
#endif /* TESTINV || TESTINV1 TESTINV2 */
/* =============================================== */
printf("\n");
if (ok == 0) {
printf("Cam testing FAILED\n");
} else {
printf("Cam testing OK\n");
}
cam->del(cam);
return 0;
}