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