Check your blue color intensity calibration with CooRecorder 8.1

Last update: 26 January 2016

Please note: You do not need the full version of CooRecorder 8.1 to check your scanner calibration as described below.
This test can be done also with the TRIAL version of CooRecorder 8.1.

The TRIAL version is available here.
(Opens in a new window. Click the word "try" in the header to find the download link!)

Blue color intensity (CI) values can be read from a tree ring image created with an inexpensive flatbed scanner. Such values have proved to correlate with both density measurements and temperature data. Though question is if these CI values are always relative to something or if they can be made absolute, i.e. calibrated.

Within the color printing industry, scanners, screens and printing machines have since long been calibrated to achieve consistent and expected results. I.e. so that a photograpic image can be scanned  on any calibrated scanner and then printed on any calibrated printer giving a printed image that looks as near as posssible to the original photographic image.

For calibration of scanners, IT8.7/2 calibration cards are used together with a datafile containing colorimetric data read from that card (or from a copy out of the same batch of cards). With the help of special software like e.g. Lasersoft's "Silverfast" a color calibration procedure can then be performed.

We would expect that if we then scan that same IT8.7/2 calibration card again on that same scanner, then we should get an image that complies with the colorimetric data given for that card. This might be a way to check the quality of the calibration.

Using CooRecorder to check color calibration

For this example we have used an Epson Perfection V750 Pro scanner calibrated with Silverfast.
The IT8.7/2 calibration card comes from Wolf Faust at who is selling affordable calibration cards.

Note: If you are using Silverfast, then consider to buy also your calibration cards from The Silverfast calibration cards have a bar code telling what card it is, so that Silverfast can easily look up the right datafile for this batch of cards. When using cards of other manufacture, you have to tell Silverfast what data file to use.

After calibrating your scanner and after rescanning your IT8.7/2 calibration card you should open that image in CooRecorder. See that you select "Raw data, normal is 1 point per group". Then set out four points as shown above and then save that .pos file.
Then make CooRecorder start analyzing your IT8.7/2 calibration card image by issuing the command highlighted in violet above.
CooRecorder will first ask for the datafile containing colorimetric data read from that IT8.7/2 card. CooRecorder will then convert the XYZ data in that file to RGB data. In case you would like to inspect that data, it is placed together with the other data into a .tmp file. A message will tell you where to find it.
Based on the positions of your four measurement points, CooRecorder will calculate where to collect data for all color spots. If all these frames are properly positioned as shown above, then click OK. On the other hand, if any frames are positioned so that they cover more than one color spot, then you have to click Cancel, adjust your measurement points and start over again. If your image is not properly aligned you may even have to make a more careful scan.
CooRecorder will now calculate three "calibration points" for each color spot. Each such point is represented by a data pair consisting of the color value read from the spot and the corresponding colorimetrically read value according to the colorimetric data file for that IT8.7/2 card. You will be prompted for a file name for these points.
CooRecorder will now automatically issue the menu command CI-Measurements/Create or load calibration curve which opens the CI calibration curve window. Do open the calibration points file you saved above.

If the scanner had been exactly calibrated all these points should be positioned on a straight line going from (0,0) to (255,255). This is not exactly the case above. Especially the dark blue colors (lower left corner) are too light so they should be made somewhat darker to comply with the data in the colorimetric data file of the IT8.7/2 card. The spreading out of dark blue data points is a bit annoying as we are especially interested in the dark blue values representing latewood blue color intensity.

As shown in the diagram, CooRecorder has calculated a mean value curve for these points based on a polynomial fit function. Such a curve can be used to adjust the blue CI values read from the image. The curve can also be used to adjust the image itself.

For practical blue CI measurements and in this case when already using reasonably good calibration with Silverfast, there is no need for an extra calibration step using CooRecorder.

There are also a green and a red diagram. Green points comply reasonably well to what is found in the colorimetric IT8.7/2 data file. But red looks a mess... This spreading out of points might be caused by the difficulty of creating an exact calibration mechanism. It should then be noted that normal color calibration aims at creating new colors that are perceived by human beings as being equal to the original colors. There exist color combinations that are perceived the same though the individual color components are different. Colors that match that way are called metamers, see Wikipedia on Metamerism. Accordingly, available color calibration mechanisms for e.g. scanners are not built for scientific measurement purposes but to adapt to human perception. If we nevertheless want to use them for scientific measurements, we probably have to use them as they are...

Details on XYZ to RGB conversion

These algorithms were found at under the heading "Color math/formulas":
//XYZ > RGB 
var_X = X / 100        //X from 0 to  95.047      (Observer = 2, Illuminant = D65) 
var_Y = Y / 100        //Y from 0 to 100.000 
var_Z = Z / 100        //Z from 0 to 108.883 
var_R = var_X *  3.2406 + var_Y * -1.5372 + var_Z * -0.4986 
var_G = var_X * -0.9689 + var_Y *  1.8758 + var_Z *  0.0415 
var_B = var_X *  0.0557 + var_Y * -0.2040 + var_Z *  1.0570 
if ( var_R > 0.0031308 ) var_R = 1.055 * ( var_R ^ ( 1 / 2.4 ) ) - 0.055 
else                     var_R = 12.92 * var_R 
if ( var_G > 0.0031308 ) var_G = 1.055 * ( var_G ^ ( 1 / 2.4 ) ) - 0.055 
else                     var_G = 12.92 * var_G 
if ( var_B > 0.0031308 ) var_B = 1.055 * ( var_B ^ ( 1 / 2.4 ) ) - 0.055 
else                     var_B = 12.92 * var_B 
R = var_R * 255 
G = var_G * 255 
B = var_B * 255 
Implemented in CooRecorder as:
    Public Class CCmatrix 
        Public m(0 To 2, 0 To 2) As Double 
    End Class 
    Public D65TosRGB, D50TosRGB As CCmatrix 
    Public Sub setupConversionMatrixes() 
        D65TosRGB = New CCmatrix : D50TosRGB = New CCmatrix 
        With D65TosRGB   'see (see srgb.pdf file in ./dok directory 
            .m(0, 0) = 3.2406 : .m(0, 1) = -1.5372 : .m(0, 2) = -0.4986 
            .m(1, 0) = -0.9689 : .m(1, 1) = 1.8758 : .m(1, 2) = 0.0415 
            .m(2, 0) = 0.0557 : .m(2, 1) = -0.204 : .m(2, 2) = 1.057 
        End With 
        With D50TosRGB  ' 
            .m(0, 0) = 3.1338561 : .m(0, 1) = -1.6168667 : .m(0, 2) = -0.4906146 
            .m(1, 0) = -0.9787684 : .m(1, 1) = 1.9161415 : .m(1, 2) = 0.033454 
            .m(2, 0) = 0.0719453 : .m(2, 1) = -0.2289914 : .m(2, 2) = 1.4052427 
        End With 
    End Sub 
    Public Function XYZ_To_RGB(ByVal X As Double, ByVal Y As Double, ByVal Z As Double, ByRef R As Double, ByRef G As Double, ByRef B As Double) As Boolean 
        Dim result As Boolean = False 
        On Error GoTo atExit 
        If D50TosRGB Is Nothing Then setupConversionMatrixes() 
        Dim ccM As CCmatrix 
        If p_CI_CalibrationTargetCardIsD50 Then 
            ccM = D50TosRGB 
            ccM = D65TosRGB 
        End If 
        Dim var_X As Double = X / 100        'X from 0 to  95.047      (Observer = 2°, Illuminant = D65) 
        Dim var_Y As Double = Y / 100        'Y from 0 to 100.000 
        Dim var_Z As Double = Z / 100        'Z from 0 to 108.883 
        Dim var_R, var_G, var_B As Double 
        With ccM 
            var_R = var_X * .m(0, 0) + var_Y * .m(0, 1) + var_Z * .m(0, 2) 
            var_G = var_X * .m(1, 0) + var_Y * .m(1, 1) + var_Z * .m(1, 2) 
            var_B = var_X * .m(2, 0) + var_Y * .m(2, 1) + var_Z * .m(2, 2) 
        End With 
        If (var_R > 0.0031308) Then var_R = 1.055 * (var_R ^ (1 / 2.4)) - 0.055 Else var_R = 12.92 * var_R 
        If (var_G > 0.0031308) Then var_G = 1.055 * (var_G ^ (1 / 2.4)) - 0.055 Else var_G = 12.92 * var_G 
        If (var_B > 0.0031308) Then var_B = 1.055 * (var_B ^ (1 / 2.4)) - 0.055 Else var_B = 12.92 * var_B 
        R = var_R * 255 : If R < 0 Then R = 0 'seems to be missing in the specification at 
        G = var_G * 255 : If G < 0 Then G = 0 'though apparently their Color calculator has implemented this test on zero. 
        B = var_B * 255 : If B < 0 Then B = 0 
        result = True 
atExit: Return result 
    End Function 

Copyright 2016, Cybis Elektronik & Data AB,