## Python 2.7 code

The “Synth” Python 2.7 library: colorimetric tools for raster-based generative drawings or prints:

Requires Numpy and Scipy

Any optimization would be appreciated :)

''' Created on 27 oct. 2014 @author: gary copyright (C) Adrien Lucca, 2014</pre> <pre>This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.</pre> <pre> ''' import numpy as np import math as m import scipy.spatial def delaunay(XYZ, SITE): """returns: tri, indices, vertices""" # Compute Delaunay tetrahedralization of the points tri = scipy.spatial.Delaunay(XYZ, furthest_site=SITE) # indices of vertices indices = tri.simplices # vertices for each tetrahedron vertices = XYZ[indices] print "- tetrahedralization OK" return tri, indices, vertices def load_RGB_XYZ(COLOURS_FILENAME): # Color list: RGB and XYZ values RGB = np.loadtxt(COLOURS_FILENAME, dtype = 'int', delimiter = ',', usecols = [0,1,2]) XYZ = np.loadtxt(COLOURS_FILENAME, delimiter = ',', usecols = [3,4,5]) print "Colors loaded from file:", COLOURS_FILENAME return RGB, XYZ def make_pbm(tri,image,RGB,filename_pbm,width,height): # compute the data ##################################################################### # Find the tetrahedron containing each target (or -1 if not found) tet = tri.find_simplex(image) # Affine transformation for tetrahedron containing each target U = tri.transform[tet, :3] # Offset of each target from the origin of its containing tetrahedron V = image - tri.transform[tet, 3] # Barycentric coordinates of each target in its tetrahedron. b = np.einsum('ijk,ik->ij', U, V) bcoords = np.c_[b, 1 - b.sum(axis=1)] # Get the sRGB colors corresponding to each vertex C = RGB[tri.simplices] # A uniform random number in [0, 1] for each target. RAND = np.random.uniform(0, 1, size=(len(image))) ##################################################################### # make the image file # http://stackoverflow.com/questions/24318486/use-numpy-random-for-fast-random-selection # get the number of rows: N = len(tet) # cumulative probabilities cumprobs = np.cumsum(bcoords, axis=1) # color indices cidx = np.zeros(N) # compare the color indices to the random vector r cidx[RAND > cumprobs[:,0]] = 1 cidx[RAND > cumprobs[:,1]] = 2 cidx[RAND > cumprobs[:,2]] = 3 rgb_data = [] for i in range(N): number = cidx[i] rgb = C[tet[i]] rgb = rgb[number] rgb_data += [rgb] rgb_data = np.array(rgb_data) np.savetxt(filename_pbm, rgb_data, fmt='%i', delimiter=' ', header='P3'+'\n'+str(width)+' '+str(height)+'\n'+'255'+'\n', comments='') print "done, isn't numpy amazing? :D" def trunc(f, n): '''Truncates/pads a float f to n decimal places without rounding http://stackoverflow.com/questions/783897/truncating-floats-in-python''' slen = len('%.*f' % (n, f)) return str(f)[:slen] def iround(x): """iround(number) -> integer Round a number to the nearest integer. http://www.daniweb.com/software-development/python/threads/299459/round-to-nearest-integer""" return int(round(x) - .5) + (x > 0) # make light events all separated, they are all the size of a canvas (identical size makes them add-able) def Spectrum_XYZ(CMF,planck,wave_start,wave_end,steps): """makes a normalized (Y_max) set of XYZ colours in a given range and number of steps returns a numpy array""" # make a spectrum Spectrum_XYZ = [] for i in range(len(CMF)): XYZ = CMF[i][0]*planck[i], CMF[i][1]*planck[i], CMF[i][2]*planck[i] Spectrum_XYZ += [XYZ] Spectrum_XYZ = np.array(Spectrum_XYZ) Spectrum_XYZ = np.divide(Spectrum_XYZ, np.max(Spectrum_XYZ[:,1])) print "spectrum built" return np.array(Spectrum_XYZ) def Circular_cumsum_spot(width,height,centre,radius,spectrum,red_or_violet): """makes a "tache de lumiere" by cumsums from the center to the periphery width, height = size of canvas x, y = center of the spot radius = magnitude of the spot in pixels spectrum = light source red = to red, violet = to violet returns a numpy array""" x,y = centre[0], centre[1] data = [] X = Y = Z = 0 for i in range(height): for j in range(width): distance = radius - np.sqrt((i-x)**2+(j-y)**2) if distance >= radius: cumsum = 0 X = Y = Z = 0 else: cumsum = iround((distance/radius) * (len(spectrum))) if red_or_violet == "red" or red_or_violet == "Red" or red_or_violet == "RED": for k in range(cumsum): X += spectrum[k][0] Y += spectrum[k][1] Z += spectrum[k][2] else: for k in range(cumsum): l = len(spectrum)-k-1 X += spectrum[l][0] Y += spectrum[l][1] Z += spectrum[l][2] data += [(X,Y,Z)] X = Y = Z = 0 data = np.array(data) divisor = np.max(data[:,1]) if divisor == 0: data = data else: data = np.divide(data, divisor) return data print "spot created is", red_or_violet def Gradient_lightness76(CMF, Illuminant, tri, width, height): """makes a neutral-grey gradient (often for a "background") within the gamut of the provided colour collection from dark to light VERTICAL! (from top to bottom) CMF, Illuminant > should have same length! tri >> tetrahedralization width, height = size of canvas min,max - optional - to change the range returns a numpy array""" Background_XYZ = [] neutral = Neutral(CMF, Illuminant) min_max_range = L_min_max_range(neutral, tri) L_min = min_max_range[0] L_range = min_max_range[2] L_step = (L_range - 0.02) / (height-1) # 0.02 prevents errors for i in range(height): L76 = L_min + 0.01 + i * L_step Y = LCH_to_XYZ(L76, 0, 1, neutral)[1] XYZ = Y * neutral[0] / 100, Y * neutral[1] / 100, Y * neutral[2] / 100 for j in range(width): Background_XYZ += [XYZ] Background_XYZ = np.array(Background_XYZ) return Background_XYZ def black_bg(CMF, Illuminant, tri, width, height): Background_XYZ = [] neutral = Neutral(CMF, Illuminant) min_max_range = L_min_max_range(neutral, tri) L_min = min_max_range[0] Y = LCH_to_XYZ(L_min, 0, 1, neutral)[1] XYZ = Y * neutral[0] / 100, Y * neutral[1] / 100, Y * neutral[2] / 100 for i in range(height): for j in range(width): Background_XYZ += [XYZ] Background_XYZ = np.array(Background_XYZ) return Background_XYZ def wavelengths(steps, wave_start, wave_end): """list of wavelengths""" Wavelengths = [] for i in range(steps): Wavelengths += [wave_start + i * (wave_end-wave_start)/steps] Wavelengths = np.array(Wavelengths) return Wavelengths def wavelengths_float(steps, wave_start, wave_end): """list of wavelengths""" SSSS = steps steps, wave_start, wave_end = float(steps), float(wave_start), float(wave_end) Wavelengths = [] for i in range(SSSS): Wavelengths += [wave_start + i * (wave_end-wave_start)/steps] Wavelengths = np.array(Wavelengths) return Wavelengths def projected_light(width,height,centre,CMF,Illuminant): x,y = centre[0], centre[1] neutralXYZ = Neutral(CMF, Illuminant) XYZ = [] for i in range(height): for j in range(width): distance = np.sqrt((i-x)**2+(j-y)**2) if distance == 0: XYZ += [[neutralXYZ]] else: XYZ += [np.multiply(neutralXYZ, 1/distance**2)] XYZ = np.array(XYZ) data = XYZ divisor = np.max(data[:,1]) if divisor == 0: data = data else: data = np.divide(data, divisor) return data print "light created" def L_min_max_range(Neutral, tri): """solver to find L76 min and max in a colour collection""" # minimal/maximal Y/L76 neutral value solver Y_max, Y_min = 100, 0 step_min = step_max = 50.0 iterations = 30 while iterations > 0: iterations += -1 test_max = [Neutral[0]/Neutral[1]*Y_max, Neutral[1]/Neutral[1]*Y_max, Neutral[2]/Neutral[1]*Y_max] test_max = np.array(test_max) # Find the tetrahedron containing each target (or -1 if not found) tet_max = tri.find_simplex(test_max) if tet_max == -1: Y_max += - step_max step_max = step_max / 2 else: Y_max += step_max step_max = step_max / 2 test_min = [Neutral[0]/Neutral[1]*Y_min, Neutral[1]/Neutral[1]*Y_min, Neutral[2]/Neutral[1]*Y_min] test_min = np.array(test_min) # Find the tetrahedron containing each target (or -1 if not found) tet_min = tri.find_simplex(test_min) if tet_min == -1: Y_min += step_min step_min = step_min / 2 else: Y_min += - step_min step_min = step_min / 2 while tet_max == -1: Y_max -= 0.00001 test_max = [Neutral[0]/Neutral[1]*Y_max, Neutral[1]/Neutral[1]*Y_max, Neutral[2]/Neutral[1]*Y_max] test_max = np.array(test_max) # Find the tetrahedron containing each target (or -1 if not found) tet_max = tri.find_simplex(test_max) print "*", while tet_min == -1: Y_min += 0.00001 test_min = [Neutral[0]/Neutral[1]*Y_min, Neutral[1]/Neutral[1]*Y_min, Neutral[2]/Neutral[1]*Y_min] test_min = np.array(test_min) # Find the tetrahedron containing each target (or -1 if not found) tet_min = tri.find_simplex(test_min) print "#", L_min, L_max = XYZ_to_LAB(1, Y_min, 1, Neutral)[0], XYZ_to_LAB(1, Y_max, 1, Neutral)[0] L_range = L_max - L_min return L_min, L_max, L_range def Neutral(CMF, Illuminant): x = np.multiply(CMF[:,0], Illuminant) y = np.multiply(CMF[:,1], Illuminant) z = np.multiply(CMF[:,2], Illuminant) y = np.sum(y) x = 100*np.sum(x)/y z = 100*np.sum(z)/y Neutral = x, 100, z return Neutral def CMF_2006_2deg(wave_start, wave_end, steps): CMF = [[389,0,0,0], [390,3.77E-03,4.15E-04,1.85E-02 ], [391,4.53E-03,5.03E-04,2.22E-02 ], [392,5.45E-03,6.08E-04,2.67E-02 ], [393,6.54E-03,7.34E-04,3.21E-02 ], [394,7.84E-03,8.84E-04,3.85E-02 ], [395,9.38E-03,1.06E-03,4.61E-02 ], [396,1.12E-02,1.27E-03,5.51E-02 ], [397,1.33E-02,1.50E-03,6.58E-02 ], [398,1.59E-02,1.78E-03,7.82E-02 ], [399,1.88E-02,2.10E-03,9.28E-02 ], [400,2.21E-02,2.45E-03,1.10E-01 ], [401,2.60E-02,2.85E-03,1.29E-01 ], [402,3.04E-02,3.30E-03,1.51E-01 ], [403,3.54E-02,3.80E-03,1.76E-01 ], [404,4.11E-02,4.35E-03,2.05E-01 ], [405,4.74E-02,4.97E-03,2.37E-01 ], [406,5.45E-02,5.66E-03,2.73E-01 ], [407,6.22E-02,6.42E-03,3.12E-01 ], [408,7.07E-02,7.25E-03,3.55E-01 ], [409,7.98E-02,8.14E-03,4.01E-01 ], [410,8.95E-02,9.08E-03,4.51E-01 ], [411,9.97E-02,1.01E-02,5.03E-01 ], [412,1.10E-01,1.11E-02,5.59E-01 ], [413,1.21E-01,1.21E-02,6.16E-01 ], [414,1.33E-01,1.32E-02,6.76E-01 ], [415,1.45E-01,1.43E-02,7.38E-01 ], [416,1.57E-01,1.55E-02,8.01E-01 ], [417,1.69E-01,1.66E-02,8.66E-01 ], [418,1.81E-01,1.79E-02,9.30E-01 ], [419,1.93E-01,1.91E-02,9.92E-01 ], [420,2.04E-01,2.03E-02,1.05E+00 ], [421,2.14E-01,2.14E-02,1.11E+00 ], [422,2.23E-01,2.26E-02,1.16E+00 ], [423,2.32E-01,2.37E-02,1.21E+00 ], [424,2.40E-01,2.49E-02,1.26E+00 ], [425,2.49E-01,2.61E-02,1.31E+00 ], [426,2.58E-01,2.74E-02,1.35E+00 ], [427,2.66E-01,2.87E-02,1.41E+00 ], [428,2.75E-01,3.02E-02,1.46E+00 ], [429,2.84E-01,3.17E-02,1.51E+00 ], [430,2.92E-01,3.32E-02,1.55E+00 ], [431,2.99E-01,3.48E-02,1.60E+00 ], [432,3.05E-01,3.64E-02,1.64E+00 ], [433,3.11E-01,3.81E-02,1.67E+00 ], [434,3.17E-01,3.98E-02,1.71E+00 ], [435,3.23E-01,4.16E-02,1.75E+00 ], [436,3.29E-01,4.34E-02,1.79E+00 ], [437,3.35E-01,4.52E-02,1.83E+00 ], [438,3.41E-01,4.70E-02,1.86E+00 ], [439,3.45E-01,4.87E-02,1.89E+00 ], [440,3.48E-01,5.03E-02,1.92E+00 ], [441,3.49E-01,5.19E-02,1.93E+00 ], [442,3.49E-01,5.33E-02,1.93E+00 ], [443,3.47E-01,5.47E-02,1.93E+00 ], [444,3.45E-01,5.61E-02,1.93E+00 ], [445,3.42E-01,5.74E-02,1.92E+00 ], [446,3.39E-01,5.89E-02,1.91E+00 ], [447,3.36E-01,6.03E-02,1.90E+00 ], [448,3.32E-01,6.18E-02,1.89E+00 ], [449,3.28E-01,6.33E-02,1.87E+00 ], [450,3.22E-01,6.47E-02,1.85E+00 ], [451,3.16E-01,6.61E-02,1.82E+00 ], [452,3.08E-01,6.76E-02,1.78E+00 ], [453,2.99E-01,6.90E-02,1.74E+00 ], [454,2.91E-01,7.06E-02,1.70E+00 ], [455,2.83E-01,7.24E-02,1.66E+00 ], [456,2.75E-01,7.44E-02,1.63E+00 ], [457,2.67E-01,7.66E-02,1.60E+00 ], [458,2.61E-01,7.91E-02,1.57E+00 ], [459,2.54E-01,8.20E-02,1.54E+00 ], [460,2.49E-01,8.51E-02,1.52E+00 ], [461,2.43E-01,8.87E-02,1.50E+00 ], [462,2.38E-01,9.27E-02,1.49E+00 ], [463,2.33E-01,9.69E-02,1.47E+00 ], [464,2.28E-01,1.01E-01,1.45E+00 ], [465,2.22E-01,1.06E-01,1.43E+00 ], [466,2.15E-01,1.11E-01,1.40E+00 ], [467,2.08E-01,1.16E-01,1.37E+00 ], [468,1.99E-01,1.20E-01,1.33E+00 ], [469,1.90E-01,1.25E-01,1.29E+00 ], [470,1.81E-01,1.30E-01,1.25E+00 ], [471,1.71E-01,1.35E-01,1.20E+00 ], [472,1.60E-01,1.39E-01,1.15E+00 ], [473,1.50E-01,1.44E-01,1.10E+00 ], [474,1.40E-01,1.49E-01,1.05E+00 ], [475,1.29E-01,1.54E-01,9.99E-01 ], [476,1.19E-01,1.58E-01,9.47E-01 ], [477,1.09E-01,1.63E-01,8.97E-01 ], [478,9.95E-02,1.68E-01,8.47E-01 ], [479,9.04E-02,1.74E-01,8.00E-01 ], [480,8.18E-02,1.79E-01,7.55E-01 ], [481,7.38E-02,1.84E-01,7.13E-01 ], [482,6.62E-02,1.90E-01,6.73E-01 ], [483,5.91E-02,1.95E-01,6.34E-01 ], [484,5.23E-02,2.01E-01,5.97E-01 ], [485,4.60E-02,2.06E-01,5.62E-01 ], [486,4.01E-02,2.12E-01,5.27E-01 ], [487,3.45E-02,2.18E-01,4.95E-01 ], [488,2.95E-02,2.24E-01,4.64E-01 ], [489,2.49E-02,2.31E-01,4.36E-01 ], [490,2.08E-02,2.38E-01,4.10E-01 ], [491,1.72E-02,2.46E-01,3.86E-01 ], [492,1.41E-02,2.55E-01,3.65E-01 ], [493,1.13E-02,2.64E-01,3.45E-01 ], [494,9.02E-03,2.74E-01,3.27E-01 ], [495,7.10E-03,2.85E-01,3.11E-01 ], [496,5.57E-03,2.96E-01,2.95E-01 ], [497,4.39E-03,3.09E-01,2.80E-01 ], [498,3.52E-03,3.21E-01,2.65E-01 ], [499,2.89E-03,3.34E-01,2.51E-01 ], [500,2.46E-03,3.48E-01,2.38E-01 ], [501,2.21E-03,3.63E-01,2.24E-01 ], [502,2.15E-03,3.78E-01,2.11E-01 ], [503,2.34E-03,3.94E-01,1.98E-01 ], [504,2.82E-03,4.11E-01,1.85E-01 ], [505,3.65E-03,4.28E-01,1.72E-01 ], [506,4.89E-03,4.45E-01,1.60E-01 ], [507,6.63E-03,4.64E-01,1.48E-01 ], [508,8.94E-03,4.82E-01,1.37E-01 ], [509,1.19E-02,5.01E-01,1.27E-01 ], [510,1.56E-02,5.20E-01,1.18E-01 ], [511,2.00E-02,5.40E-01,1.09E-01 ], [512,2.50E-02,5.60E-01,1.02E-01 ], [513,3.07E-02,5.80E-01,9.53E-02 ], [514,3.67E-02,6.00E-01,8.89E-02 ], [515,4.32E-02,6.21E-01,8.28E-02 ], [516,4.98E-02,6.41E-01,7.70E-02 ], [517,5.67E-02,6.61E-01,7.14E-02 ], [518,6.39E-02,6.81E-01,6.62E-02 ], [519,7.15E-02,7.00E-01,6.12E-02 ], [520,7.96E-02,7.18E-01,5.65E-02 ], [521,8.82E-02,7.35E-01,5.22E-02 ], [522,9.73E-02,7.51E-01,4.81E-02 ], [523,1.07E-01,7.66E-01,4.43E-02 ], [524,1.17E-01,7.81E-01,4.08E-02 ], [525,1.27E-01,7.95E-01,3.75E-02 ], [526,1.37E-01,8.08E-01,3.45E-02 ], [527,1.48E-01,8.21E-01,3.16E-02 ], [528,1.59E-01,8.34E-01,2.90E-02 ], [529,1.71E-01,8.46E-01,2.66E-02 ], [530,1.82E-01,8.58E-01,2.44E-02 ], [531,1.93E-01,8.68E-01,2.23E-02 ], [532,2.05E-01,8.78E-01,2.05E-02 ], [533,2.16E-01,8.88E-01,1.87E-02 ], [534,2.28E-01,8.98E-01,1.71E-02 ], [535,2.41E-01,9.07E-01,1.57E-02 ], [536,2.54E-01,9.17E-01,1.43E-02 ], [537,2.67E-01,9.27E-01,1.30E-02 ], [538,2.81E-01,9.37E-01,1.19E-02 ], [539,2.95E-01,9.46E-01,1.08E-02 ], [540,3.10E-01,9.54E-01,9.85E-03 ], [541,3.24E-01,9.62E-01,8.96E-03 ], [542,3.38E-01,9.68E-01,8.15E-03 ], [543,3.53E-01,9.74E-01,7.42E-03 ], [544,3.67E-01,9.78E-01,6.74E-03 ], [545,3.80E-01,9.81E-01,6.13E-03 ], [546,3.94E-01,9.84E-01,5.57E-03 ], [547,4.08E-01,9.85E-01,5.06E-03 ], [548,4.21E-01,9.86E-01,4.60E-03 ], [549,4.35E-01,9.88E-01,4.18E-03 ], [550,4.49E-01,9.89E-01,3.79E-03 ], [551,4.64E-01,9.91E-01,3.44E-03 ], [552,4.79E-01,9.93E-01,3.12E-03 ], [553,4.95E-01,9.96E-01,2.83E-03 ], [554,5.11E-01,9.98E-01,2.57E-03 ], [555,5.28E-01,9.99E-01,2.33E-03 ], [556,5.45E-01,1.00E+00,2.11E-03 ], [557,5.62E-01,1.00E+00,1.92E-03 ], [558,5.79E-01,9.99E-01,1.74E-03 ], [559,5.96E-01,9.98E-01,1.58E-03 ], [560,6.13E-01,9.97E-01,1.43E-03 ], [561,6.31E-01,9.96E-01,1.30E-03 ], [562,6.48E-01,9.95E-01,1.18E-03 ], [563,6.65E-01,9.94E-01,1.07E-03 ], [564,6.83E-01,9.92E-01,9.72E-04 ], [565,7.02E-01,9.90E-01,8.82E-04 ], [566,7.20E-01,9.88E-01,8.01E-04 ], [567,7.39E-01,9.85E-01,7.27E-04 ], [568,7.59E-01,9.82E-01,6.61E-04 ], [569,7.78E-01,9.78E-01,6.00E-04 ], [570,7.97E-01,9.73E-01,5.45E-04 ], [571,8.15E-01,9.68E-01,4.95E-04 ], [572,8.34E-01,9.63E-01,4.50E-04 ], [573,8.52E-01,9.57E-01,4.09E-04 ], [574,8.69E-01,9.50E-01,3.72E-04 ], [575,8.85E-01,9.42E-01,3.39E-04 ], [576,9.01E-01,9.34E-01,3.08E-04 ], [577,9.17E-01,9.24E-01,2.80E-04 ], [578,9.32E-01,9.15E-01,2.55E-04 ], [579,9.47E-01,9.05E-01,2.32E-04 ], [580,9.64E-01,8.96E-01,2.12E-04 ], [581,9.81E-01,8.88E-01,1.93E-04 ], [582,9.99E-01,8.81E-01,1.76E-04 ], [583,1.02E+00,8.74E-01,1.60E-04 ], [584,1.03E+00,8.66E-01,1.46E-04 ], [585,1.05E+00,8.59E-01,1.34E-04 ], [586,1.07E+00,8.50E-01,1.22E-04 ], [587,1.08E+00,8.42E-01,1.11E-04 ], [588,1.09E+00,8.32E-01,1.02E-04 ], [589,1.10E+00,8.22E-01,9.29E-05 ], [590,1.11E+00,8.12E-01,8.49E-05 ], [591,1.12E+00,8.01E-01,7.77E-05 ], [592,1.13E+00,7.90E-01,7.11E-05 ], [593,1.13E+00,7.78E-01,6.51E-05 ], [594,1.14E+00,7.66E-01,5.96E-05 ], [595,1.14E+00,7.54E-01,5.46E-05 ], [596,1.15E+00,7.42E-01,5.01E-05 ], [597,1.15E+00,7.30E-01,4.59E-05 ], [598,1.15E+00,7.17E-01,4.21E-05 ], [599,1.15E+00,7.05E-01,3.87E-05 ], [600,1.15E+00,6.92E-01,3.55E-05 ], [601,1.15E+00,6.79E-01,3.26E-05 ], [602,1.15E+00,6.66E-01,3.00E-05 ], [603,1.14E+00,6.53E-01,2.76E-05 ], [604,1.14E+00,6.40E-01,2.54E-05 ], [605,1.13E+00,6.27E-01,2.33E-05 ], [606,1.13E+00,6.14E-01,2.15E-05 ], [607,1.12E+00,6.00E-01,1.98E-05 ], [608,1.11E+00,5.86E-01,1.83E-05 ], [609,1.10E+00,5.72E-01,1.68E-05 ], [610,1.08E+00,5.58E-01,1.55E-05 ], [611,1.07E+00,5.45E-01,1.44E-05 ], [612,1.06E+00,5.31E-01,1.33E-05 ], [613,1.04E+00,5.17E-01,1.23E-05 ], [614,1.02E+00,5.03E-01,1.13E-05 ], [615,1.01E+00,4.90E-01,1.05E-05 ], [616,9.90E-01,4.76E-01,0.00E+00 ], [617,9.71E-01,4.62E-01,0.00E+00 ], [618,9.52E-01,4.49E-01,0.00E+00 ], [619,9.33E-01,4.36E-01,0.00E+00 ], [620,9.14E-01,4.23E-01,0.00E+00 ], [621,8.95E-01,4.10E-01,0.00E+00 ], [622,8.76E-01,3.98E-01,0.00E+00 ], [623,8.56E-01,3.86E-01,0.00E+00 ], [624,8.35E-01,3.73E-01,0.00E+00 ], [625,8.14E-01,3.61E-01,0.00E+00 ], [626,7.90E-01,3.48E-01,0.00E+00 ], [627,7.66E-01,3.36E-01,0.00E+00 ], [628,7.42E-01,3.23E-01,0.00E+00 ], [629,7.17E-01,3.10E-01,0.00E+00 ], [630,6.92E-01,2.98E-01,0.00E+00 ], [631,6.68E-01,2.86E-01,0.00E+00 ], [632,6.44E-01,2.74E-01,0.00E+00 ], [633,6.21E-01,2.63E-01,0.00E+00 ], [634,5.98E-01,2.52E-01,0.00E+00 ], [635,5.76E-01,2.42E-01,0.00E+00 ], [636,5.54E-01,2.31E-01,0.00E+00 ], [637,5.33E-01,2.22E-01,0.00E+00 ], [638,5.12E-01,2.12E-01,0.00E+00 ], [639,4.92E-01,2.03E-01,0.00E+00 ], [640,4.73E-01,1.94E-01,0.00E+00 ], [641,4.55E-01,1.86E-01,0.00E+00 ], [642,4.37E-01,1.78E-01,0.00E+00 ], [643,4.19E-01,1.70E-01,0.00E+00 ], [644,4.02E-01,1.62E-01,0.00E+00 ], [645,3.84E-01,1.55E-01,0.00E+00 ], [646,3.67E-01,1.47E-01,0.00E+00 ], [647,3.50E-01,1.40E-01,0.00E+00 ], [648,3.33E-01,1.33E-01,0.00E+00 ], [649,3.16E-01,1.26E-01,0.00E+00 ], [650,3.00E-01,1.19E-01,0.00E+00 ], [651,2.84E-01,1.13E-01,0.00E+00 ], [652,2.69E-01,1.07E-01,0.00E+00 ], [653,2.55E-01,1.01E-01,0.00E+00 ], [654,2.41E-01,9.52E-02,0.00E+00 ], [655,2.28E-01,8.98E-02,0.00E+00 ], [656,2.15E-01,8.47E-02,0.00E+00 ], [657,2.03E-01,7.98E-02,0.00E+00 ], [658,1.92E-01,7.52E-02,0.00E+00 ], [659,1.81E-01,7.09E-02,0.00E+00 ], [660,1.71E-01,6.67E-02,0.00E+00 ], [661,1.61E-01,6.28E-02,0.00E+00 ], [662,1.52E-01,5.90E-02,0.00E+00 ], [663,1.43E-01,5.55E-02,0.00E+00 ], [664,1.34E-01,5.22E-02,0.00E+00 ], [665,1.26E-01,4.90E-02,0.00E+00 ], [666,1.19E-01,4.60E-02,0.00E+00 ], [667,1.12E-01,4.32E-02,0.00E+00 ], [668,1.05E-01,4.05E-02,0.00E+00 ], [669,9.83E-02,3.80E-02,0.00E+00 ], [670,9.22E-02,3.56E-02,0.00E+00 ], [671,8.65E-02,3.33E-02,0.00E+00 ], [672,8.10E-02,3.12E-02,0.00E+00 ], [673,7.59E-02,2.92E-02,0.00E+00 ], [674,7.10E-02,2.73E-02,0.00E+00 ], [675,6.64E-02,2.55E-02,0.00E+00 ], [676,6.21E-02,2.39E-02,0.00E+00 ], [677,5.80E-02,2.23E-02,0.00E+00 ], [678,5.41E-02,2.08E-02,0.00E+00 ], [679,5.05E-02,1.94E-02,0.00E+00 ], [680,4.71E-02,1.81E-02,0.00E+00 ], [681,4.39E-02,1.68E-02,0.00E+00 ], [682,4.09E-02,1.57E-02,0.00E+00 ], [683,3.81E-02,1.46E-02,0.00E+00 ], [684,3.54E-02,1.36E-02,0.00E+00 ], [685,3.29E-02,1.26E-02,0.00E+00 ], [686,3.06E-02,1.17E-02,0.00E+00 ], [687,2.83E-02,1.09E-02,0.00E+00 ], [688,2.63E-02,1.01E-02,0.00E+00 ], [689,2.44E-02,9.33E-03,0.00E+00 ], [690,2.26E-02,8.66E-03,0.00E+00 ], [691,2.10E-02,8.05E-03,0.00E+00 ], [692,1.95E-02,7.48E-03,0.00E+00 ], [693,1.82E-02,6.96E-03,0.00E+00 ], [694,1.69E-02,6.48E-03,0.00E+00 ], [695,1.58E-02,6.03E-03,0.00E+00 ], [696,1.47E-02,5.61E-03,0.00E+00 ], [697,1.36E-02,5.22E-03,0.00E+00 ], [698,1.27E-02,4.85E-03,0.00E+00 ], [699,1.18E-02,4.51E-03,0.00E+00 ], [700,1.10E-02,4.20E-03,0.00E+00 ], [701,1.02E-02,3.90E-03,0.00E+00 ], [702,9.48E-03,3.63E-03,0.00E+00 ], [703,8.82E-03,3.37E-03,0.00E+00 ], [704,8.19E-03,3.13E-03,0.00E+00 ], [705,7.61E-03,2.91E-03,0.00E+00 ], [706,7.06E-03,2.70E-03,0.00E+00 ], [707,6.55E-03,2.51E-03,0.00E+00 ], [708,6.07E-03,2.32E-03,0.00E+00 ], [709,5.63E-03,2.15E-03,0.00E+00 ], [710,5.21E-03,2.00E-03,0.00E+00 ], [711,4.83E-03,1.85E-03,0.00E+00 ], [712,4.48E-03,1.71E-03,0.00E+00 ], [713,4.15E-03,1.59E-03,0.00E+00 ], [714,3.85E-03,1.47E-03,0.00E+00 ], [715,3.57E-03,1.37E-03,0.00E+00 ], [716,3.31E-03,1.27E-03,0.00E+00 ], [717,3.08E-03,1.18E-03,0.00E+00 ], [718,2.86E-03,1.09E-03,0.00E+00 ], [719,2.65E-03,1.02E-03,0.00E+00 ], [720,2.46E-03,9.45E-04,0.00E+00 ], [721,2.29E-03,8.78E-04,0.00E+00 ], [722,2.13E-03,8.15E-04,0.00E+00 ], [723,1.97E-03,7.57E-04,0.00E+00 ], [724,1.83E-03,7.03E-04,0.00E+00 ], [725,1.70E-03,6.54E-04,0.00E+00 ], [726,1.58E-03,6.08E-04,0.00E+00 ], [727,1.47E-03,5.65E-04,0.00E+00 ], [728,1.37E-03,5.26E-04,0.00E+00 ], [729,1.27E-03,4.90E-04,0.00E+00 ], [730,1.19E-03,4.56E-04,0.00E+00 ], [731,1.10E-03,4.24E-04,0.00E+00 ], [732,1.03E-03,3.95E-04,0.00E+00 ], [733,9.56E-04,3.67E-04,0.00E+00 ], [734,8.89E-04,3.42E-04,0.00E+00 ], [735,8.27E-04,3.18E-04,0.00E+00 ], [736,7.69E-04,2.96E-04,0.00E+00 ], [737,7.15E-04,2.75E-04,0.00E+00 ], [738,6.65E-04,2.56E-04,0.00E+00 ], [739,6.19E-04,2.38E-04,0.00E+00 ], [740,5.76E-04,2.22E-04,0.00E+00 ], [741,5.37E-04,2.07E-04,0.00E+00 ], [742,5.00E-04,1.93E-04,0.00E+00 ], [743,4.67E-04,1.80E-04,0.00E+00 ], [744,4.35E-04,1.68E-04,0.00E+00 ], [745,4.06E-04,1.57E-04,0.00E+00 ], [746,3.78E-04,1.46E-04,0.00E+00 ], [747,3.53E-04,1.36E-04,0.00E+00 ], [748,3.29E-04,1.27E-04,0.00E+00 ], [749,3.06E-04,1.18E-04,0.00E+00 ], [750,2.86E-04,1.10E-04,0.00E+00 ], [751,2.66E-04,1.03E-04,0.00E+00 ], [752,2.49E-04,9.61E-05,0.00E+00 ], [753,2.32E-04,8.97E-05,0.00E+00 ], [754,2.17E-04,8.38E-05,0.00E+00 ], [755,2.02E-04,7.83E-05,0.00E+00 ], [756,1.89E-04,7.31E-05,0.00E+00 ], [757,1.76E-04,6.83E-05,0.00E+00 ], [758,1.65E-04,6.39E-05,0.00E+00 ], [759,1.54E-04,5.97E-05,0.00E+00 ], [760,1.44E-04,5.58E-05,0.00E+00 ], [761,1.34E-04,5.21E-05,0.00E+00 ], [762,1.26E-04,4.87E-05,0.00E+00 ], [763,1.17E-04,4.55E-05,0.00E+00 ], [764,1.10E-04,4.26E-05,0.00E+00 ], [765,1.02E-04,3.98E-05,0.00E+00 ], [766,9.58E-05,3.73E-05,0.00E+00 ], [767,8.97E-05,3.49E-05,0.00E+00 ], [768,8.39E-05,3.26E-05,0.00E+00 ], [769,7.85E-05,3.06E-05,0.00E+00 ], [770,7.35E-05,2.86E-05,0.00E+00 ], [771,6.87E-05,2.68E-05,0.00E+00 ], [772,6.43E-05,2.50E-05,0.00E+00 ], [773,6.01E-05,2.34E-05,0.00E+00 ], [774,5.62E-05,2.19E-05,0.00E+00 ], [775,5.26E-05,2.05E-05,0.00E+00 ], [776,4.93E-05,1.92E-05,0.00E+00 ], [777,4.62E-05,1.80E-05,0.00E+00 ], [778,4.33E-05,1.69E-05,0.00E+00 ], [779,4.06E-05,1.59E-05,0.00E+00 ], [780,3.81E-05,1.49E-05,0.00E+00 ], [781,3.57E-05,1.40E-05,0.00E+00 ], [782,3.35E-05,1.31E-05,0.00E+00 ], [783,3.14E-05,1.23E-05,0.00E+00 ], [784,2.94E-05,1.15E-05,0.00E+00 ], [785,2.76E-05,1.08E-05,0.00E+00 ], [786,2.59E-05,1.01E-05,0.00E+00 ], [787,2.43E-05,9.51E-06,0.00E+00 ], [788,2.28E-05,8.93E-06,0.00E+00 ], [789,2.14E-05,8.38E-06,0.00E+00 ], [790,2.00E-05,7.86E-06,0.00E+00 ], [791,1.88E-05,7.38E-06,0.00E+00 ], [792,1.76E-05,6.93E-06,0.00E+00 ], [793,1.66E-05,6.51E-06,0.00E+00 ], [794,1.55E-05,6.11E-06,0.00E+00 ], [795,1.46E-05,5.74E-06,0.00E+00 ], [796,1.37E-05,5.39E-06,0.00E+00 ], [797,1.29E-05,5.07E-06,0.00E+00 ], [798,1.21E-05,4.76E-06,0.00E+00 ], [799,1.14E-05,4.48E-06,0.00E+00 ], [800,1.07E-05,4.21E-06,0.00E+00 ], [801,1.00E-05,3.96E-06,0.00E+00 ], [802,9.45E-06,3.73E-06,0.00E+00 ], [803,8.88E-06,3.51E-06,0.00E+00 ], [804,8.36E-06,3.30E-06,0.00E+00 ], [805,7.86E-06,3.11E-06,0.00E+00 ], [806,7.39E-06,2.92E-06,0.00E+00 ], [807,6.94E-06,2.75E-06,0.00E+00 ], [808,6.53E-06,2.58E-06,0.00E+00 ], [809,6.14E-06,2.43E-06,0.00E+00 ], [810,5.77E-06,2.29E-06,0.00E+00 ], [811,5.43E-06,2.15E-06,0.00E+00 ], [812,5.10E-06,2.03E-06,0.00E+00 ], [813,4.80E-06,1.91E-06,0.00E+00 ], [814,4.52E-06,1.80E-06,0.00E+00 ], [815,4.26E-06,1.69E-06,0.00E+00 ], [816,4.01E-06,1.60E-06,0.00E+00 ], [817,3.78E-06,1.50E-06,0.00E+00 ], [818,3.56E-06,1.42E-06,0.00E+00 ], [819,3.36E-06,1.34E-06,0.00E+00 ], [820,3.17E-06,1.26E-06,0.00E+00 ], [821,2.99E-06,1.19E-06,0.00E+00 ], [822,2.81E-06,1.12E-06,0.00E+00 ], [823,2.65E-06,1.06E-06,0.00E+00 ], [824,2.50E-06,9.99E-07,0.00E+00 ], [825,2.36E-06,9.42E-07,0.00E+00 ], [826,2.22E-06,8.89E-07,0.00E+00 ], [827,2.10E-06,8.39E-07,0.00E+00 ], [828,1.98E-06,7.91E-07,0.00E+00 ], [829,1.87E-06,7.47E-07,0.00E+00 ], [830,1.76E-06,7.05E-07,0.00E+00 ], [831, 0, 0, 0]] CMF = np.array(CMF) steps = int(steps) wave_start, wave_end = int(wave_start), int(wave_end) spectral_range = float(wave_end - wave_start) spectral_step = spectral_range / (steps-1) # resize Wavelengths = [] for i in range(steps): Wavelengths += [wave_start + i * spectral_step] Wavelengths = np.array(Wavelengths) x_bar = scipy.interp(Wavelengths, CMF[:,0], CMF[:,1]) y_bar = scipy.interp(Wavelengths, CMF[:,0], CMF[:,2]) z_bar = scipy.interp(Wavelengths, CMF[:,0], CMF[:,3]) cmf = [] for i in range(len(x_bar)): cmf += [[x_bar[i], y_bar[i], z_bar[i]]] cmf = np.array(cmf) print "loaded: Colour Matching Functions 2006 2deg cvrl" return cmf # Illuminants def Gaussian_curve(wave_start, wave_end, steps, dominant_wavelength, variance): a = 1 b = float(dominant_wavelength) c = float(variance) gaussian = [] step_size = (wave_end-wave_start)/(steps-1) for i in range(steps): x = wave_start + i * step_size value = a*m.exp(-(((x-b)**2)/(2*c*c))) gaussian += [value] gaussian = np.array(gaussian) return gaussian def Planck_spectrum(wave_start, wave_end, steps, colour_temperature): """Generates a spectrum with Boltzmann Radiation Law returns a numpy array. wave_start => the starting wavelength (integer!!) wave_end => ten ending wavelength (integer!!) steps => how many steps in-between (non-integer will be rounded!) colout_t => the colour temperature in Kelvin array structure: [[normalized_power], ..., [normalized_power]]""" steps = int(steps) wave_start, wave_end = int(wave_start), int(wave_end) spectral_range = float(wave_end - wave_start) spectral_step = spectral_range / (steps -1) h = 6.63e-34 c = 300000000.0 k = 1.38e-23 T = float(colour_temperature) spectrum = [] waves = [] for i in range(steps): wavelength = float(wave_start + i * spectral_step) / 1000 irradiance1 = (2*float(m.pi)*h*c*c) irradiance2 = (m.pow(wavelength, 5)) irradiance3 = (1/(m.exp(h*c/(wavelength*0.000001*k*T))-1))*1e24 irradiance = (irradiance1 / irradiance2) * irradiance3 spectrum += [irradiance] waves += [wavelength] spectrum = np.array(spectrum) spectrum = np.divide(spectrum, np.max(spectrum)) print "loaded: normalized spectrum computed for colour temperature:", T, "K" return spectrum def Illuminant_A(wave_start, wave_end, steps): """CIE standard illuminant A source: http://www.cis.rit.edu/research/mcsl2/online/cie.php returns a numpy array. wave_start => the starting wavelength wave_end => ten ending wavelength steps => how many steps in-between (non-integer will be rounded!) array structure: [[normalized_power], ..., [normalized_power]]""" A = [[300,0.930483], [301,0.967643], [302,1.00597 ], [303,1.04549 ], [304,1.08623 ], [305,1.12821 ], [306,1.17147 ], [307,1.21602 ], [308,1.26188 ], [309,1.3091 ], [310,1.35769 ], [311,1.40768 ], [312,1.4591 ], [313,1.51198 ], [314,1.56633 ], [315,1.62219 ], [316,1.67959 ], [317,1.73855 ], [318,1.7991 ], [319,1.86127 ], [320,1.92508 ], [321,1.99057 ], [322,2.05776 ], [323,2.12667 ], [324,2.19734 ], [325,2.2698 ], [326,2.34406 ], [327,2.42017 ], [328,2.49814 ], [329,2.57801 ], [330,2.65981 ], [331,2.74355 ], [332,2.82928 ], [333,2.91701 ], [334,3.00678 ], [335,3.09861 ], [336,3.19253 ], [337,3.28857 ], [338,3.38676 ], [339,3.48712 ], [340,3.58968 ], [341,3.69447 ], [342,3.80152 ], [343,3.91085 ], [344,4.0225 ], [345,4.13648 ], [346,4.25282 ], [347,4.37156 ], [348,4.49272 ], [349,4.61631 ], [350,4.74238 ], [351,4.87095 ], [352,5.00204 ], [353,5.13568 ], [354,5.27189 ], [355,5.4107 ], [356,5.55213 ], [357,5.69622 ], [358,5.84298 ], [359,5.99244 ], [360,6.14462 ], [361,6.29955 ], [362,6.45724 ], [363,6.61774 ], [364,6.78105 ], [365,6.9472 ], [366,7.11621 ], [367,7.28811 ], [368,7.46292 ], [369,7.64066 ], [370,7.82135 ], [371,8.00501 ], [372,8.19167 ], [373,8.38134 ], [374,8.57404 ], [375,8.7698 ], [376,8.96864 ], [377,9.17056 ], [378,9.37561 ], [379,9.58378 ], [380,9.7951 ], [381,10.0096 ], [382,10.2273 ], [383,10.4481 ], [384,10.6722 ], [385,10.8996 ], [386,11.1302 ], [387,11.364 ], [388,11.6012 ], [389,11.8416 ], [390,12.0853 ], [391,12.3324 ], [392,12.5828 ], [393,12.8366 ], [394,13.0938 ], [395,13.3543 ], [396,13.6182 ], [397,13.8855 ], [398,14.1563 ], [399,14.4304 ], [400,14.708 ], [401,14.9891 ], [402,15.2736 ], [403,15.5616 ], [404,15.853 ], [405,16.148 ], [406,16.4464 ], [407,16.7484 ], [408,17.0538 ], [409,17.3628 ], [410,17.6753 ], [411,17.9913 ], [412,18.3108 ], [413,18.6339 ], [414,18.9605 ], [415,19.2907 ], [416,19.6244 ], [417,19.9617 ], [418,20.3026 ], [419,20.647 ], [420,20.995 ], [421,21.3465 ], [422,21.7016 ], [423,22.0603 ], [424,22.4225 ], [425,22.7883 ], [426,23.1577 ], [427,23.5307 ], [428,23.9072 ], [429,24.2873 ], [430,24.6709 ], [431,25.0581 ], [432,25.4489 ], [433,25.8432 ], [434,26.2411 ], [435,26.6425 ], [436,27.0475 ], [437,27.456 ], [438,27.8681 ], [439,28.2836 ], [440,28.7027 ], [441,29.1253 ], [442,29.5515 ], [443,29.9811 ], [444,30.4142 ], [445,30.8508 ], [446,31.2909 ], [447,31.7345 ], [448,32.1815 ], [449,32.632 ], [450,33.0859 ], [451,33.5432 ], [452,34.004 ], [453,34.4682 ], [454,34.9358 ], [455,35.4068 ], [456,35.8811 ], [457,36.3588 ], [458,36.8399 ], [459,37.3243 ], [460,37.8121 ], [461,38.3031 ], [462,38.7975 ], [463,39.2951 ], [464,39.796 ], [465,40.3002 ], [466,40.8076 ], [467,41.3182 ], [468,41.832 ], [469,42.3491 ], [470,42.8693 ], [471,43.3926 ], [472,43.9192 ], [473,44.4488 ], [474,44.9816 ], [475,45.5174 ], [476,46.0563 ], [477,46.5983 ], [478,47.1433 ], [479,47.6913 ], [480,48.2423 ], [481,48.7963 ], [482,49.3533 ], [483,49.9132 ], [484,50.476 ], [485,51.0418 ], [486,51.6104 ], [487,52.1818 ], [488,52.7561 ], [489,53.3332 ], [490,53.9132 ], [491,54.4958 ], [492,55.0813 ], [493,55.6694 ], [494,56.2603 ], [495,56.8539 ], [496,57.4501 ], [497,58.0489 ], [498,58.6504 ], [499,59.2545 ], [500,59.8611 ], [501,60.4703 ], [502,61.082 ], [503,61.6962 ], [504,62.3128 ], [505,62.932 ], [506,63.5535 ], [507,64.1775 ], [508,64.8038 ], [509,65.4325 ], [510,66.0635 ], [511,66.6968 ], [512,67.3324 ], [513,67.9702 ], [514,68.6102 ], [515,69.2525 ], [516,69.8969 ], [517,70.5435 ], [518,71.1922 ], [519,71.843 ], [520,72.4959 ], [521,73.1508 ], [522,73.8077 ], [523,74.4666 ], [524,75.1275 ], [525,75.7903 ], [526,76.4551 ], [527,77.1217 ], [528,77.7902 ], [529,78.4605 ], [530,79.1326 ], [531,79.8065 ], [532,80.4821 ], [533,81.1595 ], [534,81.8386 ], [535,82.5193 ], [536,83.2017 ], [537,83.8856 ], [538,84.5712 ], [539,85.2584 ], [540,85.947 ], [541,86.6372 ], [542,87.3288 ], [543,88.0219 ], [544,88.7165 ], [545,89.4124 ], [546,90.1097 ], [547,90.8083 ], [548,91.5082 ], [549,92.2095 ], [550,92.912 ], [551,93.6157 ], [552,94.3206 ], [553,95.0267 ], [554,95.7339 ], [555,96.4423 ], [556,97.1518 ], [557,97.8623 ], [558,98.5739 ], [559,99.2864 ], [560,100 ], [561,100.715 ], [562,101.43 ], [563,102.146 ], [564,102.864 ], [565,103.582 ], [566,104.301 ], [567,105.02 ], [568,105.741 ], [569,106.462 ], [570,107.184 ], [571,107.906 ], [572,108.63 ], [573,109.354 ], [574,110.078 ], [575,110.803 ], [576,111.529 ], [577,112.255 ], [578,112.982 ], [579,113.709 ], [580,114.436 ], [581,115.164 ], [582,115.893 ], [583,116.622 ], [584,117.351 ], [585,118.08 ], [586,118.81 ], [587,119.54 ], [588,120.27 ], [589,121.001 ], [590,121.731 ], [591,122.462 ], [592,123.193 ], [593,123.924 ], [594,124.655 ], [595,125.386 ], [596,126.118 ], [597,126.849 ], [598,127.58 ], [599,128.312 ], [600,129.043 ], [601,129.774 ], [602,130.505 ], [603,131.236 ], [604,131.966 ], [605,132.697 ], [606,133.427 ], [607,134.157 ], [608,134.887 ], [609,135.617 ], [610,136.346 ], [611,137.075 ], [612,137.804 ], [613,138.532 ], [614,139.26 ], [615,139.988 ], [616,140.715 ], [617,141.441 ], [618,142.167 ], [619,142.893 ], [620,143.618 ], [621,144.343 ], [622,145.067 ], [623,145.79 ], [624,146.513 ], [625,147.235 ], [626,147.957 ], [627,148.678 ], [628,149.398 ], [629,150.117 ], [630,150.836 ], [631,151.554 ], [632,152.271 ], [633,152.988 ], [634,153.704 ], [635,154.418 ], [636,155.132 ], [637,155.845 ], [638,156.558 ], [639,157.269 ], [640,157.979 ], [641,158.689 ], [642,159.397 ], [643,160.104 ], [644,160.811 ], [645,161.516 ], [646,162.221 ], [647,162.924 ], [648,163.626 ], [649,164.327 ], [650,165.028 ], [651,165.726 ], [652,166.424 ], [653,167.121 ], [654,167.816 ], [655,168.51 ], [656,169.203 ], [657,169.895 ], [658,170.586 ], [659,171.275 ], [660,171.963 ], [661,172.65 ], [662,173.335 ], [663,174.019 ], [664,174.702 ], [665,175.383 ], [666,176.063 ], [667,176.741 ], [668,177.419 ], [669,178.094 ], [670,178.769 ], [671,179.441 ], [672,180.113 ], [673,180.783 ], [674,181.451 ], [675,182.118 ], [676,182.783 ], [677,183.447 ], [678,184.109 ], [679,184.77 ], [680,185.429 ], [681,186.087 ], [682,186.743 ], [683,187.397 ], [684,188.05 ], [685,188.701 ], [686,189.35 ], [687,189.998 ], [688,190.644 ], [689,191.288 ], [690,191.931 ], [691,192.572 ], [692,193.211 ], [693,193.849 ], [694,194.484 ], [695,195.118 ], [696,195.75 ], [697,196.381 ], [698,197.009 ], [699,197.636 ], [700,198.261 ], [701,198.884 ], [702,199.506 ], [703,200.125 ], [704,200.743 ], [705,201.359 ], [706,201.972 ], [707,202.584 ], [708,203.195 ], [709,203.803 ], [710,204.409 ], [711,205.013 ], [712,205.616 ], [713,206.216 ], [714,206.815 ], [715,207.411 ], [716,208.006 ], [717,208.599 ], [718,209.189 ], [719,209.778 ], [720,210.365 ], [721,210.949 ], [722,211.532 ], [723,212.112 ], [724,212.691 ], [725,213.268 ], [726,213.842 ], [727,214.415 ], [728,214.985 ], [729,215.553 ], [730,216.12 ], [731,216.684 ], [732,217.246 ], [733,217.806 ], [734,218.364 ], [735,218.92 ], [736,219.473 ], [737,220.025 ], [738,220.574 ], [739,221.122 ], [740,221.667 ], [741,222.21 ], [742,222.751 ], [743,223.29 ], [744,223.826 ], [745,224.361 ], [746,224.893 ], [747,225.423 ], [748,225.951 ], [749,226.477 ], [750,227 ], [751,227.522 ], [752,228.041 ], [753,228.558 ], [754,229.073 ], [755,229.585 ], [756,230.096 ], [757,230.604 ], [758,231.11 ], [759,231.614 ], [760,232.115 ], [761,232.615 ], [762,233.112 ], [763,233.606 ], [764,234.099 ], [765,234.589 ], [766,235.078 ], [767,235.564 ], [768,236.047 ], [769,236.529 ], [770,237.008 ], [771,237.485 ], [772,237.959 ], [773,238.432 ], [774,238.902 ], [775,239.37 ], [776,239.836 ], [777,240.299 ], [778,240.76 ], [779,241.219 ], [780,241.675 ], [781,242.13 ], [782,242.582 ], [783,243.031 ], [784,243.479 ], [785,243.924 ], [786,244.367 ], [787,244.808 ], [788,245.246 ], [789,245.682 ], [790,246.116 ], [791,246.548 ], [792,246.977 ], [793,247.404 ], [794,247.829 ], [795,248.251 ], [796,248.671 ], [797,249.089 ], [798,249.505 ], [799,249.918 ], [800,250.329 ], [801,250.738 ], [802,251.144 ], [803,251.548 ], [804,251.95 ], [805,252.35 ], [806,252.747 ], [807,253.142 ], [808,253.535 ], [809,253.925 ], [810,254.314 ], [811,254.7 ], [812,255.083 ], [813,255.465 ], [814,255.844 ], [815,256.221 ], [816,256.595 ], [817,256.968 ], [818,257.338 ], [819,257.706 ], [820,258.071 ], [821,258.434 ], [822,258.795 ], [823,259.154 ], [824,259.511 ], [825,259.865 ], [826,260.217 ], [827,260.567 ], [828,260.914 ], [829,261.259 ], [830,261.602 ]] A = np.array(A) steps = int(steps) wave_start, wave_end = int(wave_start), int(wave_end) spectral_range = float(wave_end - wave_start) spectral_step = spectral_range / (steps-1) # split in 2 power = A[:,1] # normalize power power = np.divide(power,np.max(power)) # resize Wavelengths = [] for i in range(steps): Wavelengths += [wave_start + i * spectral_step] Wavelengths = np.array(Wavelengths) Illuminant_A = scipy.interp(Wavelengths, A[:,0], A[:,1]) print "loaded: Illuminant A" return Illuminant_A def Illuminant_D65(wave_start, wave_end, steps): """CIE standard illuminant D65 source: http://www.cis.rit.edu/research/mcsl2/online/cie.php returns a numpy array. wave_start => the starting wavelength wave_end => ten ending wavelength steps => how many steps in-between (non-integer will be rounded!) array structure: [[normalized_power], ..., [normalized_power]]""" A = [[300,0.0341 ], [301,0.36014 ], [302,0.68618 ], [303,1.01222 ], [304,1.33826 ], [305,1.6643 ], [306,1.99034 ], [307,2.31638 ], [308,2.64242 ], [309,2.96846 ], [310,3.2945 ], [311,4.98865 ], [312,6.6828 ], [313,8.37695 ], [314,10.0711 ], [315,11.7652 ], [316,13.4594 ], [317,15.1535 ], [318,16.8477 ], [319,18.5418 ], [320,20.236 ], [321,21.9177 ], [322,23.5995 ], [323,25.2812 ], [324,26.963 ], [325,28.6447 ], [326,30.3265 ], [327,32.0082 ], [328,33.69 ], [329,35.3717 ], [330,37.0535 ], [331,37.343 ], [332,37.6326 ], [333,37.9221 ], [334,38.2116 ], [335,38.5011 ], [336,38.7907 ], [337,39.0802 ], [338,39.3697 ], [339,39.6593 ], [340,39.9488 ], [341,40.4451 ], [342,40.9414 ], [343,41.4377 ], [344,41.934 ], [345,42.4302 ], [346,42.9265 ], [347,43.4228 ], [348,43.9191 ], [349,44.4154 ], [350,44.9117 ], [351,45.0844 ], [352,45.257 ], [353,45.4297 ], [354,45.6023 ], [355,45.775 ], [356,45.9477 ], [357,46.1203 ], [358,46.293 ], [359,46.4656 ], [360,46.6383 ], [361,47.1834 ], [362,47.7285 ], [363,48.2735 ], [364,48.8186 ], [365,49.3637 ], [366,49.9088 ], [367,50.4539 ], [368,50.9989 ], [369,51.544 ], [370,52.0891 ], [371,51.8777 ], [372,51.6664 ], [373,51.455 ], [374,51.2437 ], [375,51.0323 ], [376,50.8209 ], [377,50.6096 ], [378,50.3982 ], [379,50.1869 ], [380,49.9755 ], [381,50.4428 ], [382,50.91 ], [383,51.3773 ], [384,51.8446 ], [385,52.3118 ], [386,52.7791 ], [387,53.2464 ], [388,53.7137 ], [389,54.1809 ], [390,54.6482 ], [391,57.4589 ], [392,60.2695 ], [393,63.0802 ], [394,65.8909 ], [395,68.7015 ], [396,71.5122 ], [397,74.3229 ], [398,77.1336 ], [399,79.9442 ], [400,82.7549 ], [401,83.628 ], [402,84.5011 ], [403,85.3742 ], [404,86.2473 ], [405,87.1204 ], [406,87.9936 ], [407,88.8667 ], [408,89.7398 ], [409,90.6129 ], [410,91.486 ], [411,91.6806 ], [412,91.8752 ], [413,92.0697 ], [414,92.2643 ], [415,92.4589 ], [416,92.6535 ], [417,92.8481 ], [418,93.0426 ], [419,93.2372 ], [420,93.4318 ], [421,92.7568 ], [422,92.0819 ], [423,91.4069 ], [424,90.732 ], [425,90.057 ], [426,89.3821 ], [427,88.7071 ], [428,88.0322 ], [429,87.3572 ], [430,86.6823 ], [431,88.5006 ], [432,90.3188 ], [433,92.1371 ], [434,93.9554 ], [435,95.7736 ], [436,97.5919 ], [437,99.4102 ], [438,101.228 ], [439,103.047 ], [440,104.865 ], [441,106.079 ], [442,107.294 ], [443,108.508 ], [444,109.722 ], [445,110.936 ], [446,112.151 ], [447,113.365 ], [448,114.579 ], [449,115.794 ], [450,117.008 ], [451,117.088 ], [452,117.169 ], [453,117.249 ], [454,117.33 ], [455,117.41 ], [456,117.49 ], [457,117.571 ], [458,117.651 ], [459,117.732 ], [460,117.812 ], [461,117.517 ], [462,117.222 ], [463,116.927 ], [464,116.632 ], [465,116.336 ], [466,116.041 ], [467,115.746 ], [468,115.451 ], [469,115.156 ], [470,114.861 ], [471,114.967 ], [472,115.073 ], [473,115.18 ], [474,115.286 ], [475,115.392 ], [476,115.498 ], [477,115.604 ], [478,115.711 ], [479,115.817 ], [480,115.923 ], [481,115.212 ], [482,114.501 ], [483,113.789 ], [484,113.078 ], [485,112.367 ], [486,111.656 ], [487,110.945 ], [488,110.233 ], [489,109.522 ], [490,108.811 ], [491,108.865 ], [492,108.92 ], [493,108.974 ], [494,109.028 ], [495,109.082 ], [496,109.137 ], [497,109.191 ], [498,109.245 ], [499,109.3 ], [500,109.354 ], [501,109.199 ], [502,109.044 ], [503,108.888 ], [504,108.733 ], [505,108.578 ], [506,108.423 ], [507,108.268 ], [508,108.112 ], [509,107.957 ], [510,107.802 ], [511,107.501 ], [512,107.2 ], [513,106.898 ], [514,106.597 ], [515,106.296 ], [516,105.995 ], [517,105.694 ], [518,105.392 ], [519,105.091 ], [520,104.79 ], [521,105.08 ], [522,105.37 ], [523,105.66 ], [524,105.95 ], [525,106.239 ], [526,106.529 ], [527,106.819 ], [528,107.109 ], [529,107.399 ], [530,107.689 ], [531,107.361 ], [532,107.032 ], [533,106.704 ], [534,106.375 ], [535,106.047 ], [536,105.719 ], [537,105.39 ], [538,105.062 ], [539,104.733 ], [540,104.405 ], [541,104.369 ], [542,104.333 ], [543,104.297 ], [544,104.261 ], [545,104.225 ], [546,104.19 ], [547,104.154 ], [548,104.118 ], [549,104.082 ], [550,104.046 ], [551,103.641 ], [552,103.237 ], [553,102.832 ], [554,102.428 ], [555,102.023 ], [556,101.618 ], [557,101.214 ], [558,100.809 ], [559,100.405 ], [560,100 ], [561,99.6334 ], [562,99.2668 ], [563,98.9003 ], [564,98.5337 ], [565,98.1671 ], [566,97.8005 ], [567,97.4339 ], [568,97.0674 ], [569,96.7008 ], [570,96.3342 ], [571,96.2796 ], [572,96.225 ], [573,96.1703 ], [574,96.1157 ], [575,96.0611 ], [576,96.0065 ], [577,95.9519 ], [578,95.8972 ], [579,95.8426 ], [580,95.788 ], [581,95.0778 ], [582,94.3675 ], [583,93.6573 ], [584,92.947 ], [585,92.2368 ], [586,91.5266 ], [587,90.8163 ], [588,90.1061 ], [589,89.3958 ], [590,88.6856 ], [591,88.8177 ], [592,88.9497 ], [593,89.0818 ], [594,89.2138 ], [595,89.3459 ], [596,89.478 ], [597,89.61 ], [598,89.7421 ], [599,89.8741 ], [600,90.0062 ], [601,89.9655 ], [602,89.9248 ], [603,89.8841 ], [604,89.8434 ], [605,89.8026 ], [606,89.7619 ], [607,89.7212 ], [608,89.6805 ], [609,89.6398 ], [610,89.5991 ], [611,89.4091 ], [612,89.219 ], [613,89.029 ], [614,88.8389 ], [615,88.6489 ], [616,88.4589 ], [617,88.2688 ], [618,88.0788 ], [619,87.8887 ], [620,87.6987 ], [621,87.2577 ], [622,86.8167 ], [623,86.3757 ], [624,85.9347 ], [625,85.4936 ], [626,85.0526 ], [627,84.6116 ], [628,84.1706 ], [629,83.7296 ], [630,83.2886 ], [631,83.3297 ], [632,83.3707 ], [633,83.4118 ], [634,83.4528 ], [635,83.4939 ], [636,83.535 ], [637,83.576 ], [638,83.6171 ], [639,83.6581 ], [640,83.6992 ], [641,83.332 ], [642,82.9647 ], [643,82.5975 ], [644,82.2302 ], [645,81.863 ], [646,81.4958 ], [647,81.1285 ], [648,80.7613 ], [649,80.394 ], [650,80.0268 ], [651,80.0456 ], [652,80.0644 ], [653,80.0831 ], [654,80.1019 ], [655,80.1207 ], [656,80.1395 ], [657,80.1583 ], [658,80.177 ], [659,80.1958 ], [660,80.2146 ], [661,80.4209 ], [662,80.6272 ], [663,80.8336 ], [664,81.0399 ], [665,81.2462 ], [666,81.4525 ], [667,81.6588 ], [668,81.8652 ], [669,82.0715 ], [670,82.2778 ], [671,81.8784 ], [672,81.4791 ], [673,81.0797 ], [674,80.6804 ], [675,80.281 ], [676,79.8816 ], [677,79.4823 ], [678,79.0829 ], [679,78.6836 ], [680,78.2842 ], [681,77.4279 ], [682,76.5716 ], [683,75.7153 ], [684,74.859 ], [685,74.0027 ], [686,73.1465 ], [687,72.2902 ], [688,71.4339 ], [689,70.5776 ], [690,69.7213 ], [691,69.9101 ], [692,70.0989 ], [693,70.2876 ], [694,70.4764 ], [695,70.6652 ], [696,70.854 ], [697,71.0428 ], [698,71.2315 ], [699,71.4203 ], [700,71.6091 ], [701,71.8831 ], [702,72.1571 ], [703,72.4311 ], [704,72.7051 ], [705,72.979 ], [706,73.253 ], [707,73.527 ], [708,73.801 ], [709,74.075 ], [710,74.349 ], [711,73.0745 ], [712,71.8 ], [713,70.5255 ], [714,69.251 ], [715,67.9765 ], [716,66.702 ], [717,65.4275 ], [718,64.153 ], [719,62.8785 ], [720,61.604 ], [721,62.4322 ], [722,63.2603 ], [723,64.0885 ], [724,64.9166 ], [725,65.7448 ], [726,66.573 ], [727,67.4011 ], [728,68.2293 ], [729,69.0574 ], [730,69.8856 ], [731,70.4057 ], [732,70.9259 ], [733,71.446 ], [734,71.9662 ], [735,72.4863 ], [736,73.0064 ], [737,73.5266 ], [738,74.0467 ], [739,74.5669 ], [740,75.087 ], [741,73.9376 ], [742,72.7881 ], [743,71.6387 ], [744,70.4893 ], [745,69.3398 ], [746,68.1904 ], [747,67.041 ], [748,65.8916 ], [749,64.7421 ], [750,63.5927 ], [751,61.8752 ], [752,60.1578 ], [753,58.4403 ], [754,56.7229 ], [755,55.0054 ], [756,53.288 ], [757,51.5705 ], [758,49.8531 ], [759,48.1356 ], [760,46.4182 ], [761,48.4569 ], [762,50.4956 ], [763,52.5344 ], [764,54.5731 ], [765,56.6118 ], [766,58.6505 ], [767,60.6892 ], [768,62.728 ], [769,64.7667 ], [770,66.8054 ], [771,66.4631 ], [772,66.1209 ], [773,65.7786 ], [774,65.4364 ], [775,65.0941 ], [776,64.7518 ], [777,64.4096 ], [778,64.0673 ], [779,63.7251 ], [780,63.3828 ], [781,63.4749 ], [782,63.567 ], [783,63.6592 ], [784,63.7513 ], [785,63.8434 ], [786,63.9355 ], [787,64.0276 ], [788,64.1198 ], [789,64.2119 ], [790,64.304 ], [791,63.8188 ], [792,63.3336 ], [793,62.8484 ], [794,62.3632 ], [795,61.8779 ], [796,61.3927 ], [797,60.9075 ], [798,60.4223 ], [799,59.9371 ], [800,59.4519 ], [801,58.7026 ], [802,57.9533 ], [803,57.204 ], [804,56.4547 ], [805,55.7054 ], [806,54.9562 ], [807,54.2069 ], [808,53.4576 ], [809,52.7083 ], [810,51.959 ], [811,52.5072 ], [812,53.0553 ], [813,53.6035 ], [814,54.1516 ], [815,54.6998 ], [816,55.248 ], [817,55.7961 ], [818,56.3443 ], [819,56.8924 ], [820,57.4406 ], [821,57.7278 ], [822,58.015 ], [823,58.3022 ], [824,58.5894 ], [825,58.8765 ], [826,59.1637 ], [827,59.4509 ], [828,59.7381 ], [829,60.0253 ], [830,60.3125 ]] A = np.array(A) steps = int(steps) wave_start, wave_end = int(wave_start), int(wave_end) spectral_range = float(wave_end - wave_start) spectral_step = spectral_range / (steps-1) # split in 2 power = A[:,1] # normalize power power = np.divide(power,np.max(power)) # resize Wavelengths = [] for i in range(steps): Wavelengths += [wave_start + i * spectral_step] Wavelengths = np.array(Wavelengths) Illuminant_D65 = scipy.interp(Wavelengths, A[:,0], A[:,1]) print "loaded: Illuminant D65" return Illuminant_D65 # conversions def XYZ_to_LAB(X,Y,Z,Neutral): """transforms XYZ to CIE LCH Neutral should be normalized to Y = 100""" N_x = Neutral[0] N_y = Neutral[1] N_z = Neutral[2] var_X = X / N_x var_Y = Y / N_y var_Z = Z / N_z if var_X > 0.008856: var_X = var_X ** .3333333333333 else: var_X = ( 7.787 * var_X ) + ( 16 / 116 ) if var_Y > 0.008856: var_Y = var_Y ** .3333333333333 else: var_Y = ( 7.787 * var_Y ) + ( 16 / 116 ) if var_Z > 0.008856: var_Z = var_Z ** .3333333333333 else: var_Z = ( 7.787 * var_Z ) + ( 16 / 116 ) L = ( 116 * var_Y ) - 16 a = 500 * ( var_X - var_Y ) b = 200 * ( var_Y - var_Z ) return L, a, b def LAB_to_LCH(L,a,b): """transforms LAB to CIE LCH""" var_H = m.atan2(b,a) if ( var_H > 0 ): var_H = ( var_H / m.pi ) * 180 else: var_H = 360 - ( abs( var_H ) / m.pi ) * 180 C = m.sqrt( a**2 + b**2 ) H = var_H return L, C, H def DE10_spectral_81_steps(): """81 LAB76 equi-distant steps across the EM spectrum (at 82% purity)""" waves = [[399.000000] [402.820000] [405.600000] [407.920000] [409.990000] [412.110000] [414.160000] [416.250000] [418.470000] [421.340000] [426.050000] [430.830000] [434.100000] [437.450000] [445.620000] [451.910000] [454.840000] [457.840000] [460.830000] [463.710000] [466.060000] [468.140000] [469.990000] [471.710000] [473.370000] [474.950000] [476.580000] [478.140000] [479.720000] [481.410000] [483.180000] [485.050000] [486.980000] [489.060000] [491.190000] [493.320000] [495.500000] [497.680000] [499.920000] [502.140000] [504.350000] [506.700000] [509.360000] [512.700000] [516.860000] [521.910000] [527.140000] [531.830000] [536.110000] [540.000000] [543.790000] [547.390000] [550.890000] [554.200000] [557.210000] [560.180000] [563.250000] [566.180000] [568.950000] [571.760000] [574.620000] [577.440000] [580.240000] [583.030000] [586.030000] [589.780000] [593.540000] [597.670000] [602.430000] [608.180000] [615.420000] [623.080000] [628.910000] [634.690000] [640.560000] [645.860000] [650.860000] [656.650000] [663.590000] [672.380000] [685.380000]] return waves def DE_Equidistant_LAB_waves_82pc_ill_D65(DeltaE): """produces perceptually-equidistant wavelengths with a given DeltaE value""" wave_start, wave_end, steps = 390, 830, 44000 CMF = CMF_2006_2deg(wave_start, wave_end, steps) D65 = Illuminant_D65(wave_start, wave_end, steps) spectrum_82 = np.multiply(Spectrum_XYZ(CMF, D65, wave_start, wave_end, steps), 82) Neut = Neutral(CMF, D65) Neutral_18 = np.array([Neut[0]*.18, Neut[1]*.18, Neut[2]*.18]) wavelengths = wavelengths_float(steps, wave_start, wave_end) limit_we_want = DeltaE log = [] csum = 0 last = 0,0,0 log += [[wave_start]] for i in xrange(steps): XYZ = spectrum_82[i][0] + Neutral_18[0], spectrum_82[i][1] + Neutral_18[1], spectrum_82[i][2] + Neutral_18[2] X, Y, Z = XYZ[0], XYZ[1], XYZ[2] LAB = XYZ_to_LAB(X, Y, Z, Neut) DE = np.sqrt((last[0]-LAB[0])**2+(last[1]-LAB[1])**2+(last[2]-LAB[2])**2) last = LAB if i == 0: DE = 0 csum += DE if csum > limit_we_want: log += [[wavelengths[i]]] csum += - limit_we_want log = np.array(log) return log def STEP_Equidistant_LAB_waves_82pc_ill_D65(spectral_steps): """produces perceptually-equidistant wavelengths with a given DeltaE value""" wave_start, wave_end, steps = 390, 830, 44000 CMF = CMF_2006_2deg(wave_start, wave_end, steps) D65 = Illuminant_D65(wave_start, wave_end, steps) spectrum_82 = np.multiply(Spectrum_XYZ(CMF, D65, wave_start, wave_end, steps), 82) Neut = Neutral(CMF, D65) Neutral_18 = np.array([Neut[0]*.18, Neut[1]*.18, Neut[2]*.18]) wavelengths = wavelengths_float(steps, wave_start, wave_end) totalDE = 816.533056255 DeltaE = totalDE/(spectral_steps -1) limit_we_want = DeltaE log = [] csum = 0 last = 0,0,0 totalDE = 0 log += [[wave_start]] for i in xrange(steps): XYZ = spectrum_82[i][0] + Neutral_18[0], spectrum_82[i][1] + Neutral_18[1], spectrum_82[i][2] + Neutral_18[2] X, Y, Z = XYZ[0], XYZ[1], XYZ[2] LAB = XYZ_to_LAB(X, Y, Z, Neut) DE = np.sqrt((last[0]-LAB[0])**2+(last[1]-LAB[1])**2+(last[2]-LAB[2])**2) last = LAB if i == 0: DE = 0 csum += DE totalDE += DE if csum > limit_we_want: log += [[wavelengths[i]]] csum += - limit_we_want log = np.array(log) print "total Delta E:", totalDE return log def LCH_to_XYZ(L,C,H, Neutral): """transforms CIE LCH D65 2deg to CIE XYZ""" N_x = Neutral[0] N_y = Neutral[1] N_z = Neutral[2] L, C, H = float(L), float(C), float(H) a = m.cos(m.radians(H)) * C b = m.sin(m.radians(H)) * C var_Y = ( L + 16 ) / 116 var_X = a / 500 + var_Y var_Z = var_Y - b / 200 if ( var_Y**3 > 0.008856 ): var_Y = var_Y**3 else: var_Y = ( var_Y - 16 / 116 ) / 7.787 if ( var_X**3 > 0.008856 ): var_X = var_X**3 else: var_X = ( var_X - 16 / 116 ) / 7.787 if ( var_Z**3 > 0.008856 ): var_Z = var_Z**3 else: var_Z = ( var_Z - 16 / 116 ) / 7.787 X = N_x * var_X Y = N_y * var_Y Z = N_z * var_Z return X, Y, Z def XYZ_to_sRGB(name,X,Y,Z): """transforms XYZ to sRGB (D65) returns name, R, G, B, X, Y, Z""" name = name X = float(X) Y = float(Y) Z = float(Z) var_X = X / 100 #X from 0 to 95.047 (Observer = 2deg, 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 if (R > 255): R = 255 if (R < 0): R = 0 G = var_G * 255 if (G > 255): G = 255 if (G < 0): G = 0 B = var_B * 255 if (B > 255): B = 255 if (B < 0): B = 0 return name, iround(R), iround(G), iround(B), X, Y, Z def XYZ_to_UVW(X,Y,Z): """as it says""" X = float(X) Y = float(Y) Z = float(Z) U = .6666666666666667 * X V = Y W = .5 * (-X+3*Y+Z) return U, V, W def LCHuv_to_Yuv_1960(L,C,H): var_Y = ( L + 16 ) / 116 if ( var_Y**3 > 0.008856 ): var_Y = var_Y**3 else: var_Y = ( var_Y - 16 / 116 ) / 7.787 Y = 100 * var_Y u = m.cos(m.radians(H)) * C v = m.sin(m.radians(H)) * C return Y, u, v def Chromaticity_diagram(X, Y, Z): """ projects in 2D like CIE chromaticity diagrams""" x = X/(X+Y+Z) y = Y/(X+Y+Z) return Y, x, y def XYZ_to_uv_diagram(X,Y,Z): u = (4*X)/(X+15*Y+3*Z) v = (9*Y)/(X+15*Y+3*Z) return u, v

You should definitively post this kind of things on http://github.com/ . People could fork, reuse comment and patch your code.

Also, even if I do not know a lot about Python, I would be happy to help you to make this code better. For example, CMF_2006_2deg(), Illuminant_D65() and DE10_spectral_81_steps() should be stored into a database (the simplest is to use a file, on value per line), that you convert to the appropriate data structure into you program. It makes the code easier to maintain and read, and it’s very important to separate data from their treatment. You code is well documented (it’s pretty rare, I appreciate it), but it could be better, for example, you should explain what it is supposed to do globally.

Optimization is futile : if you run it on a server with 64G of RAM, you won’t need to “optimize” anything. The program is before all read by humans, that’s what is supposed to be optimized first, even for yourself, if you want to re-use it in 10, 5, or one year, maybe even in 6 months, it can be hard for you to remind what a function is supposed to do if the code is not readable enough. So, readability is the key of success.

It start with variables names: “spectral_range” is a great, “var_Y”, “Y”, “A” is really really horrible and bug prone. “make_pbm” for a function is ok, but what is pbm? It would be a good idea to rename it to “make_pbm_real_meaning”, even if it’s longer to type, it will make it easier for your mind.

Also, think about a license (GNU GPL, etc.). It’s VERY important.

Thanks S, could you explain me how to attribute a licence to this? I have no idea…

A

You only have to add a line inside the program with a permanent link pointing to the full license. Also see https://www.gnu.org/licenses/gpl-howto.html if you agree that other people could re-use your program freely. An example (maybe not the best) : https://github.com/smonff/dependencies-searcher => the license is described inside the README file and also at the end of each program file (ex : https://github.com/smonff/dependencies-searcher/blob/master/lib/Dependencies/Searcher.pm)

comme ça?