Stefan Döhla schrieb:

b.t.w.: does someone know about spectrophotometers or colorimeters
that have a complete interfacing description (maybe even source code)?

For instance X-Rite DTP41 and DTP51, or GretagMacbeth Spectrolino/Spectroscan. Code examples see Argyll source code.

Avantes also provides a freely available Linux SDK for its Spectrocam. I've written the attached small program to make semi-automatic monitor measurements with Spectrocam under Linux (sorry, no nice user interface, just a quick and dirty hack - and black calibration is still missing).

-Gerhard

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <unistd.h>

#include <specstar.h>

static char *device = "/dev/ttyS0";

static void
initialize(void)
{
    SpcErrors ok;
    HANDLE serial_handle;
 
    serial_handle = SpectroCam_Open_Serial(device);
    if (serial_handle == INVALID_HANDLE_VALUE) {
        fprintf(stderr, "Cannot open %s\n", device);
        exit(1);
    }

    if (SpectroCam_Init(0, serial_handle, 1, &ok) == NULL) {
        fprintf(stderr, "SpectroCam_Init failed: %s\n",
                SpectroCam_ErrorString(ok));
        exit(1);
    }
}

static SpcErrors
measure_integration(MONITOR_CALIBRATION *moni)
{
    SpcErrors ok = ERR_OK;
    SPC_MEASURE_OPTIONS M;
    DATA_MEASURED dm;
    double FreqTime;
    word I;

    FreqTime = moni->FreqTime = 1000.0 / moni->ScreenFrequency;

    M.UseDefaults = FALSE;
    M.Flash = M.Flashes = 0;
    M.Store = 1;
    M.Data =  &dm;
    M.AvrCnt = 1;
    M.Deconvolution = 0;        //SPC_DECONVOLUTION_NONE;
    M.SpectrumMode = 0;         //SM_ALLPIXELS;
    M.Illuminant = ILLUMINANT_D65;
    M.Observer = OBSERVER_2;
    M.MeasureMode = SPC_MM_EMISSION_LENS;
    NextIT(NULL, 0);            // reset integration routine
    M.Integration = moni->IntegrationTime;

    while(1) {
        ok = SpectroCam_ExecuteRequest(SPC_REQUEST_MEASURE,(int)&M);
        if(ok != ERR_OK && ok != ERR_OVERFLOW)
            goto done;
        I = NextIT(&dm, FreqTime);
        printf("Time: %3d => %3.2fmSec Level: %.1f\n",
            M.Integration, IT2mSec(M.Integration), dm.MaxRaw);
        if((word)M.Integration == I)
            break;
        M.Integration = (word)I;
    }
    moni->IntegrationTime = M.Integration;
done:
    if(ok != ERR_OK) {
        printf("Spectrocam returned: %s\n", SpectroCam_ErrorString(ok));
        SpectroCam_Exit();
        exit(1);
    }
    return ok;
}

static void
measure_moni(const char *datafile)
{
    int N = 1000;
    int i;
    SpcErrors ok;
    FILE *f, *data;
    char line[256];
    DATA_MEASURED dm;
    SPC_MEASURE_OPTIONS M;
    MONITOR_CALIBRATION Moni;
    double Ywhite;

    if ((data = fopen(datafile, "r")) == NULL) {
        perror(datafile);
        SpectroCam_Exit();
        exit(1);
    }

    f = popen("wish", "w");
    fprintf(f, "frame .f -width 480 -height 640 -background #ffffff\n");
    fprintf(f, "pack .f\n");
    fflush(f);

    printf("place on white area and press return>");
    fflush(stdout);
    gets(line);

    Moni.IntegrationTime = 1;
    Moni.ScreenFrequency = 1000;
    measure_integration(&Moni);

#if 1
    printf("Measuring frequency...\n");
    ok = SpectroCam_ExecuteRequest(SPC_REQUEST_FREQUENCY,(int)&Moni);
    if(ok != ERR_OK) {
        printf("Spectrocam returned: %s\n", SpectroCam_ErrorString(ok));
        SpectroCam_Exit();
        exit(1);
    }
    printf("Frequency measured: %.1f Hz\n", Moni.ScreenFrequency);
#endif

    for (i = 0; i < N; i++) {
        int rgb[3];
        fscanf(data, "%d", &rgb[0]);
        fscanf(data, "%d", &rgb[1]);
        fscanf(data, "%d", &rgb[2]);

        fprintf(f, ".f configure -background #%02x%02x%02x\n",
            rgb[0], rgb[1], rgb[2]);
        fflush(f);

        usleep(200000);

        M.MeasureMode = SPC_MM_EMISSION_LENS;
        M.UseDefaults = FALSE;
        M.SpectrumMode = SM_FASTSPECTRUM;
        M.Store = 1;
        M.Measured = 0;
        M.Illuminant = ILLUMINANT_D50; // don't care is not used
        M.Observer = OBSERVER_2;
        M.Type = 0;                     // average/continuous/long
        M.Function = 0;                 // normal/fast/multiple
        M.Deconvolution = SPC_DECONVOLUTION_20NM;
        M.Timeout = 0;
        M.Flashes = 0;
        M.Flash = FALSE;
        M.Freq = 0;
        M.Integration = Moni.IntegrationTime; // mSec2IT(Time_in_milliseconds);
        M.AvrCnt = 4;
        M.Data = &dm;
        ok = SpectroCam_ExecuteRequest(SPC_REQUEST_MEASURE,(int)&M);
#if 0
        if (ok == ERR_OVERFLOW)
            continue;
#endif
        if(ok != ERR_OK) {
            printf("Spectrocam returned: %s\n", SpectroCam_ErrorString(ok));
            SpectroCam_Exit();
            exit(1);
        }
        if (i == 0) {
            Ywhite = dm.Cie.XYZ.Y / 100.0;
            printf("Luminance=%f\n", dm.Cie.XYZ.Y);
        }
        dm.Cie.XYZ.X /= Ywhite;
        dm.Cie.XYZ.Y /= Ywhite;
        dm.Cie.XYZ.Z /= Ywhite;
        if (i == 0)
            printf("DMIN ");
        else
            printf("A%d ", i);
        printf("%f %f %f  %f %f %f  %f\n",
            rgb[0]/2.55, rgb[1]/2.55, rgb[2]/2.55,
            dm.Cie.XYZ.X, dm.Cie.XYZ.Y, dm.Cie.XYZ.Z,
            SpectroCam_ColorTemperature(dm.Cie.xyuv.u, dm.Cie.xyuv.v));
        fflush(stdout);
    }
    fprintf(f,"exit\n");
}

int
main(int ac, char **av)
{
    SpcErrors ok;
    char line[256];
    MONITOR_CALIBRATION Moni;
    Moni.ScreenFrequency = 100;

    initialize();
    measure_moni(av[1]);
    SpectroCam_Exit();
    exit(0);
}

Reply via email to