# -*- coding: utf-8 -*-
"""
---
Title: Color Calibration with Mavo-Monitor USB
Date: 04-01-2018
Author: D.Cook
---
"""
# Import analysis modules
import pandas as pd
import numpy as np
# plot functions
import matplotlib as mpl
from matplotlib import mlab
from matplotlib import pyplot as plt
%matplotlib inline
Screen('LoadNormalizedGammaTable')
. dict
ionary below:colorCal = {"gamma":{"b":np.array([1.35, 1.36, 1.40, 1.48, 1.61, 1.79, 1.99, 2.32, 2.71, 3.23, 3.79,
4.59, 5.44, 6.55, 7.74, 9.47, 11.68, 14.3, 17.32, 19.40, 21.4]),
"g":np.array([1.35, 1.84, 2.65, 3.80, 5.40, 7.58, 9.94, 13.26, 17.10, 21.4, 25.9,
31.8, 38.5, 46.7, 56.0, 66.9, 79.9,92.6, 102.7, 113.9,127.5]),
"r":np.array([1.35, 1.38, 1.47, 1.62, 1.86, 2.21, 2.65, 3.30, 4.1, 5.09, 6.27, 7.77,
9.6, 11.87, 14.56, 18.20, 22.8, 27.9, 31.4, 35.5, 40.7])},
"noGamma": {"gr":np.array([1.35, 1.91, 2.88, 4.28, 6.26, 8.99, 12.0, 16.25, 21.2, 28.1, 36.5,
48.9, 57.8, 67.6, 78.0, 89.0, 103.1, 114.0, 120.3, 125.6, 130.1]),
"r":np.array([1.32, 1.35, 1.45, 1.61, 1.86, 2.21, 2.65, 3.3, 4.08, 5.08,6.27,
7.77, 9.61, 11.86, 14.56, 18.25, 22.9, 28.0, 31.4, 35.5, 40.8]),
"g":np.array([1.33, 1.83, 2.65, 3.80, 5.39, 7.57, 9.94, 13.26, 17.09, 21.4, 25.8,
31.7,38.5, 46.6, 56.0, 66.9, 80.2, 92.9, 103.0,114.1, 127.6]),
"b":np.array([1.33, 1.35, 1.40, 1.47, 1.61, 1.80, 2.00, 2.33, 2.72, 3.24, 3.79, 4.60, 5.46,
6.57, 7.74, 9.48, 11.67, 14.32,17.35, 19.44, 21.4])}}
We plot the results of two measurements from a Mavo-Monitor USB photometer. The $cd/m^2$ of the screen was read WITH and WITHOUT a CLUT for a gamma fit to orignal readings from a ColorCal MKII (see above).
# First, we create a color index from 0 for no color, to 256 for full brightness, with 21 even spaces.
ramp = np.linspace(0, 256, 21, dtype=int)
fig = plt.figure(figsize=(12, 3))
ax = plt.subplot(131);
ax.plot(ramp, colorCal['gamma']['r'], ".", color="r", linewidth=2);
ax.set_xlim([0, 260]);
ax.set_ylim([0, np.max(colorCal['gamma']['r'])]);
ax.set_ylabel(r'$cd/m^2$', size='xx-large');
ax = plt.subplot(132);
ax.plot(ramp, colorCal['gamma']['b'], ".", color="b", linewidth=2);
ax.set_xlim([0, 260]);
ax.set_ylim([0, np.max(colorCal['gamma']['b'])]);
ax.set_title("Screen('LoadNormalizedGammaTable') \n USED", size='x-large');
ax.set_xlabel(r'Color Index', size='x-large');
ax = plt.subplot(133);
ax.plot(ramp, colorCal['gamma']['g'], ".", color="g", linewidth=2);
ax.set_xlim([0, 260]);
ax.set_ylim([0, np.max(colorCal['gamma']['g'])]);
Figure 1. The $cd$/$m^2$ of the three guns of the CRT Monitor obtained with the Mavo-Monitor USB photometer. 22 color measurements were taken with the Gamma Table loaded. The photometer was positioned at the center of the screen, and the entire screen was set to one of the indexed color values. Read, blue, green dots show the measurements for the respective colors, etc.
fig = plt.figure(figsize=(12, 3))
ax = plt.subplot(141);
ax.plot(ramp, colorCal['noGamma']['r'], ".", color="r", linewidth=2);
ax.set_xlim([0, 260]);
ax.set_ylim([0, np.max(colorCal['noGamma']['r'])]);
ax.set_ylabel(r'$cd/m^2$', size='xx-large');
ax = plt.subplot(142);
ax.plot(ramp, colorCal['noGamma']['b'], ".", color="b", linewidth=2);
ax.set_xlim([0, 260]);
ax.set_ylim([0, np.max(colorCal['noGamma']['b'])]);
ax.set_title("Screen('LoadNormalizedGammaTable') \n NOT USED", size='x-large');
ax.set_xlabel(r'Color Index', size='x-large');
ax = plt.subplot(143);
ax.plot(ramp, colorCal['noGamma']['g'], ".", color="g", linewidth=2);
ax.set_xlim([0, 260]);
ax.set_ylim([0, np.max(colorCal['noGamma']['g'])]);
ax = plt.subplot(144);
ax.plot(ramp, colorCal['noGamma']['gr'], ".", color="black", linewidth=2);
ax.set_xlim([0, 260]);
ax.set_ylim([0, np.max(colorCal['noGamma']['gr'])]);
Figure 2. The $cd$/$m^2$ of the three guns of the CRT Monitor obtained with the Mavo-Monitor USB photometer. 22 color measurements were taken WITHOUT the Gamma Table loaded. The photometer was positioned at the center of the screen, and the entire screen was set to one of the indexed color values. Red, blue, green, grey dots show the measurements for the respective colors, etc.
ax = plt.subplot(111);
ax.plot(ramp, colorCal['gamma']['r'] - colorCal['noGamma']['r'], color='r');
ax.set_xlim([0, 256]);
ax.set_ylim([-0.5, 0.5]);
plt.plot(ramp, colorCal['gamma']['g'] - colorCal['noGamma']['g'], color='g');
plt.plot(ramp, colorCal['gamma']['b'] - colorCal['noGamma']['b'], color='b');
ax.set_title("ERROR", size='x-large');
ax.set_ylabel(r'$cd/m^2$', size='xx-large');
ax.set_xlabel(r'Color Index', size='x-large');
Figure 3. The difference between the $cd$/$m^2$ measurements for the the three guns of the CRT Monitor obtained with the Mavo-Monitor USB photometer with and without the Gamma Table loaded.
Using the Gamma table from the ColorCal MKII with Screen('LoadNormalizedGammaTable')
in PTB did not make a difference to the measurements with the Mavo-Monitor photmeter.
Possible causes:
colorCal['noGamma']
data¶The first CLUT did not make a difference to the luminance values obtained. Therefore, we re-fit curves to the readings from CRT monitor without the Gamma tables uploaded.
The data from colorCal['noGamma']
(see Python dict above) without Gamma tables uploaded was imported into Matlab, and the script below was run:
.m
% mavoRecording contains 21 cd/m^2 readings from a mavo photometer
% for the three guns of the CRT monitor
% the script produces pl
clear all
mavoRecording = {[1.32, 1.35, 1.45, 1.61, 1.86, 2.21, 2.65, 3.3, 4.08, 5.08,6.27, 7.77, 9.61, 11.86, 14.56, 18.25, 22.9, 28.0, 31.4, 35.5, 40.8],
[1.33, 1.83, 2.65, 3.80, 5.39, 7.57, 9.94, 13.26, 17.09, 21.4, 25.8, 31.7,38.5, 46.6, 56.0, 66.9, 80.2, 92.9, 103.0,114.1, 127.6],
[1.33, 1.35, 1.40, 1.47, 1.61, 1.80, 2.00, 2.33, 2.72, 3.24, 3.79, 4.60, 5.46,6.57, 7.74, 9.48, 11.67, 14.32,17.35, 19.44, 21.4]}
mavoColor={'RED', 'GREEN', 'BLUE'};
for Z = 1:3
colorCal.inputValues = mavoRecording{Z}
%colorCal.ramp = [0, 12, 25, 38, 51, 64, 76, 89, 102, 115, 128, 140, 153, 166, 179, 192, 204, 217, 230, 243, 256]
colorCal.rampNorm = [0. , 0.05, 0.1 , 0.15, 0.2 , 0.25, 0.3 , 0.35, 0.4 , 0.45, 0.5 , 0.55, 0.6 , 0.65, 0.7 , 0.75, 0.8 , 0.85,0.9 , 0.95, 1.]
colorCal.nMeasures = 21
colorCal.ramp = [0:1/(colorCal.nMeasures - 1):1];
colorCal.ramp(end) = 1;
screenBits = 8;
lumSteps = 2^screenBits;
colorCal.analysisMethods = {'pchipinterp';'smoothingspline';'cubicinterp';'splineinterp';'cubicspline'}
colorCal.canAnalyze = 1;
colorCal.displayRange = (max(colorCal.inputValues) - min(colorCal.inputValues));
colorCal.displayBaseline = min(colorCal.inputValues);
%Normalize values
colorCal.inputValuesNorm = (colorCal.inputValues - colorCal.displayBaseline)/(max(colorCal.inputValues) - min(colorCal.inputValues));
colorCal.rampNorm = colorCal.ramp;
%Gamma function fitting
g = fittype('x^g');
fo = fitoptions('Method','NonlinearLeastSquares',...
'Display','iter','MaxIter',1000,...
'Upper',3,'Lower',0,'StartPoint',1.5);
[fittedmodel, gof, output] = fit(colorCal.rampNorm',colorCal.inputValuesNorm',g,fo);
colorCal.displayGamma = fittedmodel.g;
colorCal.gammaTable{1} = ((([0:1/(lumSteps-1):1]'))).^(1/fittedmodel.g);
colorCal.modelFit{1}.method = 'Gamma';
colorCal.modelFit{1}.table = fittedmodel([0:1/(lumSteps-1):1]);
colorCal.modelFit{1}.gof = gof;
colorCal.modelFit{1}.output = output;
for i = 1:length(colorCal.analysisMethods)
method = colorCal.analysisMethods{i};
[fittedmodel,gof,output] = fit(colorCal.rampNorm',colorCal.inputValuesNorm', method);
colorCal.modelFit{i+1}.method = method;
colorCal.modelFit{i+1}.table = fittedmodel([0:1/(lumSteps-1):1]);
colorCal.modelFit{i+1}.gof = gof;
colorCal.modelFit{i+1}.output = output;
%Invert interpolation
[fittedmodel,gof] = fit(colorCal.inputValuesNorm',colorCal.rampNorm',method);
colorCal.gammaTable{i+1} = fittedmodel([0:1/(lumSteps-1):1]);
end
% ===================================================================
%> @brief plot
%> This plots the calibration results
% ===================================================================
colorCal.plotHandle = figure;
%colorCal.p = panel(colorCal.plotHandle,'defer');
scnsize = get(0,'ScreenSize');
pos=get(gcf,'Position');
%colorCal.p.pack(2,2);
%colorCal.p.margin = [15 20 5 15];
%colorCal.p.fontsize = 12;
%colorCal.p(1,1).select();
subplot(2,2,1)
plot(colorCal.ramp, colorCal.inputValues, 'k.-');
axis tight
xlabel('Indexed Values');
ylabel('Luminance cd/m^2');
title( strcat(mavoColor{Z}, ' Input -> Output Raw Data' ) );
%colorCal.p(1,2).select();
subplot(2,2,2)
hold all
for i=1:length(colorCal.modelFit)
plot([0:1/(lumSteps-1):1], colorCal.modelFit{i}.table);
legendtext{i} = colorCal.modelFit{i}.method;
end
plot(colorCal.rampNorm, colorCal.inputValuesNorm, 'r.')
legendtext{end+1} = 'Raw Data';
hold off
axis tight
xlabel('Normalised Luminance Input');
ylabel('Normalised Luminance Output');
legend(legendtext,'Location','NorthWest');
title(sprintf('Gamma model x^{%.2f} vs. Interpolation', colorCal.displayGamma));
legendtext=[];
subplot(2,2,3)
%colorCal.p(2,1).select();
hold all
for i=1:length(colorCal.gammaTable)
plot(1:length(colorCal.gammaTable{i}),colorCal.gammaTable{i});
legendtext{i} = colorCal.modelFit{i}.method;
end
hold off
axis tight
xlabel('Indexed Values')
ylabel('Normalised Luminance Output');
legend(legendtext,'Location','NorthWest');
title('Plot of output Gamma curves');
subplot(2,2,4)
%colorCal.p(2,2).select();
hold all
for i=1:length(colorCal.gammaTable)
plot(colorCal.modelFit{i}.output.residuals);
legendtext{i} = colorCal.modelFit{i}.method;
end
hold off
axis tight
xlabel('Indexed Values')
ylabel('Residual Values');
legend(legendtext,'Location','Best');
title('Model Residuals');
if scnsize(3) > 2000
scnsize(3) = scnsize(3)/2;
end
newpos = [scnsize(3)/2-scnsize(3)/3 1 scnsize(3)/1.5 scnsize(4)];
set(gcf,'Position',newpos);
if Z == 1
calibrationRed = colorCal.gammaTable
end
if Z == 2
calibrationGreen = colorCal.gammaTable
end
if Z == 3
calibrationBlue = colorCal.gammaTable
end
end
gammaCalib = [calibrationRed{1}, calibrationGreen{1}, calibrationBlue{1}]
pchipinterpCalib = [calibrationRed{2}, calibrationGreen{2}, calibrationBlue{2}]
smoothingsplineCalib = [calibrationRed{3}, calibrationGreen{3}, calibrationBlue{3}]
cubicinterpCalib = [calibrationRed{4}, calibrationGreen{4}, calibrationBlue{4}]
splineinterpCalib = [calibrationRed{5}, calibrationGreen{5}, calibrationBlue{5}]
cubicsplineCalib = [calibrationRed{6}, calibrationGreen{6}, calibrationBlue{6}]
csvwrite('gammaCalibration.csv', gammaCalib)
csvwrite('pchipinterpCalibration.csv', pchipinterpCalib)
csvwrite('smoothingsplineCalibration.csv', smoothingsplineCalib)
csvwrite('cubicinterpCalibration.csv', cubicinterpCalib)
csvwrite('splineinterpCalibration.csv', splineinterpCalib)
csvwrite('cubicsplineCalibration.csv', cubicsplineCalib)
Above Script. The Matlab script for analyzing photometric readings. This script produces 6 new CLUT tables, which are saved as .csv files, and the script outputs plots for inspecting.
The plots of the Gamma fit to the photometer measurements versus alternative fits are shown below.
from IPython.display import Image
Image('/Users/cookdj0128/Desktop/eegLab/GRAY OUTPUT.png')
Figure 4. Fits for the gray colors. 22 measurements were taken. The worst fits appear to be the SmoothingSpline, and the Gamma fit.
Image('/Users/cookdj0128/Desktop/eegLab/RED OUTPUT.png')
Image('/Users/cookdj0128/Desktop/eegLab/BLUE OUTPUT.png')
Figure 5. Fits for the blue colors. 22 measurements were taken. The worst fits appear to be the SmoothingSpline, and the Gamma fit.
Image('/Users/cookdj0128/Desktop/eegLab/GREEN OUTPUT.png')
Figure 6. Fits for the green colors. 22 measurements were taken. The worst fits appear to be the SmoothingSpline, and the Gamma fit.
import os
calibTables = [i for i in os.listdir(os.getcwd()) if i.endswith(".csv")]
fig, axes = plt.subplots(nrows=2, ncols=3, figsize=(14, 6), sharey=True)
df = pd.read_csv(calibTables[0], names=['red','green', 'blue'], index_col=False)
axes[0, 0].plot(np.linspace(0,256,256), df['red'].values,linewidth=2)
axes[0, 0].plot(np.linspace(0,256,256), df['green'].values,linewidth=2)
axes[0, 0].plot(np.linspace(0,256,256), df['blue'].values,linewidth=2)
axes[0, 0].set_ylabel('Normalized \n luminance output', size='x-large');
axes[0, 0].set_title(calibTables[0].replace(".csv",""), size='x-large');
df = pd.read_csv(calibTables[1], names=['red','green', 'blue'], index_col=False)
axes[0, 1].plot(np.linspace(0,256,256), df['red'].values,linewidth=2)
axes[0, 1].plot(np.linspace(0,256,256), df['green'].values,linewidth=2)
axes[0, 1].plot(np.linspace(0,256,256), df['blue'].values,linewidth=2)
axes[0, 1].set_title("Output Gamma Curves \n \n " +calibTables[1].replace(".csv",""), size='x-large');
df = pd.read_csv(calibTables[2], names=['red','green', 'blue'], index_col=False)
axes[0, 2].plot(np.linspace(0,256,256), df['red'].values,linewidth=2)
axes[0, 2].plot(np.linspace(0,256,256), df['green'].values,linewidth=2)
axes[0, 2].plot(np.linspace(0,256,256), df['blue'].values,linewidth=2)
axes[0, 2].set_title(calibTables[2].replace(".csv",""), size='x-large');
df = pd.read_csv(calibTables[3], names=['red','green', 'blue'], index_col=False)
axes[1, 0].plot(np.linspace(0,256,256), df['red'].values,linewidth=2)
axes[1, 0].plot(np.linspace(0,256,256), df['green'].values,linewidth=2)
axes[1, 0].plot(np.linspace(0,256,256), df['blue'].values,linewidth=2)
axes[1, 0].set_ylabel('Normalized \n luminance output', size='x-large');
axes[1, 0].set_title(calibTables[3].replace(".csv",""), size='x-large');
df = pd.read_csv(calibTables[4], names=['red','green', 'blue'], index_col=False)
axes[1, 1].plot(np.linspace(0,256,256), df['red'].values,linewidth=2)
axes[1, 1].plot(np.linspace(0,256,256), df['green'].values,linewidth=2)
axes[1, 1].plot(np.linspace(0,256,256), df['blue'].values,linewidth=2)
axes[1, 1].set_xlabel(r'Color Index', size='x-large');
axes[1, 1].set_title(calibTables[4].replace(".csv",""), size='x-large');
df = pd.read_csv(calibTables[5], names=['red','green', 'blue'], index_col=False)
axes[1, 2].plot(np.linspace(0,256,256), df['red'].values,linewidth=2)
axes[1, 2].plot(np.linspace(0,256,256), df['green'].values,linewidth=2)
axes[1, 2].plot(np.linspace(0,256,256), df['blue'].values,linewidth=2)
axes[1, 2].set_title(calibTables[5].replace(".csv",""), size='x-large');
Figure 7. The CLUT tables from the MATLAB script (above) ploted against the index of the row in the table.
The CubicSpline Calibration Table looks like it is a good fit. This table is available as a .csv file:
calibTables[5]
After fitting new curves to the colorCal['noGamma']
data above, we performed a new measurement on the monitor with the Gamma Clut uploaded to PTB.
A Mavo-Monitor USB photometer was used to re-measure the $cd/m^2$ of the CRT Monitor with the Gamma clut.
21 evenly spaced values of absolute red, green, blue and gray were presented on the screen using PsychToolBox. The RGB color values are given in the table of tuples, colorValues
(below).
Indexed colors were presented on the entire screen until a button was pressed. The Mavo-Monitor USB was positioned at the center of the screen, and measurements on the colored screen was taken twice.
We plot the results of the readings to assess linearity below.
mavoUSB = {"gamma":{"gr": np.array([1.37, 19.66, 34.1, 46.8, 55.5, 64.5, 71.6, 79.2, 87.1, 94.8, 101.0, 106.0, 110.1, 114.1, 116.6, 119.4, 122.3, 124.4,
126.9, 129.0, 130.4]),
"r": np.array([1.39, 5.88, 8.3, 10.64, 12.97, 15.43, 17.76, 20.3, 22.6, 25.2, 27.3, 28.8, 30.2, 31.5, 32.9, 34.1, 35.6, 37.1, 38.4, 39.7,
40.8]),
"g": np.array([1.38, 12.42, 19.38, 26.3, 32.7, 39.1, 45.4, 52.6, 59.8, 66.9, 73.6, 80.9, 88.1, 94.1, 98.6, 103.6, 108.9,
113.4, 118.7, 124.2, 128.7]),
"b": np.array([1.34, 3.82, 5.07, 6.3, 7.4, 8.58, 9.74, 10.9, 11.98, 13.17, 14.35, 15.6, 16.7, 17.7, 18.3, 18.98, 19.51,
20.0, 20.4, 21.0, 21.5])}}
# the table of colors that were used with the gamma clut:
colorValues = {"rValues_normed": [], "gValues_normed": [], "bValues_normed": [],
"rValues": [], "gValues": [], "bValues": []}
for i in list(np.linspace(0, 1, 21)):
colorValues['rValues_normed'].append((float(str(i)[0:4]), 0, 0))
colorValues['gValues_normed'].append((0, float(str(i)[0:4]), 0))
colorValues['bValues_normed'].append((0, 0, float(str(i)[0:4])))
for i in np.linspace(0, 255, 21, dtype=int):
colorValues['rValues'].append((i,0,0))
colorValues['gValues'].append((0,i,0))
colorValues['bValues'].append((0,0,i))
colorValues = pd.DataFrame(colorValues)
colorValues.head()
def giveRange(x):
return np.max(x) - np.min(x)
fig = plt.figure(figsize=(12, 3))
ax = plt.subplot(141);
ax.plot(ramp, mavoUSB['gamma']['r'], ".", color="r", linewidth=2);
ax.plot(range(0,256), np.linspace(0,giveRange(mavoUSB['gamma']['r']),256), 'r')
ax.set_xlim([-10, 260]);
ax.set_ylim([0, np.max(mavoUSB['gamma']['r'])]);
ax.set_ylabel(r'$cd/m^2$', size='xx-large');
ax = plt.subplot(142);
ax.plot(ramp, mavoUSB['gamma']['b'], ".", color="b", linewidth=2);
ax.plot(range(0,256), np.linspace(0,giveRange(mavoUSB['gamma']['b']),256), 'b')
ax.set_xlim([-10, 260]);
ax.set_ylim([0, np.max(mavoUSB['gamma']['b'])]);
ax.set_title("Screen('LoadNormalizedGammaTable') \n USED", size='x-large');
ax.set_xlabel(r'Color Index', size='x-large');
ax = plt.subplot(143);
ax.plot(ramp, mavoUSB['gamma']['g'], ".", color="g", linewidth=2);
ax.plot(range(0,256), np.linspace(0,giveRange(mavoUSB['gamma']['g']),256), 'g')
ax.set_xlim([-10, 260]);
ax.set_ylim([0, np.max(mavoUSB['gamma']['g'])]);
ax = plt.subplot(144);
ax.plot(ramp, mavoUSB['gamma']['gr'], ".", color="black", linewidth=2);
ax.plot(range(0,256), np.linspace(0,giveRange(mavoUSB['gamma']['gr']),256), 'black')
ax.set_xlim([-10, 260]);
ax.set_ylim([0, np.max(mavoUSB['gamma']['gr'])]);
Figure 8. Uploading a Gamma Clut fit from the colorCal['noGamma']
data nearly linearizes the guns of the CRT monitor. A linear plot of the range of luminance for the screen is shown in solid line. Dots show the measurements taken for the 21 values.
fig = plt.figure(figsize=(12, 3))
ax = plt.subplot(141);
ax.plot(ramp, colorCal['noGamma']['r'], ".", color="r", linewidth=2);
ax.plot(ramp, mavoUSB['gamma']['r'], "-", color="r", linewidth=2);
ax.set_xlim([0, 260]);
ax.set_ylim([0, np.max(colorCal['noGamma']['r'])]);
ax.set_ylabel(r'$cd/m^2$', size='xx-large');
ax = plt.subplot(142);
ax.plot(ramp, colorCal['noGamma']['b'], ".", color="b", linewidth=2);
ax.plot(ramp, mavoUSB['gamma']['b'], "-", color="b", linewidth=2);
ax.set_xlim([0, 260]);
ax.set_ylim([0, np.max(colorCal['noGamma']['b'])]);
ax.set_title("Screen('LoadNormalizedGammaTable') \n NOT USED", size='x-large');
ax.set_xlabel(r'Color Index', size='x-large');
ax = plt.subplot(143);
ax.plot(ramp, colorCal['noGamma']['g'], ".", color="g", linewidth=2);
ax.plot(ramp, mavoUSB['gamma']['g'], "-", color="g", linewidth=2);
ax.set_xlim([0, 260]);
ax.set_ylim([0, np.max(colorCal['noGamma']['g'])]);
ax = plt.subplot(144);
ax.plot(ramp, colorCal['noGamma']['gr'], ".", color="black", linewidth=2);
ax.plot(ramp, mavoUSB['gamma']['gr'], "-", color="black", linewidth=2);
ax.set_xlim([0, 260]);
ax.set_ylim([0, np.max(colorCal['noGamma']['gr'])]);
Figure 9. Uploading a Gamma Clut fit from the colorCal['noGamma']
data nearly linearizes the guns of the CRT monitor. The linearized readings of the luminance for the screen are shown with a solid line. Dots show the measurements taken for the 21 values without the CLUT uploaded.