1315 lines
40 KiB
C
1315 lines
40 KiB
C
|
|
/* Illuminant measurement utility */
|
|
|
|
/*
|
|
* Argyll Color Management System
|
|
* Author: Graeme W. Gill
|
|
* Date: 3/10/2001
|
|
*
|
|
* Derived from printread.c/chartread.c
|
|
* Was called printspot.
|
|
*
|
|
* Copyright 2001 - 2013 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 program uses an instrument capable of spectral illuminant/emissive */
|
|
/* and reflective (non-UV filtered) measurement, to measure an illuminant */
|
|
/* spectrum that includes a UV estimate. */
|
|
|
|
/* This is documented in the paper: */
|
|
/* "Estimating illuminant U.V. without a U.V. capable instrument", */
|
|
/* Graeme W. Gill, IS&T 19th Color and Imaging Conference Final Program */
|
|
/* and Proceedings, pp. 58-60(3) */
|
|
|
|
/* Code based on spotread.c */
|
|
|
|
/*
|
|
TTBD:
|
|
|
|
Should add support for converting Spyder correction readings to ccmx.
|
|
(see SpyderDeviceCorrections.txt)
|
|
|
|
*/
|
|
|
|
/*
|
|
Test mode files restored/saved:
|
|
|
|
outname_i.sp Illuminant spectrum
|
|
outname_r.sp Illuminant off paper spectrum
|
|
outname_p.sp Instrument measured paper reflectance spectrum
|
|
|
|
Just saved:
|
|
|
|
outname_mpir.sp Measured paper under illuminant spectrum
|
|
outname_cpir.sp Computed paper under illuminant spectrum
|
|
*/
|
|
|
|
#undef DEBUG /* Debug messages */
|
|
#undef PLOT_FITTING /* Plot the fitting itterations */
|
|
#undef SHOWDXX /* Plot the best matched daylight as well */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <sys/types.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
#include "copyright.h"
|
|
#include "aconfig.h"
|
|
#include "numlib.h"
|
|
#include "cgats.h"
|
|
#include "conv.h"
|
|
#include "xicc.h"
|
|
#include "inst.h"
|
|
#include "icoms.h"
|
|
#include "instappsup.h"
|
|
#include "plot.h"
|
|
#include "ui.h"
|
|
#ifdef ENABLE_USB
|
|
# include "spyd2.h"
|
|
#endif
|
|
|
|
#include <stdarg.h>
|
|
|
|
#if defined (NT)
|
|
#include <conio.h>
|
|
#endif
|
|
|
|
|
|
/* Deal with an instrument error. */
|
|
/* Return 0 to retry, 1 to abort */
|
|
static int ierror(inst *it, inst_code ic) {
|
|
int ch;
|
|
empty_con_chars();
|
|
printf("Got '%s' (%s) error.\nHit Esc or Q to give up, any other key to retry:%s",
|
|
it->inst_interp_error(it, ic), it->interp_error(it, ic), fl_end);
|
|
do_fflush();
|
|
ch = next_con_char();
|
|
printf("\n");
|
|
if (ch == 0x03 || ch == 0x1b || ch == 'q' || ch == 'Q') /* Escape, ^C or Q */
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
#if defined(__APPLE__) && defined(__POWERPC__)
|
|
|
|
/* Workaround for a ppc gcc 3.3 optimiser bug... */
|
|
static int gcc_bug_fix(int i) {
|
|
static int nn;
|
|
nn += i;
|
|
return nn;
|
|
}
|
|
|
|
#define GCC_BUGFIX(XX) gcc_bug_fix(XX);
|
|
#else /* !APPLE */
|
|
#define GCC_BUGFIX(XX)
|
|
#endif /* !APPLE */
|
|
|
|
|
|
/* ============================================================== */
|
|
/* optimizer callback */
|
|
|
|
/* Structure to hold optimisation information */
|
|
typedef struct {
|
|
xspect *i_sp; /* Illuminiant measurement */
|
|
xspect *r_sp; /* Illuminant off paper measurement */
|
|
xspect *p_sp; /* Paper reflectance measurement */
|
|
|
|
xsp2cie *pap; /* Estimated illuminant + UV on paper lookup inc FWA */
|
|
xsp2cie *ref; /* Measured illuminant on paper lookup */
|
|
|
|
xspect ill; /* Illuminant with UV added - set by bfindfunc() */
|
|
xspect cpsp; /* FWA corrected calculated paper reflectance */
|
|
xspect srop; /* Scaled measured paper reflectance */
|
|
|
|
double lab0[3], lab1[3]; /* Conversion of calculated vs. measured */
|
|
} bfinds;
|
|
|
|
/* Optimize the UV content that minimizes the (weighted) Delta E */
|
|
static double bfindfunc(void *adata, double pv[]) {
|
|
bfinds *b = (bfinds *)adata;
|
|
int i;
|
|
double rv = 0.0;
|
|
|
|
/* Add UV level to illuminant */
|
|
b->ill = *b->i_sp; /* Structure copy */
|
|
xsp_setUV(&b->ill, b->i_sp, pv[0]); /* Extends ill range into UV */
|
|
|
|
#ifdef NEVER /* Plot the two reflectance spectra */
|
|
printf("Black = Measured illum, Red = illum + %f UV\n",pv[0]);
|
|
xspect_plot(b->i_sp, &b->ill, NULL);
|
|
#endif
|
|
|
|
/* Update the conversion to use observer illuminant with UV */
|
|
if (b->pap->update_fwa_custillum(b->pap, NULL, &b->ill) != 0)
|
|
error ("Updating FWA compensation failed");
|
|
|
|
/* Apply FWA compensation to the paper reflectance */
|
|
b->pap->sconvert(b->pap, &b->cpsp, b->lab0, b->p_sp);
|
|
|
|
/* Adjust gain factor of measured illuminant off paper */
|
|
/* and divide by illuminant measurement to give reflectance */
|
|
b->srop = *b->r_sp;
|
|
for (i = 0; i < b->r_sp->spec_n; i++) {
|
|
double ww = XSPECT_XWL(b->r_sp, i);
|
|
double ival = value_xspect(b->i_sp, ww);
|
|
if (ival < 0.05) /* Stop noise sending it wild */
|
|
ival = 0.05;
|
|
b->srop.spec[i] *= pv[1]/ival;
|
|
if (b->srop.spec[i] < 0.0)
|
|
b->srop.spec[i] = 0.0;
|
|
}
|
|
|
|
/* Compute Lab of the computed reflectance under flat spectrum */
|
|
b->ref->convert(b->ref, b->lab0, &b->cpsp);
|
|
|
|
/* Compute Lab value of illuminant measured reflectance */
|
|
b->ref->convert(b->ref, b->lab1, &b->srop);
|
|
|
|
/* Weighted Delta E (low weight on a* error) */
|
|
rv = sqrt( (b->lab0[0] - b->lab1[0]) * (b->lab0[0] - b->lab1[0])
|
|
+ 0.1 * (b->lab0[1] - b->lab1[1]) * (b->lab0[1] - b->lab1[1])
|
|
+ (b->lab0[2] - b->lab1[2]) * (b->lab0[2] - b->lab1[2]));
|
|
|
|
/* Add a slight weight of the UV level, to minimize it */
|
|
/* if the case is unconstrained. */
|
|
rv += 0.1 * fabs(pv[0]);
|
|
|
|
#ifdef PLOT_FITTING /* Plot the two reflectance spectra */
|
|
printf("rev = %f (%f %f %f - %f %f %f) from UV %f GA %f\n",rv, b->lab0[0], b->lab0[1], b->lab0[2], b->lab1[0], b->lab1[1], b->lab1[2], pv[0], pv[1]);
|
|
|
|
printf("Black = Measured, Red = trial\n");
|
|
xspect_plot(&b->srop, &b->cpsp, NULL);
|
|
#endif
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* ============================================================== */
|
|
#ifdef SHOWDXX /* Plot the best matched daylight as well */
|
|
|
|
/* optimizer callback for computing daylight match */
|
|
|
|
/* Structure to hold optimisation information */
|
|
typedef struct {
|
|
xspect ill; /* Illuminant with UV added - target */
|
|
xspect dxx; /* Daylight spectrum */
|
|
|
|
xsp2cie *ref; /* reference Lab conversion */
|
|
|
|
double lab0[3], lab1[3]; /* Conversion of target vs. Daylight */
|
|
} cfinds;
|
|
|
|
/* Optimize the daylight color temperature and level to minimizes the Delta E */
|
|
static double cfindfunc(void *adata, double pv[]) {
|
|
cfinds *b = (cfinds *)adata;
|
|
int i;
|
|
double rv = 0.0;
|
|
|
|
/* Compute daylight with the given color temperature */
|
|
standardIlluminant( &b->dxx, icxIT_Dtemp, pv[0]);
|
|
b->dxx.norm = 1.0;
|
|
|
|
/* Adjust the level of daylight spectra */
|
|
for (i = 0; i < b->dxx.spec_n; i++) {
|
|
b->dxx.spec[i] *= pv[1];
|
|
}
|
|
|
|
/* Compute Lab of target */
|
|
b->ref->convert(b->ref, b->lab0, &b->ill);
|
|
|
|
/* Compute Lab of Dxx */
|
|
b->ref->convert(b->ref, b->lab1, &b->dxx);
|
|
|
|
/* Weighted Delta E (low weight on a* error) */
|
|
rv = icmLabDEsq(b->lab0, b->lab1);
|
|
|
|
//printf("~1 rev = %f (%f %f %f - %f %f %f) from %f %f\n",rv, b->lab0[0], b->lab0[1], b->lab0[2], b->lab1[0], b->lab1[1], b->lab1[2], pv[0], pv[1]);
|
|
return rv;
|
|
}
|
|
|
|
#endif /* SHOWDXX */
|
|
|
|
/* ============================================================== */
|
|
void
|
|
usage(char *diag, ...) {
|
|
icompaths *icmps;
|
|
fprintf(stderr,"Measure an illuminant, Version %s\n",ARGYLL_VERSION_STR);
|
|
fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
|
|
if (diag != NULL) {
|
|
va_list args;
|
|
fprintf(stderr,"Diagnostic: ");
|
|
va_start(args, diag);
|
|
vfprintf(stderr, diag, args);
|
|
va_end(args);
|
|
fprintf(stderr,"\n");
|
|
}
|
|
fprintf(stderr,"usage: illumread [-options] output.sp\n");
|
|
fprintf(stderr," -v Verbose mode\n");
|
|
fprintf(stderr," -S Plot spectrum for each reading\n");
|
|
fprintf(stderr," -c listno Choose instrument from the following list (default 1)\n");
|
|
if ((icmps = new_icompaths(g_log)) != NULL) {
|
|
icompath **paths;
|
|
if ((paths = icmps->paths) != NULL) {
|
|
int i;
|
|
for (i = 0; ; i++) {
|
|
if (paths[i] == NULL)
|
|
break;
|
|
if ((paths[i]->dtype == instSpyder1 && setup_spyd2(0) == 0)
|
|
|| (paths[i]->dtype == instSpyder2 && setup_spyd2(1) == 0))
|
|
fprintf(stderr," %d = '%s' !! Disabled - no firmware !!\n",i+1,paths[i]->name);
|
|
else
|
|
fprintf(stderr," %d = '%s'\n",i+1,paths[i]->name);
|
|
}
|
|
} else
|
|
fprintf(stderr," ** No ports found **\n");
|
|
}
|
|
fprintf(stderr," -N Disable initial calibration of instrument if possible\n");
|
|
fprintf(stderr," -H Use high resolution spectrum mode (if available)\n");
|
|
fprintf(stderr," -Y r Set refresh measurement mode\n");
|
|
fprintf(stderr," -Y R:rate Override measured refresh rate with rate Hz\n");
|
|
fprintf(stderr," -W n|h|x Override serial port flow control: n = none, h = HW, x = Xon/Xoff\n");
|
|
fprintf(stderr," -T Test mode - restore & save measurements to\n");
|
|
fprintf(stderr," *_i.sp, *_r.sp, *_p.sp, *_mpir.sp, *_cpir.sp files\n");
|
|
fprintf(stderr," -D [level] Print debug diagnostics to stderr\n");
|
|
fprintf(stderr," illuminant.sp File to save measurement to\n");
|
|
|
|
if (icmps != NULL)
|
|
icmps->del(icmps);
|
|
exit(1);
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
int i,j;
|
|
int fa, nfa, mfa; /* current argument we're looking at */
|
|
int verb = 0;
|
|
int debug = 0;
|
|
int nocal = 0; /* Disable initial calibration */
|
|
int pspec = 0; /* 2 = Plot out the spectrum for each reading */
|
|
int highres = 0; /* Use high res mode if available */
|
|
int refrmode = -1; /* -1 = default, = non-refresh mode, 1 = non-refresh mode */
|
|
double refrate = 0.0; /* 0.0 = default, > 0.0 = override refresh rate */
|
|
static char outname[MAXNAMEL+1] = "\000"; /* Spectral output file name */
|
|
|
|
int tmode = 0; /* Test mode */
|
|
static char tname[MAXNAMEL+11] = "\000", *tnp; /* Test mode file names */
|
|
int rd_i = 0, rd_r = 0, rd_p = 0; /* Test mode flags */
|
|
|
|
icompaths *icmps = NULL; /* Ports to choose from */
|
|
int comno = 1; /* Specific port suggested by user */
|
|
inst *it = NULL; /* Instrument object, NULL if none */
|
|
inst_mode mode = 0; /* Instrument reading mode */
|
|
inst_opt_type trigmode = inst_opt_unknown; /* Chosen trigger mode */
|
|
instType itype = instUnknown; /* No default target instrument */
|
|
inst_mode cap = inst_mode_none; /* Instrument mode capabilities */
|
|
inst2_capability cap2 = inst2_none; /* Instrument capabilities 2 */
|
|
inst3_capability cap3 = inst3_none; /* Instrument capabilities 3 */
|
|
baud_rate br = baud_38400; /* Target baud rate */
|
|
flow_control fc = fc_nc; /* Default flow control */
|
|
|
|
inst_code rv;
|
|
int uswitch = 0; /* Instrument switch is enabled */
|
|
xspect i_sp; /* Illuminant emsission spectrum */
|
|
xspect r_sp; /* Illuminant reflected from paper emission spectrum */
|
|
xspect p_sp; /* Paper reflectance spectrum */
|
|
xspect insp; /* Instrument illuminant (for FWA) */
|
|
xspect ill; /* Estimated illuminant */
|
|
xspect aill; /* Accumulated result */
|
|
int nacc = 0; /* Number accumulated */
|
|
ipatch val; /* Value read */
|
|
|
|
|
|
set_exe_path(argv[0]); /* Set global exe_path and error_program */
|
|
check_if_not_interactive();
|
|
|
|
i_sp.spec_n = 0;
|
|
r_sp.spec_n = 0;
|
|
p_sp.spec_n = 0;
|
|
insp.spec_n = 0;
|
|
ill.spec_n = 0;
|
|
aill.spec_n = 0;
|
|
|
|
/* Process the arguments */
|
|
mfa = 0; /* Minimum final 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+mfa) < argc) {
|
|
if (argv[fa+1][0] != '-') {
|
|
nfa = fa + 1;
|
|
na = argv[nfa]; /* next is seperate non-flag argument */
|
|
}
|
|
}
|
|
}
|
|
|
|
if (argv[fa][1] == '?') {
|
|
usage(NULL);
|
|
|
|
} else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
|
|
verb = 1;
|
|
g_log->verb = verb;
|
|
|
|
} else if (argv[fa][1] == 'S') {
|
|
pspec = 2;
|
|
|
|
/* COM port */
|
|
} else if (argv[fa][1] == 'c') {
|
|
fa = nfa;
|
|
if (na == NULL) usage(NULL);
|
|
comno = atoi(na);
|
|
if (comno < 1 || comno > 99) usage(NULL);
|
|
|
|
/* No initial calibration */
|
|
} else if (argv[fa][1] == 'N') {
|
|
nocal = 1;
|
|
|
|
/* High res mode */
|
|
} else if (argv[fa][1] == 'H') {
|
|
highres = 1;
|
|
|
|
/* Extra flags */
|
|
} else if (argv[fa][1] == 'Y') {
|
|
if (na == NULL)
|
|
usage(NULL);
|
|
|
|
if (na[0] == 'R') {
|
|
if (na[1] != ':')
|
|
usage("-Y R:rate syntax incorrect");
|
|
refrate = atof(na+2);
|
|
if (refrate < 5.0 || refrate > 150.0)
|
|
usage("-Y R:rate %f Hz not in valid range",refrate);
|
|
} else if (na[0] == 'r')
|
|
refrmode = 1;
|
|
else
|
|
usage(NULL);
|
|
fa = nfa;
|
|
|
|
/* Serial port flow control */
|
|
} else if (argv[fa][1] == 'W') {
|
|
fa = nfa;
|
|
if (na == NULL) usage(NULL);
|
|
|
|
if (na[0] == 'n' || na[0] == 'N')
|
|
fc = fc_None;
|
|
else if (na[0] == 'h' || na[0] == 'H')
|
|
fc = fc_Hardware;
|
|
else if (na[0] == 'x' || na[0] == 'X')
|
|
fc = fc_XonXOff;
|
|
else
|
|
usage(NULL);
|
|
|
|
} else if (argv[fa][1] == 'T') {
|
|
tmode = 1;
|
|
|
|
} else if (argv[fa][1] == 'D') {
|
|
debug = 1;
|
|
if (na != NULL && na[0] >= '0' && na[0] <= '9') {
|
|
debug = atoi(na);
|
|
fa = nfa;
|
|
}
|
|
g_log->debug = debug;
|
|
} else
|
|
usage(NULL);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
|
|
/* Get the output spectrum file name argument */
|
|
if (fa >= argc)
|
|
usage(NULL);
|
|
|
|
strncpy(outname,argv[fa++],MAXNAMEL-1); outname[MAXNAMEL-1] = '\000';
|
|
|
|
if (tmode) {
|
|
strcpy(tname, outname);
|
|
if ((tnp = strrchr(tname, '.')) == NULL)
|
|
tnp = tname + strlen(tname);
|
|
|
|
/* Special debug */
|
|
strcpy(tnp, "_i.sp");
|
|
if (read_xspect(&i_sp, NULL, NULL, tname) == 0) {
|
|
rd_i = 1;
|
|
printf("(Found '%s' file and loaded it)\n",tname);
|
|
}
|
|
strcpy(tnp, "_r.sp");
|
|
if (read_xspect(&r_sp, NULL, NULL, tname) == 0) {
|
|
rd_r = 1;
|
|
printf("(Found '%s' file and loaded it)\n",tname);
|
|
}
|
|
strcpy(tnp, "_p.sp");
|
|
if (read_xspect(&p_sp, NULL, NULL, tname) == 0) {
|
|
rd_p = 1;
|
|
/* Should read instrument type from debug_p.sp !! */
|
|
if (inst_illuminant(&insp, instI1Pro) != 0) /* Hack !! */
|
|
error ("Instrument doesn't have an FWA illuminent");
|
|
printf("(Found '%s' file and loaded it)\n",tname);
|
|
}
|
|
}
|
|
|
|
|
|
/* Until the measurements are done, or we give up */
|
|
for (;;) {
|
|
int c;
|
|
|
|
/* Print the menue of adjustments */
|
|
printf("\nPress 1 .. 7\n");
|
|
printf("1) Measure direct illuminant%s\n",i_sp.spec_n != 0 ? " (measured)":"");
|
|
printf("2) Measure illuminant reflected from paper%s\n", r_sp.spec_n != 0 ? " (measured)":"");
|
|
printf("3) Measure paper%s\n", p_sp.spec_n != 0 ? " (measured)":"");
|
|
if (it == NULL) {
|
|
printf("4) Select another instrument, Currently %d (", comno);
|
|
if (icmps == NULL)
|
|
icmps = new_icompaths(g_log);
|
|
else
|
|
icmps->refresh(icmps);
|
|
if (icmps != NULL) {
|
|
icompath **paths;
|
|
if ((paths = icmps->paths) != NULL) {
|
|
int i;
|
|
for (i = 0; ; i++) {
|
|
if (paths[i] == NULL)
|
|
break;
|
|
if ((i+1) == comno) {
|
|
printf(" '%s'",paths[i]->name);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
printf(")\n");
|
|
} else
|
|
printf("4) Select another instrument, Currently %s\n", inst_name(itype));
|
|
printf("5) Compute illuminant spectrum, average result with %d previous readings & save it\n",nacc);
|
|
printf("6) Compute illuminant spectrum from this reading & save result\n");
|
|
printf("7) Exit\n");
|
|
|
|
empty_con_chars();
|
|
c = next_con_char();
|
|
printf("'%c'\n",c);
|
|
|
|
/* Deal with doing a measurement */
|
|
if (c == '1' || c == '2' || c == '3') {
|
|
int ch;
|
|
|
|
if (it == NULL) {
|
|
icompath *ipath;
|
|
if (icmps == NULL)
|
|
icmps = new_icompaths(g_log);
|
|
|
|
/* Open the instrument */
|
|
ipath = icmps->get_path(icmps, comno);
|
|
if ((it = new_inst(ipath, 0, g_log, DUIH_FUNC_AND_CONTEXT)) == NULL) {
|
|
printf("!!! Unknown, inappropriate or no instrument detected !!!\n");
|
|
continue;
|
|
}
|
|
|
|
if (verb)
|
|
printf("Connecting to the instrument ..\n");
|
|
|
|
#ifdef DEBUG
|
|
printf("About to init the comms\n");
|
|
#endif
|
|
|
|
/* Establish communications */
|
|
if ((rv = it->init_coms(it, br, fc, 15.0)) != inst_ok) {
|
|
printf("!!! Failed to initialise communications with instrument\n"
|
|
" or wrong instrument or bad configuration !!!\n"
|
|
" ('%s' + '%s')\n", it->inst_interp_error(it, rv), it->interp_error(it, rv));
|
|
it->del(it);
|
|
it = NULL;
|
|
itype = instUnknown;
|
|
continue;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf("Established comms & initing the instrument\n");
|
|
#endif
|
|
|
|
/* Initialise the instrument */
|
|
if ((rv = it->init_inst(it)) != inst_ok) {
|
|
printf("!!! Instrument initialisation failed with '%s' (%s) !!!\n",
|
|
it->inst_interp_error(it, rv), it->interp_error(it, rv));
|
|
it->del(it);
|
|
it = NULL;
|
|
itype = instUnknown;
|
|
continue;
|
|
}
|
|
|
|
itype = it->get_itype(it); /* get actual type of instrument */
|
|
|
|
/* Check the instrument has the necessary capabilities */
|
|
it->capabilities(it, &cap, &cap2, &cap3);
|
|
|
|
/* Need spectral */
|
|
if (!IMODETST(cap, inst_mode_spectral)) {
|
|
printf("Instrument lacks spectral measurement capability");
|
|
}
|
|
|
|
if (refrmode >= 0 && it->check_mode(it, inst_mode_emis_refresh_ovd) != inst_ok
|
|
&& it->check_mode(it, inst_mode_emis_norefresh_ovd) != inst_ok) {
|
|
if (verb) {
|
|
printf("Requested refresh mode override and instrument doesn't support it (ignored)\n");
|
|
refrmode = -1;
|
|
}
|
|
}
|
|
|
|
/* Disable iniial calibration of machine if selected */
|
|
if (nocal != 0) {
|
|
if ((rv = it->get_set_opt(it,inst_opt_noinitcalib, 0)) != inst_ok) {
|
|
printf("Setting no-initial calibrate failed failed with '%s' (%s) !!!\n",
|
|
it->inst_interp_error(it, rv), it->interp_error(it, rv));
|
|
printf("Disable initial-calibrate not supported\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Check the instrument has the necessary capabilities for this measurement */
|
|
it->capabilities(it, &cap, &cap2, &cap3);
|
|
|
|
if (c == '1') {
|
|
if (it->check_mode(it, inst_mode_emis_ambient) == inst_ok) {
|
|
mode = inst_mode_emis_ambient;
|
|
} else if (it->check_mode(it, inst_mode_emis_spot) == inst_ok) {
|
|
mode = inst_mode_emis_spot;
|
|
} else {
|
|
printf("!!! Instrument doesn't have ambient or emissive capability !!!\n");
|
|
continue;
|
|
}
|
|
}
|
|
if (c == '2') {
|
|
if (it->check_mode(it, inst_mode_emis_tele) == inst_ok) {
|
|
mode = inst_mode_emis_tele;
|
|
} else if (it->check_mode(it, inst_mode_emis_spot) == inst_ok) {
|
|
mode = inst_mode_emis_spot;
|
|
} else {
|
|
printf("!!! Instrument doesn't have telephoto or emissive capability !!!\n");
|
|
continue;
|
|
}
|
|
}
|
|
if (c == '3') {
|
|
inst_opt_filter filt;
|
|
|
|
if (it->check_mode(it, inst_mode_ref_spot) == inst_ok) {
|
|
mode = inst_mode_ref_spot;
|
|
} else {
|
|
printf("!!! Instrument lacks reflective spot measurement capability !!!\n");
|
|
continue;
|
|
}
|
|
|
|
if ((rv = it->get_set_opt(it, inst_stat_get_filter, &filt)) == inst_ok) {
|
|
if (filt & inst_opt_filter_UVCut) {
|
|
printf("!!! Instrument has UV filter - can't measure FWA !!!\n");
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
mode |= inst_mode_spectral;
|
|
|
|
if (refrmode == 0)
|
|
mode |= inst_mode_emis_norefresh_ovd;
|
|
else if (refrmode == 1)
|
|
mode |= inst_mode_emis_refresh_ovd;
|
|
|
|
if (highres) {
|
|
if (IMODETST(cap, inst_mode_highres)) {
|
|
mode |= inst_mode_highres;
|
|
} else if (verb) {
|
|
printf("!!! High resolution ignored - instrument doesn't support it !!!\n");
|
|
}
|
|
}
|
|
|
|
if ((rv = it->set_mode(it, mode)) != inst_ok) {
|
|
printf("!!! Setting instrument mode failed with error :'%s' (%s) !!!\n",
|
|
it->inst_interp_error(it, rv), it->interp_error(it, rv));
|
|
continue;
|
|
}
|
|
it->capabilities(it, &cap, &cap2, &cap3);
|
|
|
|
if (refrate > 0.0) {
|
|
if (!(cap2 & inst2_set_refresh_rate)) {
|
|
if (verb)
|
|
printf("Attempted to set refresh rate and instrument doesn't support setting it (ignored)\n");
|
|
refrate = 0.0;
|
|
} else {
|
|
if ((rv = it->set_refr_rate(it, refrate)) != inst_ok) {
|
|
error("Setting instrument refresh rate to %f Hz failed with error :'%s' (%s)",
|
|
refrate, it->inst_interp_error(it, rv), it->interp_error(it, rv));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If it batter powered, show the status of the battery */
|
|
if ((cap2 & inst2_has_battery)) {
|
|
double batstat = 0.0;
|
|
if ((rv = it->get_set_opt(it, inst_stat_battery, &batstat)) == inst_ok)
|
|
printf("The battery charged level is %.0f%%\n",batstat * 100.0);
|
|
}
|
|
|
|
/* If it's an instrument that need positioning do trigger using user via uicallback */
|
|
/* in illumread, else enable switch or keyboard trigger if possible. */
|
|
if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
|
|
trigmode = inst_opt_trig_prog;
|
|
|
|
} else if (cap2 & inst2_user_switch_trig) {
|
|
trigmode = inst_opt_trig_user_switch;
|
|
uswitch = 1;
|
|
|
|
/* Or go for user via uicallback trigger */
|
|
} else if (cap2 & inst2_user_trig) {
|
|
trigmode = inst_opt_trig_user;
|
|
|
|
/* Or something is wrong with instrument capabilities */
|
|
} else {
|
|
printf("!!! No reasonable trigger mode available for this instrument !!!\n");
|
|
continue;
|
|
}
|
|
if ((rv = it->get_set_opt(it, trigmode)) != inst_ok) {
|
|
printf("!!! Setting trigger mode failed with error :'%s' (%s) !!!\n",
|
|
it->inst_interp_error(it, rv), it->interp_error(it, rv));
|
|
continue;
|
|
}
|
|
|
|
/* Setup the keyboard trigger to return our commands */
|
|
inst_set_uih(0x0, 0xff, DUIH_TRIG);
|
|
inst_set_uih('q', 'q', DUIH_ABORT);
|
|
inst_set_uih('Q', 'Q', DUIH_ABORT);
|
|
inst_set_uih(0x03, 0x03, DUIH_ABORT); /* ^c */
|
|
inst_set_uih(0x1b, 0x1b, DUIH_ABORT); /* Esc */
|
|
|
|
/* Hold table */
|
|
if (cap2 & inst2_xy_holdrel) {
|
|
for (;;) { /* retry loop */
|
|
if ((rv = it->xy_sheet_hold(it)) == inst_ok)
|
|
break;
|
|
|
|
if (ierror(it, rv)) {
|
|
printf("!!! Setting paper hold failed with error :'%s' (%s) !!!\n",
|
|
it->inst_interp_error(it, rv), it->interp_error(it, rv));
|
|
it->xy_clear(it);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Do any needed calibration before the user places the instrument on a desired spot */
|
|
if (it->needs_calibration(it) != inst_calt_none) {
|
|
double lx, ly;
|
|
inst_code ev;
|
|
|
|
printf("\nInstrument needs a calibration before continuing\n");
|
|
|
|
/* save current location */
|
|
if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
|
|
for (;;) { /* retry loop */
|
|
if ((ev = it->xy_get_location(it, &lx, &ly)) == inst_ok)
|
|
break;
|
|
if (ierror(it, ev) == 0) /* Ignore */
|
|
continue;
|
|
break; /* Abort */
|
|
}
|
|
if (ev != inst_ok) {
|
|
printf("!!! Setting calibration location failed with error :'%s' (%s) !!!\n",
|
|
it->inst_interp_error(it, rv), it->interp_error(it, rv));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL, 0);
|
|
if (ev != inst_ok) { /* Abort or fatal error */
|
|
printf("!!! Calibration failed with error :'%s' (%s) !!!\n",
|
|
it->inst_interp_error(it, rv), it->interp_error(it, rv));
|
|
continue;
|
|
}
|
|
|
|
/* restore location */
|
|
if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
|
|
for (;;) { /* retry loop */
|
|
if ((ev = it->xy_position(it, 0, lx, ly)) == inst_ok)
|
|
break;
|
|
if (ierror(it, ev) == 0) /* Ignore */
|
|
continue;
|
|
break; /* Abort */
|
|
}
|
|
if (ev != inst_ok) {
|
|
printf("!!! Restoring location failed with error :'%s' (%s) !!!\n",
|
|
it->inst_interp_error(it, rv), it->interp_error(it, rv));
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Now do the measurement: */
|
|
|
|
/* If this is an xy instrument: */
|
|
if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
|
|
|
|
/* Allow the user to position the instrument */
|
|
for (;;) { /* retry loop */
|
|
if ((rv = it->xy_locate_start(it)) == inst_ok)
|
|
break;
|
|
if (ierror(it, rv) == 0) /* Ignore */
|
|
continue;
|
|
break; /* Abort */
|
|
}
|
|
if (rv != inst_ok)
|
|
break; /* Abort */
|
|
|
|
if (c != 3) {
|
|
printf("!!! Unexpected: XY instrument used for emissive measurements !!!\n");
|
|
continue;
|
|
}
|
|
|
|
printf("Using the XY table controls, position the instrument sight\n");
|
|
printf("so as to read the paper,\n");
|
|
|
|
/* Purely manual instrument */
|
|
} else {
|
|
|
|
if (c == '1') {
|
|
if (it->check_mode(it, inst_mode_emis_ambient) == inst_ok) {
|
|
printf("\n(If applicable) set instrument to ambient measurenent mode, or place\n");
|
|
printf("ambient adapter on it, and position it so as to measure the illuminant directly.\n");
|
|
} else {
|
|
printf("\n(If applicable) set instrument to emissive measurenent mode,\n");
|
|
printf("and position it so as to measure the illuminant directly.\n");
|
|
}
|
|
} else if (c == '2') {
|
|
if (it->check_mode(it, inst_mode_emis_tele) == inst_ok) {
|
|
printf("\n(If applicable) set instrument to telephoto measurenent mode,\n");
|
|
printf("position it so as to measure the illuminant reflected from the paper.\n");
|
|
} else {
|
|
printf("\n(If applicable) set instrument to emsissive measurenent mode,\n");
|
|
printf("position it so as to measure the illuminant reflected from the paper.\n");
|
|
}
|
|
} else if (c == '3') {
|
|
printf("\n(If applicable) set instrument to reflective measurenent mode,\n");
|
|
printf("position it so as to measure the paper.");
|
|
} else
|
|
error("Unexpected choice");
|
|
}
|
|
if (uswitch)
|
|
printf("Hit ESC or Q to abort, or instrument switch or any other key to take a reading: %s",fl_end);
|
|
else
|
|
printf("Hit ESC or Q to abort, any any other key to take a reading: %s",fl_end);
|
|
do_fflush();
|
|
|
|
if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
|
|
|
|
/* Wait for the user to hit a key */
|
|
for (;;) {
|
|
if ((rv = inst_get_uicallback()(inst_get_uicontext(), inst_armed)) != inst_ok)
|
|
break;
|
|
}
|
|
|
|
if (rv == inst_user_abort) {
|
|
break; /* Abort */
|
|
|
|
} else if (rv == inst_user_trig) {
|
|
double lx, ly;
|
|
inst_code ev;
|
|
|
|
/* Take the location set on the sight, and move the instrument */
|
|
/* to take the measurement there. */
|
|
if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
|
|
for (;;) { /* retry loop */
|
|
if ((rv = it->xy_get_location(it, &lx, &ly)) == inst_ok)
|
|
break;
|
|
if (ierror(it, rv) == 0) /* Ignore */
|
|
continue;
|
|
break; /* Abort */
|
|
}
|
|
if (rv != inst_ok)
|
|
break; /* Abort */
|
|
|
|
for (;;) { /* retry loop */
|
|
if ((rv = it->xy_locate_end(it)) == inst_ok)
|
|
break;
|
|
if (ierror(it, rv) == 0) /* Ignore */
|
|
continue;
|
|
break; /* Abort */
|
|
}
|
|
if (rv != inst_ok)
|
|
break; /* Abort */
|
|
|
|
for (;;) { /* retry loop */
|
|
if ((rv = it->xy_position(it, 1, lx, ly)) == inst_ok)
|
|
break;
|
|
if (ierror(it, rv) == 0) /* Ignore */
|
|
continue;
|
|
break; /* Abort */
|
|
}
|
|
if (rv != inst_ok)
|
|
break; /* Abort */
|
|
}
|
|
rv = it->read_sample(it, "SPOT", &val, 1);
|
|
|
|
/* Restore the location the instrument to have the location */
|
|
/* sight over the selected patch. */
|
|
for (;;) { /* retry loop */
|
|
if ((ev = it->xy_position(it, 0, lx, ly)) == inst_ok)
|
|
break;
|
|
if (ierror(it, ev) == 0) /* Ignore */
|
|
continue;
|
|
break; /* Abort */
|
|
}
|
|
if (ev != inst_ok)
|
|
break; /* Abort */
|
|
}
|
|
/* else what ? */
|
|
|
|
/* Not an XY instrument */
|
|
} else {
|
|
rv = it->read_sample(it, "SPOT", &val, 1);
|
|
}
|
|
|
|
/* Release paper */
|
|
if (cap2 & inst2_xy_holdrel) {
|
|
it->xy_clear(it);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf("read_sample returned '%s' (%s)\n",
|
|
it->inst_interp_error(it, rv), it->interp_error(it, rv));
|
|
#endif /* DEBUG */
|
|
|
|
/* Deal with a trigger or command */
|
|
if ((rv & inst_mask) == inst_user_trig) {
|
|
ch = inst_get_uih_char() & 0xff;
|
|
|
|
/* Deal with a command or abort */
|
|
} else if ((rv & inst_mask) == inst_user_abort) {
|
|
ch = inst_get_uih_char();
|
|
|
|
if (ch & DUIH_CMND) {
|
|
ch &= 0xff;
|
|
} else if (ch & DUIH_ABORT) {
|
|
printf("\nIlluminant measure aborted at user request!\n");
|
|
continue;
|
|
}
|
|
|
|
/* Deal with a needs calibration */
|
|
} else if ((rv & inst_mask) == inst_needs_cal) {
|
|
inst_code ev;
|
|
printf("\nIlluminant measure failed because instruments needs calibration.\n");
|
|
ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL, 0);
|
|
continue;
|
|
|
|
/* Deal with a bad sensor position */
|
|
} else if ((rv & inst_mask) == inst_wrong_config) {
|
|
printf("\nIlluminant measure failed due to the sensor being in the wrong position\n(%s)\n",it->interp_error(it, rv));
|
|
continue;
|
|
|
|
/* Deal with a misread */
|
|
} else if ((rv & inst_mask) == inst_misread) {
|
|
printf("\nIlluminant measure failed due to misread (%s)\n",it->interp_error(it, rv));
|
|
continue;
|
|
|
|
/* Deal with a communications error */
|
|
} else if ((rv & inst_mask) == inst_coms_fail) {
|
|
empty_con_chars();
|
|
printf("\nIlluminant measure failed due to communication problem.\n");
|
|
printf("Hit Esc or Q to give up, any other key to retry:%s",fl_end); do_fflush();
|
|
continue;
|
|
|
|
/* Some other fatal error */
|
|
} else if (rv != inst_ok) {
|
|
printf("\nGot fatal error '%s' (%s)\n",
|
|
it->inst_interp_error(it, rv), it->interp_error(it, rv));
|
|
continue;
|
|
}
|
|
|
|
if (c == '1') { /* Illuminant */
|
|
i_sp = val.sp;
|
|
if (tmode && rd_i == 0) {
|
|
strcpy(tnp, "_i.sp");
|
|
write_xspect(tname, inst_mrt_emission, inst_mrc_none, &i_sp);
|
|
}
|
|
} else if (c == '2') { /* Illuminant reflected on paper */
|
|
r_sp = val.sp;
|
|
if (tmode && rd_r == 0) {
|
|
strcpy(tnp, "_r.sp");
|
|
write_xspect(tname, inst_mrt_emission, inst_mrc_none, &r_sp);
|
|
}
|
|
} else if (c == '3') { /* Paper reflectance */
|
|
p_sp = val.sp;
|
|
|
|
/* Get the illuminant spectrum too */
|
|
if (inst_illuminant(&insp, itype) != 0)
|
|
error ("Instrument doesn't have an FWA illuminent");
|
|
|
|
if (tmode && rd_p == 0) {
|
|
/* Should save instrument type/instrument illuminant spectrum !!! */
|
|
strcpy(tnp, "_p.sp");
|
|
write_xspect(tname, inst_mrt_reflective, inst_mrc_none, &p_sp);
|
|
}
|
|
}
|
|
|
|
if (pspec) {
|
|
double xx[XSPECT_MAX_BANDS];
|
|
double y1[XSPECT_MAX_BANDS];
|
|
double xmin, xmax, ymin, ymax;
|
|
int nn;
|
|
|
|
if (val.sp.spec_n <= 0)
|
|
error("Instrument didn't return spectral data");
|
|
|
|
printf("Spectrum from %f to %f nm in %d steps\n",
|
|
val.sp.spec_wl_short, val.sp.spec_wl_long, val.sp.spec_n);
|
|
|
|
if (val.sp.spec_n > XSPECT_MAX_BANDS)
|
|
error("Got > %d spectral values (%d)",XSPECT_MAX_BANDS,val.sp.spec_n);
|
|
|
|
for (j = 0; j < val.sp.spec_n; j++) {
|
|
GCC_BUGFIX(j)
|
|
xx[j] = val.sp.spec_wl_short
|
|
+ j * (val.sp.spec_wl_long - val.sp.spec_wl_short)/(val.sp.spec_n-1);
|
|
|
|
y1[j] = value_xspect(&val.sp, xx[j]);
|
|
}
|
|
|
|
xmax = val.sp.spec_wl_long;
|
|
xmin = val.sp.spec_wl_short;
|
|
ymin = ymax = 0.0; /* let it scale */
|
|
do_plot_x(xx, y1, NULL, NULL, val.sp.spec_n, 1,
|
|
xmin, xmax, ymin, ymax, 2.0);
|
|
}
|
|
|
|
continue;
|
|
} /* End of take a measurement */
|
|
|
|
/* Deal with selecting the instrument */
|
|
if (c == '4') {
|
|
|
|
if (it != NULL)
|
|
it->del(it);
|
|
it = NULL;
|
|
itype = instUnknown;
|
|
|
|
if (icmps == NULL)
|
|
icmps = new_icompaths(g_log);
|
|
else
|
|
icmps->refresh(icmps);
|
|
if (icmps != NULL) {
|
|
icompath **paths;
|
|
if ((paths = icmps->paths) != NULL) {
|
|
int i;
|
|
for (i = 0; ; i++) {
|
|
if (paths[i] == NULL)
|
|
break;
|
|
if ((paths[i]->dtype == instSpyder1 && setup_spyd2(0) == 0)
|
|
|| (paths[i]->dtype == instSpyder2 && setup_spyd2(1) == 0))
|
|
fprintf(stderr," %d = '%s' !! Disabled - no firmware !!\n",i+1,paths[i]->name);
|
|
else
|
|
fprintf(stderr," %d = '%s'\n",i+1,paths[i]->name);
|
|
}
|
|
printf("Select device 1 - %d: \n",i);
|
|
empty_con_chars();
|
|
c = next_con_char();
|
|
|
|
if (c < '1' || c > ('0' + i)) {
|
|
printf("'%c' is out of range - ignored !\n",c);
|
|
} else {
|
|
comno = c - '0';
|
|
}
|
|
|
|
} else {
|
|
fprintf(stderr,"No ports to select from!\n");
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
if (c == '5' || c == '6') { /* Compute result */
|
|
xspect cpisp; /* FWA corrected calculated initial paper reflectance */
|
|
double gain;
|
|
bfinds bf; /* Optimization context */
|
|
double xyz0[3], xyz1[3];
|
|
double tt[2], sr[2];
|
|
double rv;
|
|
|
|
if (i_sp.spec_n == 0) {
|
|
printf("Need to measure the direct illuminant\n");
|
|
continue;
|
|
}
|
|
if (r_sp.spec_n == 0) {
|
|
printf("Need to measure the illuminant reflected off paper\n");
|
|
continue;
|
|
}
|
|
if (p_sp.spec_n == 0) {
|
|
printf("Need to measure the paper\n");
|
|
continue;
|
|
}
|
|
|
|
/* Normalize direct illumination */
|
|
for (gain = 0.0, i = 0; i < i_sp.spec_n; i++)
|
|
gain += i_sp.spec[i];
|
|
gain /= i_sp.spec_n;
|
|
for (i = 0; i < i_sp.spec_n; i++)
|
|
i_sp.spec[i] /= gain;
|
|
|
|
/* Normalize indirect illumination */
|
|
for (gain = 0.0, i = 0; i < r_sp.spec_n; i++)
|
|
gain += r_sp.spec[i];
|
|
gain /= r_sp.spec_n;
|
|
for (i = 0; i < r_sp.spec_n; i++)
|
|
r_sp.spec[i] /= gain;
|
|
|
|
/* Normalize paper reflectance to 1.0 */
|
|
xspect_denorm(&p_sp);
|
|
|
|
bf.i_sp = &i_sp;
|
|
bf.r_sp = &r_sp;
|
|
bf.p_sp = &p_sp;
|
|
|
|
if ((bf.pap = new_xsp2cie(icxIT_custom, 0.0, &i_sp, icxOT_CIE_1931_2, NULL, icSigLabData, icxClamp)) == NULL)
|
|
error("new_xsp2cie pap failed");
|
|
|
|
if (bf.pap->set_fwa(bf.pap, &insp, NULL, &p_sp) != 0)
|
|
error ("Setting FWA compensation failed");
|
|
|
|
/* Setup the equal energy to Lab conversion */
|
|
if ((bf.ref = new_xsp2cie(icxIT_E, 0.0, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, icxClamp)) == NULL)
|
|
error("new_xsp2cie ref failed");
|
|
|
|
/* Estimate an initial gain match */
|
|
tt[0] = 0.0;
|
|
tt[1] = 1.0;
|
|
bfindfunc((void *)&bf, tt);
|
|
icmLab2XYZ(&icmD50, xyz0, bf.lab0);
|
|
icmLab2XYZ(&icmD50, xyz1, bf.lab1);
|
|
|
|
gain = xyz0[1] / xyz1[1];
|
|
//printf("~1 Target XYZ %f %f %f, is %f %f %f, gain needed = %f\n",xyz0[0],xyz0[1],xyz0[2],xyz1[0],xyz1[1],xyz1[2],gain);
|
|
|
|
for (i = 0; i < r_sp.spec_n; i++)
|
|
r_sp.spec[i] *= gain;
|
|
|
|
/* Check initial gain match is OK */
|
|
bfindfunc((void *)&bf, tt);
|
|
cpisp = bf.cpsp; /* Copy initial match */
|
|
icmLab2XYZ(&icmD50, xyz0, bf.lab0);
|
|
icmLab2XYZ(&icmD50, xyz1, bf.lab1);
|
|
#ifdef NEVER
|
|
printf("~1 Target XYZ %f %f %f, now %f %f %f\n",xyz0[0],xyz0[1],xyz0[2],xyz1[0],xyz1[1],xyz1[2]);
|
|
#endif
|
|
|
|
tt[0] = 0.1, tt[1] = 1.0; /* Search parameter starting values */
|
|
sr[0] = sr[1] = 0.1; /* Search parameter search radiuses */
|
|
|
|
if (powell(&rv, 2, tt, sr, 0.0001, 1000,
|
|
bfindfunc, (void *)&bf, NULL, NULL) != 0) {
|
|
printf("Optimization search failed\n");
|
|
continue;
|
|
}
|
|
printf("(Best match DE %f, UV content = %f (gain match %f))\n", rv, tt[0], tt[1]);
|
|
|
|
/* Compute the result */
|
|
bfindfunc((void *)&bf, tt);
|
|
ill = bf.ill;
|
|
|
|
if (c == '5' && nacc > 0) {
|
|
for (i = 0; i < ill.spec_n; i++)
|
|
aill.spec[i] += ill.spec[i];
|
|
nacc++;
|
|
} else {
|
|
aill = ill;
|
|
nacc = 1;
|
|
}
|
|
|
|
/* Save the result */
|
|
if (aill.spec_n == 0) {
|
|
printf("Nothing to save!\n");
|
|
} else {
|
|
for (i = 0; i < ill.spec_n; i++)
|
|
ill.spec[i] = aill.spec[i]/nacc;
|
|
|
|
if (write_xspect(outname, inst_mrt_ambient, inst_mrc_none, &ill))
|
|
printf("\nWriting file '%s' failed\n",outname);
|
|
else
|
|
printf("\nWriting file '%s' succeeded\n",outname);
|
|
|
|
if (tmode) {
|
|
strcpy(tnp, "_mpir.sp"); // Measured paper under illuminant spectrum
|
|
write_xspect(tname, inst_mrt_reflective, inst_mrc_none, &bf.srop);
|
|
strcpy(tnp, "_cpir.sp"); // Computed paper under illuminant spectrum
|
|
write_xspect(tname, inst_mrt_reflective, inst_mrc_none, &bf.cpsp);
|
|
}
|
|
}
|
|
|
|
/* Plot the result */
|
|
if (pspec) {
|
|
double xx[XSPECT_MAX_BANDS];
|
|
double y1[XSPECT_MAX_BANDS];
|
|
double y2[XSPECT_MAX_BANDS];
|
|
double y3[XSPECT_MAX_BANDS];
|
|
double xmin, xmax, ymin, ymax;
|
|
int nn;
|
|
|
|
#ifdef SHOWDXX
|
|
cfinds cf; /* Optimization context */
|
|
double tt[2], sr[2];
|
|
double rv;
|
|
xspect cpdsp; /* FWA corrected calculated daylight paper reflectance */
|
|
|
|
/* Setup the referencec comversion */
|
|
if ((cf.ref = new_xsp2cie(icxIT_E, 0.0, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, icxClamp)) == NULL)
|
|
error("new_xsp2cie ref failed");
|
|
|
|
cf.ill = bf.ill;
|
|
|
|
/* Set starting values */
|
|
tt[0] = 5000.0; /* degrees */
|
|
tt[1] = 1.0;
|
|
cfindfunc((void *)&cf, tt);
|
|
icmLab2XYZ(&icmD50, xyz0, cf.lab0);
|
|
icmLab2XYZ(&icmD50, xyz1, cf.lab1);
|
|
|
|
tt[1] = xyz0[1] / xyz1[1];
|
|
|
|
sr[0] = 10.0;
|
|
sr[1] = 0.1; /* Search parameter search radiuses */
|
|
|
|
if (powell(&rv, 2, tt, sr, 0.0001, 1000,
|
|
cfindfunc, (void *)&cf, NULL, NULL) != 0) {
|
|
error("Optimization search failed\n");
|
|
}
|
|
printf("(Best daylight match DE %f, temp = %f (gain match %f))\n", rv, tt[0], tt[1]);
|
|
|
|
/* Compute the result */
|
|
cfindfunc((void *)&cf, tt);
|
|
|
|
printf("Illuminant: Black - Measured, Red - with estimated UV, Green - daylight\n");
|
|
|
|
if (bf.ill.spec_n > XSPECT_MAX_BANDS)
|
|
error("Got > %d spectral values (%d)",XSPECT_MAX_BANDS,bf.ill.spec_n);
|
|
|
|
for (j = 0; j < bf.ill.spec_n; j++) {
|
|
GCC_BUGFIX(j)
|
|
xx[j] = XSPECT_XWL(&bf.ill, j);
|
|
y1[j] = value_xspect(bf.i_sp, xx[j]); /* Measured (black) */
|
|
y2[j] = value_xspect(&bf.ill, xx[j]); /* Computed (red)*/
|
|
y3[j] = value_xspect(&cf.dxx, xx[j]); /* Daylight match (green)*/
|
|
}
|
|
|
|
xmax = bf.ill.spec_wl_long;
|
|
xmin = bf.ill.spec_wl_short;
|
|
ymin = ymax = 0.0; /* let it scale */
|
|
do_plot_x(xx, y1, y2, y3, bf.ill.spec_n, 1,
|
|
xmin, xmax, ymin, ymax, 2.0);
|
|
|
|
/* Update the conversion to the matched Dayligh */
|
|
if (bf.pap->update_fwa_custillum(bf.pap, NULL, &cf.dxx) != 0)
|
|
error ("Updating FWA compensation to daylight failed");
|
|
|
|
/* Apply FWA compensation to the paper reflectance */
|
|
bf.pap->sconvert(bf.pap, &cpdsp, NULL, bf.p_sp);
|
|
|
|
printf("Paper Reflectance: Black - Measured, Red - Initial FWA model, Green - FWA Final FWA model\n");
|
|
// printf("Paper Reflectance: Black - Measured, Red - FWA Modelled, Green - Daylight modelled\n");
|
|
|
|
for (j = 0; j < bf.cpsp.spec_n; j++) {
|
|
GCC_BUGFIX(j)
|
|
xx[j] = XSPECT_XWL(&bf.cpsp, j);
|
|
y1[j] = value_xspect(&bf.srop, xx[j]); /* Measured reflectance (black) */
|
|
y2[j] = value_xspect(&cpisp, xx[j]); /* Computed initial reflectance (red) */
|
|
y3[j] = value_xspect(&bf.cpsp, xx[j]); /* Computed final reflectance (green) */
|
|
// y3[j] = value_xspect(&cpdsp, xx[j]); /* Computed daylight reflectance (green) */
|
|
}
|
|
|
|
xmax = bf.cpsp.spec_wl_long;
|
|
xmin = bf.cpsp.spec_wl_short;
|
|
ymin = ymax = 0.0; /* let it scale */
|
|
do_plot_x(xx, y1, y2, y3, bf.cpsp.spec_n, 1,
|
|
xmin, xmax, ymin, ymax, 2.0);
|
|
|
|
#else // !SHOWDXX
|
|
printf("Illuminant: Black - Measured, Red - with estimated UV\n");
|
|
|
|
if (bf.ill.spec_n > XSPECT_MAX_BANDS)
|
|
error("Got > %d spectral values (%d)",XSPECT_MAX_BANDS,bf.ill.spec_n);
|
|
|
|
for (j = 0; j < bf.ill.spec_n; j++) {
|
|
GCC_BUGFIX(j)
|
|
xx[j] = XSPECT_XWL(&bf.ill, j);
|
|
y1[j] = value_xspect(bf.i_sp, xx[j]); /* Measured (black) */
|
|
y2[j] = value_xspect(&bf.ill, xx[j]); /* Computed (red)*/
|
|
}
|
|
|
|
xmax = bf.ill.spec_wl_long;
|
|
xmin = bf.ill.spec_wl_short;
|
|
ymin = ymax = 0.0; /* let it scale */
|
|
do_plot_x(xx, y1, y2, NULL, bf.ill.spec_n, 1,
|
|
xmin, xmax, ymin, ymax, 2.0);
|
|
|
|
printf("Paper Reflectance: Black - Measured, Red - Initial FWA model, Green - FWA Final FWA model\n");
|
|
|
|
for (j = 0; j < bf.cpsp.spec_n; j++) {
|
|
GCC_BUGFIX(j)
|
|
xx[j] = XSPECT_XWL(&bf.cpsp, j);
|
|
y1[j] = value_xspect(&bf.srop, xx[j]); /* Measured reflectance (black) */
|
|
y2[j] = value_xspect(&cpisp, xx[j]); /* Computed initial reflectance (red) */
|
|
y3[j] = value_xspect(&bf.cpsp, xx[j]); /* Computed final reflectance (green) */
|
|
}
|
|
|
|
xmax = bf.cpsp.spec_wl_long;
|
|
xmin = bf.cpsp.spec_wl_short;
|
|
ymin = ymax = 0.0; /* let it scale */
|
|
do_plot_x(xx, y1, y2, y3, bf.cpsp.spec_n, 1,
|
|
xmin, xmax, ymin, ymax, 2.0);
|
|
|
|
#endif // !SHOWDXX
|
|
printf("%s illuminant with UV:\n",c == '5' ? "Averaged" : "Computed");
|
|
|
|
for (j = 0; j < ill.spec_n; j++) {
|
|
GCC_BUGFIX(j)
|
|
xx[j] = XSPECT_XWL(&ill, j);
|
|
y1[j] = value_xspect(&ill, xx[j]);
|
|
}
|
|
|
|
xmax = ill.spec_wl_long;
|
|
xmin = ill.spec_wl_short;
|
|
ymin = ymax = 0.0; /* let it scale */
|
|
do_plot_x(xx, y1, NULL, NULL, ill.spec_n, 1,
|
|
xmin, xmax, ymin, ymax, 2.0);
|
|
}
|
|
|
|
/* Make sure that the illuminant is re-measured for another reading */
|
|
i_sp.spec_n = 0;
|
|
r_sp.spec_n = 0;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (c == '7' || c == 0x3) { /* Exit */
|
|
break;
|
|
}
|
|
|
|
} /* Next command */
|
|
|
|
#ifdef DEBUG
|
|
printf("About to exit\n");
|
|
#endif
|
|
|
|
/* Free instrument */
|
|
if (it != NULL)
|
|
it->del(it);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|