321 lines
7.6 KiB
C
321 lines
7.6 KiB
C
|
|
/*
|
|
* International Color Consortium color transform expanded support
|
|
*
|
|
* Author: Graeme W. Gill
|
|
* Date: 2006/5/9
|
|
* Version: 1.00
|
|
*
|
|
* Copyright 2006 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 Daylight and Plankian spectra,
|
|
* Correlated and Visual Color Temperatures, and CRI.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <math.h>
|
|
#include "aconfig.h"
|
|
#include "cgats.h"
|
|
#include "xspect.h"
|
|
#include "numlib.h"
|
|
#include "plot.h"
|
|
#include "ui.h"
|
|
|
|
#define PLANKIAN
|
|
#define XRES 500
|
|
|
|
|
|
#ifdef PLANKIAN
|
|
#define BBTYPE icxIT_Ptemp
|
|
#else
|
|
#define BBTYPE icxIT_Dtemp
|
|
#endif
|
|
|
|
static int do_spec(char *name, xspect *sp) {
|
|
int i;
|
|
double xyz[3]; /* Color temperature */
|
|
double Yxy[3];
|
|
double xx[XRES];
|
|
double y1[XRES];
|
|
double cct, vct;
|
|
double cct_xyz[3], vct_xyz[3];
|
|
double cct_lab[3], vct_lab[3];
|
|
icmXYZNumber wp;
|
|
double de;
|
|
|
|
printf("\n");
|
|
|
|
/* Compute normalise XYZ of illuminant */
|
|
if (icx_ill_sp2XYZ(xyz, icxOT_CIE_1931_2, NULL, icxIT_custom, 0, sp, 0) != 0)
|
|
error ("icx_sp_temp2XYZ returned error");
|
|
|
|
icmXYZ2Yxy(Yxy, xyz);
|
|
|
|
printf("Type = %s\n",name);
|
|
printf("XYZ = %f %f %f, x,y = %f %f\n", xyz[0], xyz[1], xyz[2], Yxy[1], Yxy[2]);
|
|
|
|
/* Compute CCT */
|
|
if ((cct = icx_XYZ2ill_ct(cct_xyz, BBTYPE, icxOT_CIE_1931_2, NULL, xyz, NULL, 0)) < 0)
|
|
error ("Got bad cct\n");
|
|
|
|
/* Compute VCT */
|
|
if ((vct = icx_XYZ2ill_ct(vct_xyz, BBTYPE, icxOT_CIE_1931_2, NULL, xyz, NULL, 1)) < 0)
|
|
error ("Got bad vct\n");
|
|
|
|
#ifdef PLANKIAN
|
|
printf("CCT = %f, VCT = %f\n",cct, vct);
|
|
#else
|
|
printf("CDT = %f, VDT = %f\n",cct, vct);
|
|
#endif
|
|
|
|
{
|
|
int invalid = 0;
|
|
double RR[14];
|
|
double cri;
|
|
cri = icx_CIE1995_CRI(&invalid, RR, sp);
|
|
printf("CRI = %.1f [ R9 = %.1f ]%s\n",cri,RR[9],invalid ? " (Invalid)" : "");
|
|
}
|
|
|
|
/* Use modern color difference - gives a better visual match */
|
|
icmAry2XYZ(wp, vct_xyz);
|
|
icmXYZ2Lab(&wp, cct_lab, cct_xyz);
|
|
icmXYZ2Lab(&wp, vct_lab, vct_xyz);
|
|
de = icmCIE2K(cct_lab, vct_lab);
|
|
printf("CIEDE2000 Delta E = %f\n",de);
|
|
|
|
/* Plot spectrum out */
|
|
for (i = 0; i < XRES; i++) {
|
|
double ww;
|
|
|
|
ww = (sp->spec_wl_long - sp->spec_wl_short)
|
|
* ((double)i/(XRES-1.0)) + sp->spec_wl_short;
|
|
|
|
xx[i] = ww;
|
|
y1[i] = value_xspect(sp, ww);
|
|
}
|
|
do_plot(xx,y1,NULL,NULL,i);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void usage(void) {
|
|
fprintf(stderr,"Plot spectrum and calculate CCT and VCT\n");
|
|
fprintf(stderr,"Author: Graeme W. Gill\n");
|
|
fprintf(stderr,"usage: ccttest [infile.sp]\n");
|
|
fprintf(stderr," [infile.sp] spectrum to plot\n");
|
|
fprintf(stderr," default is all built in illuminants\n");
|
|
exit(1);
|
|
}
|
|
|
|
int
|
|
main(
|
|
int argc,
|
|
char *argv[]
|
|
) {
|
|
int fa,nfa; /* argument we're looking at */
|
|
int k;
|
|
int verb = 0;
|
|
static char in_name[MAXNAMEL+1] = { '\000' }; /* Spectrum name */
|
|
double temp;
|
|
xspect sp; /* Spectra */
|
|
icxIllumeType ilType;
|
|
char buf[200];
|
|
|
|
error_program = argv[0];
|
|
|
|
/* Process the arguments */
|
|
for(fa = 1;fa < argc;fa++) {
|
|
nfa = fa; /* skip to nfa if next argument is used */
|
|
if (argv[fa][0] == '-') { /* Look for any flags */
|
|
char *na = NULL; /* next argument after flag, null if none */
|
|
|
|
if (argv[fa][2] != '\000')
|
|
na = &argv[fa][2]; /* next is directly after flag */
|
|
else {
|
|
if ((fa+1) < argc) {
|
|
if (argv[fa+1][0] != '-') {
|
|
nfa = fa + 1;
|
|
na = argv[nfa]; /* next is seperate non-flag argument */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Verbosity */
|
|
if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
|
|
verb = 1;
|
|
} else {
|
|
usage();
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (fa < argc && argv[fa][0] != '-')
|
|
strncpy(in_name,argv[fa++],MAXNAMEL); in_name[MAXNAMEL] = '\000';
|
|
|
|
#ifndef NEVER /* hack test */
|
|
{
|
|
#define NTESTS 5
|
|
int i;
|
|
double cct, vct;
|
|
double de1, de2;
|
|
double xyz[NTESTS][3] = {
|
|
{ 92.250000, 97.750000, 89.650000 }, /* Rogers spotread verification result */
|
|
{ 94.197915, 97.686362, 80.560411, }, /* Rogers target */
|
|
{ 93.51, 97.12, 80.86 }, /* Rogers test ? */
|
|
{ 75.31, 78.20, 64.59 }, /* Mac LCD test */
|
|
{ 42.98, 44.62, 36.95 } /* Hitachie CRT test */
|
|
};
|
|
double axyz[3];
|
|
double lab[3], alab[3];
|
|
|
|
for (i = 0; i < NTESTS; i++) {
|
|
/* Compute CCT */
|
|
if ((cct = icx_XYZ2ill_ct(axyz, icxIT_Ptemp, icxOT_CIE_1931_2, NULL, xyz[i], NULL, 0)) < 0)
|
|
error ("Got bad cct\n");
|
|
|
|
axyz[0] /= axyz[1];
|
|
axyz[2] /= axyz[1];
|
|
axyz[1] /= axyz[1];
|
|
icmXYZ2Lab(&icmD50, alab, axyz);
|
|
axyz[0] = xyz[i][0] / xyz[i][1];
|
|
axyz[2] = xyz[i][2] / xyz[i][1];
|
|
axyz[1] = xyz[i][1] / xyz[i][1];
|
|
icmXYZ2Lab(&icmD50, lab, axyz);
|
|
de1 = icmCIE2K(lab, alab);
|
|
|
|
/* Compute VCT */
|
|
if ((vct = icx_XYZ2ill_ct(axyz, icxIT_Ptemp, icxOT_CIE_1931_2, NULL, xyz[i], NULL, 1)) < 0)
|
|
error ("Got bad vct\n");
|
|
axyz[0] /= axyz[1];
|
|
axyz[2] /= axyz[1];
|
|
axyz[1] /= axyz[1];
|
|
icmXYZ2Lab(&icmD50, alab, axyz);
|
|
axyz[0] = xyz[i][0] / xyz[i][1];
|
|
axyz[2] = xyz[i][2] / xyz[i][1];
|
|
axyz[1] = xyz[i][1] / xyz[i][1];
|
|
icmXYZ2Lab(&icmD50, lab, axyz);
|
|
de2 = icmCIE2K(lab, alab);
|
|
|
|
printf("XYZ %f %f %f, CCT = %f de %f, VCT = %f de %f\n",xyz[i][0], xyz[i][1], xyz[i][2], cct, de1, vct, de1);
|
|
|
|
/* Compute CCT */
|
|
if ((cct = icx_XYZ2ill_ct(axyz, icxIT_Dtemp, icxOT_CIE_1931_2, NULL, xyz[i], NULL, 0)) < 0)
|
|
error ("Got bad cct\n");
|
|
axyz[0] /= axyz[1];
|
|
axyz[2] /= axyz[1];
|
|
axyz[1] /= axyz[1];
|
|
icmXYZ2Lab(&icmD50, alab, axyz);
|
|
axyz[0] = xyz[i][0] / xyz[i][1];
|
|
axyz[2] = xyz[i][2] / xyz[i][1];
|
|
axyz[1] = xyz[i][1] / xyz[i][1];
|
|
icmXYZ2Lab(&icmD50, lab, axyz);
|
|
de1 = icmCIE2K(lab, alab);
|
|
|
|
/* Compute VCT */
|
|
if ((vct = icx_XYZ2ill_ct(axyz, icxIT_Dtemp, icxOT_CIE_1931_2, NULL, xyz[i], NULL, 1)) < 0)
|
|
error ("Got bad vct\n");
|
|
|
|
axyz[0] /= axyz[1];
|
|
axyz[2] /= axyz[1];
|
|
axyz[1] /= axyz[1];
|
|
icmXYZ2Lab(&icmD50, alab, axyz);
|
|
axyz[0] = xyz[i][0] / xyz[i][1];
|
|
axyz[2] = xyz[i][2] / xyz[i][1];
|
|
axyz[1] = xyz[i][1] / xyz[i][1];
|
|
icmXYZ2Lab(&icmD50, lab, axyz);
|
|
de2 = icmCIE2K(lab, alab);
|
|
|
|
printf("XYZ %f %f %f, CDT = %f de %f, VDT = %f de %f\n",xyz[i][0], xyz[i][1], xyz[i][2], cct, de1, vct, de2);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (in_name[0] != '\000') {
|
|
inst_meas_type mt;
|
|
|
|
if (read_xspect(&sp, &mt, NULL, in_name) != 0)
|
|
error ("Unable to read custom spectrum '%s'",in_name);
|
|
|
|
if (mt != inst_mrt_none
|
|
&& mt != inst_mrt_emission
|
|
&& mt != inst_mrt_ambient
|
|
&& mt != inst_mrt_emission_flash
|
|
&& mt != inst_mrt_ambient_flash)
|
|
error("Custom illuminant '%s' is wrong measurement type",in_name);
|
|
|
|
sprintf(buf, "File '%s'",in_name);
|
|
|
|
do_spec(buf, &sp);
|
|
|
|
} else {
|
|
|
|
/* For each standard illuminant */
|
|
for (ilType = icxIT_A; ilType <= icxIT_F10; ilType++) {
|
|
char *inm = NULL;
|
|
|
|
switch (ilType) {
|
|
case icxIT_A:
|
|
inm = "A"; break;
|
|
case icxIT_C:
|
|
inm = "C"; break;
|
|
case icxIT_D50:
|
|
inm = "D50"; break;
|
|
case icxIT_D50M2:
|
|
inm = "D50M2"; break;
|
|
case icxIT_D65:
|
|
inm = "D65"; break;
|
|
case icxIT_F5:
|
|
inm = "F5"; break;
|
|
case icxIT_F8:
|
|
inm = "F8"; break;
|
|
case icxIT_F10:
|
|
inm = "F10"; break;
|
|
default:
|
|
inm = "Unknown"; break;
|
|
break;
|
|
}
|
|
|
|
if (standardIlluminant(&sp, ilType, 0) != 0)
|
|
error ("standardIlluminant returned error");
|
|
|
|
do_spec(inm, &sp);
|
|
}
|
|
|
|
/* For each material and illuminant */
|
|
for (temp = 2500; temp <= 9000; temp += 500) {
|
|
|
|
for (k = 0; k < 2; k++) {
|
|
|
|
ilType = k == 0 ? icxIT_Dtemp : icxIT_Ptemp;
|
|
|
|
if (standardIlluminant(&sp, ilType, temp) != 0)
|
|
error ("standardIlluminant returned error");
|
|
|
|
sprintf(buf, "%s at %f", k == 0 ? "Daylight" : "Black body", temp);
|
|
|
|
do_spec(buf, &sp);
|
|
}
|
|
}
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|