summaryrefslogtreecommitdiff
path: root/spectro/illumread.c
diff options
context:
space:
mode:
Diffstat (limited to 'spectro/illumread.c')
-rw-r--r--spectro/illumread.c1232
1 files changed, 1232 insertions, 0 deletions
diff --git a/spectro/illumread.c b/spectro/illumread.c
new file mode 100644
index 0000000..282ec2f
--- /dev/null
+++ b/spectro/illumread.c
@@ -0,0 +1,1232 @@
+
+ /* Illuminant measurement utility */
+
+/*
+ * Argyll Color Correction 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. */
+
+/* Based on spotread.c */
+
+/*
+ TTBD:
+
+ Should add support for converting Spyder correction readings to ccmx.
+ (see SpyderDeviceCorrections.txt)
+
+ */
+
+#undef DEBUG /* Save measurements and restore them to outname_X.sp */
+ /*
+
+ outname_i.sp Illuminant spectrum
+ outname_r.sp Illuminant off paper spectrum
+ outname_p.sp Instrument measured paper reflectance spectrum
+ outname_mpir.sp Measured paper under illuminant spectrum
+ outname_cpir.sp Computed paper under illuminant spectrum
+
+ */
+
+#define 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 "xicc.h"
+#include "conv.h"
+#include "inst.h"
+#include "icoms.h"
+#include "instappsup.h"
+#include "plot.h"
+#include "spyd2setup.h" /* Enable Spyder 2 access */
+
+#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:",
+ it->inst_interp_error(it, ic), it->interp_error(it, ic));
+ fflush(stdout);
+ 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 */
+ 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;
+ xsp_setUV(&b->ill, b->i_sp, pv[0]);
+
+ /* Update the conversion */
+ 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]);
+
+//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;
+}
+
+/* ============================================================== */
+#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() {
+ 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 (setup_spyd2() == 2)
+ fprintf(stderr,"WARNING: This file contains a proprietary firmware image, and may not be freely distributed !\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]->itype == instSpyder2 && setup_spyd2() == 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," -W n|h|x Override serial port flow control: n = none, h = HW, x = Xon/Xoff\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 */
+ char outname[MAXNAMEL+1] = "\000"; /* Spectral output file name */
+#ifdef DEBUG
+ char tname[MAXNAMEL+11] = "\000", *tnp;
+ int rd_i = 0, rd_r = 0, rd_p = 0;
+#endif
+
+ 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();
+ setup_spyd2(); /* Load firware if available */
+
+ 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();
+
+ } 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();
+ comno = atoi(na);
+ if (comno < 1 || comno > 99) usage();
+
+ /* No initial calibration */
+ } else if (argv[fa][1] == 'N') {
+ nocal = 1;
+
+ /* High res mode */
+ } else if (argv[fa][1] == 'H') {
+ highres = 1;
+
+ /* Serial port flow control */
+ } else if (argv[fa][1] == 'W') {
+ fa = nfa;
+ if (na == NULL) usage();
+ 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();
+
+ } 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();
+ }
+ else
+ break;
+ }
+
+ /* Get the output spectrum file name argument */
+ if (fa >= argc)
+ usage();
+
+ strncpy(outname,argv[fa++],MAXNAMEL-1); outname[MAXNAMEL-1] = '\000';
+
+#ifdef DEBUG
+ strcpy(tname, outname);
+ if ((tnp = strrchr(tname, '.')) == NULL)
+ tnp = tname + strlen(tname);
+
+ /* Special debug */
+ strcpy(tnp, "_i.sp");
+ if (read_xspect(&i_sp, tname) == 0) {
+ rd_i = 1;
+ printf("(Found '%s' file and loaded it)\n",tname);
+ }
+ strcpy(tnp, "_r.sp");
+ if (read_xspect(&r_sp, tname) == 0) {
+ rd_r = 1;
+ printf("(Found '%s' file and loaded it)\n",tname);
+ }
+ strcpy(tnp, "_p.sp");
+ if (read_xspect(&p_sp, 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);
+ }
+#endif /* DEBUG */
+
+ /* 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) {
+ if (icmps == NULL)
+ icmps = new_icompaths(g_log);
+
+ /* Open the instrument */
+ if ((it = new_inst(icmps->get_path(icmps, comno), 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");
+ }
+
+ /* 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");
+ }
+ }
+ if (highres) {
+ if (IMODETST(cap, inst_mode_highres)) {
+ inst_code ev;
+ if ((ev = it->get_set_opt(it, inst_opt_highres)) != inst_ok) {
+ printf("!!! Setting high res mode failed with error :'%s' (%s) !!!\n",
+ it->inst_interp_error(it, ev), it->interp_error(it, ev));
+ }
+ } else if (verb) {
+ printf("!!! High resolution ignored - instrument doesn't support it !!!\n");
+ }
+ }
+ }
+
+ /* Check the instrument has the necessary capabilities for this measurement */
+ it->capabilities(it, &cap, &cap2, &cap3);
+
+ if (c == '1') {
+ if (IMODETST(cap, inst_mode_emis_ambient)) {
+ mode = inst_mode_emis_ambient;
+ } else if (IMODETST(cap, inst_mode_emis_spot)) {
+ mode = inst_mode_emis_spot;
+ } else {
+ printf("!!! Instrument doesn't have ambient or emissive capability !!!\n");
+ continue;
+ }
+ }
+ if (c == '2') {
+ if (IMODETST(cap, inst_mode_emis_tele)) {
+ mode = inst_mode_emis_tele;
+ } else if (IMODETST(cap, inst_mode_emis_spot)) {
+ 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 (IMODETST(cap, inst_mode_ref_spot)) {
+ 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 ((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 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 avilable 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);
+ 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 (IMODETST(cap, inst_mode_emis_ambient)) {
+ 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 (IMODETST(cap, inst_mode_emis_tele)) {
+ 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: ");
+ else
+ printf("Hit ESC or Q to abort, any any other key to take a reading: ");
+ fflush(stdout);
+
+ 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);
+ 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:"); fflush(stdout);
+ 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') {
+ i_sp = val.sp;
+#ifdef DEBUG
+ if (rd_i == 0) {
+ strcpy(tnp, "_i.sp");
+ write_xspect(tname,&i_sp);
+ }
+#endif
+ } else if (c == '2') {
+ r_sp = val.sp;
+#ifdef DEBUG
+ if (rd_r == 0) {
+ strcpy(tnp, "_r.sp");
+ write_xspect(tname,&r_sp);
+ }
+#endif
+ } else if (c == '3') {
+ p_sp = val.sp;
+
+ /* Get the illuminant spectrum too */
+ if (inst_illuminant(&insp, itype) != 0)
+ error ("Instrument doesn't have an FWA illuminent");
+
+#ifdef DEBUG
+ if (rd_p == 0) {
+ /* Should save instrument type/instrument illuminant spectrum !!! */
+ strcpy(tnp, "_p.sp");
+ write_xspect(tname,&p_sp);
+ }
+#endif
+ }
+
+ 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]->itype == instSpyder2 && setup_spyd2() == 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, &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, 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, &ill))
+ printf("\nWriting file '%s' failed\n",outname);
+ else
+ printf("\nWriting file '%s' succeeded\n",outname);
+#ifdef DEBUG
+ strcpy(tnp, "_mpir.sp"); // Measured paper under illuminant spectrum
+ write_xspect(tname,&bf.srop);
+ strcpy(tnp, "_cpir.sp"); // Computed paper under illuminant spectrum
+ write_xspect(tname,&bf.cpsp);
+#endif
+ }
+
+ /* 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, 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;
+}
+
+
+
+