├── LICENSE ├── README.md └── colorpy ├── COPYING.LESSER.txt ├── COPYING.txt ├── ColorPy.html ├── MANIFEST.in ├── PKG-INFO ├── README.txt ├── __init__.py ├── blackbody.py ├── ciexyz.py ├── colormodels.py ├── data ├── CIEXYZ_1931_x2.txt ├── CIEXYZ_1931_y2.txt ├── CIEXYZ_1931_z2.txt ├── Illuminanta.txt ├── Illuminantd65.txt ├── ciexyz31_1.txt └── massage_CIEXYZ.py ├── dist ├── colorpy-0.1.0.tar.gz ├── colorpy-0.1.0.win32.exe └── colorpy-0.1.0.zip ├── figures.py ├── illuminants.py ├── index.html ├── license.txt ├── misc.py ├── plots.py ├── rayleigh.py ├── setup.py ├── test.py ├── test_blackbody.py ├── test_ciexyz.py ├── test_colormodels.py ├── test_illuminants.py ├── test_rayleigh.py ├── test_thinfilm.py └── thinfilm.py /README.md: -------------------------------------------------------------------------------- 1 | ColorPy 2 | ======= 3 | 4 | Physical color calculations in Python. 5 | 6 | More documentation is currently at http://markkness.net/colorpy/ColorPy.html. 7 | 8 |

9 |
10 | A taste of the plots that ColorPy can create: RGB values for the pure spectral lines. 11 |

12 | 13 | Version 0.1.1. 14 | Changes from 0.1.0: 15 | Various things I did on my local machine. 16 | A better shark fin plot, for example. 17 | Now on GitHub! 18 | 19 | Version 0.1.0. 20 | I had this hosted at http://markkness.net 21 | (and still do) but GitHub is a better place for it now. 22 | 23 | -------------------------------------------------------------------------------- /colorpy/COPYING.LESSER.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /colorpy/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.py 2 | include README.txt 3 | include COPYING.txt 4 | include COPYING.LESSER.txt 5 | include license.txt 6 | include ColorPy.html 7 | prune data/massage_CIEXYZ.py 8 | -------------------------------------------------------------------------------- /colorpy/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.0 2 | Name: colorpy 3 | Version: 0.1.0 4 | Summary: Color calculations with physical descriptions of light spectra 5 | Home-page: http://markkness.net/colorpy/ 6 | Author: Mark Kness 7 | Author-email: mkness@alumni.utexas.net 8 | License: GNU Lesser GPL Version 3 9 | Description: 10 | ColorPy is a Python package to convert physical descriptions of light - 11 | spectra of light intensity vs. wavelength - into RGB colors that can 12 | be drawn on a computer screen. 13 | It provides a nice set of attractive plots that you can make of such 14 | spectra, and some other color related functions as well. 15 | 16 | Platform: UNKNOWN 17 | -------------------------------------------------------------------------------- /colorpy/README.txt: -------------------------------------------------------------------------------- 1 | *** ReadMe for ColorPy 0.1.0. *** 2 | 3 | ColorPy is a Python package that can convert physical descriptions of light - 4 | spectra of light intensity vs. wavelength - into RGB colors that can 5 | be drawn on a computer screen. 6 | It provides a nice set of attractive plots that you can make of such 7 | spectra, and some other color related functions as well. 8 | 9 | Unpacking the Distribution: 10 | 11 | The instruction depend on if you are using Windows or Linux. 12 | If you are using Windows, you can use the binary distribution executable, 13 | and all you need to do is run that. Otherwise... 14 | 15 | Windows - 16 | 17 | Unzip the .zip distribution. Recent versions of Windows (XP or later), 18 | will unpack the directory automatically, you can simply enter the 19 | directory in Windows Explorer. You will probably need to copy the 20 | uncompressed files into another directory. 21 | 22 | Linux - 23 | 24 | The distribution is a compressed tar archive, uncompress it as follows: 25 | 26 | gunzip -c colorpy-0.1.0.tar.gz | tar xf - 27 | cd colorpy-0.1.0 28 | 29 | Installation: 30 | 31 | To install ColorPy from the source distributions (.zip on Windows, 32 | or .tar.gz on Linux) you must first unpack the distribution. 33 | 34 | Then, from the directory in which the files are unpacked, run: 35 | 36 | python setup.py install 37 | 38 | It is possible that you may need to supply a path to the Python executable. 39 | You also probably will need administrator privileges to do this. 40 | 41 | This should complete the installation. 42 | 43 | If you are installing from the Windows binary distribution (.win32.exe), 44 | then all you need to do is run that executable and follow the prompts. 45 | 46 | After installation, I recommend that you run the test cases. 47 | In the Python interpreter, do: 48 | 49 | import colorpy.test 50 | colorpy.test.test() 51 | 52 | This should run several test cases. 53 | As an additional (and more interesting) test, create the sample figures: 54 | 55 | import colorpy.figures 56 | colorpy.figures.figures() 57 | 58 | This should create a number of plot files (typically .png files) in 59 | the current directory. These will include all of the plots in the HTML 60 | documentation, as well as several others. 61 | 62 | License: 63 | 64 | Copyright (C) 2008 Mark Kness 65 | 66 | Author - Mark Kness - mkness@alumni.utexas.net 67 | 68 | This file is part of ColorPy. 69 | 70 | ColorPy is free software: you can redistribute it and/or modify 71 | it under the terms of the GNU Lesser General Public License as 72 | published by the Free Software Foundation, either version 3 of 73 | the License, or (at your option) any later version. 74 | 75 | ColorPy is distributed in the hope that it will be useful, 76 | but WITHOUT ANY WARRANTY; without even the implied warranty of 77 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 78 | GNU Lesser General Public License for more details. 79 | 80 | You should have received a copy of the GNU Lesser General Public License 81 | along with ColorPy. If not, see . 82 | -------------------------------------------------------------------------------- /colorpy/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | __init__.py 3 | 4 | ColorPy is a Python package to convert physical descriptions of light: 5 | spectra of light intensity vs. wavelength - into RGB colors that can 6 | be drawn on a computer screen. 7 | It provides a nice set of attractive plots that you can make of such 8 | spectra, and some other color related functions as well. 9 | 10 | License: 11 | 12 | Copyright (C) 2008 Mark Kness 13 | 14 | Author - Mark Kness - mkness@alumni.utexas.net 15 | 16 | This file is part of ColorPy. 17 | 18 | ColorPy is free software: you can redistribute it and/or modify 19 | it under the terms of the GNU Lesser General Public License as 20 | published by the Free Software Foundation, either version 3 of 21 | the License, or (at your option) any later version. 22 | 23 | ColorPy is distributed in the hope that it will be useful, 24 | but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 | GNU Lesser General Public License for more details. 27 | 28 | You should have received a copy of the GNU Lesser General Public License 29 | along with ColorPy. If not, see . 30 | ''' 31 | 32 | # This file only needs to exist to indicate that this is a package. 33 | -------------------------------------------------------------------------------- /colorpy/blackbody.py: -------------------------------------------------------------------------------- 1 | ''' 2 | blackbody.py - Color of thermal blackbodies. 3 | 4 | Description: 5 | 6 | Calculate the spectrum of a thermal blackbody at an arbitrary temperature. 7 | 8 | Constants: 9 | 10 | PLANCK_CONSTANT - Planck's constant, in J-sec 11 | SPEED_OF_LIGHT - Speed of light, in m/sec 12 | BOLTZMAN_CONSTANT - Boltzman's constant, in J/K 13 | SUN_TEMPERATURE - Surface temperature of the Sun, in K 14 | 15 | Functions: 16 | 17 | blackbody_specific_intensity (wl_nm, T_K) - 18 | Get the monochromatic specific intensity for a blackbody - 19 | wl_nm = wavelength [nm] 20 | T_K = temperature [K] 21 | This is the energy radiated per second per unit wavelength per unit solid angle. 22 | Reference - Shu, eq. 4.6, p. 78. 23 | 24 | blackbody_spectrum (T_K) - 25 | Get the spectrum of a blackbody, as a numpy array. 26 | 27 | blackbody_color (T_K) - 28 | Given a temperature (K), return the xyz color of a thermal blackbody. 29 | 30 | Plots: 31 | 32 | blackbody_patch_plot (T_list, title, filename) - 33 | Draw a patch plot of blackbody colors for the given temperature range. 34 | 35 | blackbody_color_vs_temperature_plot (T_list, title, filename) - 36 | Draw a color vs temperature plot for the given temperature range. 37 | 38 | blackbody_spectrum_plot (T_K) - 39 | Draw the spectrum of a blackbody at the given temperature. 40 | 41 | References: 42 | 43 | Frank H. Shu, The Physical Universe. An Introduction to Astronomy, 44 | University Science Books, Mill Valley, California. 1982. ISBN 0-935702-05-9. 45 | 46 | Charles Kittel and Herbert Kroemer, Thermal Physics, 2nd edition, 47 | W. H. Freeman, New York, 1980. ISBN 0-7167-1088-9. 48 | 49 | License: 50 | 51 | Copyright (C) 2008 Mark Kness 52 | 53 | Author - Mark Kness - mkness@alumni.utexas.net 54 | 55 | This file is part of ColorPy. 56 | 57 | ColorPy is free software: you can redistribute it and/or modify 58 | it under the terms of the GNU Lesser General Public License as 59 | published by the Free Software Foundation, either version 3 of 60 | the License, or (at your option) any later version. 61 | 62 | ColorPy is distributed in the hope that it will be useful, 63 | but WITHOUT ANY WARRANTY; without even the implied warranty of 64 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 65 | GNU Lesser General Public License for more details. 66 | 67 | You should have received a copy of the GNU Lesser General Public License 68 | along with ColorPy. If not, see . 69 | ''' 70 | import math 71 | import numpy 72 | import pylab 73 | 74 | import colormodels 75 | import ciexyz 76 | import plots 77 | 78 | # Physical constants in mks units 79 | PLANCK_CONSTANT = 6.6237e-34 # J-sec 80 | SPEED_OF_LIGHT = 2.997925e+08 # m/sec 81 | BOLTZMAN_CONSTANT = 1.3802e-23 # J/K 82 | SUN_TEMPERATURE = 5778.0 # K 83 | 84 | def blackbody_specific_intensity (wl_nm, T_K): 85 | '''Get the monochromatic specific intensity for a blackbody - 86 | wl_nm = wavelength [nm] 87 | T_K = temperature [K] 88 | This is the energy radiated per second per unit wavelength per unit solid angle. 89 | Reference - Shu, eq. 4.6, p. 78.''' 90 | # precalculations that could be made global 91 | a = (PLANCK_CONSTANT * SPEED_OF_LIGHT) / (BOLTZMAN_CONSTANT) 92 | b = (2.0 * PLANCK_CONSTANT * SPEED_OF_LIGHT * SPEED_OF_LIGHT) 93 | wl_m = wl_nm * 1.0e-9 94 | inv_exponent = (wl_m * T_K) / a 95 | # Very large exponents (small inv_exponent) result in nearly zero intensity. 96 | # Avoid the numeric troubles in this case and return zero intensity. 97 | if inv_exponent < 1.0 / 500.0: 98 | return 0.0 99 | exponent = 1.0 / inv_exponent 100 | specific_intensity = b / (math.pow (wl_m, 5) * (math.exp (exponent) - 1.0)) 101 | return specific_intensity 102 | 103 | def blackbody_spectrum (T_K): 104 | '''Get the spectrum of a blackbody, as a numpy array.''' 105 | spectrum = ciexyz.empty_spectrum() 106 | num_wl = spectrum.shape[0] 107 | for i in range (0, num_wl): 108 | # Intensity per unit wavelength. 109 | specific_intensity = blackbody_specific_intensity (spectrum [i][0], T_K) 110 | # Scale by size of wavelength interval. 111 | spectrum [i][1] = specific_intensity * ciexyz.delta_wl_nm * 1.0e-9 112 | return spectrum 113 | 114 | def blackbody_color (T_K): 115 | '''Given a temperature (K), return the xyz color of a thermal blackbody.''' 116 | spectrum = blackbody_spectrum (T_K) 117 | xyz = ciexyz.xyz_from_spectrum (spectrum) 118 | return xyz 119 | 120 | # 121 | # Figures 122 | # 123 | 124 | def blackbody_patch_plot (T_list, title, filename): 125 | '''Draw a patch plot of blackbody colors for the given temperature range.''' 126 | xyz_colors = [] 127 | color_names = [] 128 | for Ti in T_list: 129 | xyz = blackbody_color (Ti) 130 | xyz_colors.append (xyz) 131 | name = '%g K' % (Ti) 132 | color_names.append (name) 133 | plots.xyz_patch_plot (xyz_colors, color_names, title, filename) 134 | 135 | def blackbody_color_vs_temperature_plot (T_list, title, filename): 136 | '''Draw a color vs temperature plot for the given temperature range.''' 137 | num_T = len (T_list) 138 | rgb_list = numpy.empty ((num_T, 3)) 139 | for i in range (0, num_T): 140 | T_i = T_list [i] 141 | xyz = blackbody_color (T_i) 142 | rgb_list [i] = colormodels.rgb_from_xyz (xyz) 143 | # Note that b and g become negative for low T. 144 | # MatPlotLib skips those on the semilog plot. 145 | plots.color_vs_param_plot ( 146 | T_list, 147 | rgb_list, 148 | title, 149 | filename, 150 | plotfunc = pylab.semilogy, 151 | tight = True, 152 | xlabel = r'Temperature (K)', 153 | ylabel = r'RGB Color') 154 | 155 | def blackbody_spectrum_plot (T_K): 156 | '''Draw the spectrum of a blackbody at the given temperature.''' 157 | spectrum = blackbody_spectrum (T_K) 158 | title = 'Blackbody Spectrum - T %d K' % (round (T_K)) 159 | filename = 'BlackbodySpectrum-%dK' % (round (T_K)) 160 | plots.spectrum_plot ( 161 | spectrum, 162 | title, 163 | filename, 164 | xlabel = 'Wavelength (nm)', 165 | ylabel = 'Specific Intensity') 166 | #ylabel = 'Intensity ($W/m^2$)') # with LaTex symbols, the axis text gets too big... 167 | 168 | # Create sample figures 169 | 170 | def figures (): 171 | '''Create some blackbody plots.''' 172 | # Some patch plots. 173 | T_norm = plots.log_interpolate ( 1200.0, 20000.0, 48) 174 | T_hot = plots.log_interpolate (10000.0, 40000.0, 24) 175 | T_cool = plots.log_interpolate ( 950.0, 1200.0, 24) 176 | blackbody_patch_plot (T_norm, 'Blackbody Colors', 'Blackbody-Patch') 177 | blackbody_patch_plot (T_hot, 'Hot Blackbody Colors', 'Blackbody-HotPatch') 178 | blackbody_patch_plot (T_cool, 'Cool Blackbody Colors', 'Blackbody-CoolPatch') 179 | 180 | # Color vs temperature. 181 | T_norm = numpy.linspace( 1200.0, 16000.0, 300) 182 | T_hot = numpy.linspace(10000.0, 40000.0, 300) 183 | T_cool = numpy.linspace( 950.0, 1200.0, 300) 184 | blackbody_color_vs_temperature_plot (T_norm, 'Blackbody Colors', 'Blackbody-Colors') 185 | blackbody_color_vs_temperature_plot (T_hot, 'Hot Blackbody Colors', 'Blackbody-HotColors') 186 | blackbody_color_vs_temperature_plot (T_cool, 'Cool Blackbody Colors', 'Blackbody-CoolColors') 187 | 188 | # Spectrum for some specific temperatures. 189 | blackbody_spectrum_plot (2000.0) 190 | blackbody_spectrum_plot (3000.0) # Proxima Centauri. 191 | blackbody_spectrum_plot (SUN_TEMPERATURE) # Sun. 192 | blackbody_spectrum_plot (11000.0) # Rigel. 193 | blackbody_spectrum_plot (15000.0) 194 | 195 | 196 | if __name__ == '__main__': 197 | figures() 198 | -------------------------------------------------------------------------------- /colorpy/data/CIEXYZ_1931_x2.txt: -------------------------------------------------------------------------------- 1 | l, nm x2bar(l) 2 | 380 0,001368 3 | 385 0,002236 4 | 390 0,004243 5 | 395 0,007650 6 | 400 0,014310 7 | 405 0,023190 8 | 410 0,043510 9 | 415 0,077630 10 | 420 0,134380 11 | 425 0,214770 12 | 430 0,283900 13 | 435 0,328500 14 | 440 0,348280 15 | 445 0,348060 16 | 450 0,336200 17 | 455 0,318700 18 | 460 0,290800 19 | 465 0,251100 20 | 470 0,195360 21 | 475 0,142100 22 | 480 0,095640 23 | 485 0,057950 24 | 490 0,032010 25 | 495 0,014700 26 | 500 0,004900 27 | 505 0,002400 28 | 510 0,009300 29 | 515 0,029100 30 | 520 0,063270 31 | 525 0,109600 32 | 530 0,165500 33 | 535 0,225750 34 | 540 0,290400 35 | 545 0,359700 36 | 550 0,433450 37 | 555 0,512050 38 | 560 0,594500 39 | 565 0,678400 40 | 570 0,762100 41 | 575 0,842500 42 | 580 0,916300 43 | 585 0,978600 44 | 590 1,026300 45 | 595 1,056700 46 | 600 1,062200 47 | 605 1,045600 48 | 610 1,002600 49 | 615 0,938400 50 | 620 0,854450 51 | 625 0,751400 52 | 630 0,642400 53 | 635 0,541900 54 | 640 0,447900 55 | 645 0,360800 56 | 650 0,283500 57 | 655 0,218700 58 | 660 0,164900 59 | 665 0,121200 60 | 670 0,087400 61 | 675 0,063600 62 | 680 0,046770 63 | 685 0,032900 64 | 690 0,022700 65 | 695 0,015840 66 | 700 0,011359 67 | 705 0,008111 68 | 710 0,005790 69 | 715 0,004109 70 | 720 0,002899 71 | 725 0,002049 72 | 730 0,001440 73 | 735 0,001000 74 | 740 0,000690 75 | 745 0,000476 76 | 750 0,000332 77 | 755 0,000235 78 | 760 0,000166 79 | 765 0,000117 80 | 770 0,000083 81 | 775 0,000059 82 | 780 0,000042 83 | Sum.: 21,371524 84 | -------------------------------------------------------------------------------- /colorpy/data/CIEXYZ_1931_y2.txt: -------------------------------------------------------------------------------- 1 | l, nm y2bar(l) 2 | 380 0,000039 3 | 385 0,000064 4 | 390 0,000120 5 | 395 0,000217 6 | 400 0,000396 7 | 405 0,000640 8 | 410 0,001210 9 | 415 0,002180 10 | 420 0,004000 11 | 425 0,007300 12 | 430 0,011600 13 | 435 0,016840 14 | 440 0,023000 15 | 445 0,029800 16 | 450 0,038000 17 | 455 0,048000 18 | 460 0,060000 19 | 465 0,073900 20 | 470 0,090980 21 | 475 0,112600 22 | 480 0,139020 23 | 485 0,169300 24 | 490 0,208020 25 | 495 0,258600 26 | 500 0,323000 27 | 505 0,407300 28 | 510 0,503000 29 | 515 0,608200 30 | 520 0,710000 31 | 525 0,793200 32 | 530 0,862000 33 | 535 0,914850 34 | 540 0,954000 35 | 545 0,980300 36 | 550 0,994950 37 | 555 1,000000 38 | 560 0,995000 39 | 565 0,978600 40 | 570 0,952000 41 | 575 0,915400 42 | 580 0,870000 43 | 585 0,816300 44 | 590 0,757000 45 | 595 0,694900 46 | 600 0,631000 47 | 605 0,566800 48 | 610 0,503000 49 | 615 0,441200 50 | 620 0,381000 51 | 625 0,321000 52 | 630 0,265000 53 | 635 0,217000 54 | 640 0,175000 55 | 645 0,138200 56 | 650 0,107000 57 | 655 0,081600 58 | 660 0,061000 59 | 665 0,044580 60 | 670 0,032000 61 | 675 0,023200 62 | 680 0,017000 63 | 685 0,011920 64 | 690 0,008210 65 | 695 0,005723 66 | 700 0,004102 67 | 705 0,002929 68 | 710 0,002091 69 | 715 0,001484 70 | 720 0,001047 71 | 725 0,000740 72 | 730 0,000520 73 | 735 0,000361 74 | 740 0,000249 75 | 745 0,000172 76 | 750 0,000120 77 | 755 0,000085 78 | 760 0,000060 79 | 765 0,000042 80 | 770 0,000030 81 | 775 0,000021 82 | 780 0,000015 83 | Sum.: 21,371327 84 | -------------------------------------------------------------------------------- /colorpy/data/CIEXYZ_1931_z2.txt: -------------------------------------------------------------------------------- 1 | l, nm z2bar(l) 2 | 380 0,006450 3 | 385 0,010550 4 | 390 0,020050 5 | 395 0,036210 6 | 400 0,067850 7 | 405 0,110200 8 | 410 0,207400 9 | 415 0,371300 10 | 420 0,645600 11 | 425 1,039050 12 | 430 1,385600 13 | 435 1,622960 14 | 440 1,747060 15 | 445 1,782600 16 | 450 1,772110 17 | 455 1,744100 18 | 460 1,669200 19 | 465 1,528100 20 | 470 1,287640 21 | 475 1,041900 22 | 480 0,812950 23 | 485 0,616200 24 | 490 0,465180 25 | 495 0,353300 26 | 500 0,272000 27 | 505 0,212300 28 | 510 0,158200 29 | 515 0,111700 30 | 520 0,078250 31 | 525 0,057250 32 | 530 0,042160 33 | 535 0,029840 34 | 540 0,020300 35 | 545 0,013400 36 | 550 0,008750 37 | 555 0,005750 38 | 560 0,003900 39 | 565 0,002750 40 | 570 0,002100 41 | 575 0,001800 42 | 580 0,001650 43 | 585 0,001400 44 | 590 0,001100 45 | 595 0,001000 46 | 600 0,000800 47 | 605 0,000600 48 | 610 0,000340 49 | 615 0,000240 50 | 620 0,000190 51 | 625 0,000100 52 | 630 0,000050 53 | 635 0,000030 54 | 640 0,000020 55 | 645 0,000010 56 | 650 0,000000 57 | 655 0,000000 58 | 660 0,000000 59 | 665 0,000000 60 | 670 0,000000 61 | 675 0,000000 62 | 680 0,000000 63 | 685 0,000000 64 | 690 0,000000 65 | 695 0,000000 66 | 700 0,000000 67 | 705 0,000000 68 | 710 0,000000 69 | 715 0,000000 70 | 720 0,000000 71 | 725 0,000000 72 | 730 0,000000 73 | 735 0,000000 74 | 740 0,000000 75 | 745 0,000000 76 | 750 0,000000 77 | 755 0,000000 78 | 760 0,000000 79 | 765 0,000000 80 | 770 0,000000 81 | 775 0,000000 82 | 780 0,000000 83 | Sum.: 21,37154 84 | -------------------------------------------------------------------------------- /colorpy/data/Illuminanta.txt: -------------------------------------------------------------------------------- 1 | 300, 0.930483 2 | 301, 0.967643 3 | 302, 1.005970 4 | 303, 1.045490 5 | 304, 1.086230 6 | 305, 1.128210 7 | 306, 1.171470 8 | 307, 1.216020 9 | 308, 1.261880 10 | 309, 1.309100 11 | 310, 1.357690 12 | 311, 1.407680 13 | 312, 1.459100 14 | 313, 1.511980 15 | 314, 1.566330 16 | 315, 1.622190 17 | 316, 1.679590 18 | 317, 1.738550 19 | 318, 1.799100 20 | 319, 1.861270 21 | 320, 1.925080 22 | 321, 1.990570 23 | 322, 2.057760 24 | 323, 2.126670 25 | 324, 2.197340 26 | 325, 2.269800 27 | 326, 2.344060 28 | 327, 2.420170 29 | 328, 2.498140 30 | 329, 2.578010 31 | 330, 2.659810 32 | 331, 2.743550 33 | 332, 2.829280 34 | 333, 2.917010 35 | 334, 3.006780 36 | 335, 3.098610 37 | 336, 3.192530 38 | 337, 3.288570 39 | 338, 3.386760 40 | 339, 3.487120 41 | 340, 3.589680 42 | 341, 3.694470 43 | 342, 3.801520 44 | 343, 3.910850 45 | 344, 4.022500 46 | 345, 4.136480 47 | 346, 4.252820 48 | 347, 4.371560 49 | 348, 4.492720 50 | 349, 4.616310 51 | 350, 4.742380 52 | 351, 4.870950 53 | 352, 5.002040 54 | 353, 5.135680 55 | 354, 5.271890 56 | 355, 5.410700 57 | 356, 5.552130 58 | 357, 5.696220 59 | 358, 5.842980 60 | 359, 5.992440 61 | 360, 6.144620 62 | 361, 6.299550 63 | 362, 6.457240 64 | 363, 6.617740 65 | 364, 6.781050 66 | 365, 6.947200 67 | 366, 7.116210 68 | 367, 7.288110 69 | 368, 7.462920 70 | 369, 7.640660 71 | 370, 7.821350 72 | 371, 8.005010 73 | 372, 8.191670 74 | 373, 8.381340 75 | 374, 8.574040 76 | 375, 8.769800 77 | 376, 8.968640 78 | 377, 9.170560 79 | 378, 9.375610 80 | 379, 9.583780 81 | 380, 9.795100 82 | 381, 10.009600 83 | 382, 10.227300 84 | 383, 10.448100 85 | 384, 10.672200 86 | 385, 10.899600 87 | 386, 11.130200 88 | 387, 11.364000 89 | 388, 11.601200 90 | 389, 11.841600 91 | 390, 12.085300 92 | 391, 12.332400 93 | 392, 12.582800 94 | 393, 12.836600 95 | 394, 13.093800 96 | 395, 13.354300 97 | 396, 13.618200 98 | 397, 13.885500 99 | 398, 14.156300 100 | 399, 14.430400 101 | 400, 14.708000 102 | 401, 14.989100 103 | 402, 15.273600 104 | 403, 15.561600 105 | 404, 15.853000 106 | 405, 16.148000 107 | 406, 16.446400 108 | 407, 16.748400 109 | 408, 17.053800 110 | 409, 17.362800 111 | 410, 17.675300 112 | 411, 17.991300 113 | 412, 18.310800 114 | 413, 18.633900 115 | 414, 18.960500 116 | 415, 19.290700 117 | 416, 19.624400 118 | 417, 19.961700 119 | 418, 20.302600 120 | 419, 20.647000 121 | 420, 20.995000 122 | 421, 21.346500 123 | 422, 21.701600 124 | 423, 22.060300 125 | 424, 22.422500 126 | 425, 22.788300 127 | 426, 23.157700 128 | 427, 23.530700 129 | 428, 23.907200 130 | 429, 24.287300 131 | 430, 24.670900 132 | 431, 25.058100 133 | 432, 25.448900 134 | 433, 25.843200 135 | 434, 26.241100 136 | 435, 26.642500 137 | 436, 27.047500 138 | 437, 27.456000 139 | 438, 27.868100 140 | 439, 28.283600 141 | 440, 28.702700 142 | 441, 29.125300 143 | 442, 29.551500 144 | 443, 29.981100 145 | 444, 30.414200 146 | 445, 30.850800 147 | 446, 31.290900 148 | 447, 31.734500 149 | 448, 32.181500 150 | 449, 32.632000 151 | 450, 33.085900 152 | 451, 33.543200 153 | 452, 34.004000 154 | 453, 34.468200 155 | 454, 34.935800 156 | 455, 35.406800 157 | 456, 35.881100 158 | 457, 36.358800 159 | 458, 36.839900 160 | 459, 37.324300 161 | 460, 37.812100 162 | 461, 38.303100 163 | 462, 38.797500 164 | 463, 39.295100 165 | 464, 39.796000 166 | 465, 40.300200 167 | 466, 40.807600 168 | 467, 41.318200 169 | 468, 41.832000 170 | 469, 42.349100 171 | 470, 42.869300 172 | 471, 43.392600 173 | 472, 43.919200 174 | 473, 44.448800 175 | 474, 44.981600 176 | 475, 45.517400 177 | 476, 46.056300 178 | 477, 46.598300 179 | 478, 47.143300 180 | 479, 47.691300 181 | 480, 48.242300 182 | 481, 48.796300 183 | 482, 49.353300 184 | 483, 49.913200 185 | 484, 50.476000 186 | 485, 51.041800 187 | 486, 51.610400 188 | 487, 52.181800 189 | 488, 52.756100 190 | 489, 53.333200 191 | 490, 53.913200 192 | 491, 54.495800 193 | 492, 55.081300 194 | 493, 55.669400 195 | 494, 56.260300 196 | 495, 56.853900 197 | 496, 57.450100 198 | 497, 58.048900 199 | 498, 58.650400 200 | 499, 59.254500 201 | 500, 59.861100 202 | 501, 60.470300 203 | 502, 61.082000 204 | 503, 61.696200 205 | 504, 62.312800 206 | 505, 62.932000 207 | 506, 63.553500 208 | 507, 64.177500 209 | 508, 64.803800 210 | 509, 65.432500 211 | 510, 66.063500 212 | 511, 66.696800 213 | 512, 67.332400 214 | 513, 67.970200 215 | 514, 68.610200 216 | 515, 69.252500 217 | 516, 69.896900 218 | 517, 70.543500 219 | 518, 71.192200 220 | 519, 71.843000 221 | 520, 72.495900 222 | 521, 73.150800 223 | 522, 73.807700 224 | 523, 74.466600 225 | 524, 75.127500 226 | 525, 75.790300 227 | 526, 76.455100 228 | 527, 77.121700 229 | 528, 77.790200 230 | 529, 78.460500 231 | 530, 79.132600 232 | 531, 79.806500 233 | 532, 80.482100 234 | 533, 81.159500 235 | 534, 81.838600 236 | 535, 82.519300 237 | 536, 83.201700 238 | 537, 83.885600 239 | 538, 84.571200 240 | 539, 85.258400 241 | 540, 85.947000 242 | 541, 86.637200 243 | 542, 87.328800 244 | 543, 88.021900 245 | 544, 88.716500 246 | 545, 89.412400 247 | 546, 90.109700 248 | 547, 90.808300 249 | 548, 91.508200 250 | 549, 92.209500 251 | 550, 92.912000 252 | 551, 93.615700 253 | 552, 94.320600 254 | 553, 95.026700 255 | 554, 95.733900 256 | 555, 96.442300 257 | 556, 97.151800 258 | 557, 97.862300 259 | 558, 98.573900 260 | 559, 99.286400 261 | 560, 100.000000 262 | 561, 100.715000 263 | 562, 101.430000 264 | 563, 102.146000 265 | 564, 102.864000 266 | 565, 103.582000 267 | 566, 104.301000 268 | 567, 105.020000 269 | 568, 105.741000 270 | 569, 106.462000 271 | 570, 107.184000 272 | 571, 107.906000 273 | 572, 108.630000 274 | 573, 109.354000 275 | 574, 110.078000 276 | 575, 110.803000 277 | 576, 111.529000 278 | 577, 112.255000 279 | 578, 112.982000 280 | 579, 113.709000 281 | 580, 114.436000 282 | 581, 115.164000 283 | 582, 115.893000 284 | 583, 116.622000 285 | 584, 117.351000 286 | 585, 118.080000 287 | 586, 118.810000 288 | 587, 119.540000 289 | 588, 120.270000 290 | 589, 121.001000 291 | 590, 121.731000 292 | 591, 122.462000 293 | 592, 123.193000 294 | 593, 123.924000 295 | 594, 124.655000 296 | 595, 125.386000 297 | 596, 126.118000 298 | 597, 126.849000 299 | 598, 127.580000 300 | 599, 128.312000 301 | 600, 129.043000 302 | 601, 129.774000 303 | 602, 130.505000 304 | 603, 131.236000 305 | 604, 131.966000 306 | 605, 132.697000 307 | 606, 133.427000 308 | 607, 134.157000 309 | 608, 134.887000 310 | 609, 135.617000 311 | 610, 136.346000 312 | 611, 137.075000 313 | 612, 137.804000 314 | 613, 138.532000 315 | 614, 139.260000 316 | 615, 139.988000 317 | 616, 140.715000 318 | 617, 141.441000 319 | 618, 142.167000 320 | 619, 142.893000 321 | 620, 143.618000 322 | 621, 144.343000 323 | 622, 145.067000 324 | 623, 145.790000 325 | 624, 146.513000 326 | 625, 147.235000 327 | 626, 147.957000 328 | 627, 148.678000 329 | 628, 149.398000 330 | 629, 150.117000 331 | 630, 150.836000 332 | 631, 151.554000 333 | 632, 152.271000 334 | 633, 152.988000 335 | 634, 153.704000 336 | 635, 154.418000 337 | 636, 155.132000 338 | 637, 155.845000 339 | 638, 156.558000 340 | 639, 157.269000 341 | 640, 157.979000 342 | 641, 158.689000 343 | 642, 159.397000 344 | 643, 160.104000 345 | 644, 160.811000 346 | 645, 161.516000 347 | 646, 162.221000 348 | 647, 162.924000 349 | 648, 163.626000 350 | 649, 164.327000 351 | 650, 165.028000 352 | 651, 165.726000 353 | 652, 166.424000 354 | 653, 167.121000 355 | 654, 167.816000 356 | 655, 168.510000 357 | 656, 169.203000 358 | 657, 169.895000 359 | 658, 170.586000 360 | 659, 171.275000 361 | 660, 171.963000 362 | 661, 172.650000 363 | 662, 173.335000 364 | 663, 174.019000 365 | 664, 174.702000 366 | 665, 175.383000 367 | 666, 176.063000 368 | 667, 176.741000 369 | 668, 177.419000 370 | 669, 178.094000 371 | 670, 178.769000 372 | 671, 179.441000 373 | 672, 180.113000 374 | 673, 180.783000 375 | 674, 181.451000 376 | 675, 182.118000 377 | 676, 182.783000 378 | 677, 183.447000 379 | 678, 184.109000 380 | 679, 184.770000 381 | 680, 185.429000 382 | 681, 186.087000 383 | 682, 186.743000 384 | 683, 187.397000 385 | 684, 188.050000 386 | 685, 188.701000 387 | 686, 189.350000 388 | 687, 189.998000 389 | 688, 190.644000 390 | 689, 191.288000 391 | 690, 191.931000 392 | 691, 192.572000 393 | 692, 193.211000 394 | 693, 193.849000 395 | 694, 194.484000 396 | 695, 195.118000 397 | 696, 195.750000 398 | 697, 196.381000 399 | 698, 197.009000 400 | 699, 197.636000 401 | 700, 198.261000 402 | 701, 198.884000 403 | 702, 199.506000 404 | 703, 200.125000 405 | 704, 200.743000 406 | 705, 201.359000 407 | 706, 201.972000 408 | 707, 202.584000 409 | 708, 203.195000 410 | 709, 203.803000 411 | 710, 204.409000 412 | 711, 205.013000 413 | 712, 205.616000 414 | 713, 206.216000 415 | 714, 206.815000 416 | 715, 207.411000 417 | 716, 208.006000 418 | 717, 208.599000 419 | 718, 209.189000 420 | 719, 209.778000 421 | 720, 210.365000 422 | 721, 210.949000 423 | 722, 211.532000 424 | 723, 212.112000 425 | 724, 212.691000 426 | 725, 213.268000 427 | 726, 213.842000 428 | 727, 214.415000 429 | 728, 214.985000 430 | 729, 215.553000 431 | 730, 216.120000 432 | 731, 216.684000 433 | 732, 217.246000 434 | 733, 217.806000 435 | 734, 218.364000 436 | 735, 218.920000 437 | 736, 219.473000 438 | 737, 220.025000 439 | 738, 220.574000 440 | 739, 221.122000 441 | 740, 221.667000 442 | 741, 222.210000 443 | 742, 222.751000 444 | 743, 223.290000 445 | 744, 223.826000 446 | 745, 224.361000 447 | 746, 224.893000 448 | 747, 225.423000 449 | 748, 225.951000 450 | 749, 226.477000 451 | 750, 227.000000 452 | 751, 227.522000 453 | 752, 228.041000 454 | 753, 228.558000 455 | 754, 229.073000 456 | 755, 229.585000 457 | 756, 230.096000 458 | 757, 230.604000 459 | 758, 231.110000 460 | 759, 231.614000 461 | 760, 232.115000 462 | 761, 232.615000 463 | 762, 233.112000 464 | 763, 233.606000 465 | 764, 234.099000 466 | 765, 234.589000 467 | 766, 235.078000 468 | 767, 235.564000 469 | 768, 236.047000 470 | 769, 236.529000 471 | 770, 237.008000 472 | 771, 237.485000 473 | 772, 237.959000 474 | 773, 238.432000 475 | 774, 238.902000 476 | 775, 239.370000 477 | 776, 239.836000 478 | 777, 240.299000 479 | 778, 240.760000 480 | 779, 241.219000 481 | 780, 241.675000 482 | 781, 242.130000 483 | 782, 242.582000 484 | 783, 243.031000 485 | 784, 243.479000 486 | 785, 243.924000 487 | 786, 244.367000 488 | 787, 244.808000 489 | 788, 245.246000 490 | 789, 245.682000 491 | 790, 246.116000 492 | 791, 246.548000 493 | 792, 246.977000 494 | 793, 247.404000 495 | 794, 247.829000 496 | 795, 248.251000 497 | 796, 248.671000 498 | 797, 249.089000 499 | 798, 249.505000 500 | 799, 249.918000 501 | 800, 250.329000 502 | 801, 250.738000 503 | 802, 251.144000 504 | 803, 251.548000 505 | 804, 251.950000 506 | 805, 252.350000 507 | 806, 252.747000 508 | 807, 253.142000 509 | 808, 253.535000 510 | 809, 253.925000 511 | 810, 254.314000 512 | 811, 254.700000 513 | 812, 255.083000 514 | 813, 255.465000 515 | 814, 255.844000 516 | 815, 256.221000 517 | 816, 256.595000 518 | 817, 256.968000 519 | 818, 257.338000 520 | 819, 257.706000 521 | 820, 258.071000 522 | 821, 258.434000 523 | 822, 258.795000 524 | 823, 259.154000 525 | 824, 259.511000 526 | 825, 259.865000 527 | 826, 260.217000 528 | 827, 260.567000 529 | 828, 260.914000 530 | 829, 261.259000 531 | 830, 261.602000 532 | -------------------------------------------------------------------------------- /colorpy/data/Illuminantd65.txt: -------------------------------------------------------------------------------- 1 | 300, 0.034100 2 | 301, 0.360140 3 | 302, 0.686180 4 | 303, 1.012220 5 | 304, 1.338260 6 | 305, 1.664300 7 | 306, 1.990340 8 | 307, 2.316380 9 | 308, 2.642420 10 | 309, 2.968460 11 | 310, 3.294500 12 | 311, 4.988650 13 | 312, 6.682800 14 | 313, 8.376950 15 | 314, 10.071100 16 | 315, 11.765200 17 | 316, 13.459400 18 | 317, 15.153500 19 | 318, 16.847700 20 | 319, 18.541800 21 | 320, 20.236000 22 | 321, 21.917700 23 | 322, 23.599500 24 | 323, 25.281200 25 | 324, 26.963000 26 | 325, 28.644700 27 | 326, 30.326500 28 | 327, 32.008200 29 | 328, 33.690000 30 | 329, 35.371700 31 | 330, 37.053500 32 | 331, 37.343000 33 | 332, 37.632600 34 | 333, 37.922100 35 | 334, 38.211600 36 | 335, 38.501100 37 | 336, 38.790700 38 | 337, 39.080200 39 | 338, 39.369700 40 | 339, 39.659300 41 | 340, 39.948800 42 | 341, 40.445100 43 | 342, 40.941400 44 | 343, 41.437700 45 | 344, 41.934000 46 | 345, 42.430200 47 | 346, 42.926500 48 | 347, 43.422800 49 | 348, 43.919100 50 | 349, 44.415400 51 | 350, 44.911700 52 | 351, 45.084400 53 | 352, 45.257000 54 | 353, 45.429700 55 | 354, 45.602300 56 | 355, 45.775000 57 | 356, 45.947700 58 | 357, 46.120300 59 | 358, 46.293000 60 | 359, 46.465600 61 | 360, 46.638300 62 | 361, 47.183400 63 | 362, 47.728500 64 | 363, 48.273500 65 | 364, 48.818600 66 | 365, 49.363700 67 | 366, 49.908800 68 | 367, 50.453900 69 | 368, 50.998900 70 | 369, 51.544000 71 | 370, 52.089100 72 | 371, 51.877700 73 | 372, 51.666400 74 | 373, 51.455000 75 | 374, 51.243700 76 | 375, 51.032300 77 | 376, 50.820900 78 | 377, 50.609600 79 | 378, 50.398200 80 | 379, 50.186900 81 | 380, 49.975500 82 | 381, 50.442800 83 | 382, 50.910000 84 | 383, 51.377300 85 | 384, 51.844600 86 | 385, 52.311800 87 | 386, 52.779100 88 | 387, 53.246400 89 | 388, 53.713700 90 | 389, 54.180900 91 | 390, 54.648200 92 | 391, 57.458900 93 | 392, 60.269500 94 | 393, 63.080200 95 | 394, 65.890900 96 | 395, 68.701500 97 | 396, 71.512200 98 | 397, 74.322900 99 | 398, 77.133600 100 | 399, 79.944200 101 | 400, 82.754900 102 | 401, 83.628000 103 | 402, 84.501100 104 | 403, 85.374200 105 | 404, 86.247300 106 | 405, 87.120400 107 | 406, 87.993600 108 | 407, 88.866700 109 | 408, 89.739800 110 | 409, 90.612900 111 | 410, 91.486000 112 | 411, 91.680600 113 | 412, 91.875200 114 | 413, 92.069700 115 | 414, 92.264300 116 | 415, 92.458900 117 | 416, 92.653500 118 | 417, 92.848100 119 | 418, 93.042600 120 | 419, 93.237200 121 | 420, 93.431800 122 | 421, 92.756800 123 | 422, 92.081900 124 | 423, 91.406900 125 | 424, 90.732000 126 | 425, 90.057000 127 | 426, 89.382100 128 | 427, 88.707100 129 | 428, 88.032200 130 | 429, 87.357200 131 | 430, 86.682300 132 | 431, 88.500600 133 | 432, 90.318800 134 | 433, 92.137100 135 | 434, 93.955400 136 | 435, 95.773600 137 | 436, 97.591900 138 | 437, 99.410200 139 | 438, 101.228000 140 | 439, 103.047000 141 | 440, 104.865000 142 | 441, 106.079000 143 | 442, 107.294000 144 | 443, 108.508000 145 | 444, 109.722000 146 | 445, 110.936000 147 | 446, 112.151000 148 | 447, 113.365000 149 | 448, 114.579000 150 | 449, 115.794000 151 | 450, 117.008000 152 | 451, 117.088000 153 | 452, 117.169000 154 | 453, 117.249000 155 | 454, 117.330000 156 | 455, 117.410000 157 | 456, 117.490000 158 | 457, 117.571000 159 | 458, 117.651000 160 | 459, 117.732000 161 | 460, 117.812000 162 | 461, 117.517000 163 | 462, 117.222000 164 | 463, 116.927000 165 | 464, 116.632000 166 | 465, 116.336000 167 | 466, 116.041000 168 | 467, 115.746000 169 | 468, 115.451000 170 | 469, 115.156000 171 | 470, 114.861000 172 | 471, 114.967000 173 | 472, 115.073000 174 | 473, 115.180000 175 | 474, 115.286000 176 | 475, 115.392000 177 | 476, 115.498000 178 | 477, 115.604000 179 | 478, 115.711000 180 | 479, 115.817000 181 | 480, 115.923000 182 | 481, 115.212000 183 | 482, 114.501000 184 | 483, 113.789000 185 | 484, 113.078000 186 | 485, 112.367000 187 | 486, 111.656000 188 | 487, 110.945000 189 | 488, 110.233000 190 | 489, 109.522000 191 | 490, 108.811000 192 | 491, 108.865000 193 | 492, 108.920000 194 | 493, 108.974000 195 | 494, 109.028000 196 | 495, 109.082000 197 | 496, 109.137000 198 | 497, 109.191000 199 | 498, 109.245000 200 | 499, 109.300000 201 | 500, 109.354000 202 | 501, 109.199000 203 | 502, 109.044000 204 | 503, 108.888000 205 | 504, 108.733000 206 | 505, 108.578000 207 | 506, 108.423000 208 | 507, 108.268000 209 | 508, 108.112000 210 | 509, 107.957000 211 | 510, 107.802000 212 | 511, 107.501000 213 | 512, 107.200000 214 | 513, 106.898000 215 | 514, 106.597000 216 | 515, 106.296000 217 | 516, 105.995000 218 | 517, 105.694000 219 | 518, 105.392000 220 | 519, 105.091000 221 | 520, 104.790000 222 | 521, 105.080000 223 | 522, 105.370000 224 | 523, 105.660000 225 | 524, 105.950000 226 | 525, 106.239000 227 | 526, 106.529000 228 | 527, 106.819000 229 | 528, 107.109000 230 | 529, 107.399000 231 | 530, 107.689000 232 | 531, 107.361000 233 | 532, 107.032000 234 | 533, 106.704000 235 | 534, 106.375000 236 | 535, 106.047000 237 | 536, 105.719000 238 | 537, 105.390000 239 | 538, 105.062000 240 | 539, 104.733000 241 | 540, 104.405000 242 | 541, 104.369000 243 | 542, 104.333000 244 | 543, 104.297000 245 | 544, 104.261000 246 | 545, 104.225000 247 | 546, 104.190000 248 | 547, 104.154000 249 | 548, 104.118000 250 | 549, 104.082000 251 | 550, 104.046000 252 | 551, 103.641000 253 | 552, 103.237000 254 | 553, 102.832000 255 | 554, 102.428000 256 | 555, 102.023000 257 | 556, 101.618000 258 | 557, 101.214000 259 | 558, 100.809000 260 | 559, 100.405000 261 | 560, 100.000000 262 | 561, 99.633400 263 | 562, 99.266800 264 | 563, 98.900300 265 | 564, 98.533700 266 | 565, 98.167100 267 | 566, 97.800500 268 | 567, 97.433900 269 | 568, 97.067400 270 | 569, 96.700800 271 | 570, 96.334200 272 | 571, 96.279600 273 | 572, 96.225000 274 | 573, 96.170300 275 | 574, 96.115700 276 | 575, 96.061100 277 | 576, 96.006500 278 | 577, 95.951900 279 | 578, 95.897200 280 | 579, 95.842600 281 | 580, 95.788000 282 | 581, 95.077800 283 | 582, 94.367500 284 | 583, 93.657300 285 | 584, 92.947000 286 | 585, 92.236800 287 | 586, 91.526600 288 | 587, 90.816300 289 | 588, 90.106100 290 | 589, 89.395800 291 | 590, 88.685600 292 | 591, 88.817700 293 | 592, 88.949700 294 | 593, 89.081800 295 | 594, 89.213800 296 | 595, 89.345900 297 | 596, 89.478000 298 | 597, 89.610000 299 | 598, 89.742100 300 | 599, 89.874100 301 | 600, 90.006200 302 | 601, 89.965500 303 | 602, 89.924800 304 | 603, 89.884100 305 | 604, 89.843400 306 | 605, 89.802600 307 | 606, 89.761900 308 | 607, 89.721200 309 | 608, 89.680500 310 | 609, 89.639800 311 | 610, 89.599100 312 | 611, 89.409100 313 | 612, 89.219000 314 | 613, 89.029000 315 | 614, 88.838900 316 | 615, 88.648900 317 | 616, 88.458900 318 | 617, 88.268800 319 | 618, 88.078800 320 | 619, 87.888700 321 | 620, 87.698700 322 | 621, 87.257700 323 | 622, 86.816700 324 | 623, 86.375700 325 | 624, 85.934700 326 | 625, 85.493600 327 | 626, 85.052600 328 | 627, 84.611600 329 | 628, 84.170600 330 | 629, 83.729600 331 | 630, 83.288600 332 | 631, 83.329700 333 | 632, 83.370700 334 | 633, 83.411800 335 | 634, 83.452800 336 | 635, 83.493900 337 | 636, 83.535000 338 | 637, 83.576000 339 | 638, 83.617100 340 | 639, 83.658100 341 | 640, 83.699200 342 | 641, 83.332000 343 | 642, 82.964700 344 | 643, 82.597500 345 | 644, 82.230200 346 | 645, 81.863000 347 | 646, 81.495800 348 | 647, 81.128500 349 | 648, 80.761300 350 | 649, 80.394000 351 | 650, 80.026800 352 | 651, 80.045600 353 | 652, 80.064400 354 | 653, 80.083100 355 | 654, 80.101900 356 | 655, 80.120700 357 | 656, 80.139500 358 | 657, 80.158300 359 | 658, 80.177000 360 | 659, 80.195800 361 | 660, 80.214600 362 | 661, 80.420900 363 | 662, 80.627200 364 | 663, 80.833600 365 | 664, 81.039900 366 | 665, 81.246200 367 | 666, 81.452500 368 | 667, 81.658800 369 | 668, 81.865200 370 | 669, 82.071500 371 | 670, 82.277800 372 | 671, 81.878400 373 | 672, 81.479100 374 | 673, 81.079700 375 | 674, 80.680400 376 | 675, 80.281000 377 | 676, 79.881600 378 | 677, 79.482300 379 | 678, 79.082900 380 | 679, 78.683600 381 | 680, 78.284200 382 | 681, 77.427900 383 | 682, 76.571600 384 | 683, 75.715300 385 | 684, 74.859000 386 | 685, 74.002700 387 | 686, 73.146500 388 | 687, 72.290200 389 | 688, 71.433900 390 | 689, 70.577600 391 | 690, 69.721300 392 | 691, 69.910100 393 | 692, 70.098900 394 | 693, 70.287600 395 | 694, 70.476400 396 | 695, 70.665200 397 | 696, 70.854000 398 | 697, 71.042800 399 | 698, 71.231500 400 | 699, 71.420300 401 | 700, 71.609100 402 | 701, 71.883100 403 | 702, 72.157100 404 | 703, 72.431100 405 | 704, 72.705100 406 | 705, 72.979000 407 | 706, 73.253000 408 | 707, 73.527000 409 | 708, 73.801000 410 | 709, 74.075000 411 | 710, 74.349000 412 | 711, 73.074500 413 | 712, 71.800000 414 | 713, 70.525500 415 | 714, 69.251000 416 | 715, 67.976500 417 | 716, 66.702000 418 | 717, 65.427500 419 | 718, 64.153000 420 | 719, 62.878500 421 | 720, 61.604000 422 | 721, 62.432200 423 | 722, 63.260300 424 | 723, 64.088500 425 | 724, 64.916600 426 | 725, 65.744800 427 | 726, 66.573000 428 | 727, 67.401100 429 | 728, 68.229300 430 | 729, 69.057400 431 | 730, 69.885600 432 | 731, 70.405700 433 | 732, 70.925900 434 | 733, 71.446000 435 | 734, 71.966200 436 | 735, 72.486300 437 | 736, 73.006400 438 | 737, 73.526600 439 | 738, 74.046700 440 | 739, 74.566900 441 | 740, 75.087000 442 | 741, 73.937600 443 | 742, 72.788100 444 | 743, 71.638700 445 | 744, 70.489300 446 | 745, 69.339800 447 | 746, 68.190400 448 | 747, 67.041000 449 | 748, 65.891600 450 | 749, 64.742100 451 | 750, 63.592700 452 | 751, 61.875200 453 | 752, 60.157800 454 | 753, 58.440300 455 | 754, 56.722900 456 | 755, 55.005400 457 | 756, 53.288000 458 | 757, 51.570500 459 | 758, 49.853100 460 | 759, 48.135600 461 | 760, 46.418200 462 | 761, 48.456900 463 | 762, 50.495600 464 | 763, 52.534400 465 | 764, 54.573100 466 | 765, 56.611800 467 | 766, 58.650500 468 | 767, 60.689200 469 | 768, 62.728000 470 | 769, 64.766700 471 | 770, 66.805400 472 | 771, 66.463100 473 | 772, 66.120900 474 | 773, 65.778600 475 | 774, 65.436400 476 | 775, 65.094100 477 | 776, 64.751800 478 | 777, 64.409600 479 | 778, 64.067300 480 | 779, 63.725100 481 | 780, 63.382800 482 | 781, 63.474900 483 | 782, 63.567000 484 | 783, 63.659200 485 | 784, 63.751300 486 | 785, 63.843400 487 | 786, 63.935500 488 | 787, 64.027600 489 | 788, 64.119800 490 | 789, 64.211900 491 | 790, 64.304000 492 | 791, 63.818800 493 | 792, 63.333600 494 | 793, 62.848400 495 | 794, 62.363200 496 | 795, 61.877900 497 | 796, 61.392700 498 | 797, 60.907500 499 | 798, 60.422300 500 | 799, 59.937100 501 | 800, 59.451900 502 | 801, 58.702600 503 | 802, 57.953300 504 | 803, 57.204000 505 | 804, 56.454700 506 | 805, 55.705400 507 | 806, 54.956200 508 | 807, 54.206900 509 | 808, 53.457600 510 | 809, 52.708300 511 | 810, 51.959000 512 | 811, 52.507200 513 | 812, 53.055300 514 | 813, 53.603500 515 | 814, 54.151600 516 | 815, 54.699800 517 | 816, 55.248000 518 | 817, 55.796100 519 | 818, 56.344300 520 | 819, 56.892400 521 | 820, 57.440600 522 | 821, 57.727800 523 | 822, 58.015000 524 | 823, 58.302200 525 | 824, 58.589400 526 | 825, 58.876500 527 | 826, 59.163700 528 | 827, 59.450900 529 | 828, 59.738100 530 | 829, 60.025300 531 | 830, 60.312500 532 | -------------------------------------------------------------------------------- /colorpy/data/ciexyz31_1.txt: -------------------------------------------------------------------------------- 1 | 360, 0.000129900000, 0.000003917000, 0.000606100000 2 | 361, 0.000145847000, 0.000004393581, 0.000680879200 3 | 362, 0.000163802100, 0.000004929604, 0.000765145600 4 | 363, 0.000184003700, 0.000005532136, 0.000860012400 5 | 364, 0.000206690200, 0.000006208245, 0.000966592800 6 | 365, 0.000232100000, 0.000006965000, 0.001086000000 7 | 366, 0.000260728000, 0.000007813219, 0.001220586000 8 | 367, 0.000293075000, 0.000008767336, 0.001372729000 9 | 368, 0.000329388000, 0.000009839844, 0.001543579000 10 | 369, 0.000369914000, 0.000011043230, 0.001734286000 11 | 370, 0.000414900000, 0.000012390000, 0.001946000000 12 | 371, 0.000464158700, 0.000013886410, 0.002177777000 13 | 372, 0.000518986000, 0.000015557280, 0.002435809000 14 | 373, 0.000581854000, 0.000017442960, 0.002731953000 15 | 374, 0.000655234700, 0.000019583750, 0.003078064000 16 | 375, 0.000741600000, 0.000022020000, 0.003486000000 17 | 376, 0.000845029600, 0.000024839650, 0.003975227000 18 | 377, 0.000964526800, 0.000028041260, 0.004540880000 19 | 378, 0.001094949000, 0.000031531040, 0.005158320000 20 | 379, 0.001231154000, 0.000035215210, 0.005802907000 21 | 380, 0.001368000000, 0.000039000000, 0.006450001000 22 | 381, 0.001502050000, 0.000042826400, 0.007083216000 23 | 382, 0.001642328000, 0.000046914600, 0.007745488000 24 | 383, 0.001802382000, 0.000051589600, 0.008501152000 25 | 384, 0.001995757000, 0.000057176400, 0.009414544000 26 | 385, 0.002236000000, 0.000064000000, 0.010549990000 27 | 386, 0.002535385000, 0.000072344210, 0.011965800000 28 | 387, 0.002892603000, 0.000082212240, 0.013655870000 29 | 388, 0.003300829000, 0.000093508160, 0.015588050000 30 | 389, 0.003753236000, 0.000106136100, 0.017730150000 31 | 390, 0.004243000000, 0.000120000000, 0.020050010000 32 | 391, 0.004762389000, 0.000134984000, 0.022511360000 33 | 392, 0.005330048000, 0.000151492000, 0.025202880000 34 | 393, 0.005978712000, 0.000170208000, 0.028279720000 35 | 394, 0.006741117000, 0.000191816000, 0.031897040000 36 | 395, 0.007650000000, 0.000217000000, 0.036210000000 37 | 396, 0.008751373000, 0.000246906700, 0.041437710000 38 | 397, 0.010028880000, 0.000281240000, 0.047503720000 39 | 398, 0.011421700000, 0.000318520000, 0.054119880000 40 | 399, 0.012869010000, 0.000357266700, 0.060998030000 41 | 400, 0.014310000000, 0.000396000000, 0.067850010000 42 | 401, 0.015704430000, 0.000433714700, 0.074486320000 43 | 402, 0.017147440000, 0.000473024000, 0.081361560000 44 | 403, 0.018781220000, 0.000517876000, 0.089153640000 45 | 404, 0.020748010000, 0.000572218700, 0.098540480000 46 | 405, 0.023190000000, 0.000640000000, 0.110200000000 47 | 406, 0.026207360000, 0.000724560000, 0.124613300000 48 | 407, 0.029782480000, 0.000825500000, 0.141701700000 49 | 408, 0.033880920000, 0.000941160000, 0.161303500000 50 | 409, 0.038468240000, 0.001069880000, 0.183256800000 51 | 410, 0.043510000000, 0.001210000000, 0.207400000000 52 | 411, 0.048995600000, 0.001362091000, 0.233692100000 53 | 412, 0.055022600000, 0.001530752000, 0.262611400000 54 | 413, 0.061718800000, 0.001720368000, 0.294774600000 55 | 414, 0.069212000000, 0.001935323000, 0.330798500000 56 | 415, 0.077630000000, 0.002180000000, 0.371300000000 57 | 416, 0.086958110000, 0.002454800000, 0.416209100000 58 | 417, 0.097176720000, 0.002764000000, 0.465464200000 59 | 418, 0.108406300000, 0.003117800000, 0.519694800000 60 | 419, 0.120767200000, 0.003526400000, 0.579530300000 61 | 420, 0.134380000000, 0.004000000000, 0.645600000000 62 | 421, 0.149358200000, 0.004546240000, 0.718483800000 63 | 422, 0.165395700000, 0.005159320000, 0.796713300000 64 | 423, 0.181983100000, 0.005829280000, 0.877845900000 65 | 424, 0.198611000000, 0.006546160000, 0.959439000000 66 | 425, 0.214770000000, 0.007300000000, 1.039050100000 67 | 426, 0.230186800000, 0.008086507000, 1.115367300000 68 | 427, 0.244879700000, 0.008908720000, 1.188497100000 69 | 428, 0.258777300000, 0.009767680000, 1.258123300000 70 | 429, 0.271807900000, 0.010664430000, 1.323929600000 71 | 430, 0.283900000000, 0.011600000000, 1.385600000000 72 | 431, 0.294943800000, 0.012573170000, 1.442635200000 73 | 432, 0.304896500000, 0.013582720000, 1.494803500000 74 | 433, 0.313787300000, 0.014629680000, 1.542190300000 75 | 434, 0.321645400000, 0.015715090000, 1.584880700000 76 | 435, 0.328500000000, 0.016840000000, 1.622960000000 77 | 436, 0.334351300000, 0.018007360000, 1.656404800000 78 | 437, 0.339210100000, 0.019214480000, 1.685295900000 79 | 438, 0.343121300000, 0.020453920000, 1.709874500000 80 | 439, 0.346129600000, 0.021718240000, 1.730382100000 81 | 440, 0.348280000000, 0.023000000000, 1.747060000000 82 | 441, 0.349599900000, 0.024294610000, 1.760044600000 83 | 442, 0.350147400000, 0.025610240000, 1.769623300000 84 | 443, 0.350013000000, 0.026958570000, 1.776263700000 85 | 444, 0.349287000000, 0.028351250000, 1.780433400000 86 | 445, 0.348060000000, 0.029800000000, 1.782600000000 87 | 446, 0.346373300000, 0.031310830000, 1.782968200000 88 | 447, 0.344262400000, 0.032883680000, 1.781699800000 89 | 448, 0.341808800000, 0.034521120000, 1.779198200000 90 | 449, 0.339094100000, 0.036225710000, 1.775867100000 91 | 450, 0.336200000000, 0.038000000000, 1.772110000000 92 | 451, 0.333197700000, 0.039846670000, 1.768258900000 93 | 452, 0.330041100000, 0.041768000000, 1.764039000000 94 | 453, 0.326635700000, 0.043766000000, 1.758943800000 95 | 454, 0.322886800000, 0.045842670000, 1.752466300000 96 | 455, 0.318700000000, 0.048000000000, 1.744100000000 97 | 456, 0.314025100000, 0.050243680000, 1.733559500000 98 | 457, 0.308884000000, 0.052573040000, 1.720858100000 99 | 458, 0.303290400000, 0.054980560000, 1.705936900000 100 | 459, 0.297257900000, 0.057458720000, 1.688737200000 101 | 460, 0.290800000000, 0.060000000000, 1.669200000000 102 | 461, 0.283970100000, 0.062601970000, 1.647528700000 103 | 462, 0.276721400000, 0.065277520000, 1.623412700000 104 | 463, 0.268917800000, 0.068042080000, 1.596022300000 105 | 464, 0.260422700000, 0.070911090000, 1.564528000000 106 | 465, 0.251100000000, 0.073900000000, 1.528100000000 107 | 466, 0.240847500000, 0.077016000000, 1.486111400000 108 | 467, 0.229851200000, 0.080266400000, 1.439521500000 109 | 468, 0.218407200000, 0.083666800000, 1.389879900000 110 | 469, 0.206811500000, 0.087232800000, 1.338736200000 111 | 470, 0.195360000000, 0.090980000000, 1.287640000000 112 | 471, 0.184213600000, 0.094917550000, 1.237422300000 113 | 472, 0.173327300000, 0.099045840000, 1.187824300000 114 | 473, 0.162688100000, 0.103367400000, 1.138761100000 115 | 474, 0.152283300000, 0.107884600000, 1.090148000000 116 | 475, 0.142100000000, 0.112600000000, 1.041900000000 117 | 476, 0.132178600000, 0.117532000000, 0.994197600000 118 | 477, 0.122569600000, 0.122674400000, 0.947347300000 119 | 478, 0.113275200000, 0.127992800000, 0.901453100000 120 | 479, 0.104297900000, 0.133452800000, 0.856619300000 121 | 480, 0.095640000000, 0.139020000000, 0.812950100000 122 | 481, 0.087299550000, 0.144676400000, 0.770517300000 123 | 482, 0.079308040000, 0.150469300000, 0.729444800000 124 | 483, 0.071717760000, 0.156461900000, 0.689913600000 125 | 484, 0.064580990000, 0.162717700000, 0.652104900000 126 | 485, 0.057950010000, 0.169300000000, 0.616200000000 127 | 486, 0.051862110000, 0.176243100000, 0.582328600000 128 | 487, 0.046281520000, 0.183558100000, 0.550416200000 129 | 488, 0.041150880000, 0.191273500000, 0.520337600000 130 | 489, 0.036412830000, 0.199418000000, 0.491967300000 131 | 490, 0.032010000000, 0.208020000000, 0.465180000000 132 | 491, 0.027917200000, 0.217119900000, 0.439924600000 133 | 492, 0.024144400000, 0.226734500000, 0.416183600000 134 | 493, 0.020687000000, 0.236857100000, 0.393882200000 135 | 494, 0.017540400000, 0.247481200000, 0.372945900000 136 | 495, 0.014700000000, 0.258600000000, 0.353300000000 137 | 496, 0.012161790000, 0.270184900000, 0.334857800000 138 | 497, 0.009919960000, 0.282293900000, 0.317552100000 139 | 498, 0.007967240000, 0.295050500000, 0.301337500000 140 | 499, 0.006296346000, 0.308578000000, 0.286168600000 141 | 500, 0.004900000000, 0.323000000000, 0.272000000000 142 | 501, 0.003777173000, 0.338402100000, 0.258817100000 143 | 502, 0.002945320000, 0.354685800000, 0.246483800000 144 | 503, 0.002424880000, 0.371698600000, 0.234771800000 145 | 504, 0.002236293000, 0.389287500000, 0.223453300000 146 | 505, 0.002400000000, 0.407300000000, 0.212300000000 147 | 506, 0.002925520000, 0.425629900000, 0.201169200000 148 | 507, 0.003836560000, 0.444309600000, 0.190119600000 149 | 508, 0.005174840000, 0.463394400000, 0.179225400000 150 | 509, 0.006982080000, 0.482939500000, 0.168560800000 151 | 510, 0.009300000000, 0.503000000000, 0.158200000000 152 | 511, 0.012149490000, 0.523569300000, 0.148138300000 153 | 512, 0.015535880000, 0.544512000000, 0.138375800000 154 | 513, 0.019477520000, 0.565690000000, 0.128994200000 155 | 514, 0.023992770000, 0.586965300000, 0.120075100000 156 | 515, 0.029100000000, 0.608200000000, 0.111700000000 157 | 516, 0.034814850000, 0.629345600000, 0.103904800000 158 | 517, 0.041120160000, 0.650306800000, 0.096667480000 159 | 518, 0.047985040000, 0.670875200000, 0.089982720000 160 | 519, 0.055378610000, 0.690842400000, 0.083845310000 161 | 520, 0.063270000000, 0.710000000000, 0.078249990000 162 | 521, 0.071635010000, 0.728185200000, 0.073208990000 163 | 522, 0.080462240000, 0.745463600000, 0.068678160000 164 | 523, 0.089739960000, 0.761969400000, 0.064567840000 165 | 524, 0.099456450000, 0.777836800000, 0.060788350000 166 | 525, 0.109600000000, 0.793200000000, 0.057250010000 167 | 526, 0.120167400000, 0.808110400000, 0.053904350000 168 | 527, 0.131114500000, 0.822496200000, 0.050746640000 169 | 528, 0.142367900000, 0.836306800000, 0.047752760000 170 | 529, 0.153854200000, 0.849491600000, 0.044898590000 171 | 530, 0.165500000000, 0.862000000000, 0.042160000000 172 | 531, 0.177257100000, 0.873810800000, 0.039507280000 173 | 532, 0.189140000000, 0.884962400000, 0.036935640000 174 | 533, 0.201169400000, 0.895493600000, 0.034458360000 175 | 534, 0.213365800000, 0.905443200000, 0.032088720000 176 | 535, 0.225749900000, 0.914850100000, 0.029840000000 177 | 536, 0.238320900000, 0.923734800000, 0.027711810000 178 | 537, 0.251066800000, 0.932092400000, 0.025694440000 179 | 538, 0.263992200000, 0.939922600000, 0.023787160000 180 | 539, 0.277101700000, 0.947225200000, 0.021989250000 181 | 540, 0.290400000000, 0.954000000000, 0.020300000000 182 | 541, 0.303891200000, 0.960256100000, 0.018718050000 183 | 542, 0.317572600000, 0.966007400000, 0.017240360000 184 | 543, 0.331438400000, 0.971260600000, 0.015863640000 185 | 544, 0.345482800000, 0.976022500000, 0.014584610000 186 | 545, 0.359700000000, 0.980300000000, 0.013400000000 187 | 546, 0.374083900000, 0.984092400000, 0.012307230000 188 | 547, 0.388639600000, 0.987418200000, 0.011301880000 189 | 548, 0.403378400000, 0.990312800000, 0.010377920000 190 | 549, 0.418311500000, 0.992811600000, 0.009529306000 191 | 550, 0.433449900000, 0.994950100000, 0.008749999000 192 | 551, 0.448795300000, 0.996710800000, 0.008035200000 193 | 552, 0.464336000000, 0.998098300000, 0.007381600000 194 | 553, 0.480064000000, 0.999112000000, 0.006785400000 195 | 554, 0.495971300000, 0.999748200000, 0.006242800000 196 | 555, 0.512050100000, 1.000000000000, 0.005749999000 197 | 556, 0.528295900000, 0.999856700000, 0.005303600000 198 | 557, 0.544691600000, 0.999304600000, 0.004899800000 199 | 558, 0.561209400000, 0.998325500000, 0.004534200000 200 | 559, 0.577821500000, 0.996898700000, 0.004202400000 201 | 560, 0.594500000000, 0.995000000000, 0.003900000000 202 | 561, 0.611220900000, 0.992600500000, 0.003623200000 203 | 562, 0.627975800000, 0.989742600000, 0.003370600000 204 | 563, 0.644760200000, 0.986444400000, 0.003141400000 205 | 564, 0.661569700000, 0.982724100000, 0.002934800000 206 | 565, 0.678400000000, 0.978600000000, 0.002749999000 207 | 566, 0.695239200000, 0.974083700000, 0.002585200000 208 | 567, 0.712058600000, 0.969171200000, 0.002438600000 209 | 568, 0.728828400000, 0.963856800000, 0.002309400000 210 | 569, 0.745518800000, 0.958134900000, 0.002196800000 211 | 570, 0.762100000000, 0.952000000000, 0.002100000000 212 | 571, 0.778543200000, 0.945450400000, 0.002017733000 213 | 572, 0.794825600000, 0.938499200000, 0.001948200000 214 | 573, 0.810926400000, 0.931162800000, 0.001889800000 215 | 574, 0.826824800000, 0.923457600000, 0.001840933000 216 | 575, 0.842500000000, 0.915400000000, 0.001800000000 217 | 576, 0.857932500000, 0.907006400000, 0.001766267000 218 | 577, 0.873081600000, 0.898277200000, 0.001737800000 219 | 578, 0.887894400000, 0.889204800000, 0.001711200000 220 | 579, 0.902318100000, 0.879781600000, 0.001683067000 221 | 580, 0.916300000000, 0.870000000000, 0.001650001000 222 | 581, 0.929799500000, 0.859861300000, 0.001610133000 223 | 582, 0.942798400000, 0.849392000000, 0.001564400000 224 | 583, 0.955277600000, 0.838622000000, 0.001513600000 225 | 584, 0.967217900000, 0.827581300000, 0.001458533000 226 | 585, 0.978600000000, 0.816300000000, 0.001400000000 227 | 586, 0.989385600000, 0.804794700000, 0.001336667000 228 | 587, 0.999548800000, 0.793082000000, 0.001270000000 229 | 588, 1.009089200000, 0.781192000000, 0.001205000000 230 | 589, 1.018006400000, 0.769154700000, 0.001146667000 231 | 590, 1.026300000000, 0.757000000000, 0.001100000000 232 | 591, 1.033982700000, 0.744754100000, 0.001068800000 233 | 592, 1.040986000000, 0.732422400000, 0.001049400000 234 | 593, 1.047188000000, 0.720003600000, 0.001035600000 235 | 594, 1.052466700000, 0.707496500000, 0.001021200000 236 | 595, 1.056700000000, 0.694900000000, 0.001000000000 237 | 596, 1.059794400000, 0.682219200000, 0.000968640000 238 | 597, 1.061799200000, 0.669471600000, 0.000929920000 239 | 598, 1.062806800000, 0.656674400000, 0.000886880000 240 | 599, 1.062909600000, 0.643844800000, 0.000842560000 241 | 600, 1.062200000000, 0.631000000000, 0.000800000000 242 | 601, 1.060735200000, 0.618155500000, 0.000760960000 243 | 602, 1.058443600000, 0.605314400000, 0.000723680000 244 | 603, 1.055224400000, 0.592475600000, 0.000685920000 245 | 604, 1.050976800000, 0.579637900000, 0.000645440000 246 | 605, 1.045600000000, 0.566800000000, 0.000600000000 247 | 606, 1.039036900000, 0.553961100000, 0.000547866700 248 | 607, 1.031360800000, 0.541137200000, 0.000491600000 249 | 608, 1.022666200000, 0.528352800000, 0.000435400000 250 | 609, 1.013047700000, 0.515632300000, 0.000383466700 251 | 610, 1.002600000000, 0.503000000000, 0.000340000000 252 | 611, 0.991367500000, 0.490468800000, 0.000307253300 253 | 612, 0.979331400000, 0.478030400000, 0.000283160000 254 | 613, 0.966491600000, 0.465677600000, 0.000265440000 255 | 614, 0.952847900000, 0.453403200000, 0.000251813300 256 | 615, 0.938400000000, 0.441200000000, 0.000240000000 257 | 616, 0.923194000000, 0.429080000000, 0.000229546700 258 | 617, 0.907244000000, 0.417036000000, 0.000220640000 259 | 618, 0.890502000000, 0.405032000000, 0.000211960000 260 | 619, 0.872920000000, 0.393032000000, 0.000202186700 261 | 620, 0.854449900000, 0.381000000000, 0.000190000000 262 | 621, 0.835084000000, 0.368918400000, 0.000174213300 263 | 622, 0.814946000000, 0.356827200000, 0.000155640000 264 | 623, 0.794186000000, 0.344776800000, 0.000135960000 265 | 624, 0.772954000000, 0.332817600000, 0.000116853300 266 | 625, 0.751400000000, 0.321000000000, 0.000100000000 267 | 626, 0.729583600000, 0.309338100000, 0.000086133330 268 | 627, 0.707588800000, 0.297850400000, 0.000074600000 269 | 628, 0.685602200000, 0.286593600000, 0.000065000000 270 | 629, 0.663810400000, 0.275624500000, 0.000056933330 271 | 630, 0.642400000000, 0.265000000000, 0.000049999990 272 | 631, 0.621514900000, 0.254763200000, 0.000044160000 273 | 632, 0.601113800000, 0.244889600000, 0.000039480000 274 | 633, 0.581105200000, 0.235334400000, 0.000035720000 275 | 634, 0.561397700000, 0.226052800000, 0.000032640000 276 | 635, 0.541900000000, 0.217000000000, 0.000030000000 277 | 636, 0.522599500000, 0.208161600000, 0.000027653330 278 | 637, 0.503546400000, 0.199548800000, 0.000025560000 279 | 638, 0.484743600000, 0.191155200000, 0.000023640000 280 | 639, 0.466193900000, 0.182974400000, 0.000021813330 281 | 640, 0.447900000000, 0.175000000000, 0.000020000000 282 | 641, 0.429861300000, 0.167223500000, 0.000018133330 283 | 642, 0.412098000000, 0.159646400000, 0.000016200000 284 | 643, 0.394644000000, 0.152277600000, 0.000014200000 285 | 644, 0.377533300000, 0.145125900000, 0.000012133330 286 | 645, 0.360800000000, 0.138200000000, 0.000010000000 287 | 646, 0.344456300000, 0.131500300000, 0.000007733333 288 | 647, 0.328516800000, 0.125024800000, 0.000005400000 289 | 648, 0.313019200000, 0.118779200000, 0.000003200000 290 | 649, 0.298001100000, 0.112769100000, 0.000001333333 291 | 650, 0.283500000000, 0.107000000000, 0.000000000000 292 | 651, 0.269544800000, 0.101476200000, 0.000000000000 293 | 652, 0.256118400000, 0.096188640000, 0.000000000000 294 | 653, 0.243189600000, 0.091122960000, 0.000000000000 295 | 654, 0.230727200000, 0.086264850000, 0.000000000000 296 | 655, 0.218700000000, 0.081600000000, 0.000000000000 297 | 656, 0.207097100000, 0.077120640000, 0.000000000000 298 | 657, 0.195923200000, 0.072825520000, 0.000000000000 299 | 658, 0.185170800000, 0.068710080000, 0.000000000000 300 | 659, 0.174832300000, 0.064769760000, 0.000000000000 301 | 660, 0.164900000000, 0.061000000000, 0.000000000000 302 | 661, 0.155366700000, 0.057396210000, 0.000000000000 303 | 662, 0.146230000000, 0.053955040000, 0.000000000000 304 | 663, 0.137490000000, 0.050673760000, 0.000000000000 305 | 664, 0.129146700000, 0.047549650000, 0.000000000000 306 | 665, 0.121200000000, 0.044580000000, 0.000000000000 307 | 666, 0.113639700000, 0.041758720000, 0.000000000000 308 | 667, 0.106465000000, 0.039084960000, 0.000000000000 309 | 668, 0.099690440000, 0.036563840000, 0.000000000000 310 | 669, 0.093330610000, 0.034200480000, 0.000000000000 311 | 670, 0.087400000000, 0.032000000000, 0.000000000000 312 | 671, 0.081900960000, 0.029962610000, 0.000000000000 313 | 672, 0.076804280000, 0.028076640000, 0.000000000000 314 | 673, 0.072077120000, 0.026329360000, 0.000000000000 315 | 674, 0.067686640000, 0.024708050000, 0.000000000000 316 | 675, 0.063600000000, 0.023200000000, 0.000000000000 317 | 676, 0.059806850000, 0.021800770000, 0.000000000000 318 | 677, 0.056282160000, 0.020501120000, 0.000000000000 319 | 678, 0.052971040000, 0.019281080000, 0.000000000000 320 | 679, 0.049818610000, 0.018120690000, 0.000000000000 321 | 680, 0.046770000000, 0.017000000000, 0.000000000000 322 | 681, 0.043784050000, 0.015903790000, 0.000000000000 323 | 682, 0.040875360000, 0.014837180000, 0.000000000000 324 | 683, 0.038072640000, 0.013810680000, 0.000000000000 325 | 684, 0.035404610000, 0.012834780000, 0.000000000000 326 | 685, 0.032900000000, 0.011920000000, 0.000000000000 327 | 686, 0.030564190000, 0.011068310000, 0.000000000000 328 | 687, 0.028380560000, 0.010273390000, 0.000000000000 329 | 688, 0.026344840000, 0.009533311000, 0.000000000000 330 | 689, 0.024452750000, 0.008846157000, 0.000000000000 331 | 690, 0.022700000000, 0.008210000000, 0.000000000000 332 | 691, 0.021084290000, 0.007623781000, 0.000000000000 333 | 692, 0.019599880000, 0.007085424000, 0.000000000000 334 | 693, 0.018237320000, 0.006591476000, 0.000000000000 335 | 694, 0.016987170000, 0.006138485000, 0.000000000000 336 | 695, 0.015840000000, 0.005723000000, 0.000000000000 337 | 696, 0.014790640000, 0.005343059000, 0.000000000000 338 | 697, 0.013831320000, 0.004995796000, 0.000000000000 339 | 698, 0.012948680000, 0.004676404000, 0.000000000000 340 | 699, 0.012129200000, 0.004380075000, 0.000000000000 341 | 700, 0.011359160000, 0.004102000000, 0.000000000000 342 | 701, 0.010629350000, 0.003838453000, 0.000000000000 343 | 702, 0.009938846000, 0.003589099000, 0.000000000000 344 | 703, 0.009288422000, 0.003354219000, 0.000000000000 345 | 704, 0.008678854000, 0.003134093000, 0.000000000000 346 | 705, 0.008110916000, 0.002929000000, 0.000000000000 347 | 706, 0.007582388000, 0.002738139000, 0.000000000000 348 | 707, 0.007088746000, 0.002559876000, 0.000000000000 349 | 708, 0.006627313000, 0.002393244000, 0.000000000000 350 | 709, 0.006195408000, 0.002237275000, 0.000000000000 351 | 710, 0.005790346000, 0.002091000000, 0.000000000000 352 | 711, 0.005409826000, 0.001953587000, 0.000000000000 353 | 712, 0.005052583000, 0.001824580000, 0.000000000000 354 | 713, 0.004717512000, 0.001703580000, 0.000000000000 355 | 714, 0.004403507000, 0.001590187000, 0.000000000000 356 | 715, 0.004109457000, 0.001484000000, 0.000000000000 357 | 716, 0.003833913000, 0.001384496000, 0.000000000000 358 | 717, 0.003575748000, 0.001291268000, 0.000000000000 359 | 718, 0.003334342000, 0.001204092000, 0.000000000000 360 | 719, 0.003109075000, 0.001122744000, 0.000000000000 361 | 720, 0.002899327000, 0.001047000000, 0.000000000000 362 | 721, 0.002704348000, 0.000976589600, 0.000000000000 363 | 722, 0.002523020000, 0.000911108800, 0.000000000000 364 | 723, 0.002354168000, 0.000850133200, 0.000000000000 365 | 724, 0.002196616000, 0.000793238400, 0.000000000000 366 | 725, 0.002049190000, 0.000740000000, 0.000000000000 367 | 726, 0.001910960000, 0.000690082700, 0.000000000000 368 | 727, 0.001781438000, 0.000643310000, 0.000000000000 369 | 728, 0.001660110000, 0.000599496000, 0.000000000000 370 | 729, 0.001546459000, 0.000558454700, 0.000000000000 371 | 730, 0.001439971000, 0.000520000000, 0.000000000000 372 | 731, 0.001340042000, 0.000483913600, 0.000000000000 373 | 732, 0.001246275000, 0.000450052800, 0.000000000000 374 | 733, 0.001158471000, 0.000418345200, 0.000000000000 375 | 734, 0.001076430000, 0.000388718400, 0.000000000000 376 | 735, 0.000999949300, 0.000361100000, 0.000000000000 377 | 736, 0.000928735800, 0.000335383500, 0.000000000000 378 | 737, 0.000862433200, 0.000311440400, 0.000000000000 379 | 738, 0.000800750300, 0.000289165600, 0.000000000000 380 | 739, 0.000743396000, 0.000268453900, 0.000000000000 381 | 740, 0.000690078600, 0.000249200000, 0.000000000000 382 | 741, 0.000640515600, 0.000231301900, 0.000000000000 383 | 742, 0.000594502100, 0.000214685600, 0.000000000000 384 | 743, 0.000551864600, 0.000199288400, 0.000000000000 385 | 744, 0.000512429000, 0.000185047500, 0.000000000000 386 | 745, 0.000476021300, 0.000171900000, 0.000000000000 387 | 746, 0.000442453600, 0.000159778100, 0.000000000000 388 | 747, 0.000411511700, 0.000148604400, 0.000000000000 389 | 748, 0.000382981400, 0.000138301600, 0.000000000000 390 | 749, 0.000356649100, 0.000128792500, 0.000000000000 391 | 750, 0.000332301100, 0.000120000000, 0.000000000000 392 | 751, 0.000309758600, 0.000111859500, 0.000000000000 393 | 752, 0.000288887100, 0.000104322400, 0.000000000000 394 | 753, 0.000269539400, 0.000097335600, 0.000000000000 395 | 754, 0.000251568200, 0.000090845870, 0.000000000000 396 | 755, 0.000234826100, 0.000084800000, 0.000000000000 397 | 756, 0.000219171000, 0.000079146670, 0.000000000000 398 | 757, 0.000204525800, 0.000073858000, 0.000000000000 399 | 758, 0.000190840500, 0.000068916000, 0.000000000000 400 | 759, 0.000178065400, 0.000064302670, 0.000000000000 401 | 760, 0.000166150500, 0.000060000000, 0.000000000000 402 | 761, 0.000155023600, 0.000055981870, 0.000000000000 403 | 762, 0.000144621900, 0.000052225600, 0.000000000000 404 | 763, 0.000134909800, 0.000048718400, 0.000000000000 405 | 764, 0.000125852000, 0.000045447470, 0.000000000000 406 | 765, 0.000117413000, 0.000042400000, 0.000000000000 407 | 766, 0.000109551500, 0.000039561040, 0.000000000000 408 | 767, 0.000102224500, 0.000036915120, 0.000000000000 409 | 768, 0.000095394450, 0.000034448680, 0.000000000000 410 | 769, 0.000089023900, 0.000032148160, 0.000000000000 411 | 770, 0.000083075270, 0.000030000000, 0.000000000000 412 | 771, 0.000077512690, 0.000027991250, 0.000000000000 413 | 772, 0.000072313040, 0.000026113560, 0.000000000000 414 | 773, 0.000067457780, 0.000024360240, 0.000000000000 415 | 774, 0.000062928440, 0.000022724610, 0.000000000000 416 | 775, 0.000058706520, 0.000021200000, 0.000000000000 417 | 776, 0.000054770280, 0.000019778550, 0.000000000000 418 | 777, 0.000051099180, 0.000018452850, 0.000000000000 419 | 778, 0.000047676540, 0.000017216870, 0.000000000000 420 | 779, 0.000044485670, 0.000016064590, 0.000000000000 421 | 780, 0.000041509940, 0.000014990000, 0.000000000000 422 | 781, 0.000038733240, 0.000013987280, 0.000000000000 423 | 782, 0.000036142030, 0.000013051550, 0.000000000000 424 | 783, 0.000033723520, 0.000012178180, 0.000000000000 425 | 784, 0.000031464870, 0.000011362540, 0.000000000000 426 | 785, 0.000029353260, 0.000010600000, 0.000000000000 427 | 786, 0.000027375730, 0.000009885877, 0.000000000000 428 | 787, 0.000025524330, 0.000009217304, 0.000000000000 429 | 788, 0.000023793760, 0.000008592362, 0.000000000000 430 | 789, 0.000022178700, 0.000008009133, 0.000000000000 431 | 790, 0.000020673830, 0.000007465700, 0.000000000000 432 | 791, 0.000019272260, 0.000006959567, 0.000000000000 433 | 792, 0.000017966400, 0.000006487995, 0.000000000000 434 | 793, 0.000016749910, 0.000006048699, 0.000000000000 435 | 794, 0.000015616480, 0.000005639396, 0.000000000000 436 | 795, 0.000014559770, 0.000005257800, 0.000000000000 437 | 796, 0.000013573870, 0.000004901771, 0.000000000000 438 | 797, 0.000012654360, 0.000004569720, 0.000000000000 439 | 798, 0.000011797230, 0.000004260194, 0.000000000000 440 | 799, 0.000010998440, 0.000003971739, 0.000000000000 441 | 800, 0.000010253980, 0.000003702900, 0.000000000000 442 | 801, 0.000009559646, 0.000003452163, 0.000000000000 443 | 802, 0.000008912044, 0.000003218302, 0.000000000000 444 | 803, 0.000008308358, 0.000003000300, 0.000000000000 445 | 804, 0.000007745769, 0.000002797139, 0.000000000000 446 | 805, 0.000007221456, 0.000002607800, 0.000000000000 447 | 806, 0.000006732475, 0.000002431220, 0.000000000000 448 | 807, 0.000006276423, 0.000002266531, 0.000000000000 449 | 808, 0.000005851304, 0.000002113013, 0.000000000000 450 | 809, 0.000005455118, 0.000001969943, 0.000000000000 451 | 810, 0.000005085868, 0.000001836600, 0.000000000000 452 | 811, 0.000004741466, 0.000001712230, 0.000000000000 453 | 812, 0.000004420236, 0.000001596228, 0.000000000000 454 | 813, 0.000004120783, 0.000001488090, 0.000000000000 455 | 814, 0.000003841716, 0.000001387314, 0.000000000000 456 | 815, 0.000003581652, 0.000001293400, 0.000000000000 457 | 816, 0.000003339127, 0.000001205820, 0.000000000000 458 | 817, 0.000003112949, 0.000001124143, 0.000000000000 459 | 818, 0.000002902121, 0.000001048009, 0.000000000000 460 | 819, 0.000002705645, 0.000000977058, 0.000000000000 461 | 820, 0.000002522525, 0.000000910930, 0.000000000000 462 | 821, 0.000002351726, 0.000000849251, 0.000000000000 463 | 822, 0.000002192415, 0.000000791721, 0.000000000000 464 | 823, 0.000002043902, 0.000000738090, 0.000000000000 465 | 824, 0.000001905497, 0.000000688110, 0.000000000000 466 | 825, 0.000001776509, 0.000000641530, 0.000000000000 467 | 826, 0.000001656215, 0.000000598090, 0.000000000000 468 | 827, 0.000001544022, 0.000000557575, 0.000000000000 469 | 828, 0.000001439440, 0.000000519808, 0.000000000000 470 | 829, 0.000001341977, 0.000000484612, 0.000000000000 471 | 830, 0.000001251141, 0.000000451810, 0.000000000000 472 |  -------------------------------------------------------------------------------- /colorpy/data/massage_CIEXYZ.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | massage_CIEXYZ.py - Convert CIE XYZ tables (1931 matching functions, D65) 4 | into appropriate Python syntax to be inserted into ColorPy. 5 | 6 | This was used in developing ColorPy. 7 | 8 | References: 9 | 10 | CVRL Color and Vision Database - http://cvrl.ioo.ucl.ac.uk/index.htm - (accessed 17 Sep 2008) 11 | Color and Vision Research Laboratories. 12 | Provides a set of data sets related to color vision. 13 | ColorPy uses the tables from this site for the 1931 CIE XYZ matching functions, 14 | and for Illuminant D65, both at 1 nm wavelength increments. 15 | 16 | CIE Standards - http://cvrl.ioo.ucl.ac.uk/cie.htm - (accessed 17 Sep 2008) 17 | CIE standards as maintained by CVRL. 18 | The 1931 CIE XYZ and D65 tables that ColorPy uses were obtained from the following files, linked here: 19 | http://cvrl.ioo.ucl.ac.uk/database/data/cmfs/ciexyz31_1.txt 20 | http://cvrl.ioo.ucl.ac.uk/database/data/cie/Illuminantd65.txt 21 | 22 | CIE International Commission on Illumination - http://www.cie.co.at/ - (accessed 17 Sep 2008) 23 | Official website of the CIE. 24 | There are tables of the standard functions (matching functions, illuminants) here: 25 | http://www.cie.co.at/main/freepubs.html 26 | http://www.cie.co.at/publ/abst/datatables15_2004/x2.txt 27 | http://www.cie.co.at/publ/abst/datatables15_2004/y2.txt 28 | http://www.cie.co.at/publ/abst/datatables15_2004/z2.txt 29 | http://www.cie.co.at/publ/abst/datatables15_2004/sid65.txt 30 | ColorPy does not use these specific files. 31 | 32 | License: 33 | 34 | Copyright (C) 2008 Mark Kness 35 | 36 | Author - Mark Kness - mkness@alumni.utexas.net 37 | 38 | This file is part of ColorPy. 39 | 40 | ColorPy is free software: you can redistribute it and/or modify 41 | it under the terms of the GNU Lesser General Public License as 42 | published by the Free Software Foundation, either version 3 of 43 | the License, or (at your option) any later version. 44 | 45 | ColorPy is distributed in the hope that it will be useful, 46 | but WITHOUT ANY WARRANTY; without even the implied warranty of 47 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 48 | GNU Lesser General Public License for more details. 49 | 50 | You should have received a copy of the GNU Lesser General Public License 51 | along with ColorPy. If not, see . 52 | ''' 53 | from __future__ import print_function 54 | 55 | # Conversions for data (5 nm increments) from CIE website: 56 | # http://www.cie.co.at/main/freepubs.html 57 | # http://www.cie.co.at/publ/abst/datatables15_2004/x2.txt 58 | # http://www.cie.co.at/publ/abst/datatables15_2004/y2.txt 59 | # http://www.cie.co.at/publ/abst/datatables15_2004/z2.txt 60 | # ColorPy is not using this data. 61 | 62 | # filenames as downloaded 63 | CIE_x = 'CIEXYZ_1931_x2.txt' 64 | CIE_y = 'CIEXYZ_1931_y2.txt' 65 | CIE_z = 'CIEXYZ_1931_z2.txt' 66 | 67 | def read_CIE_file (filename): 68 | rtn = dict() 69 | f = open (filename, 'r') 70 | lines = f.readlines() 71 | f.close() 72 | # discard first and last lines 73 | lines = lines [1:-1] 74 | for i in lines: 75 | # fields are: wl (nm), intensity (with comma as decimal separator) 76 | fields = i.split() 77 | wl_nm = int (fields [0]) 78 | intensity = fields[1].replace (',', '.') 79 | rtn [wl_nm] = intensity 80 | return rtn 81 | 82 | def create_CIE_XYZ_1931_table_5nm (): 83 | '''Create the table, in (mostly) correct Python.''' 84 | msgs = [] 85 | dict_x = read_CIE_file (CIE_x) 86 | dict_y = read_CIE_file (CIE_y) 87 | dict_z = read_CIE_file (CIE_z) 88 | # get keys 89 | keys = dict_x.keys() # all should be the same 90 | keys.sort() 91 | msgs.append ('_CIEXYZ_1931_table = [\n') 92 | for i in xrange (0, len (keys)): 93 | ikey = keys [i] 94 | wl_nm = ikey 95 | x = dict_x [ikey] 96 | y = dict_y [ikey] 97 | z = dict_z [ikey] 98 | sep = ',' 99 | if i == len (keys)-1: 100 | sep = '' 101 | msgs.append (' [ %3d, %s, %s, %s ]%s\n' % ( 102 | wl_nm, x, y, z, sep)) 103 | msgs.append (']\n') 104 | return msgs 105 | 106 | def doit_CIE_XYZ_1931_5nm (): 107 | '''Create tables from the official CIE data.''' 108 | msgs = create_CIE_XYZ_1931_table_5nm() 109 | for i in msgs: 110 | print (i, end='') 111 | f = open ('CIE_XYZ_1931_5nm.txt', 'w') 112 | f.writelines (msgs) 113 | f.close() 114 | 115 | # Conversions for data (1 nm increments) from CVRL (Color and Vision Research Laboratories) 116 | # http://cvrl.ioo.ucl.ac.uk/database/data/cmfs/ciexyz31_1.txt 117 | # http://cvrl.ioo.ucl.ac.uk/database/data/cie/Illuminantd65.txt 118 | # ColorPy IS using this data. 119 | 120 | def create_CVRL_XYZ_1931_table_1nm (): 121 | msgs = [] 122 | filename = 'ciexyz31_1.txt' 123 | f = open (filename, 'r') 124 | lines = f.readlines() 125 | f.close() 126 | msgs.append ('_CIEXYZ_1931_table = [\n') 127 | for i in xrange (0, len (lines)): 128 | iline = lines [i].rstrip() 129 | sep = ',' 130 | if i == len (lines)-1: 131 | sep = '' 132 | msgs.append (' [ %s ]%s\n' % (iline, sep)) 133 | msgs.append (']\n') 134 | return msgs 135 | 136 | def doit_CVRL_XYZ_1931_table_1nm (): 137 | msgs = create_CVRL_XYZ_1931_table_1nm() 138 | for i in msgs: 139 | print (i, end='') 140 | f = open ('CVRL_XYZ_1931_1nm.txt', 'w') 141 | f.writelines (msgs) 142 | f.close() 143 | 144 | # Data for CIE Illuminant D65 145 | 146 | def create_CVRL_D65_table_1nm (): 147 | msgs = [] 148 | filename = 'Illuminantd65.txt' 149 | f = open (filename, 'r') 150 | lines = f.readlines() 151 | f.close() 152 | msgs.append ('_Illuminant_D65_table = [\n') 153 | for i in xrange (0, len (lines)): 154 | iline = lines [i].rstrip() 155 | sep = ',' 156 | if i == len (lines)-1: 157 | sep = '' 158 | msgs.append (' [ %s ]%s\n' % (iline, sep)) 159 | msgs.append (']\n') 160 | return msgs 161 | 162 | def doit_CVRL_D65_table_1nm (): 163 | msgs = create_CVRL_D65_table_1nm() 164 | for i in msgs: 165 | print (i, end='') 166 | f = open ('CVRL_D65_1nm.txt', 'w') 167 | f.writelines (msgs) 168 | f.close() 169 | 170 | # Main - perform all of the conversions. 171 | # The resulting source files are manually incorporated into the ColorPy code. 172 | 173 | def main (): 174 | doit_CIE_XYZ_1931_5nm () 175 | doit_CVRL_XYZ_1931_table_1nm () 176 | doit_CVRL_D65_table_1nm () 177 | 178 | 179 | if __name__ == '__main__': 180 | main() 181 | -------------------------------------------------------------------------------- /colorpy/dist/colorpy-0.1.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markkness/ColorPy/f2dad2c268895d4b046b767f3aa884f2889b84cb/colorpy/dist/colorpy-0.1.0.tar.gz -------------------------------------------------------------------------------- /colorpy/dist/colorpy-0.1.0.win32.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markkness/ColorPy/f2dad2c268895d4b046b767f3aa884f2889b84cb/colorpy/dist/colorpy-0.1.0.win32.exe -------------------------------------------------------------------------------- /colorpy/dist/colorpy-0.1.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markkness/ColorPy/f2dad2c268895d4b046b767f3aa884f2889b84cb/colorpy/dist/colorpy-0.1.0.zip -------------------------------------------------------------------------------- /colorpy/figures.py: -------------------------------------------------------------------------------- 1 | ''' 2 | figures.py - Create all the ColorPy sample figures. 3 | 4 | Description: 5 | 6 | Creates the sample figures. 7 | 8 | This can also create the figures with some non-default initialization conditions. 9 | 10 | Functions: 11 | 12 | figures() - 13 | Create all the sample figures. 14 | 15 | figures_clip_clamp_to_zero () - 16 | Adjust the color clipping method, and create the sample figures. 17 | 18 | figures_gamma_245 () - 19 | Adjust the gamma correction to a power law gamma = 2.45 and create samples. 20 | 21 | figures_white_A () - 22 | Adjust the white point (for Luv/Lab) and create sample figures. 23 | 24 | License: 25 | 26 | Copyright (C) 2008 Mark Kness 27 | 28 | Author - Mark Kness - mkness@alumni.utexas.net 29 | 30 | This file is part of ColorPy. 31 | 32 | ColorPy is free software: you can redistribute it and/or modify 33 | it under the terms of the GNU Lesser General Public License as 34 | published by the Free Software Foundation, either version 3 of 35 | the License, or (at your option) any later version. 36 | 37 | ColorPy is distributed in the hope that it will be useful, 38 | but WITHOUT ANY WARRANTY; without even the implied warranty of 39 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 40 | GNU Lesser General Public License for more details. 41 | 42 | You should have received a copy of the GNU Lesser General Public License 43 | along with ColorPy. If not, see . 44 | ''' 45 | import colormodels 46 | import illuminants 47 | import plots 48 | import blackbody 49 | import rayleigh 50 | import thinfilm 51 | import misc 52 | 53 | def figures (): 54 | '''Create all the ColorPy sample figures.''' 55 | # no figures for colormodels and ciexyz 56 | colormodels.init() # default 57 | illuminants.figures() 58 | plots.figures() 59 | blackbody.figures() 60 | rayleigh.figures() 61 | thinfilm.figures() 62 | misc.figures() 63 | 64 | def figures_clip_clamp_to_zero (): 65 | '''Adjust the color clipping method, and create the sample figures.''' 66 | colormodels.init() 67 | colormodels.init_clipping (colormodels.CLIP_CLAMP_TO_ZERO) 68 | figures() 69 | 70 | def figures_gamma_245 (): 71 | '''Adjust the gamma correction to a power law gamma = 2.45 and create samples.''' 72 | colormodels.init() 73 | colormodels.init_gamma_correction ( 74 | display_from_linear_function = colormodels.simple_gamma_invert, 75 | linear_from_display_function = colormodels.simple_gamma_correct, 76 | gamma = 2.45) 77 | figures() 78 | 79 | def figures_white_A (): 80 | '''Adjust the white point (for Luv/Lab) and create sample figures.''' 81 | colormodels.init() 82 | colormodels.init_Luv_Lab_white_point (colormodels.WhiteA) 83 | figures() 84 | 85 | 86 | if __name__ == '__main__': 87 | figures() 88 | -------------------------------------------------------------------------------- /colorpy/illuminants.py: -------------------------------------------------------------------------------- 1 | ''' 2 | illuminants.py - Definitions of some standard illuminants. 3 | 4 | Description: 5 | 6 | Illuminants are spectrums, normalized so that Y = 1.0. 7 | 8 | Spectrums are 2D numpy arrays, with one row for each wavelength, 9 | with the first column holding the wavelength in nm, and the 10 | second column the intensity. 11 | 12 | The spectrums have a wavelength increment of 1 nm. 13 | 14 | Functions: 15 | 16 | init () - 17 | Initialize CIE Illuminant D65. This runs on module startup. 18 | 19 | get_illuminant_D65 () - 20 | Get CIE Illuminant D65, as a spectrum, normalized to Y = 1.0. 21 | 22 | CIE standard illuminant D65 represents a phase of natural daylight 23 | with a correlated color temperature of approximately 6504 K. (Wyszecki, p. 144) 24 | 25 | In the interest of standardization the CIE recommends that D65 be used 26 | whenever possible. Otherwise, D55 or D75 are recommended. (Wyszecki, p. 145) 27 | 28 | (ColorPy does not currently provide D55 or D75, however.) 29 | 30 | get_illuminant_A () - 31 | Get CIE Illuminant A, as a spectrum, normalized to Y = 1.0. 32 | This is actually a blackbody illuminant for T = 2856 K. (Wyszecki, p. 143) 33 | 34 | get_blackbody_illuminant (T_K) - 35 | Get the spectrum of a blackbody at the given temperature, normalized to Y = 1.0. 36 | 37 | get_constant_illuminant () - 38 | Get an illuminant, with spectrum constant over wavelength, normalized to Y = 1.0. 39 | 40 | scale_illuminant (illuminant, scaling) - 41 | Scale the illuminant intensity by the specfied factor. 42 | 43 | References: 44 | 45 | Wyszecki and Stiles, Color Science: Concepts and Methods, Quantitative Data and Formulae, 46 | 2nd edition, John Wiley, 1982. Wiley Classics Library Edition 2000. ISBN 0-471-39918-3. 47 | 48 | CVRL Color and Vision Database - http://cvrl.ioo.ucl.ac.uk/index.htm - (accessed 17 Sep 2008) 49 | Color and Vision Research Laboratories. 50 | Provides a set of data sets related to color vision. 51 | ColorPy uses the tables from this site for the 1931 CIE XYZ matching functions, 52 | and for Illuminant D65, both at 1 nm wavelength increments. 53 | 54 | CIE Standards - http://cvrl.ioo.ucl.ac.uk/cie.htm - (accessed 17 Sep 2008) 55 | CIE standards as maintained by CVRL. 56 | The 1931 CIE XYZ and D65 tables that ColorPy uses were obtained from the following files, linked here: 57 | http://cvrl.ioo.ucl.ac.uk/database/data/cmfs/ciexyz31_1.txt 58 | http://cvrl.ioo.ucl.ac.uk/database/data/cie/Illuminantd65.txt 59 | 60 | CIE International Commission on Illumination - http://www.cie.co.at/ - (accessed 17 Sep 2008) 61 | Official website of the CIE. 62 | There are tables of the standard functions (matching functions, illuminants) here: 63 | http://www.cie.co.at/main/freepubs.html 64 | http://www.cie.co.at/publ/abst/datatables15_2004/x2.txt 65 | http://www.cie.co.at/publ/abst/datatables15_2004/y2.txt 66 | http://www.cie.co.at/publ/abst/datatables15_2004/z2.txt 67 | http://www.cie.co.at/publ/abst/datatables15_2004/sid65.txt 68 | ColorPy does not use these specific files. 69 | 70 | License: 71 | 72 | Copyright (C) 2008 Mark Kness 73 | 74 | Author - Mark Kness - mkness@alumni.utexas.net 75 | 76 | This file is part of ColorPy. 77 | 78 | ColorPy is free software: you can redistribute it and/or modify 79 | it under the terms of the GNU Lesser General Public License as 80 | published by the Free Software Foundation, either version 3 of 81 | the License, or (at your option) any later version. 82 | 83 | ColorPy is distributed in the hope that it will be useful, 84 | but WITHOUT ANY WARRANTY; without even the implied warranty of 85 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 86 | GNU Lesser General Public License for more details. 87 | 88 | You should have received a copy of the GNU Lesser General Public License 89 | along with ColorPy. If not, see . 90 | ''' 91 | import ciexyz 92 | import blackbody 93 | import plots 94 | 95 | # table of CIE Illuminant D65 spectrum. 96 | # data from: http://cvrl.ioo.ucl.ac.uk/database/data/cie/Illuminantd65.txt 97 | # massaged into this format. 98 | _Illuminant_D65_table = [ 99 | [ 300, 0.034100 ], 100 | [ 301, 0.360140 ], 101 | [ 302, 0.686180 ], 102 | [ 303, 1.012220 ], 103 | [ 304, 1.338260 ], 104 | [ 305, 1.664300 ], 105 | [ 306, 1.990340 ], 106 | [ 307, 2.316380 ], 107 | [ 308, 2.642420 ], 108 | [ 309, 2.968460 ], 109 | [ 310, 3.294500 ], 110 | [ 311, 4.988650 ], 111 | [ 312, 6.682800 ], 112 | [ 313, 8.376950 ], 113 | [ 314, 10.071100 ], 114 | [ 315, 11.765200 ], 115 | [ 316, 13.459400 ], 116 | [ 317, 15.153500 ], 117 | [ 318, 16.847700 ], 118 | [ 319, 18.541800 ], 119 | [ 320, 20.236000 ], 120 | [ 321, 21.917700 ], 121 | [ 322, 23.599500 ], 122 | [ 323, 25.281200 ], 123 | [ 324, 26.963000 ], 124 | [ 325, 28.644700 ], 125 | [ 326, 30.326500 ], 126 | [ 327, 32.008200 ], 127 | [ 328, 33.690000 ], 128 | [ 329, 35.371700 ], 129 | [ 330, 37.053500 ], 130 | [ 331, 37.343000 ], 131 | [ 332, 37.632600 ], 132 | [ 333, 37.922100 ], 133 | [ 334, 38.211600 ], 134 | [ 335, 38.501100 ], 135 | [ 336, 38.790700 ], 136 | [ 337, 39.080200 ], 137 | [ 338, 39.369700 ], 138 | [ 339, 39.659300 ], 139 | [ 340, 39.948800 ], 140 | [ 341, 40.445100 ], 141 | [ 342, 40.941400 ], 142 | [ 343, 41.437700 ], 143 | [ 344, 41.934000 ], 144 | [ 345, 42.430200 ], 145 | [ 346, 42.926500 ], 146 | [ 347, 43.422800 ], 147 | [ 348, 43.919100 ], 148 | [ 349, 44.415400 ], 149 | [ 350, 44.911700 ], 150 | [ 351, 45.084400 ], 151 | [ 352, 45.257000 ], 152 | [ 353, 45.429700 ], 153 | [ 354, 45.602300 ], 154 | [ 355, 45.775000 ], 155 | [ 356, 45.947700 ], 156 | [ 357, 46.120300 ], 157 | [ 358, 46.293000 ], 158 | [ 359, 46.465600 ], 159 | [ 360, 46.638300 ], 160 | [ 361, 47.183400 ], 161 | [ 362, 47.728500 ], 162 | [ 363, 48.273500 ], 163 | [ 364, 48.818600 ], 164 | [ 365, 49.363700 ], 165 | [ 366, 49.908800 ], 166 | [ 367, 50.453900 ], 167 | [ 368, 50.998900 ], 168 | [ 369, 51.544000 ], 169 | [ 370, 52.089100 ], 170 | [ 371, 51.877700 ], 171 | [ 372, 51.666400 ], 172 | [ 373, 51.455000 ], 173 | [ 374, 51.243700 ], 174 | [ 375, 51.032300 ], 175 | [ 376, 50.820900 ], 176 | [ 377, 50.609600 ], 177 | [ 378, 50.398200 ], 178 | [ 379, 50.186900 ], 179 | [ 380, 49.975500 ], 180 | [ 381, 50.442800 ], 181 | [ 382, 50.910000 ], 182 | [ 383, 51.377300 ], 183 | [ 384, 51.844600 ], 184 | [ 385, 52.311800 ], 185 | [ 386, 52.779100 ], 186 | [ 387, 53.246400 ], 187 | [ 388, 53.713700 ], 188 | [ 389, 54.180900 ], 189 | [ 390, 54.648200 ], 190 | [ 391, 57.458900 ], 191 | [ 392, 60.269500 ], 192 | [ 393, 63.080200 ], 193 | [ 394, 65.890900 ], 194 | [ 395, 68.701500 ], 195 | [ 396, 71.512200 ], 196 | [ 397, 74.322900 ], 197 | [ 398, 77.133600 ], 198 | [ 399, 79.944200 ], 199 | [ 400, 82.754900 ], 200 | [ 401, 83.628000 ], 201 | [ 402, 84.501100 ], 202 | [ 403, 85.374200 ], 203 | [ 404, 86.247300 ], 204 | [ 405, 87.120400 ], 205 | [ 406, 87.993600 ], 206 | [ 407, 88.866700 ], 207 | [ 408, 89.739800 ], 208 | [ 409, 90.612900 ], 209 | [ 410, 91.486000 ], 210 | [ 411, 91.680600 ], 211 | [ 412, 91.875200 ], 212 | [ 413, 92.069700 ], 213 | [ 414, 92.264300 ], 214 | [ 415, 92.458900 ], 215 | [ 416, 92.653500 ], 216 | [ 417, 92.848100 ], 217 | [ 418, 93.042600 ], 218 | [ 419, 93.237200 ], 219 | [ 420, 93.431800 ], 220 | [ 421, 92.756800 ], 221 | [ 422, 92.081900 ], 222 | [ 423, 91.406900 ], 223 | [ 424, 90.732000 ], 224 | [ 425, 90.057000 ], 225 | [ 426, 89.382100 ], 226 | [ 427, 88.707100 ], 227 | [ 428, 88.032200 ], 228 | [ 429, 87.357200 ], 229 | [ 430, 86.682300 ], 230 | [ 431, 88.500600 ], 231 | [ 432, 90.318800 ], 232 | [ 433, 92.137100 ], 233 | [ 434, 93.955400 ], 234 | [ 435, 95.773600 ], 235 | [ 436, 97.591900 ], 236 | [ 437, 99.410200 ], 237 | [ 438, 101.228000 ], 238 | [ 439, 103.047000 ], 239 | [ 440, 104.865000 ], 240 | [ 441, 106.079000 ], 241 | [ 442, 107.294000 ], 242 | [ 443, 108.508000 ], 243 | [ 444, 109.722000 ], 244 | [ 445, 110.936000 ], 245 | [ 446, 112.151000 ], 246 | [ 447, 113.365000 ], 247 | [ 448, 114.579000 ], 248 | [ 449, 115.794000 ], 249 | [ 450, 117.008000 ], 250 | [ 451, 117.088000 ], 251 | [ 452, 117.169000 ], 252 | [ 453, 117.249000 ], 253 | [ 454, 117.330000 ], 254 | [ 455, 117.410000 ], 255 | [ 456, 117.490000 ], 256 | [ 457, 117.571000 ], 257 | [ 458, 117.651000 ], 258 | [ 459, 117.732000 ], 259 | [ 460, 117.812000 ], 260 | [ 461, 117.517000 ], 261 | [ 462, 117.222000 ], 262 | [ 463, 116.927000 ], 263 | [ 464, 116.632000 ], 264 | [ 465, 116.336000 ], 265 | [ 466, 116.041000 ], 266 | [ 467, 115.746000 ], 267 | [ 468, 115.451000 ], 268 | [ 469, 115.156000 ], 269 | [ 470, 114.861000 ], 270 | [ 471, 114.967000 ], 271 | [ 472, 115.073000 ], 272 | [ 473, 115.180000 ], 273 | [ 474, 115.286000 ], 274 | [ 475, 115.392000 ], 275 | [ 476, 115.498000 ], 276 | [ 477, 115.604000 ], 277 | [ 478, 115.711000 ], 278 | [ 479, 115.817000 ], 279 | [ 480, 115.923000 ], 280 | [ 481, 115.212000 ], 281 | [ 482, 114.501000 ], 282 | [ 483, 113.789000 ], 283 | [ 484, 113.078000 ], 284 | [ 485, 112.367000 ], 285 | [ 486, 111.656000 ], 286 | [ 487, 110.945000 ], 287 | [ 488, 110.233000 ], 288 | [ 489, 109.522000 ], 289 | [ 490, 108.811000 ], 290 | [ 491, 108.865000 ], 291 | [ 492, 108.920000 ], 292 | [ 493, 108.974000 ], 293 | [ 494, 109.028000 ], 294 | [ 495, 109.082000 ], 295 | [ 496, 109.137000 ], 296 | [ 497, 109.191000 ], 297 | [ 498, 109.245000 ], 298 | [ 499, 109.300000 ], 299 | [ 500, 109.354000 ], 300 | [ 501, 109.199000 ], 301 | [ 502, 109.044000 ], 302 | [ 503, 108.888000 ], 303 | [ 504, 108.733000 ], 304 | [ 505, 108.578000 ], 305 | [ 506, 108.423000 ], 306 | [ 507, 108.268000 ], 307 | [ 508, 108.112000 ], 308 | [ 509, 107.957000 ], 309 | [ 510, 107.802000 ], 310 | [ 511, 107.501000 ], 311 | [ 512, 107.200000 ], 312 | [ 513, 106.898000 ], 313 | [ 514, 106.597000 ], 314 | [ 515, 106.296000 ], 315 | [ 516, 105.995000 ], 316 | [ 517, 105.694000 ], 317 | [ 518, 105.392000 ], 318 | [ 519, 105.091000 ], 319 | [ 520, 104.790000 ], 320 | [ 521, 105.080000 ], 321 | [ 522, 105.370000 ], 322 | [ 523, 105.660000 ], 323 | [ 524, 105.950000 ], 324 | [ 525, 106.239000 ], 325 | [ 526, 106.529000 ], 326 | [ 527, 106.819000 ], 327 | [ 528, 107.109000 ], 328 | [ 529, 107.399000 ], 329 | [ 530, 107.689000 ], 330 | [ 531, 107.361000 ], 331 | [ 532, 107.032000 ], 332 | [ 533, 106.704000 ], 333 | [ 534, 106.375000 ], 334 | [ 535, 106.047000 ], 335 | [ 536, 105.719000 ], 336 | [ 537, 105.390000 ], 337 | [ 538, 105.062000 ], 338 | [ 539, 104.733000 ], 339 | [ 540, 104.405000 ], 340 | [ 541, 104.369000 ], 341 | [ 542, 104.333000 ], 342 | [ 543, 104.297000 ], 343 | [ 544, 104.261000 ], 344 | [ 545, 104.225000 ], 345 | [ 546, 104.190000 ], 346 | [ 547, 104.154000 ], 347 | [ 548, 104.118000 ], 348 | [ 549, 104.082000 ], 349 | [ 550, 104.046000 ], 350 | [ 551, 103.641000 ], 351 | [ 552, 103.237000 ], 352 | [ 553, 102.832000 ], 353 | [ 554, 102.428000 ], 354 | [ 555, 102.023000 ], 355 | [ 556, 101.618000 ], 356 | [ 557, 101.214000 ], 357 | [ 558, 100.809000 ], 358 | [ 559, 100.405000 ], 359 | [ 560, 100.000000 ], 360 | [ 561, 99.633400 ], 361 | [ 562, 99.266800 ], 362 | [ 563, 98.900300 ], 363 | [ 564, 98.533700 ], 364 | [ 565, 98.167100 ], 365 | [ 566, 97.800500 ], 366 | [ 567, 97.433900 ], 367 | [ 568, 97.067400 ], 368 | [ 569, 96.700800 ], 369 | [ 570, 96.334200 ], 370 | [ 571, 96.279600 ], 371 | [ 572, 96.225000 ], 372 | [ 573, 96.170300 ], 373 | [ 574, 96.115700 ], 374 | [ 575, 96.061100 ], 375 | [ 576, 96.006500 ], 376 | [ 577, 95.951900 ], 377 | [ 578, 95.897200 ], 378 | [ 579, 95.842600 ], 379 | [ 580, 95.788000 ], 380 | [ 581, 95.077800 ], 381 | [ 582, 94.367500 ], 382 | [ 583, 93.657300 ], 383 | [ 584, 92.947000 ], 384 | [ 585, 92.236800 ], 385 | [ 586, 91.526600 ], 386 | [ 587, 90.816300 ], 387 | [ 588, 90.106100 ], 388 | [ 589, 89.395800 ], 389 | [ 590, 88.685600 ], 390 | [ 591, 88.817700 ], 391 | [ 592, 88.949700 ], 392 | [ 593, 89.081800 ], 393 | [ 594, 89.213800 ], 394 | [ 595, 89.345900 ], 395 | [ 596, 89.478000 ], 396 | [ 597, 89.610000 ], 397 | [ 598, 89.742100 ], 398 | [ 599, 89.874100 ], 399 | [ 600, 90.006200 ], 400 | [ 601, 89.965500 ], 401 | [ 602, 89.924800 ], 402 | [ 603, 89.884100 ], 403 | [ 604, 89.843400 ], 404 | [ 605, 89.802600 ], 405 | [ 606, 89.761900 ], 406 | [ 607, 89.721200 ], 407 | [ 608, 89.680500 ], 408 | [ 609, 89.639800 ], 409 | [ 610, 89.599100 ], 410 | [ 611, 89.409100 ], 411 | [ 612, 89.219000 ], 412 | [ 613, 89.029000 ], 413 | [ 614, 88.838900 ], 414 | [ 615, 88.648900 ], 415 | [ 616, 88.458900 ], 416 | [ 617, 88.268800 ], 417 | [ 618, 88.078800 ], 418 | [ 619, 87.888700 ], 419 | [ 620, 87.698700 ], 420 | [ 621, 87.257700 ], 421 | [ 622, 86.816700 ], 422 | [ 623, 86.375700 ], 423 | [ 624, 85.934700 ], 424 | [ 625, 85.493600 ], 425 | [ 626, 85.052600 ], 426 | [ 627, 84.611600 ], 427 | [ 628, 84.170600 ], 428 | [ 629, 83.729600 ], 429 | [ 630, 83.288600 ], 430 | [ 631, 83.329700 ], 431 | [ 632, 83.370700 ], 432 | [ 633, 83.411800 ], 433 | [ 634, 83.452800 ], 434 | [ 635, 83.493900 ], 435 | [ 636, 83.535000 ], 436 | [ 637, 83.576000 ], 437 | [ 638, 83.617100 ], 438 | [ 639, 83.658100 ], 439 | [ 640, 83.699200 ], 440 | [ 641, 83.332000 ], 441 | [ 642, 82.964700 ], 442 | [ 643, 82.597500 ], 443 | [ 644, 82.230200 ], 444 | [ 645, 81.863000 ], 445 | [ 646, 81.495800 ], 446 | [ 647, 81.128500 ], 447 | [ 648, 80.761300 ], 448 | [ 649, 80.394000 ], 449 | [ 650, 80.026800 ], 450 | [ 651, 80.045600 ], 451 | [ 652, 80.064400 ], 452 | [ 653, 80.083100 ], 453 | [ 654, 80.101900 ], 454 | [ 655, 80.120700 ], 455 | [ 656, 80.139500 ], 456 | [ 657, 80.158300 ], 457 | [ 658, 80.177000 ], 458 | [ 659, 80.195800 ], 459 | [ 660, 80.214600 ], 460 | [ 661, 80.420900 ], 461 | [ 662, 80.627200 ], 462 | [ 663, 80.833600 ], 463 | [ 664, 81.039900 ], 464 | [ 665, 81.246200 ], 465 | [ 666, 81.452500 ], 466 | [ 667, 81.658800 ], 467 | [ 668, 81.865200 ], 468 | [ 669, 82.071500 ], 469 | [ 670, 82.277800 ], 470 | [ 671, 81.878400 ], 471 | [ 672, 81.479100 ], 472 | [ 673, 81.079700 ], 473 | [ 674, 80.680400 ], 474 | [ 675, 80.281000 ], 475 | [ 676, 79.881600 ], 476 | [ 677, 79.482300 ], 477 | [ 678, 79.082900 ], 478 | [ 679, 78.683600 ], 479 | [ 680, 78.284200 ], 480 | [ 681, 77.427900 ], 481 | [ 682, 76.571600 ], 482 | [ 683, 75.715300 ], 483 | [ 684, 74.859000 ], 484 | [ 685, 74.002700 ], 485 | [ 686, 73.146500 ], 486 | [ 687, 72.290200 ], 487 | [ 688, 71.433900 ], 488 | [ 689, 70.577600 ], 489 | [ 690, 69.721300 ], 490 | [ 691, 69.910100 ], 491 | [ 692, 70.098900 ], 492 | [ 693, 70.287600 ], 493 | [ 694, 70.476400 ], 494 | [ 695, 70.665200 ], 495 | [ 696, 70.854000 ], 496 | [ 697, 71.042800 ], 497 | [ 698, 71.231500 ], 498 | [ 699, 71.420300 ], 499 | [ 700, 71.609100 ], 500 | [ 701, 71.883100 ], 501 | [ 702, 72.157100 ], 502 | [ 703, 72.431100 ], 503 | [ 704, 72.705100 ], 504 | [ 705, 72.979000 ], 505 | [ 706, 73.253000 ], 506 | [ 707, 73.527000 ], 507 | [ 708, 73.801000 ], 508 | [ 709, 74.075000 ], 509 | [ 710, 74.349000 ], 510 | [ 711, 73.074500 ], 511 | [ 712, 71.800000 ], 512 | [ 713, 70.525500 ], 513 | [ 714, 69.251000 ], 514 | [ 715, 67.976500 ], 515 | [ 716, 66.702000 ], 516 | [ 717, 65.427500 ], 517 | [ 718, 64.153000 ], 518 | [ 719, 62.878500 ], 519 | [ 720, 61.604000 ], 520 | [ 721, 62.432200 ], 521 | [ 722, 63.260300 ], 522 | [ 723, 64.088500 ], 523 | [ 724, 64.916600 ], 524 | [ 725, 65.744800 ], 525 | [ 726, 66.573000 ], 526 | [ 727, 67.401100 ], 527 | [ 728, 68.229300 ], 528 | [ 729, 69.057400 ], 529 | [ 730, 69.885600 ], 530 | [ 731, 70.405700 ], 531 | [ 732, 70.925900 ], 532 | [ 733, 71.446000 ], 533 | [ 734, 71.966200 ], 534 | [ 735, 72.486300 ], 535 | [ 736, 73.006400 ], 536 | [ 737, 73.526600 ], 537 | [ 738, 74.046700 ], 538 | [ 739, 74.566900 ], 539 | [ 740, 75.087000 ], 540 | [ 741, 73.937600 ], 541 | [ 742, 72.788100 ], 542 | [ 743, 71.638700 ], 543 | [ 744, 70.489300 ], 544 | [ 745, 69.339800 ], 545 | [ 746, 68.190400 ], 546 | [ 747, 67.041000 ], 547 | [ 748, 65.891600 ], 548 | [ 749, 64.742100 ], 549 | [ 750, 63.592700 ], 550 | [ 751, 61.875200 ], 551 | [ 752, 60.157800 ], 552 | [ 753, 58.440300 ], 553 | [ 754, 56.722900 ], 554 | [ 755, 55.005400 ], 555 | [ 756, 53.288000 ], 556 | [ 757, 51.570500 ], 557 | [ 758, 49.853100 ], 558 | [ 759, 48.135600 ], 559 | [ 760, 46.418200 ], 560 | [ 761, 48.456900 ], 561 | [ 762, 50.495600 ], 562 | [ 763, 52.534400 ], 563 | [ 764, 54.573100 ], 564 | [ 765, 56.611800 ], 565 | [ 766, 58.650500 ], 566 | [ 767, 60.689200 ], 567 | [ 768, 62.728000 ], 568 | [ 769, 64.766700 ], 569 | [ 770, 66.805400 ], 570 | [ 771, 66.463100 ], 571 | [ 772, 66.120900 ], 572 | [ 773, 65.778600 ], 573 | [ 774, 65.436400 ], 574 | [ 775, 65.094100 ], 575 | [ 776, 64.751800 ], 576 | [ 777, 64.409600 ], 577 | [ 778, 64.067300 ], 578 | [ 779, 63.725100 ], 579 | [ 780, 63.382800 ], 580 | [ 781, 63.474900 ], 581 | [ 782, 63.567000 ], 582 | [ 783, 63.659200 ], 583 | [ 784, 63.751300 ], 584 | [ 785, 63.843400 ], 585 | [ 786, 63.935500 ], 586 | [ 787, 64.027600 ], 587 | [ 788, 64.119800 ], 588 | [ 789, 64.211900 ], 589 | [ 790, 64.304000 ], 590 | [ 791, 63.818800 ], 591 | [ 792, 63.333600 ], 592 | [ 793, 62.848400 ], 593 | [ 794, 62.363200 ], 594 | [ 795, 61.877900 ], 595 | [ 796, 61.392700 ], 596 | [ 797, 60.907500 ], 597 | [ 798, 60.422300 ], 598 | [ 799, 59.937100 ], 599 | [ 800, 59.451900 ], 600 | [ 801, 58.702600 ], 601 | [ 802, 57.953300 ], 602 | [ 803, 57.204000 ], 603 | [ 804, 56.454700 ], 604 | [ 805, 55.705400 ], 605 | [ 806, 54.956200 ], 606 | [ 807, 54.206900 ], 607 | [ 808, 53.457600 ], 608 | [ 809, 52.708300 ], 609 | [ 810, 51.959000 ], 610 | [ 811, 52.507200 ], 611 | [ 812, 53.055300 ], 612 | [ 813, 53.603500 ], 613 | [ 814, 54.151600 ], 614 | [ 815, 54.699800 ], 615 | [ 816, 55.248000 ], 616 | [ 817, 55.796100 ], 617 | [ 818, 56.344300 ], 618 | [ 819, 56.892400 ], 619 | [ 820, 57.440600 ], 620 | [ 821, 57.727800 ], 621 | [ 822, 58.015000 ], 622 | [ 823, 58.302200 ], 623 | [ 824, 58.589400 ], 624 | [ 825, 58.876500 ], 625 | [ 826, 59.163700 ], 626 | [ 827, 59.450900 ], 627 | [ 828, 59.738100 ], 628 | [ 829, 60.025300 ], 629 | [ 830, 60.312500 ] 630 | ] 631 | 632 | _Illuminant_D65 = None 633 | 634 | def init (): 635 | '''Initialize CIE Illuminant D65. This runs on module startup.''' 636 | first_wl = _Illuminant_D65_table [0][0] 637 | # for now, only consider the part in the normal visible range (360-830 nm) 638 | first_index = ciexyz.start_wl_nm - first_wl 639 | table_first = _Illuminant_D65_table [first_index][0] 640 | assert (table_first == 360), 'Mismatch finding 360 nm entry in D65 table' 641 | global _Illuminant_D65 642 | _Illuminant_D65 = ciexyz.empty_spectrum() 643 | (num_wl, num_cols) = _Illuminant_D65.shape 644 | for i in range (0, num_wl): 645 | _Illuminant_D65 [i][1] = _Illuminant_D65_table [first_index + i][1] 646 | # normalization - illuminant is scaled so that Y = 1.0 647 | xyz = ciexyz.xyz_from_spectrum (_Illuminant_D65) 648 | scaling = 1.0 / xyz [1] 649 | _Illuminant_D65 [:,1] *= scaling 650 | 651 | # 652 | # Get any of the available illuminants - D65, A, any blackbody, or a constant spectrum. 653 | # ColorPy does not currently provide D55 or D75. 654 | # 655 | 656 | def get_illuminant_D65 (): 657 | '''Get CIE Illuminant D65, as a spectrum, normalized to Y = 1.0. 658 | 659 | CIE standard illuminant D65 represents a phase of natural daylight 660 | with a correlated color temperature of approximately 6504 K. (Wyszecki, p. 144) 661 | 662 | In the interest of standardization the CIE recommends that D65 be used 663 | whenever possible. Otherwise, D55 or D75 are recommended. (Wyszecki, p. 145) 664 | 665 | (ColorPy does not currently provide D55 or D75, however.)''' 666 | illuminant = _Illuminant_D65.copy() 667 | return illuminant 668 | 669 | def get_illuminant_A (): 670 | '''Get CIE Illuminant A, as a spectrum, normalized to Y = 1.0. 671 | This is actually a blackbody illuminant for T = 2856 K. (Wyszecki, p. 143)''' 672 | illuminant = get_blackbody_illuminant (2856.0) 673 | return illuminant 674 | 675 | def get_blackbody_illuminant (T_K): 676 | '''Get the spectrum of a blackbody at the given temperature, normalized to Y = 1.0.''' 677 | illuminant = blackbody.blackbody_spectrum (T_K) 678 | xyz = ciexyz.xyz_from_spectrum (illuminant) 679 | if xyz [1] != 0.0: 680 | scaling = 1.0 / xyz [1] 681 | illuminant [:,1] *= scaling 682 | return illuminant 683 | 684 | def get_constant_illuminant (): 685 | '''Get an illuminant, with spectrum constant over wavelength, normalized to Y = 1.0.''' 686 | illuminant = ciexyz.empty_spectrum() 687 | (num_wl, num_cols) = illuminant.shape 688 | for i in range (0, num_wl): 689 | illuminant [i][1] = 1.0 690 | xyz = ciexyz.xyz_from_spectrum (illuminant) 691 | if xyz [1] != 0.0: 692 | scaling = 1.0 / xyz [1] 693 | illuminant [:,1] *= scaling 694 | return illuminant 695 | 696 | # Scale an illuminant by an arbitrary factor 697 | 698 | def scale_illuminant (illuminant, scaling): 699 | '''Scale the illuminant intensity by the specfied factor.''' 700 | illuminant [:,1] *= scaling 701 | return illuminant 702 | 703 | # Initialize at module startup 704 | init() 705 | 706 | # Figures - Plot some of the illuminants 707 | 708 | def figures (): 709 | '''Plot spectra for several illuminants.''' 710 | # D65 711 | plots.spectrum_plot ( 712 | get_illuminant_D65(), 'CIE Illuminant D65', 'Illuminant-D65') 713 | # A 714 | plots.spectrum_plot ( 715 | get_illuminant_A(), 'CIE Illuminant A', 'Illuminant-A') 716 | # Constant 717 | plots.spectrum_plot ( 718 | get_constant_illuminant(), 'Constant Illuminant', 'Illuminant-Const') 719 | # Blackbody (5778) 720 | plots.spectrum_plot ( 721 | get_blackbody_illuminant (5778.0), '5778 K Illuminant', 'Illuminant-5778') 722 | -------------------------------------------------------------------------------- /colorpy/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ColorPy 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /colorpy/license.txt: -------------------------------------------------------------------------------- 1 | License: 2 | 3 | Copyright (C) 2008 Mark Kness 4 | 5 | Author - Mark Kness - mkness@alumni.utexas.net 6 | 7 | This file is part of ColorPy. 8 | 9 | ColorPy is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU Lesser General Public License as 11 | published by the Free Software Foundation, either version 3 of 12 | the License, or (at your option) any later version. 13 | 14 | ColorPy is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU Lesser General Public License for more details. 18 | 19 | You should have received a copy of the GNU Lesser General Public License 20 | along with ColorPy. If not, see . 21 | -------------------------------------------------------------------------------- /colorpy/misc.py: -------------------------------------------------------------------------------- 1 | ''' 2 | misc.py - Miscellaneous color plots. 3 | 4 | Description: 5 | 6 | Some miscellaneous plots. 7 | 8 | colorstring_patch_plot (colorstrings, color_names, title, filename, num_across=6) - 9 | Color patch plot for colors specified as hex strings. 10 | 11 | MacBeth_ColorChecker_patch_plot () - 12 | MacBeth ColorChecker Chart. 13 | The xyz values are from Hall p. 119. I do not know for what lighting conditions this applies. 14 | 15 | chemical_solutions_patch_plot () - 16 | Colors of some chemical solutions. 17 | Darren L. Williams et. al., 'Beyond lambda-max: Transforming Visible Spectra into 24-bit Color Values'. 18 | Journal of Chemical Education, Vol 84, No 11, Nov 2007, p1873-1877. 19 | A student laboratory experiment to measure the transmission spectra of some common chemical solutions, 20 | and determine the rgb values. 21 | 22 | universe_patch_plot () - 23 | The average color of the universe. 24 | Karl Glazebrook and Ivan Baldry 25 | http://www.pha.jhu.edu/~kgb/cosspec/ (accessed 17 Sep 2008) 26 | The color of the sum of all light in the universe. 27 | This originally caused some controversy when the (correct) xyz color was incorrectly reported as light green. 28 | The authors also consider several other white points, here we just use the default (normally D65). 29 | 30 | spectral_colors_patch_plot () - 31 | Colors of the pure spectral lines. 32 | 33 | spectral_colors_plus_purples_patch_plot () - 34 | Colors of the pure spectral lines plus purples. 35 | 36 | perceptually_uniform_spectral_colors () - 37 | Patch plot of (nearly) perceptually equally spaced colors, covering the pure spectral lines plus purples. 38 | 39 | spectral_line_555nm_plot () - 40 | Plot a spectrum that has mostly only a line at 555 nm. 41 | It is widened a bit only so the plot looks nicer, otherwise the black curve covers up the color. 42 | 43 | License: 44 | 45 | Copyright (C) 2008 Mark Kness 46 | 47 | Author - Mark Kness - mkness@alumni.utexas.net 48 | 49 | This file is part of ColorPy. 50 | 51 | ColorPy is free software: you can redistribute it and/or modify 52 | it under the terms of the GNU Lesser General Public License as 53 | published by the Free Software Foundation, either version 3 of 54 | the License, or (at your option) any later version. 55 | 56 | ColorPy is distributed in the hope that it will be useful, 57 | but WITHOUT ANY WARRANTY; without even the implied warranty of 58 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 59 | GNU Lesser General Public License for more details. 60 | 61 | You should have received a copy of the GNU Lesser General Public License 62 | along with ColorPy. If not, see . 63 | ''' 64 | import math, numpy 65 | 66 | import colormodels 67 | import ciexyz 68 | import plots 69 | 70 | # Some sample lists of displayable RGB colors as hex strings 71 | 72 | # default colors in Matplotlib 73 | matplotlib_colors = [ 74 | '#0000FF', # b 75 | '#008000', # g 76 | '#FF0000', # r 77 | '#00BFBF', # c 78 | '#BF00BF', # m 79 | '#BFBF00', # y 80 | '#000000' # k 81 | ] 82 | 83 | matplotlib_names = [ 'b', 'g', 'r', 'c', 'm', 'y', 'k' ] 84 | 85 | # Following determined by sampling rgb values of a MATLAB gif of their colormaps - this is imperfect for several reasons... 86 | hsv_colors = [ 87 | '#FF0000', # red 88 | '#FF6300', # orange 89 | '#FFBD00', # yellow-orange 90 | '#DEFF00', # yellow 91 | '#84FF00', # yellow-green 92 | '#21FF00', # green 93 | '#00FF42', # green 94 | '#00FF9C', # green 95 | '#00FFFF', # cyan 96 | '#009CFF', # light blue 97 | '#0042FF', # blue 98 | '#2100FF', # blue 99 | '#8400FF', # violet 100 | '#DE00FF', # magenta 101 | '#FF00BD', # hot pink 102 | '#FF0063' # red 103 | ] 104 | 105 | # Following determined by sampling rgb values of a MATLAB gif of their colormaps - this is imperfect for several reasons... 106 | # The jet colormap is associated with an astrophysical fluid jet simulation from the National Center for Supercomputer Applications. 107 | jet_colors = [ 108 | '#0000BD', '#0000FF', '#0042FF', '#0084FF', 109 | '#00DBFF', '#00FFFF', '#08FFEF', '#42FFBD', 110 | '#84FF84', '#BDFF42', '#FFFF00', '#FFBD00', 111 | '#FF8400', '#FF4200', '#FF0000', '#BD0000', 112 | '#840000' 113 | ] 114 | 115 | # some primary colors, convenient for printer ribbon tests and calibration 116 | primary_colors = [ 117 | '#000000', 118 | '#FF0000', 119 | '#00FF00', 120 | '#0000FF', 121 | '#FFFF00', 122 | '#FF00FF', 123 | '#00FFFF', 124 | '#FFFFFF' 125 | ] 126 | 127 | primary_names = [ 'Black', 'Red', 'Green', 'Blue', 'Yellow', 'Magenta', 'Cyan', 'White' ] 128 | 129 | def colorstring_patch_plot (colorstrings, color_names, title, filename, num_across=6): 130 | '''Color patch plot for colors specified as hex strings.''' 131 | rgb_colors = [] 132 | for color in colorstrings: 133 | irgb = colormodels.irgb_from_irgb_string (color) 134 | rgb = colormodels.rgb_from_irgb (irgb) 135 | rgb_colors.append (rgb) 136 | plots.rgb_patch_plot ( 137 | rgb_colors, 138 | color_names, 139 | title, 140 | filename, 141 | num_across=num_across) 142 | 143 | # Patch plots from xyz color values 144 | 145 | def MacBeth_ColorChecker_patch_plot (): 146 | '''MacBeth ColorChecker Chart. 147 | The xyz values are from Hall p. 119. I do not know for what lighting conditions this applies.''' 148 | xyz_colors = [] 149 | xyz_colors.append (colormodels.xyz_color (0.092, 0.081, 0.058)) 150 | xyz_colors.append (colormodels.xyz_color (0.411, 0.376, 0.303)) 151 | xyz_colors.append (colormodels.xyz_color (0.183, 0.186, 0.373)) 152 | xyz_colors.append (colormodels.xyz_color (0.094, 0.117, 0.067)) 153 | xyz_colors.append (colormodels.xyz_color (0.269, 0.244, 0.503)) 154 | xyz_colors.append (colormodels.xyz_color (0.350, 0.460, 0.531)) 155 | xyz_colors.append (colormodels.xyz_color (0.386, 0.311, 0.066)) 156 | xyz_colors.append (colormodels.xyz_color (0.123, 0.102, 0.359)) 157 | xyz_colors.append (colormodels.xyz_color (0.284, 0.192, 0.151)) 158 | xyz_colors.append (colormodels.xyz_color (0.059, 0.040, 0.102)) 159 | xyz_colors.append (colormodels.xyz_color (0.368, 0.474, 0.127)) 160 | xyz_colors.append (colormodels.xyz_color (0.497, 0.460, 0.094)) 161 | xyz_colors.append (colormodels.xyz_color (0.050, 0.035, 0.183)) 162 | xyz_colors.append (colormodels.xyz_color (0.149, 0.234, 0.106)) 163 | xyz_colors.append (colormodels.xyz_color (0.176, 0.102, 0.048)) 164 | xyz_colors.append (colormodels.xyz_color (0.614, 0.644, 0.112)) 165 | xyz_colors.append (colormodels.xyz_color (0.300, 0.192, 0.332)) 166 | xyz_colors.append (colormodels.xyz_color (0.149, 0.192, 0.421)) 167 | xyz_colors.append (colormodels.xyz_color (0.981, 1.000, 1.184)) 168 | xyz_colors.append (colormodels.xyz_color (0.632, 0.644, 0.763)) 169 | xyz_colors.append (colormodels.xyz_color (0.374, 0.381, 0.451)) 170 | xyz_colors.append (colormodels.xyz_color (0.189, 0.192, 0.227)) 171 | xyz_colors.append (colormodels.xyz_color (0.067, 0.068, 0.080)) 172 | xyz_colors.append (colormodels.xyz_color (0.000, 0.000, 0.000)) 173 | 174 | color_names = [] 175 | color_names.append ('dark skin') 176 | color_names.append ('light skin') 177 | color_names.append ('blue sky') 178 | color_names.append ('foliage') 179 | color_names.append ('blue flower') 180 | color_names.append ('bluish green') 181 | color_names.append ('orange') 182 | color_names.append ('purplish blue') 183 | color_names.append ('moderate red') 184 | color_names.append ('purple') 185 | color_names.append ('yellow green') 186 | color_names.append ('orange yellow') 187 | color_names.append ('blue') 188 | color_names.append ('green') 189 | color_names.append ('red') 190 | color_names.append ('yellow') 191 | color_names.append ('magenta') 192 | color_names.append ('cyan') 193 | color_names.append ('white') 194 | color_names.append ('neutral 8') 195 | color_names.append ('neutral 6.5') 196 | color_names.append ('neutral 5') 197 | color_names.append ('neutral 3.5') 198 | color_names.append ('black') 199 | 200 | plots.xyz_patch_plot ( 201 | xyz_colors, 202 | color_names, 203 | 'MacBeth ColorChecker Chart', 204 | 'MacBeth') 205 | 206 | def chemical_solutions_patch_plot (): 207 | '''Colors of some chemical solutions. 208 | Darren L. Williams et. al., 'Beyond lambda-max: Transforming Visible Spectra into 24-bit Color Values'. 209 | Journal of Chemical Education, Vol 84, No 11, Nov 2007, p1873-1877. 210 | A student laboratory experiment to measure the transmission spectra of some common chemical solutions, 211 | and determine the rgb values.''' 212 | xyz_colors = [] 213 | xyz_colors.append (colormodels.xyz_color (0.360, 0.218, 0.105)) 214 | xyz_colors.append (colormodels.xyz_color (0.458, 0.691, 0.587)) 215 | xyz_colors.append (colormodels.xyz_color (0.445, 0.621, 1.052)) 216 | xyz_colors.append (colormodels.xyz_color (0.742, 0.579, 0.905)) 217 | xyz_colors.append (colormodels.xyz_color (0.949, 1.000, 1.087)) 218 | color_names = [] 219 | color_names.append ('1 M CoCl2') 220 | color_names.append ('1 M NiCl2') 221 | color_names.append ('1 M CuSO4') 222 | color_names.append ('0.005 M KMnO4') 223 | color_names.append ('H2O') 224 | plots.xyz_patch_plot ( 225 | xyz_colors, 226 | color_names, 227 | 'Colors of some chemical solutions\nJ. Chem. Ed., Vol 84, No 11, Nov 2007, p 1873-1877.', 228 | 'ChemSolutions') 229 | 230 | def universe_patch_plot (): 231 | '''The average color of the universe. 232 | Karl Glazebrook and Ivan Baldry 233 | http://www.pha.jhu.edu/~kgb/cosspec/ (accessed 17 Sep 2008) 234 | The color of the sum of all light in the universe. 235 | This caused some controversy when the (correct) xyz color was incorrectly reported as light green. 236 | The authors also consider several other white points, here we just use the default (normally D65).''' 237 | # use the published chromaticity but Y=1.0 238 | xyz_colors = [colormodels.xyz_color_from_xyY (0.345, 0.345, 1.0)] 239 | color_names = ['The Universe'] 240 | plots.xyz_patch_plot ( 241 | xyz_colors, 242 | color_names, 243 | 'Average Color of the Universe\nhttp://www.pha.jhu.edu/~kgb/cosspec/', 244 | 'Universe') 245 | 246 | # Pure spectral colors 247 | 248 | def spectral_colors_patch_plot (): 249 | '''Colors of the pure spectral lines.''' 250 | xyzs = ciexyz.get_normalized_spectral_line_colors (brightness=1.0, num_purples=0, dwl_angstroms=10) 251 | plots.xyz_patch_plot ( 252 | xyzs, None, 'Colors of pure spectral lines', 'Spectral', num_across=20) 253 | 254 | 255 | def spectral_colors_plus_purples_patch_plot (): 256 | '''Colors of the pure spectral lines plus purples.''' 257 | xyzs = ciexyz.get_normalized_spectral_line_colors (brightness=1.0, num_purples=200, dwl_angstroms=10) 258 | plots.xyz_patch_plot ( 259 | xyzs, None, 'Colors of pure spectral lines plus purples', 'SpectralPlusPurples', num_across=20) 260 | 261 | # An attempt to get a perceptually equally spaced (almost) subset of the pure spectral colors 262 | 263 | def perceptually_uniform_spectral_colors ( 264 | brightness = 1.0, 265 | plot_name = 'PerceptuallyEqualColors', 266 | plot_title = 'Perceptually (almost) Equally Spaced Pure Colors', 267 | table_name = 'percep_equal_names.txt'): 268 | '''Patch plot of (nearly) perceptually equally spaced colors, covering the pure spectral lines plus purples.''' 269 | # TODO - This may or may not be quite right... 270 | # get pure colors 271 | # xyzs = ciexyz.get_normalized_spectral_line_colors (brightness=1.0, num_purples=200, dwl_angstroms=1) 272 | (xyzs, names) = ciexyz.get_normalized_spectral_line_colors_annotated (brightness=brightness, num_purples=200, dwl_angstroms=1) 273 | (num_colors, num_columns) = xyzs.shape 274 | 275 | # pick these two functions for either Luv or Lab 276 | uniform_from_xyz = colormodels.luv_from_xyz 277 | xyz_from_uniform = colormodels.xyz_from_luv 278 | #uniform_from_xyz = colormodels.lab_from_xyz 279 | #xyz_from_uniform = colormodels.xyz_from_lab 280 | 281 | # convert colors to a nearly perceptually uniform space 282 | uniforms = numpy.empty ((num_colors, 3)) 283 | for i in range (0, num_colors): 284 | uniforms [i] = uniform_from_xyz (xyzs [i]) 285 | # determine spacing 286 | sum_ds = 0.0 287 | dss = numpy.empty ((num_colors, 1)) 288 | for i in range (0, num_colors-1): 289 | dri = uniforms [i+1] - uniforms [i] 290 | dsi = math.sqrt (numpy.dot (dri, dri)) 291 | dss [i] = dsi 292 | sum_ds += dsi 293 | # last point closes the curve 294 | dri = uniforms [0] - uniforms [num_colors - 1] 295 | dsi = math.sqrt (numpy.dot (dri, dri)) 296 | dss [num_colors - 1] = dsi 297 | sum_ds += dsi 298 | # pick out subsamples as evenly spaced as possible 299 | num_samples = 160 300 | ds_avg = sum_ds / float (num_samples - 1) 301 | E_indices = [] 302 | index = 0 303 | count = 0 304 | need = 0.0 305 | while True: 306 | while need > 1.0e-10: 307 | need -= dss [index] 308 | index += 1 309 | E_indices.append (index) 310 | need += ds_avg 311 | count += 1 312 | if count >= num_samples: 313 | break 314 | # patch plot and save names 315 | xyz_list = [] 316 | fil = open (table_name, 'wt') 317 | fil.write ('%s\n' % plot_title) 318 | fil.write ('Name iRGB\n') 319 | fil.write ('\n') 320 | for index in E_indices: 321 | uniform_color = uniforms [index] 322 | uniform_xyz = xyz_from_uniform (uniform_color) 323 | uniform_irgb = colormodels.irgb_from_xyz (uniform_xyz) 324 | uniform_name = names [index] 325 | xyz_list.append (uniform_xyz) 326 | fil.write ('%s %s\n' % (uniform_name, str (uniform_irgb))) 327 | fil.close () 328 | plots.xyz_patch_plot ( 329 | xyz_list, None, plot_title, plot_name, num_across=20) 330 | 331 | def perceptually_uniform_spectral_color_plots (): 332 | brightness_list = [1.0, 0.9, 0.8, 0.75, 0.6, 0.5, 0.4, 0.3, 0.25] 333 | for brightness in brightness_list: 334 | ibright = math.floor (100.0 * brightness + 0.5) 335 | plot_name = 'PerceptuallyEqualColors_%d' % ibright 336 | plot_title = 'Perceptually (almost) Equally Spaced Pure Colors %d%%' % ibright 337 | table_name = 'percep_equal_names_%d.txt' % ibright 338 | perceptually_uniform_spectral_colors (brightness, plot_name, plot_title, table_name) 339 | 340 | # A sample spectrum that doesn't have equally spaced wavelengths 341 | 342 | def spectral_line_555nm_plot (): 343 | '''Plot a spectrum that has mostly only a line at 555 nm. 344 | It is widened a bit only so the plot looks nicer, otherwise the black curve covers up the color.''' 345 | spectrum_list = [ 346 | [360.0, 0.0], 347 | [549.0, 0.0], 348 | [552.0, 100.0], 349 | [553.0, 100.0], 350 | [554.0, 100.0], 351 | [555.0, 100.0], 352 | [556.0, 100.0], 353 | [557.0, 100.0], 354 | [558.0, 100.0], 355 | [557.0, 0.0], 356 | [830.0, 0.0]] 357 | spectrum = numpy.array (spectrum_list) 358 | plots.spectrum_plot (spectrum, '555 nm Spectral Line', 'line555nm') 359 | 360 | # 361 | 362 | def figures (): 363 | '''Draw the various miscellaneous figures.''' 364 | # patch plots of lists of color hex strings 365 | colorstring_patch_plot (matplotlib_colors, matplotlib_names, 'Default MatPlotLib Colormap', 'matplotlib', num_across=7) 366 | colorstring_patch_plot (hsv_colors, None, 'HSV Colormap', 'hsv') 367 | colorstring_patch_plot (jet_colors, None, 'Jet Colormap', 'jet') 368 | colorstring_patch_plot (primary_colors, primary_names, 'Primary Colors', 'primary', num_across=4) 369 | # patch charts of xyz color tables 370 | MacBeth_ColorChecker_patch_plot () 371 | chemical_solutions_patch_plot () 372 | universe_patch_plot () 373 | # pure colors 374 | spectral_colors_patch_plot () 375 | spectral_colors_plus_purples_patch_plot () 376 | perceptually_uniform_spectral_color_plots () 377 | spectral_line_555nm_plot () 378 | -------------------------------------------------------------------------------- /colorpy/plots.py: -------------------------------------------------------------------------------- 1 | ''' 2 | plots.py - Various types of plots. 3 | 4 | Description: 5 | 6 | Functions to draw various types of plots for light spectra. 7 | 8 | Functions: 9 | 10 | log_interpolate (y0, y1, num_values) - 11 | Return a list of values, num_values in size, logarithmically interpolated 12 | between y0 and y1. The first value will be y0, the last y1. 13 | 14 | tighten_x_axis (x_list) - 15 | Tighten the x axis (only) of the current plot to match the given range of x values. 16 | The y axis limits are not affected. 17 | 18 | General plots: 19 | 20 | rgb_patch_plot ( 21 | rgb_colors, 22 | color_names, 23 | title, 24 | filename, 25 | patch_gap = 0.05, 26 | num_across = 6) - 27 | Draw a set of color patches, specified as linear rgb colors. 28 | 29 | xyz_patch_plot ( 30 | xyz_colors, 31 | color_names, 32 | title, 33 | filename, 34 | patch_gap = 0.05, 35 | num_across = 6) - 36 | Draw a set of color patches specified as xyz colors. 37 | 38 | spectrum_subplot (spectrum) - 39 | Plot a spectrum, with x-axis the wavelength, and y-axis the intensity. 40 | The curve is colored at that wavelength by the (approximate) color of a 41 | pure spectral color at that wavelength, with intensity constant over wavelength. 42 | (This means that dark looking colors here mean that wavelength is poorly viewed by the eye. 43 | This is not a complete plotting function, e.g. no file is saved, etc. 44 | It is assumed that this function is being called by one that handles those things. 45 | 46 | spectrum_plot ( 47 | spectrum, 48 | title, 49 | filename, 50 | xlabel = 'Wavelength ($nm$)', 51 | ylabel = 'Intensity ($W/m^2$)') - 52 | 53 | Plot for a single spectrum - 54 | In a two part graph, plot: 55 | top: color of the spectrum, as a large patch. 56 | low: graph of spectrum intensity vs wavelength (x axis). 57 | The graph is colored by the (approximated) color of each wavelength. 58 | Each wavelength has equal physical intensity, so the variation in 59 | apparent intensity (e.g. 400, 800 nm are very dark, 550 nm is bright), 60 | is due to perceptual factors in the eye. This helps show how much 61 | each wavelength contributes to the percieved color. 62 | 63 | spectrum - spectrum to plot 64 | title - title for plot 65 | filename - filename to save plot to 66 | xlabel - label for x axis 67 | ylabel - label for y axis 68 | 69 | color_vs_param_plot ( 70 | param_list, 71 | rgb_colors, 72 | title, 73 | filename, 74 | tight = False, 75 | plotfunc = pylab.plot, 76 | xlabel = 'param', 77 | ylabel = 'RGB Color') - 78 | 79 | Plot for a color that varies with a parameter - 80 | In a two part figure, draw: 81 | top: color as it varies with parameter (x axis) 82 | low: r,g,b values, as linear 0.0-1.0 values, of the attempted color. 83 | 84 | param_list - list of parameters (x axis) 85 | rgb_colors - numpy array, one row for each param in param_list 86 | title - title for plot 87 | filename - filename to save plot to 88 | plotfunc - optional plot function to use (default pylab.plot) 89 | xlabel - label for x axis 90 | ylabel - label for y axis (default 'RGB Color') 91 | 92 | Specialized plots: 93 | 94 | visible_spectrum_plot () - 95 | Plot the visible spectrum, as a plot vs wavelength. 96 | 97 | cie_matching_functions_plot () - 98 | Plot the CIE XYZ matching functions, as three spectral subplots. 99 | 100 | shark_fin_plot () - 101 | Draw the 'shark fin' CIE chromaticity diagram of the pure spectral lines (plus purples) in xy space. 102 | 103 | License: 104 | 105 | Copyright (C) 2008 Mark Kness 106 | 107 | Author - Mark Kness - mkness@alumni.utexas.net 108 | 109 | This file is part of ColorPy. 110 | 111 | ColorPy is free software: you can redistribute it and/or modify 112 | it under the terms of the GNU Lesser General Public License as 113 | published by the Free Software Foundation, either version 3 of 114 | the License, or (at your option) any later version. 115 | 116 | ColorPy is distributed in the hope that it will be useful, 117 | but WITHOUT ANY WARRANTY; without even the implied warranty of 118 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 119 | GNU Lesser General Public License for more details. 120 | 121 | You should have received a copy of the GNU Lesser General Public License 122 | along with ColorPy. If not, see . 123 | ''' 124 | from __future__ import print_function 125 | 126 | import math 127 | import numpy, pylab 128 | 129 | import colormodels 130 | import ciexyz 131 | 132 | # Miscellaneous utilities for plots 133 | 134 | def log_interpolate (y0, y1, num_values): 135 | '''Return a list of values, num_values in size, logarithmically interpolated 136 | between y0 and y1. The first value will be y0, the last y1.''' 137 | rtn = [] 138 | if num_values <= 0: 139 | raise ValueError('Invalid number of divisions %s in log_interpolate' % (str (num_values))) 140 | if num_values == 1: 141 | # can't use both endpoints, too constrained 142 | yi = math.sqrt (y0 * y1) 143 | rtn.append (yi) 144 | else: 145 | # normal case 146 | beta = math.log (y1 / y0) / float (num_values - 1) 147 | for i in range (0, num_values): 148 | yi = y0 * math.exp (beta * float (i)) 149 | rtn.append (yi) 150 | return rtn 151 | 152 | def tighten_x_axis (x_list): 153 | '''Tighten the x axis (only) of the current plot to match the given range of x values. 154 | The y axis limits are not affected.''' 155 | x_min = min (x_list) 156 | x_max = max (x_list) 157 | pylab.xlim ((x_min, x_max)) 158 | 159 | # 160 | # Patch plots - Plots with each color value as a solid patch, with optional labels. 161 | # 162 | 163 | def rgb_patch_plot ( 164 | rgb_colors, 165 | color_names, 166 | title, 167 | filename, 168 | patch_gap = 0.05, 169 | num_across = 6): 170 | '''Draw a set of color patches, specified as linear rgb colors.''' 171 | 172 | def draw_patch (x0, y0, color, name, patch_gap): 173 | '''Draw a patch of color.''' 174 | # patch relative vertices 175 | m = patch_gap 176 | omm = 1.0 - m 177 | poly_dx = [m, m, omm, omm] 178 | poly_dy = [m, omm, omm, m] 179 | # construct vertices 180 | poly_x = [ x0 + dx_i for dx_i in poly_dx ] 181 | poly_y = [ y0 + dy_i for dy_i in poly_dy ] 182 | pylab.fill (poly_x, poly_y, color) 183 | if name != None: 184 | dtext = 0.1 185 | pylab.text (x0+dtext, y0+dtext, name, size=8.0) 186 | 187 | # make plot with each color with one patch 188 | pylab.clf() 189 | num_colors = len (rgb_colors) 190 | for i in range (0, num_colors): 191 | (iy, ix) = divmod (i, num_across) 192 | # get color as a displayable string 193 | colorstring = colormodels.irgb_string_from_rgb (rgb_colors [i]) 194 | if color_names != None: 195 | name = color_names [i] 196 | else: 197 | name = None 198 | draw_patch (float (ix), float (-iy), colorstring, name, patch_gap) 199 | pylab.axis ('off') 200 | pylab.title (title) 201 | print ('Saving plot %s' % str (filename)) 202 | pylab.savefig (filename) 203 | 204 | def xyz_patch_plot ( 205 | xyz_colors, 206 | color_names, 207 | title, 208 | filename, 209 | patch_gap = 0.05, 210 | num_across = 6): 211 | '''Draw a set of color patches specified as xyz colors.''' 212 | rgb_colors = [] 213 | for xyz in xyz_colors: 214 | rgb = colormodels.rgb_from_xyz (xyz) 215 | rgb_colors.append (rgb) 216 | rgb_patch_plot (rgb_colors, color_names, title, filename, patch_gap=patch_gap, num_across=num_across) 217 | 218 | # 219 | # Spectrum plots 220 | # 221 | 222 | def spectrum_subplot (spectrum): 223 | '''Plot a spectrum, with x-axis the wavelength, and y-axis the intensity. 224 | The curve is colored at that wavelength by the (approximate) color of a 225 | pure spectral color at that wavelength, with intensity constant over wavelength. 226 | (This means that dark looking colors here mean that wavelength is poorly viewed by the eye. 227 | 228 | This is not a complete plotting function, e.g. no file is saved, etc. 229 | It is assumed that this function is being called by one that handles those things.''' 230 | (num_wl, num_cols) = spectrum.shape 231 | # get rgb colors for each wavelength 232 | rgb_colors = numpy.empty ((num_wl, 3)) 233 | for i in range (0, num_wl): 234 | wl_nm = spectrum [i][0] 235 | xyz = ciexyz.xyz_from_wavelength (wl_nm) 236 | rgb_colors [i] = colormodels.rgb_from_xyz (xyz) 237 | # scale to make brightest rgb value = 1.0 238 | rgb_max = numpy.max (rgb_colors) 239 | scaling = 1.0 / rgb_max 240 | rgb_colors *= scaling 241 | # draw color patches (thin vertical lines matching the spectrum curve) in color 242 | for i in range (0, num_wl-1): # skipping the last one here to stay in range 243 | x0 = spectrum [i][0] 244 | x1 = spectrum [i+1][0] 245 | y0 = spectrum [i][1] 246 | y1 = spectrum [i+1][1] 247 | poly_x = [x0, x1, x1, x0] 248 | poly_y = [0.0, 0.0, y1, y0] 249 | color_string = colormodels.irgb_string_from_rgb (rgb_colors [i]) 250 | pylab.fill (poly_x, poly_y, color_string, edgecolor=color_string) 251 | # plot intensity as a curve 252 | pylab.plot ( 253 | spectrum [:,0], spectrum [:,1], 254 | color='k', linewidth=2.0, antialiased=True) 255 | 256 | def spectrum_plot ( 257 | spectrum, 258 | title, 259 | filename, 260 | xlabel = 'Wavelength ($nm$)', 261 | ylabel = 'Intensity ($W/m^2$)'): 262 | '''Plot for a single spectrum - 263 | In a two part graph, plot: 264 | top: color of the spectrum, as a large patch. 265 | low: graph of spectrum intensity vs wavelength (x axis). 266 | The graph is colored by the (approximated) color of each wavelength. 267 | Each wavelength has equal physical intensity, so the variation in 268 | apparent intensity (e.g. 400, 800 nm are very dark, 550 nm is bright), 269 | is due to perceptual factors in the eye. This helps show how much 270 | each wavelength contributes to the percieved color. 271 | 272 | spectrum - spectrum to plot 273 | title - title for plot 274 | filename - filename to save plot to 275 | xlabel - label for x axis 276 | ylabel - label for y axis 277 | ''' 278 | pylab.clf () 279 | # upper plot - solid patch of color that matches the spectrum color 280 | pylab.subplot (2,1,1) 281 | pylab.title (title) 282 | color_string = colormodels.irgb_string_from_rgb ( 283 | colormodels.rgb_from_xyz (ciexyz.xyz_from_spectrum (spectrum))) 284 | poly_x = [0.0, 1.0, 1.0, 0.0] 285 | poly_y = [0.0, 0.0, 1.0, 1.0] 286 | pylab.fill (poly_x, poly_y, color_string) 287 | # draw a solid line around the patch to look nicer 288 | pylab.plot (poly_x, poly_y, color='k', linewidth=2.0) 289 | pylab.axis ('off') 290 | # lower plot - spectrum vs wavelength, with colors of the associated spectral lines below 291 | pylab.subplot (2,1,2) 292 | spectrum_subplot (spectrum) 293 | tighten_x_axis (spectrum [:,0]) 294 | pylab.xlabel (xlabel) 295 | pylab.ylabel (ylabel) 296 | # done 297 | print ('Saving plot %s' % str (filename)) 298 | pylab.savefig (filename) 299 | 300 | # 301 | # Color vs param plot 302 | # 303 | 304 | def color_vs_param_plot ( 305 | param_list, 306 | rgb_colors, 307 | title, 308 | filename, 309 | tight = False, 310 | plotfunc = pylab.plot, 311 | xlabel = 'param', 312 | ylabel = 'RGB Color'): 313 | '''Plot for a color that varies with a parameter - 314 | In a two part figure, draw: 315 | top: color as it varies with parameter (x axis) 316 | low: r,g,b values, as linear 0.0-1.0 values, of the attempted color. 317 | 318 | param_list - list of parameters (x axis) 319 | rgb_colors - numpy array, one row for each param in param_list 320 | title - title for plot 321 | filename - filename to save plot to 322 | plotfunc - optional plot function to use (default pylab.plot) 323 | xlabel - label for x axis 324 | ylabel - label for y axis (default 'RGB Color') 325 | ''' 326 | pylab.clf () 327 | # draw color bars in upper plot 328 | pylab.subplot (2,1,1) 329 | pylab.title (title) 330 | # no xlabel, ylabel in upper plot 331 | num_points = len (param_list) 332 | for i in range (0, num_points-1): 333 | x0 = param_list [i] 334 | x1 = param_list [i+1] 335 | y0 = 0.0 336 | y1 = 1.0 337 | poly_x = [x0, x1, x1, x0] 338 | poly_y = [y0, y0, y1, y1] 339 | color_string = colormodels.irgb_string_from_rgb (rgb_colors [i]) 340 | pylab.fill (poly_x, poly_y, color_string, edgecolor=color_string) 341 | if tight: 342 | tighten_x_axis (param_list) 343 | # draw rgb curves in lower plot 344 | pylab.subplot (2,1,2) 345 | # no title in lower plot 346 | plotfunc (param_list, rgb_colors [:,0], color='r', label='Red') 347 | plotfunc (param_list, rgb_colors [:,1], color='g', label='Green') 348 | plotfunc (param_list, rgb_colors [:,2], color='b', label='Blue') 349 | if tight: 350 | tighten_x_axis (param_list) 351 | pylab.xlabel (xlabel) 352 | pylab.ylabel (ylabel) 353 | print ('Saving plot %s' % str (filename)) 354 | pylab.savefig (filename) 355 | 356 | # 357 | # Some specialized plots 358 | # 359 | 360 | def visible_spectrum_plot (): 361 | '''Plot the visible spectrum, as a plot vs wavelength.''' 362 | spectrum = ciexyz.empty_spectrum() 363 | (num_wl, num_cols) = spectrum.shape 364 | # get rgb colors for each wavelength 365 | rgb_colors = numpy.empty ((num_wl, 3)) 366 | for i in range (0, num_wl): 367 | xyz = ciexyz.xyz_from_wavelength (spectrum [i][0]) 368 | rgb = colormodels.rgb_from_xyz (xyz) 369 | rgb_colors [i] = rgb 370 | # scale to make brightest rgb value = 1.0 371 | rgb_max = numpy.max (rgb_colors) 372 | scaling = 1.0 / rgb_max 373 | rgb_colors *= scaling 374 | # plot colors and rgb values vs wavelength 375 | color_vs_param_plot ( 376 | spectrum [:,0], 377 | rgb_colors, 378 | 'The Visible Spectrum', 379 | 'VisibleSpectrum', 380 | tight = True, 381 | xlabel = r'Wavelength (nm)', 382 | ylabel = r'RGB Color') 383 | 384 | def cie_matching_functions_plot (): 385 | '''Plot the CIE XYZ matching functions, as three spectral subplots.''' 386 | # get 'spectra' for x,y,z matching functions 387 | spectrum_x = ciexyz.empty_spectrum() 388 | spectrum_y = ciexyz.empty_spectrum() 389 | spectrum_z = ciexyz.empty_spectrum() 390 | (num_wl, num_cols) = spectrum_x.shape 391 | for i in range (0, num_wl): 392 | wl_nm = spectrum_x [i][0] 393 | xyz = ciexyz.xyz_from_wavelength (wl_nm) 394 | spectrum_x [i][1] = xyz [0] 395 | spectrum_y [i][1] = xyz [1] 396 | spectrum_z [i][1] = xyz [2] 397 | # Plot three separate subplots, with CIE X in the first, CIE Y in the second, and CIE Z in the third. 398 | # Label appropriately for the whole plot. 399 | pylab.clf () 400 | # X 401 | pylab.subplot (3,1,1) 402 | pylab.title ('1931 CIE XYZ Matching Functions') 403 | pylab.ylabel ('CIE $X$') 404 | spectrum_subplot (spectrum_x) 405 | tighten_x_axis (spectrum_x [:,0]) 406 | # Y 407 | pylab.subplot (3,1,2) 408 | pylab.ylabel ('CIE $Y$') 409 | spectrum_subplot (spectrum_y) 410 | tighten_x_axis (spectrum_x [:,0]) 411 | # Z 412 | pylab.subplot (3,1,3) 413 | pylab.xlabel ('Wavelength (nm)') 414 | pylab.ylabel ('CIE $Z$') 415 | spectrum_subplot (spectrum_z) 416 | tighten_x_axis (spectrum_x [:,0]) 417 | # done 418 | filename = 'CIEXYZ_Matching' 419 | print ('Saving plot %s' % str (filename)) 420 | pylab.savefig (filename) 421 | 422 | def scattered_visual_brightness (): 423 | '''Plot the perceptual brightness of Rayleigh scattered light.''' 424 | # get 'spectra' for y matching functions and multiply by 1/wl^4 425 | spectrum_y = ciexyz.empty_spectrum() 426 | (num_wl, num_cols) = spectrum_y.shape 427 | for i in range (0, num_wl): 428 | wl_nm = spectrum_y [i][0] 429 | rayleigh = math.pow (550.0 / wl_nm, 4) 430 | xyz = ciexyz.xyz_from_wavelength (wl_nm) 431 | spectrum_y [i][1] = xyz [1] * rayleigh 432 | pylab.clf () 433 | pylab.title ('Perceptual Brightness of Rayleigh Scattered Light') 434 | pylab.xlabel ('Wavelength (nm)') 435 | pylab.ylabel ('CIE $Y$ / $\lambda^4$') 436 | spectrum_subplot (spectrum_y) 437 | tighten_x_axis (spectrum_y [:,0]) 438 | # done 439 | filename = 'Visual_scattering' 440 | print ('Saving plot %s' % str (filename)) 441 | pylab.savefig (filename) 442 | 443 | def shark_fin_plot (): 444 | '''Draw the 'shark fin' CIE chromaticity diagram of the pure spectral lines (plus purples) in xy space.''' 445 | # get array of (approximate) colors for the boundary of the fin 446 | xyz_list = ciexyz.get_normalized_spectral_line_colors (brightness=1.0, num_purples=200, dwl_angstroms=2) 447 | # get normalized colors 448 | xy_list = xyz_list.copy() 449 | (num_colors, num_cols) = xy_list.shape 450 | for i in range (0, num_colors): 451 | colormodels.xyz_normalize (xy_list [i]) 452 | # get phosphor colors and normalize 453 | red = colormodels.PhosphorRed 454 | green = colormodels.PhosphorGreen 455 | blue = colormodels.PhosphorBlue 456 | white = colormodels.PhosphorWhite 457 | colormodels.xyz_normalize (red) 458 | colormodels.xyz_normalize (green) 459 | colormodels.xyz_normalize (blue) 460 | colormodels.xyz_normalize (white) 461 | 462 | def get_direc_to_white (xyz): 463 | '''Get unit vector (xy plane) in direction of the white point.''' 464 | direc = white - xyz 465 | mag = math.hypot (direc [0], direc [1]) 466 | if mag != 0.0: 467 | direc /= mag 468 | return (direc[0], direc[1]) 469 | 470 | # plot 471 | pylab.clf () 472 | 473 | # draw best attempt at pure spectral colors on inner edge of shark fin 474 | s = 0.025 # distance in xy plane towards white point 475 | for i in range (0, len (xy_list)-1): 476 | x0 = xy_list [i][0] 477 | y0 = xy_list [i][1] 478 | x1 = xy_list [i+1][0] 479 | y1 = xy_list [i+1][1] 480 | # get unit vectors in direction of white point 481 | (dir_x0, dir_y0) = get_direc_to_white (xy_list [i]) 482 | (dir_x1, dir_y1) = get_direc_to_white (xy_list [i+1]) 483 | # polygon vertices 484 | poly_x = [x0, x1, x1 + s*dir_x1, x0 + s*dir_x0] 485 | poly_y = [y0, y1, y1 + s*dir_y1, y0 + s*dir_y0] 486 | # draw (using full color, not normalized value) 487 | color_string = colormodels.irgb_string_from_rgb ( 488 | colormodels.rgb_from_xyz (xyz_list [i])) 489 | pylab.fill (poly_x, poly_y, color_string, edgecolor=color_string) 490 | 491 | # fill in the monitor gamut with true colors 492 | def get_brightest_irgb_string (xyz): 493 | '''Convert the xyz color to rgb, scale to maximum displayable brightness, and convert to a string.''' 494 | rgb = colormodels.brightest_rgb_from_xyz (xyz) 495 | color_string = colormodels.irgb_string_from_rgb (rgb) 496 | return color_string 497 | 498 | def fill_gamut_slice (v0, v1, v2): 499 | '''Fill in a slice of the monitor gamut with the correct colors.''' 500 | #num_s, num_t = 10, 10 501 | #num_s, num_t = 25, 25 502 | num_s, num_t = 50, 50 503 | dv10 = v1 - v0 504 | dv21 = v2 - v1 505 | for i_s in range (num_s): 506 | s_a = float (i_s) / float (num_s) 507 | s_b = float (i_s+1) / float (num_s) 508 | for i_t in range (num_t): 509 | t_a = float (i_t) / float (num_t) 510 | t_b = float (i_t+1) / float (num_t) 511 | # vertex coords 512 | v_aa = v0 + t_a * (dv10 + s_a * dv21) 513 | v_ab = v0 + t_b * (dv10 + s_a * dv21) 514 | v_ba = v0 + t_a * (dv10 + s_b * dv21) 515 | v_bb = v0 + t_b * (dv10 + s_b * dv21) 516 | # poly coords 517 | poly_x = [v_aa [0], v_ba [0], v_bb [0], v_ab [0]] 518 | poly_y = [v_aa [1], v_ba [1], v_bb [1], v_ab [1]] 519 | # average color 520 | avg = 0.25 * (v_aa + v_ab + v_ba + v_bb) 521 | # convert to rgb and scale to maximum displayable brightness 522 | color_string = get_brightest_irgb_string (avg) 523 | pylab.fill (poly_x, poly_y, color_string, edgecolor=color_string) 524 | fill_gamut_slice (white, blue, green) 525 | fill_gamut_slice (white, green, red) 526 | fill_gamut_slice (white, red, blue) 527 | 528 | # draw the curve of the xy values of the spectral lines and purples 529 | pylab.plot (xy_list [:,0], xy_list [:,1], color='#808080', linewidth=3.0) 530 | # draw monitor gamut and white point 531 | pylab.plot ([red [0], green[0]], [red [1], green[1]], 'o-', color='k') 532 | pylab.plot ([green[0], blue [0]], [green[1], blue [1]], 'o-', color='k') 533 | pylab.plot ([blue [0], red [0]], [blue [1], red [1]], 'o-', color='k') 534 | pylab.plot ([white[0], white[0]], [white[1], white[1]], 'o-', color='k') 535 | # label phosphors 536 | dx = 0.01 537 | dy = 0.01 538 | pylab.text (red [0] + dx, red [1], 'Red', ha='left', va='center') 539 | pylab.text (green [0], green [1] + dy, 'Green', ha='center', va='bottom') 540 | pylab.text (blue [0] - dx, blue [1], 'Blue', ha='right', va='center') 541 | pylab.text (white [0], white [1] + dy, 'White', ha='center', va='bottom') 542 | # titles etc 543 | pylab.axis ([0.0, 0.85, 0.0, 0.85]) 544 | pylab.xlabel (r'CIE $x$') 545 | pylab.ylabel (r'CIE $y$') 546 | pylab.title (r'CIE Chromaticity Diagram') 547 | filename = 'ChromaticityDiagram' 548 | print ('Saving plot %s' % (str (filename))) 549 | pylab.savefig (filename) 550 | 551 | # Special figures 552 | 553 | def figures (): 554 | '''Draw specific figures not used anywhere else.''' 555 | visible_spectrum_plot() 556 | cie_matching_functions_plot() 557 | shark_fin_plot() 558 | scattered_visual_brightness() 559 | 560 | # 561 | # HTML 562 | # 563 | 564 | def get_color_hex_string (red, green, blue): 565 | '''Convert color values to a hex string.''' 566 | hexstr = '#%02X%02X%02X' % (red, green, blue) 567 | return hexstr 568 | 569 | def visible_spectrum_table (filename='visible_spectrum.html'): 570 | '''Write an HTML table with the visible spectrum colors.''' 571 | spectrum = ciexyz.empty_spectrum() 572 | (num_wl, num_cols) = spectrum.shape 573 | # get rgb colors for each wavelength 574 | rgb_colors_1 = numpy.empty ((num_wl, 3)) 575 | rgb_colors_2 = numpy.empty ((num_wl, 3)) 576 | for i in range (0, num_wl): 577 | xyz = ciexyz.xyz_from_wavelength (spectrum [i][0]) 578 | rgb_1 = colormodels.rgb_from_xyz (xyz) 579 | rgb_2 = colormodels.brightest_rgb_from_xyz (xyz) 580 | rgb_colors_1 [i] = rgb_1 581 | rgb_colors_2 [i] = rgb_2 582 | # scale 1 to make brightest rgb value = 1.0 583 | rgb_max = numpy.max (rgb_colors_1) 584 | scaling = 1.0 / rgb_max 585 | rgb_colors_1 *= scaling 586 | # write HTML file 587 | 588 | def write_link (f, url, text): 589 | '''Write an html link.''' 590 | link = '%s
\n' % (url, text) 591 | f.write (link) 592 | 593 | f = open (filename, 'w') 594 | # html headers 595 | f.write ('\n') 596 | f.write ('\n') 597 | f.write ('Colors of Pure Spectral Lines\n') 598 | f.write ('\n') 599 | f.write ('\n') 600 | f.write ('

Colors of Pure Spectral Lines

\n') 601 | f.write ('

%s

\n' % 'White added to undisplayable pure colors to fit into rgb space.') 602 | f.write ('
\n') 603 | # table header 604 | f.write ('\n') 605 | f.write ('\n') 606 | f.write ('\n') 607 | f.write ('\n') 608 | f.write ('\n') 609 | f.write ('\n') 610 | f.write ('\n') 611 | f.write ('\n') 612 | f.write ('\n') 613 | f.write ('\n') 614 | # each row 615 | 616 | for i in range (0, num_wl): 617 | irgb_1 = colormodels.irgb_from_rgb (rgb_colors_1 [i]) 618 | irgb_2 = colormodels.irgb_from_rgb (rgb_colors_2 [i]) 619 | red = irgb_2 [0] 620 | green = irgb_2 [1] 621 | blue = irgb_2 [2] 622 | hexstr_1 = colormodels.irgb_string_from_irgb (irgb_1) 623 | hexstr_2 = colormodels.irgb_string_from_irgb (irgb_2) 624 | 625 | iwl = spectrum [i][0] 626 | code = '%.1f nm' % iwl 627 | 628 | f.write ('\n') 629 | f.write ('\n' % (code)) 630 | f.write ('\n' % (red)) 631 | f.write ('\n' % (green)) 632 | f.write ('\n' % (blue)) 633 | f.write ('\n' % (hexstr_2)) 634 | swatch = " " 635 | f.write ('\n' % (hexstr_2, swatch)) 636 | f.write ('\n' % (hexstr_1, swatch)) 637 | f.write ('\n') 638 | 639 | f.write ('
WavelengthRGBHex CodeFull BrightnessPerceptual Brightness
%s%d%d%d%s%s%s
\n') 640 | # references 641 | f.write ('
\n') 642 | f.write ('

References

\n') 643 | # one source for data 644 | write_link (f, 'http://goffgrafix.com/pantone-rgb-100.php', 'Goffgrafix.com') 645 | # another source with basically the same data 646 | write_link (f, 'http://www.sandaleo.com/pantone.asp', 'Sandaleo.com') 647 | # one with more colors including metallic (also some errors), not quite consistent with the first two 648 | write_link (f, 'http://www.loral.org/Z/Colors/100.html', 649 | 'Loral.org - Conversions based on CorelDRAW v12 Pantone Solid Coated or Pastel Coated tables and sRGB color space.') 650 | # some colors for various sports teams 651 | write_link (f, 'http://www.pennjersey.info/forums/questions-answers/7895-pantone-colors-colleges-university-mlb-nfl-teams.html', 652 | 'Pantone colors for some sports teams.') 653 | # some colors for various national flags 654 | write_link (f, 'http://desktoppub.about.com/od/colorpalettes/l/aa_flagcolors.htm', 'What color is your flag? Pantone colors for some flags.') 655 | write_link (f, 'http://desktoppub.about.com/library/weekly/blcpflagsrwb.htm', 'Red, White, & Blue - Pantone colors for some flags.') 656 | write_link (f, 'http://desktoppub.about.com/library/weekly/blcpflagsyellow.htm', 'Yellow or Gold - Pantone colors for some flags.') 657 | write_link (f, 'http://desktoppub.about.com/library/weekly/blcpflagsgreen.htm', 'Green - Pantone colors for some flags.') 658 | write_link (f, 'http://desktoppub.about.com/library/weekly/blcpatrioticswatches.htm', 'Color swatches - Pantone colors for some flags.') 659 | # official Pantone webpages 660 | write_link (f, 'http://pantone.com/pages/pantone/Pantone.aspx?pg=19970&ca=25', 'An official PANTONE page') 661 | write_link (f, 'http://pantone.com/pages/products/product.aspx?ca=1&pid=293&', 'Another official PANTONE page') 662 | # html ending 663 | f.write ('\n') 664 | f.write ('\n') 665 | f.close() 666 | 667 | def vst (): 668 | visible_spectrum_table () 669 | 670 | 671 | if __name__ == '__main__': 672 | figures() 673 | -------------------------------------------------------------------------------- /colorpy/rayleigh.py: -------------------------------------------------------------------------------- 1 | ''' 2 | rayleigh.py - Rayleigh scattering 3 | 4 | Description: 5 | 6 | Calculation of the scattering by very small particles (compared to the wavelength). 7 | Also known as Rayleigh scattering. 8 | The scattering intensity is proportional to 1/wavelength^4. 9 | It is scaled so that the scattering factor for 555.0 nm is 1.0. 10 | This is the basic physical reason that the sky is blue. 11 | 12 | Functions: 13 | 14 | rayleigh_scattering (wl_nm) - 15 | Get the Rayleigh scattering factor for the wavelength. 16 | Scattering is proportional to 1/wavelength^4. 17 | The scattering is scaled so that the factor for wl_nm = 555.0 is 1.0. 18 | 19 | rayleigh_scattering_spectrum () - 20 | Get the Rayleigh scattering spectrum (independent of illuminant), as a numpy array. 21 | 22 | rayleigh_illuminated_spectrum (illuminant) - 23 | Get the spectrum when illuminated by the specified illuminant. 24 | 25 | rayleigh_illuminated_color (illuminant) - 26 | Get the xyz color when illuminated by the specified illuminant. 27 | 28 | Plots: 29 | 30 | rayleigh_patch_plot (named_illuminant_list, title, filename) - 31 | Make a patch plot of the Rayleigh scattering color for each illuminant. 32 | 33 | rayleigh_color_vs_illuminant_temperature_plot (T_list, title, filename) - 34 | Make a plot of the Rayleigh scattered color vs. temperature of blackbody illuminant. 35 | 36 | rayleigh_spectrum_plot (illuminant, title, filename) - 37 | Plot the spectrum of Rayleigh scattering of the specified illuminant. 38 | 39 | References: 40 | 41 | H.C. van de Hulst, Light Scattering by Small Particles, 42 | Dover Publications, New York, 1981. ISBN 0-486-64228-3. 43 | 44 | License: 45 | 46 | Copyright (C) 2008 Mark Kness 47 | 48 | Author - Mark Kness - mkness@alumni.utexas.net 49 | 50 | This file is part of ColorPy. 51 | 52 | ColorPy is free software: you can redistribute it and/or modify 53 | it under the terms of the GNU Lesser General Public License as 54 | published by the Free Software Foundation, either version 3 of 55 | the License, or (at your option) any later version. 56 | 57 | ColorPy is distributed in the hope that it will be useful, 58 | but WITHOUT ANY WARRANTY; without even the implied warranty of 59 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 60 | GNU Lesser General Public License for more details. 61 | 62 | You should have received a copy of the GNU Lesser General Public License 63 | along with ColorPy. If not, see . 64 | ''' 65 | import math 66 | import numpy, pylab 67 | 68 | import colormodels 69 | import ciexyz 70 | import illuminants 71 | import blackbody 72 | import plots 73 | 74 | def rayleigh_scattering (wl_nm): 75 | '''Get the Rayleigh scattering factor for the wavelength. 76 | Scattering is proportional to 1/wavelength^4. 77 | The scattering is scaled so that the factor for wl_nm = 555.0 is 1.0.''' 78 | wl_0_nm = 555.0 79 | wl_rel = wl_nm / wl_0_nm 80 | rayleigh_factor = math.pow (wl_rel, -4) 81 | return rayleigh_factor 82 | 83 | def rayleigh_scattering_spectrum (): 84 | '''Get the Rayleigh scattering spectrum (independent of illuminant), as a numpy array.''' 85 | spectrum = ciexyz.empty_spectrum() 86 | num_wl = spectrum.shape[0] 87 | for i in range (0, num_wl): 88 | spectrum [i][1] = rayleigh_scattering (spectrum [i][0]) 89 | return spectrum 90 | 91 | def rayleigh_illuminated_spectrum (illuminant): 92 | '''Get the spectrum when illuminated by the specified illuminant.''' 93 | spectrum = rayleigh_scattering_spectrum() 94 | num_wl = spectrum.shape[0] 95 | for i in range (0, num_wl): 96 | spectrum [i][1] *= illuminant [i][1] 97 | return spectrum 98 | 99 | def rayleigh_illuminated_color (illuminant): 100 | '''Get the xyz color when illuminated by the specified illuminant.''' 101 | spectrum = rayleigh_illuminated_spectrum (illuminant) 102 | xyz = ciexyz.xyz_from_spectrum (spectrum) 103 | return xyz 104 | 105 | # 106 | # Figures 107 | # 108 | 109 | def rayleigh_patch_plot (named_illuminant_list, title, filename): 110 | '''Make a patch plot of the Rayleigh scattering color for each illuminant.''' 111 | xyz_colors = [] 112 | color_names = [] 113 | for (illuminant, name) in named_illuminant_list: 114 | xyz = rayleigh_illuminated_color (illuminant) 115 | xyz_colors.append (xyz) 116 | color_names.append (name) 117 | plots.xyz_patch_plot (xyz_colors, color_names, title, filename) 118 | 119 | def rayleigh_color_vs_illuminant_temperature_plot (T_list, title, filename): 120 | '''Make a plot of the Rayleigh scattered color vs. temperature of blackbody illuminant.''' 121 | num_T = len (T_list) 122 | rgb_list = numpy.empty ((num_T, 3)) 123 | for i in range (0, num_T): 124 | T_i = T_list [i] 125 | illuminant = illuminants.get_blackbody_illuminant (T_i) 126 | xyz = rayleigh_illuminated_color (illuminant) 127 | rgb_list [i] = colormodels.rgb_from_xyz (xyz) 128 | plots.color_vs_param_plot ( 129 | T_list, 130 | rgb_list, 131 | title, 132 | filename, 133 | tight = True, 134 | plotfunc = pylab.plot, 135 | xlabel = r'Illuminant Temperature (K)', 136 | ylabel = r'RGB Color') 137 | 138 | def rayleigh_spectrum_plot (illuminant, title, filename): 139 | '''Plot the spectrum of Rayleigh scattering of the specified illuminant.''' 140 | spectrum = rayleigh_illuminated_spectrum (illuminant) 141 | plots.spectrum_plot ( 142 | spectrum, 143 | title, 144 | filename, 145 | xlabel = 'Wavelength (nm)', 146 | ylabel = 'Intensity ($W/m^2$)') 147 | 148 | def figures (): 149 | '''Draw some plots of Rayleigh scattering.''' 150 | # Patch plots for some illuminants. 151 | rayleigh_patch_plot ( 152 | [(illuminants.get_blackbody_illuminant (blackbody.SUN_TEMPERATURE), 'Sun')], 153 | 'Rayleigh Scattering by the Sun', 'Rayleigh-PatchSun') 154 | 155 | rayleigh_patch_plot ( 156 | [(illuminants.get_illuminant_D65 (), 'D65'), 157 | (illuminants.get_blackbody_illuminant (2000.0), '2000 K'), 158 | (illuminants.get_blackbody_illuminant (3500.0), '3500 K'), 159 | (illuminants.get_blackbody_illuminant (blackbody.SUN_TEMPERATURE), 'Sun'), 160 | (illuminants.get_blackbody_illuminant (6500.0), '6500 K'), 161 | (illuminants.get_blackbody_illuminant (15000.0), '15000 K')], 162 | 'Rayleigh Scattering by Various Illuminants', 'Rayleigh-PatchVarious') 163 | 164 | # Scattered color vs blackbody illuminant temperature. 165 | T_list = numpy.linspace(1200.0, 16000.0, 300) 166 | rayleigh_color_vs_illuminant_temperature_plot ( 167 | T_list, 'Rayleigh Scattering Sky Colors', 'Rayleigh-SkyColors') 168 | 169 | # Spectra for several illuminants. 170 | T_list = [2000.0, 3000.0, blackbody.SUN_TEMPERATURE, 6500.0, 11000.0, 15000.0] 171 | for T in T_list: 172 | T_label = '%dK' % (round(T)) 173 | rayleigh_spectrum_plot ( 174 | illuminants.get_blackbody_illuminant (T), 175 | 'Rayleigh Scattering\nIlluminant %g K' % (T), 176 | 'Rayleigh-Spectrum-%s' % (T_label)) 177 | 178 | 179 | if __name__ == '__main__': 180 | figures() 181 | -------------------------------------------------------------------------------- /colorpy/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | setup.py - Setup script to install the ColorPy package. 4 | 5 | To install the ColorPy package: 6 | From the directory in which the ColorPy distribution was unpacked, run: 7 | 8 | python setup.py install 9 | 10 | You should now be able to say 'import colorpy' in your programs and use the package. 11 | 12 | Creating the distribution: 13 | 14 | python setup.py sdist --formats=zip 15 | python setup.py sdist --formats=gztar 16 | python setup.py bdist_wininst 17 | ''' 18 | 19 | from distutils.core import setup 20 | 21 | data_files = [ 22 | 'README.txt', 23 | 'COPYING.txt', 24 | 'COPYING.LESSER.txt', 25 | 'license.txt', 26 | 'ColorPy.html', 27 | ] 28 | 29 | long_description = ''' 30 | ColorPy is a Python package to convert physical descriptions of light - 31 | spectra of light intensity vs. wavelength - into RGB colors that can 32 | be drawn on a computer screen. 33 | It provides a nice set of attractive plots that you can make of such 34 | spectra, and some other color related functions as well. 35 | ''' 36 | 37 | setup ( 38 | name='colorpy', 39 | version='0.1.0', 40 | description='Color calculations with physical descriptions of light spectra', 41 | long_description=long_description, 42 | author='Mark Kness', 43 | author_email='mkness@alumni.utexas.net', 44 | url='http://markkness.net/colorpy/', 45 | license='GNU Lesser GPL Version 3', 46 | package_dir={'colorpy': ''}, 47 | packages=['colorpy'], 48 | package_data={'colorpy': data_files}, 49 | ) 50 | -------------------------------------------------------------------------------- /colorpy/test.py: -------------------------------------------------------------------------------- 1 | ''' 2 | test.py - Run all ColorPy test cases. 3 | 4 | Functions: 5 | 6 | test() - 7 | Run all the test cases. 8 | 9 | License: 10 | 11 | Copyright (C) 2008 Mark Kness 12 | 13 | Author - Mark Kness - mkness@alumni.utexas.net 14 | 15 | This file is part of ColorPy. 16 | 17 | ColorPy is free software: you can redistribute it and/or modify 18 | it under the terms of the GNU Lesser General Public License as 19 | published by the Free Software Foundation, either version 3 of 20 | the License, or (at your option) any later version. 21 | 22 | ColorPy is distributed in the hope that it will be useful, 23 | but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | GNU Lesser General Public License for more details. 26 | 27 | You should have received a copy of the GNU Lesser General Public License 28 | along with ColorPy. If not, see . 29 | ''' 30 | from __future__ import print_function 31 | 32 | import unittest 33 | 34 | import test_colormodels 35 | import test_ciexyz 36 | import test_illuminants 37 | import test_blackbody 38 | import test_rayleigh 39 | import test_thinfilm 40 | 41 | def test (): 42 | # no test cases for plots/misc - but figures.py will exercise those. 43 | # Explicitly run the unittest cases in the modules. 44 | # This is perhaps a bit clumsy. 45 | # A more conventional way to run all of the tests, is at the command line: 46 | # python -m unittest discover 47 | modules = [ 48 | test_blackbody, 49 | test_ciexyz, 50 | test_colormodels, 51 | test_illuminants, 52 | test_rayleigh, 53 | test_thinfilm, 54 | ] 55 | for module in modules: 56 | result = unittest.TestResult() 57 | loader = unittest.TestLoader() 58 | suite = loader.loadTestsFromModule(module) 59 | suite.run(result) 60 | # Print results. 61 | msg = 'Module: %s Errors: %s Failures: %s' % ( 62 | module.__name__, result.errors, result.failures) 63 | print (msg) 64 | print (str(result)) 65 | # Raise an exception if there were problems. 66 | ok = (len(result.errors) == 0) and (len(result.failures) == 0) 67 | if not ok: 68 | # Perhaps not the right exception type... 69 | raise ValueError(msg) 70 | 71 | 72 | if __name__ == '__main__': 73 | test() 74 | -------------------------------------------------------------------------------- /colorpy/test_blackbody.py: -------------------------------------------------------------------------------- 1 | ''' 2 | test_blackbody.py - Test cases for blackbody.py 3 | 4 | License: 5 | 6 | Copyright (C) 2008 Mark Kness 7 | 8 | Author - Mark Kness - mkness@alumni.utexas.net 9 | 10 | This file is part of ColorPy. 11 | 12 | ColorPy is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | ColorPy is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public License 23 | along with ColorPy. If not, see . 24 | ''' 25 | from __future__ import print_function 26 | 27 | import math 28 | import numpy 29 | import unittest 30 | 31 | import blackbody 32 | import colormodels 33 | 34 | # FIXME: The following calculation is not working currently. 35 | # It is an attempt to get the scale of the intensity correct. 36 | # It needs more investigation. 37 | 38 | STEFAN_BOLTZMAN = 5.670e-8 # W/(m^2 K^4) 39 | 40 | def blackbody_total_intensity (T_K, start_wl_nm, end_wl_nm): 41 | '''Get the sum of the specific intensity, at 1 nm increments, from start_wl_nm to end_wl_nm.''' 42 | total = 0.0 43 | for wl_nm in range (start_wl_nm, end_wl_nm+1): 44 | specific = blackbody.blackbody_specific_intensity (wl_nm, T_K) 45 | total += specific 46 | return total 47 | 48 | def blackbody_total_intensity_stefan_boltzman (T_K): 49 | '''Get the sum of the intensities over all wavelengths, assuming the Stefan-Boltzman law.''' 50 | total = STEFAN_BOLTZMAN * math.pow (T_K, 4) 51 | # TODO - What (if any) scaling is required of this result to correspond to blackbody_specific_intensity()? 52 | # I am not sure, and there is a mismatch. 53 | # not entirely sure about the following scaling... See Shu. 54 | scaling = blackbody.SPEED_OF_LIGHT # almost 55 | total *= scaling 56 | return total 57 | 58 | def test_stefan_boltzman(): 59 | '''Test that the total intensity over many wavelengths matches the Stefan-Boltman formula. 60 | NOTE - This currently does not match. I am not sure what the situation is.''' 61 | T = 100.0 62 | sb_test0 = blackbody_total_intensity_stefan_boltzman (T) 63 | print ('sb_test0', sb_test0) 64 | sb_test1 = blackbody_total_intensity (T, 0, 1000) 65 | print ('sb_test1', sb_test1) 66 | sb_test2 = blackbody_total_intensity (T, 0, 10000) 67 | print ('sb_test2', sb_test2) 68 | sb_test3 = blackbody_total_intensity (T, 0, 100000) 69 | print ('sb_test3', sb_test3) 70 | # following start to get slow... 71 | #sb_test4 = blackbody_total_intensity (T, 0, 1000000) 72 | #print ('sb_test4', sb_test4) 73 | #sb_test5 = blackbody_total_intensity (T, 0, 10000000) 74 | #print ('sb_test5', sb_test5) 75 | 76 | # compare the computed result with the stefan-boltzman formula 77 | # TODO - these do not match, although the T^4 behavior is observed... 78 | T_list = [100.0, 1000.0, 4000.0, 6500.0, 10000.0, 15000.0] 79 | for T in T_list: 80 | total_sb = blackbody_total_intensity_stefan_boltzman (T) 81 | # larger wavelength intervals capture more of the total power 82 | total1 = blackbody_total_intensity (T, 360, 830) 83 | total2 = blackbody_total_intensity (T, 1, 1000) 84 | total3 = blackbody_total_intensity (T, 1, 10000) 85 | total4 = blackbody_total_intensity (T, 1, 100000) 86 | ratio = total4 / total_sb 87 | print ('T', T) 88 | print ('total_sb', total_sb) 89 | print ('total1', total1) 90 | print ('total2', total2) 91 | print ('total3', total3) 92 | print ('total4', total4) 93 | print ('ratio', ratio) 94 | 95 | 96 | # Table of xy chromaticities for blackbodies. From (I think): 97 | # Judd and Wyszecki, Color in Business, Science and Industry, 1975, p. 164. 98 | 99 | Judd_Wyszeki_blackbody_chromaticity_table = numpy.array ([ 100 | [ 1000.0, 0.6528, 0.3444], 101 | [ 1400.0, 0.5985, 0.3858], 102 | [ 1600.0, 0.5732, 0.3993], 103 | [ 1800.0, 0.5493, 0.4082], 104 | [ 2000.0, 0.5267, 0.4133], 105 | [ 2200.0, 0.5056, 0.4152], 106 | [ 2400.0, 0.4862, 0.4147], 107 | [ 2600.0, 0.4682, 0.4123], 108 | [ 2800.0, 0.4519, 0.4086], 109 | [ 3000.0, 0.4369, 0.4041], 110 | [ 3200.0, 0.4234, 0.3990], 111 | [ 3400.0, 0.4110, 0.3935], 112 | [ 3600.0, 0.3999, 0.3879], 113 | [ 3800.0, 0.3897, 0.3823], 114 | [ 4200.0, 0.3720, 0.3714], 115 | [ 4500.0, 0.3608, 0.3636], 116 | [ 4800.0, 0.3510, 0.3562], 117 | [ 5200.0, 0.3397, 0.3472], 118 | [ 5800.0, 0.3260, 0.3354], 119 | [ 6500.0, 0.3135, 0.3237], 120 | [ 7500.0, 0.3004, 0.3103], 121 | [ 8500.0, 0.2908, 0.3000], 122 | [10000.0, 0.2807, 0.2884], 123 | [30000.0, 0.2501, 0.2489]]) 124 | 125 | 126 | class TestBlackbody(unittest.TestCase): 127 | ''' Test cases for blackbody spectrum. ''' 128 | 129 | def test_coverage_color(self, verbose=False): 130 | ''' Coverage test of blackbody color. ''' 131 | # Calculate the color for a variety of temperatures. 132 | T_list = numpy.logspace(1.0, 6.0, 21, base=10).tolist() 133 | for T in T_list: 134 | xyz = blackbody.blackbody_color (T) 135 | msg = 'T: %g K xyz: %s' % (T, str(xyz)) 136 | if verbose: 137 | print (msg) 138 | 139 | def test_coverage_total_intensity(self): 140 | ''' Coverage test of blackbody total intensity. ''' 141 | # FIXME: This function is only used in a test that is not working now. 142 | blackbody_total_intensity (100.0, 0, 100) 143 | blackbody_total_intensity (0.0, 0, 100) 144 | blackbody_total_intensity (100000.0, 0, 100) 145 | blackbody_total_intensity (0.0, 0, 100000) 146 | blackbody_total_intensity (100000.0, 0, 100000) 147 | 148 | def test_gold_point(self, verbose=False): 149 | ''' Test the chromaticity at the 'gold point'. ''' 150 | # From Wyszecki & Stiles, p. 28. 151 | T = 1336.0 # 'Gold' point 152 | x_expect = 0.607 153 | y_expect = 0.381 154 | xyz = blackbody.blackbody_color (T) 155 | colormodels.xyz_normalize (xyz) 156 | x_actual = xyz[0] 157 | y_actual = xyz[1] 158 | # Check result. The tolerance is high, there is a discrepancy 159 | # in the last printed digit in the table in the book. 160 | # A tolerance of 5.0e-4 would match the precision in the book. 161 | tolerance = 6.0e-4 162 | self.assertAlmostEqual(x_actual, x_expect, delta=tolerance) 163 | self.assertAlmostEqual(y_actual, y_expect, delta=tolerance) 164 | # This source is supposed to be 0.11 cd/cm^2 = 1100 cd/m^2, 165 | # whereas monitors are c. 80 cd/m^2 to 300 cd/m^2. 166 | msg = 'Blackbody color at gold point: %s' % (str (xyz)) 167 | if verbose: 168 | print (msg) 169 | 170 | def test_judd_wyszecki(self, verbose=False): 171 | ''' Test computed chromaticities vs table in Judd and Wyszecki. ''' 172 | if verbose: 173 | print ('Test vs. Judd and Wyszecki:') 174 | table = Judd_Wyszeki_blackbody_chromaticity_table 175 | num_rows = table.shape[0] 176 | for i in range (0, num_rows): 177 | # Read temperature and expected chromaticity. 178 | T = table [i][0] 179 | x_expect = table [i][1] 180 | y_expect = table [i][2] 181 | # Calculate chromaticity for the temperature. 182 | xyz = blackbody.blackbody_color (T) 183 | colormodels.xyz_normalize (xyz) 184 | x_actual = xyz[0] 185 | y_actual = xyz[1] 186 | # Check against the tabulated result. 187 | x_error = math.fabs(x_actual - x_expect) 188 | y_error = math.fabs(y_actual - y_expect) 189 | # The tolerance used is larger than desired. 190 | # A tolerance of 5.0e-5 would match the precision in the book. 191 | tolerance = 15.0e-5 192 | self.assertAlmostEqual(x_actual, x_expect, delta=tolerance) 193 | self.assertAlmostEqual(y_actual, y_expect, delta=tolerance) 194 | # Print results. 195 | msg = 'T: %8.1f K Calculated x,y: %.5f, %.5f Expected x,y: %.5f, %.5f Error: %.5e, %.5e' % ( 196 | T, x_actual, y_actual, x_expect, y_expect, x_error, y_error) 197 | if verbose: 198 | print (msg) 199 | 200 | 201 | if __name__ == '__main__': 202 | if False: 203 | # This calculation is not working yet... 204 | test_stefan_boltzman() 205 | unittest.main() 206 | -------------------------------------------------------------------------------- /colorpy/test_ciexyz.py: -------------------------------------------------------------------------------- 1 | ''' 2 | test_ciexyz.py - Test module for ciexyz.py. 3 | 4 | License: 5 | 6 | Copyright (C) 2008 Mark Kness 7 | 8 | Author - Mark Kness - mkness@alumni.utexas.net 9 | 10 | This file is part of ColorPy. 11 | 12 | ColorPy is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | ColorPy is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public License 23 | along with ColorPy. If not, see . 24 | ''' 25 | from __future__ import print_function 26 | 27 | import random 28 | import unittest 29 | 30 | import ciexyz 31 | 32 | 33 | class TestCiexyz(unittest.TestCase): 34 | ''' Test cases for CIE XYZ conversions. ''' 35 | 36 | def test_coverage_1(self, verbose=False): 37 | ''' A coverage test. ''' 38 | for i in range (100): 39 | wl_nm = 1000.0 * random.random() 40 | xyz = ciexyz.xyz_from_wavelength (wl_nm) 41 | msg = 'wl_nm = %7.3f, xyz = %s' % (wl_nm, str (xyz)) 42 | if verbose: 43 | print (msg) 44 | 45 | def test_coverage_2(self, verbose=False): 46 | ''' Another coverage test. ''' 47 | empty = ciexyz.empty_spectrum () 48 | xyz = ciexyz.xyz_from_spectrum (empty) 49 | if verbose: 50 | print ('black = %s' % (str (xyz))) 51 | xyz_555 = ciexyz.xyz_from_wavelength (555.0) 52 | if verbose: 53 | print ('555 nm = %s' % (str (xyz_555))) 54 | 55 | 56 | if __name__ == '__main__': 57 | unittest.main() 58 | -------------------------------------------------------------------------------- /colorpy/test_colormodels.py: -------------------------------------------------------------------------------- 1 | ''' 2 | test_colormodels.py - Test routines for colormodels.py. 3 | 4 | License: 5 | 6 | Copyright (C) 2008 Mark Kness 7 | 8 | Author - Mark Kness - mkness@alumni.utexas.net 9 | 10 | This file is part of ColorPy. 11 | 12 | ColorPy is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | ColorPy is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public License 23 | along with ColorPy. If not, see . 24 | ''' 25 | from __future__ import print_function 26 | 27 | import math, random, numpy 28 | import unittest 29 | 30 | import colormodels 31 | import ciexyz 32 | 33 | # Functions to calculate the cutoff point between various algorithms. 34 | # These do not really belong here... 35 | 36 | # Luminance function [of Y value of an XYZ color] used in Luv and Lab. 37 | # See [Kasson p.399] for details. 38 | # The linear range coefficient L_LUM_C has more digits than in the paper, 39 | # this makes the function more continuous over the boundary. 40 | 41 | def calc_L_LUM_C (): 42 | '''L_LUM_C should be ideally chosen so that the two models in L_luminance() agree exactly at the cutoff point. 43 | This is where the extra digits in L_LUM_C, over Kasson, come from.''' 44 | wanted = (colormodels.L_LUM_A * math.pow (colormodels.L_LUM_CUTOFF, 1.0/3.0) - colormodels.L_LUM_B) / colormodels.L_LUM_CUTOFF 45 | print ('optimal L_LUM_C = %.16e' % (wanted)) 46 | 47 | # Utility function for Lab. 48 | # See [Kasson p.399] for details. 49 | # The linear range coefficient has more digits than in the paper, 50 | # this makes the function more continuous over the boundary. 51 | 52 | def calc_LAB_F_A (): 53 | '''LAB_F_A should be ideally chosen so that the two models in Lab_f() agree exactly at the cutoff point. 54 | This is where the extra digits in LAB_F_A, over Kasson, come from.''' 55 | wanted = (math.pow (colormodels.L_LUM_CUTOFF, 1.0/3.0) - colormodels.LAB_F_B) / colormodels.L_LUM_CUTOFF 56 | print ('optimal LAB_F_A = %.16e' % (wanted)) 57 | 58 | 59 | class TestColormodels(unittest.TestCase): 60 | ''' Test cases for colormodel conversions. ''' 61 | 62 | def test_rgb_xyz_matrices_inverses(self, verbose=False): 63 | ''' Test that the rgb<--->xyz conversion matrices are inverses of each other. ''' 64 | test_eye0 = numpy.dot (colormodels.rgb_from_xyz_matrix, colormodels.xyz_from_rgb_matrix) 65 | test_eye1 = numpy.dot (colormodels.xyz_from_rgb_matrix, colormodels.rgb_from_xyz_matrix) 66 | msg0 = 'RGB_from_XYZ * XYZ_from_RGB =\n%s' % (str(test_eye0)) 67 | msg1 = 'XYZ_from_RGB * RGB_from_XYZ =\n%s' % (str(test_eye1)) 68 | if verbose: 69 | print (msg0) 70 | print (msg1) 71 | atol = 1.0e-8 72 | ok0 = numpy.allclose (test_eye0, numpy.eye (3), atol=atol) 73 | ok1 = numpy.allclose (test_eye1, numpy.eye (3), atol=atol) 74 | self.assertTrue(ok0) 75 | self.assertTrue(ok1) 76 | 77 | def check_xyz_rgb(self, xyz0, verbose): 78 | ''' Check that the xyz color, converted to rgb then back, remains the same. ''' 79 | rgb0 = colormodels.rgb_from_xyz (xyz0) 80 | xyz1 = colormodels.xyz_from_rgb (rgb0) 81 | rgb1 = colormodels.rgb_from_xyz (xyz1) 82 | # Check errors. 83 | err_rgb = rgb1 - rgb0 84 | error_rgb = math.sqrt (numpy.dot (err_rgb, err_rgb)) 85 | err_xyz = xyz1 - xyz0 86 | error_xyz = math.sqrt (numpy.dot (err_xyz, err_xyz)) 87 | tolerance = 1.0e-10 88 | self.assertLess(error_xyz, tolerance) 89 | self.assertLess(error_rgb, tolerance) 90 | msg = 'xyz: %s rgb: %s xyz2: %s rgb2: %s' % ( 91 | str(xyz0), str(rgb0), str(xyz1), str(rgb1)) 92 | if verbose: 93 | print (msg) 94 | 95 | def test_xyz_rgb(self, verbose=False): 96 | ''' Test some color values via check_xyz_rgb(). ''' 97 | for i in range (100): 98 | x0 = 10.0 * random.random() 99 | y0 = 10.0 * random.random() 100 | z0 = 10.0 * random.random() 101 | xyz0 = colormodels.xyz_color (x0, y0, z0) 102 | self.check_xyz_rgb (xyz0, verbose) 103 | 104 | def check_xyz_irgb(self, xyz0, verbose): 105 | ''' Check the direct conversions from xyz to irgb. ''' 106 | irgb0 = colormodels.irgb_from_rgb ( 107 | colormodels.rgb_from_xyz (xyz0)) 108 | irgb1 = colormodels.irgb_from_xyz (xyz0) 109 | self.assertEqual(irgb0[0], irgb1[0]) 110 | self.assertEqual(irgb0[1], irgb1[1]) 111 | self.assertEqual(irgb0[2], irgb1[2]) 112 | # The string should also match. 113 | irgbs0 = colormodels.irgb_string_from_rgb ( 114 | colormodels.rgb_from_xyz (xyz0)) 115 | irgbs1 = colormodels.irgb_string_from_xyz (xyz0) 116 | msg = 'irgb0: %s text0: %s irgb1: %s text1: %s' % ( 117 | str(irgb0), irgbs0, str(irgb1), irgbs1) 118 | if verbose: 119 | print (msg) 120 | self.assertEqual(irgbs0, irgbs1) 121 | 122 | def test_xyz_irgb(self, verbose=False): 123 | ''' Test the direct conversions from xyz to irgb. ''' 124 | for i in range (100): 125 | x0 = 10.0 * random.random() 126 | y0 = 10.0 * random.random() 127 | z0 = 10.0 * random.random() 128 | xyz0 = colormodels.xyz_color (x0,y0,z0) 129 | self.check_xyz_irgb(xyz0, verbose) 130 | 131 | def check_rgb_irgb(self, irgb0, verbose): 132 | ''' Check that conversions between rgb and irgb are invertible. ''' 133 | rgb0 = colormodels.rgb_from_irgb (irgb0) 134 | irgb1 = colormodels.irgb_from_rgb (rgb0) 135 | rgb1 = colormodels.rgb_from_irgb (irgb1) 136 | # Integer conversion should match exactly. 137 | self.assertEqual(irgb0[0], irgb1[0]) 138 | self.assertEqual(irgb0[1], irgb1[1]) 139 | self.assertEqual(irgb0[2], irgb1[2]) 140 | msg = 'irgb0: %s irgb1: %s' % (str(irgb0), str(irgb1)) 141 | if verbose: 142 | print (msg) 143 | # Float conversion should match closely. 144 | # (It actually seems to match exactly for me.) 145 | tolerance = 1.0e-14 146 | err_rgb = rgb1 - rgb0 147 | err_r = math.fabs (err_rgb [0]) 148 | err_g = math.fabs (err_rgb [1]) 149 | err_b = math.fabs (err_rgb [2]) 150 | self.assertLessEqual(err_r, tolerance) 151 | self.assertLessEqual(err_g, tolerance) 152 | self.assertLessEqual(err_b, tolerance) 153 | msg = 'rgb0: %s rgb1: %s' % (str(rgb0), str(rgb1)) 154 | if verbose: 155 | print (msg) 156 | 157 | def test_rgb_irgb(self, verbose=False): 158 | ''' Test that conversions between rgb and irgb are invertible. ''' 159 | for i in range (100): 160 | ir = random.randrange (0, 256) 161 | ig = random.randrange (0, 256) 162 | ib = random.randrange (0, 256) 163 | irgb0 = colormodels.irgb_color (ir, ig, ib) 164 | self.check_rgb_irgb(irgb0, verbose) 165 | 166 | def check_irgb_string(self, irgb, verbose): 167 | ''' Convert back and forth from irgb and irgb_string. ''' 168 | irgb_string = colormodels.irgb_string_from_irgb (irgb) 169 | irgb2 = colormodels.irgb_from_irgb_string (irgb_string) 170 | irgb_string2 = colormodels.irgb_string_from_irgb (irgb2) 171 | # Values should match. 172 | self.assertEqual(irgb[0], irgb2[0]) 173 | self.assertEqual(irgb[1], irgb2[1]) 174 | self.assertEqual(irgb[2], irgb2[2]) 175 | # String should match. 176 | self.assertEqual(irgb_string, irgb_string2) 177 | msg = 'irgb: %s irgb2: %s irgb_string: %s irgb_string2: %s' % ( 178 | str(irgb), str(irgb2), irgb_string, irgb_string2) 179 | if verbose: 180 | print (msg) 181 | 182 | def test_irgb_string(self, verbose=False): 183 | ''' Convert back and forth from irgb and irgb_string. ''' 184 | for i in range (100): 185 | ir = random.randrange (0, 256) 186 | ig = random.randrange (0, 256) 187 | ib = random.randrange (0, 256) 188 | irgb = colormodels.irgb_color (ir, ig, ib) 189 | self.check_irgb_string(irgb, verbose) 190 | 191 | # Clipping. 192 | 193 | def test_clipping(self, verbose=False): 194 | ''' Test the various color clipping methods. ''' 195 | # This is just a coverage test. 196 | xyz_colors = ciexyz.get_normalized_spectral_line_colors () 197 | num_wl = xyz_colors.shape[0] 198 | for i in range (num_wl): 199 | # Get rgb values for standard add white clipping. 200 | colormodels.init_clipping (colormodels.CLIP_ADD_WHITE) 201 | rgb_white_color = colormodels.irgb_string_from_rgb ( 202 | colormodels.rgb_from_xyz (xyz_colors [i])) 203 | 204 | # Get rgb values for clamp-to-zero clipping. 205 | colormodels.init_clipping (colormodels.CLIP_CLAMP_TO_ZERO) 206 | rgb_clamp_color = colormodels.irgb_string_from_rgb ( 207 | colormodels.rgb_from_xyz (xyz_colors [i])) 208 | 209 | msg = 'Wavelength: %s White: %s Clamp: %s' % ( 210 | str(i), # FIXME: Put in Angstroms. 211 | rgb_white_color, 212 | rgb_clamp_color) 213 | if verbose: 214 | print (msg) 215 | 216 | # Gamma correction. 217 | 218 | def check_gamma_correction(self, verbose): 219 | ''' Check if the current gamma correction is consistent. ''' 220 | for i in range (10): 221 | x = 10.0 * (2.0 * random.random() - 1.0) 222 | a = colormodels.linear_from_display_component (x) 223 | y = colormodels.display_from_linear_component (a) 224 | b = colormodels.linear_from_display_component (y) 225 | # Check errors. 226 | abs_err1 = math.fabs (y - x) 227 | rel_err1 = math.fabs (abs_err1 / (y + x)) 228 | abs_err2 = math.fabs (b - a) 229 | rel_err2 = math.fabs (abs_err2 / (b + a)) 230 | msg1 = 'x = %g, y = %g, err = %g, rel = %g' % (x, y, abs_err1, rel_err1) 231 | msg2 = 'a = %g, b = %g, err = %g, rel = %g' % (a, b, abs_err2, rel_err2) 232 | if verbose: 233 | print (msg1) 234 | print (msg2) 235 | tolerance = 1.0e-14 236 | self.assertLessEqual(rel_err1, tolerance) 237 | self.assertLessEqual(rel_err2, tolerance) 238 | 239 | def test_gamma_srgb(self, verbose=False): 240 | ''' Test default sRGB component (cannot supply exponent). ''' 241 | msg = 'Testing sRGB gamma:' 242 | if verbose: 243 | print (msg) 244 | colormodels.init_gamma_correction ( 245 | display_from_linear_function = colormodels.srgb_gamma_invert, 246 | linear_from_display_function = colormodels.srgb_gamma_correct) 247 | self.check_gamma_correction(verbose) 248 | 249 | def test_gamma_power(self, verbose=False): 250 | ''' Test simple power law gamma (can supply exponent). ''' 251 | gamma_set = [0.1, 0.5, 1.0, 1.1, 1.5, 2.0, 2.2, 2.5, 10.0] 252 | for gamma in gamma_set: 253 | msg = 'Testing power-law gamma: %g' % (gamma) 254 | if verbose: 255 | print (msg) 256 | colormodels.init_gamma_correction ( 257 | display_from_linear_function = colormodels.simple_gamma_invert, 258 | linear_from_display_function = colormodels.simple_gamma_correct, 259 | gamma = gamma) 260 | self.check_gamma_correction(verbose) 261 | 262 | # Conversions between standard device independent color space (CIE XYZ) 263 | # and the almost perceptually uniform space Luv. 264 | 265 | def check_xyz_luv(self, xyz0, verbose): 266 | ''' Check that luv_from_xyz() and xyz_from_luv() are inverses. ''' 267 | tolerance = 1.0e-10 268 | luv0 = colormodels.luv_from_xyz (xyz0) 269 | xyz1 = colormodels.xyz_from_luv (luv0) 270 | luv1 = colormodels.luv_from_xyz (xyz1) 271 | # Check errors. 272 | dluv = luv1 - luv0 273 | error_luv = math.sqrt (numpy.dot (dluv, dluv)) 274 | dxyz = xyz1 - xyz0 275 | error_xyz = math.sqrt (numpy.dot (dxyz, dxyz)) 276 | self.assertLessEqual(error_luv, tolerance) 277 | self.assertLessEqual(error_xyz, tolerance) 278 | msg = 'xyz0: %s luv0: %s xyz1: %s luv1: %s' % ( 279 | str(xyz0), str(luv0), str(xyz1), str(luv1)) 280 | if verbose: 281 | print (msg) 282 | 283 | def test_xyz_luv_black(self, verbose=False): 284 | ''' Test Luv conversions on black. ''' 285 | xyz0 = colormodels.xyz_color (0.0, 0.0, 0.0) 286 | self.check_xyz_luv(xyz0, verbose) 287 | 288 | def test_xyz_luv(self, verbose=False): 289 | ''' Test that luv_from_xyz() and xyz_from_luv() are inverses. ''' 290 | for i in range (100): 291 | x0 = 10.0 * random.random() 292 | y0 = 10.0 * random.random() 293 | z0 = 10.0 * random.random() 294 | xyz0 = colormodels.xyz_color (x0, y0, z0) 295 | self.check_xyz_luv(xyz0, verbose) 296 | 297 | # Conversions between standard device independent color space (CIE XYZ) 298 | # and the almost perceptually uniform space Lab. 299 | 300 | def check_xyz_lab(self, xyz0, verbose): 301 | ''' Check that lab_from_xyz() and xyz_from_lab() are inverses. ''' 302 | tolerance = 1.0e-10 303 | lab0 = colormodels.lab_from_xyz (xyz0) 304 | xyz1 = colormodels.xyz_from_lab (lab0) 305 | lab1 = colormodels.lab_from_xyz (xyz1) 306 | # Check errors. 307 | dlab = lab1 - lab0 308 | error_lab = math.sqrt (numpy.dot (dlab, dlab)) 309 | dxyz = xyz1 - xyz0 310 | error_xyz = math.sqrt (numpy.dot (dxyz, dxyz)) 311 | self.assertLessEqual(error_lab, tolerance) 312 | self.assertLessEqual(error_xyz, tolerance) 313 | msg = 'xyz0: %s lab0: %s xyz1: %s lab1: %s' % ( 314 | str(xyz0), str(lab0), str(xyz1), str(lab1)) 315 | if verbose: 316 | print (msg) 317 | 318 | def test_xyz_lab_black(self, verbose=False): 319 | ''' Test Lab conversions on black. ''' 320 | xyz0 = colormodels.xyz_color (0.0, 0.0, 0.0) 321 | self.check_xyz_lab(xyz0, verbose) 322 | 323 | def test_xyz_lab(self, verbose=False): 324 | '''Test that lab_from_xyz() and xyz_from_lab() are inverses.''' 325 | for i in range (100): 326 | x0 = 10.0 * random.random() 327 | y0 = 10.0 * random.random() 328 | z0 = 10.0 * random.random() 329 | xyz0 = colormodels.xyz_color (x0, y0, z0) 330 | self.check_xyz_lab(xyz0, verbose) 331 | 332 | # Luminance function [of Y value of an XYZ color] used in Luv and Lab. 333 | 334 | def check_L_luminance_inverse_1(self, y0, verbose): 335 | ''' Check that L_luminance_inverse() is the inverse of L_luminance() for the given y0. ''' 336 | L0 = colormodels.L_luminance (y0) 337 | y1 = colormodels.L_luminance_inverse (L0) 338 | # Check error. 339 | error = math.fabs (y1 - y0) 340 | tolerance = 1.0e-13 341 | self.assertLessEqual(error, tolerance) 342 | msg = 'y0: %g L(y0): %g y(L(y0)): %g Error: %g' % ( 343 | y0, L0, y1, error) 344 | if verbose: 345 | print (msg) 346 | 347 | def check_L_luminance_inverse_2(self, L0, verbose): 348 | ''' Check that L_luminance() is the inverse of L_luminance_inverse() for the given L0. ''' 349 | y0 = colormodels.L_luminance_inverse (L0) 350 | L1 = colormodels.L_luminance (y0) 351 | # Check error. 352 | error = math.fabs (L1 - L0) 353 | tolerance = 1.0e-10 354 | self.assertLessEqual(error, tolerance) 355 | msg = 'L0: %g y(L0): %g L(y(L0)): %g Error: %g' % ( 356 | L0, y0, L1, error) 357 | if verbose: 358 | print (msg) 359 | 360 | def test_L_luminance_inverse_1(self, verbose=False): 361 | ''' Test that L_luminance_inverse(L_luminance(y)) = y. ''' 362 | # Test with specific values on both sides of cutoff value. 363 | vals = [0.1, 0.5, 0.9, 1.1, 2.0, 10.0] 364 | for val in vals: 365 | y0 = val * colormodels.L_LUM_CUTOFF 366 | self.check_L_luminance_inverse_1(y0, verbose) 367 | # Test with random fairly small y values. 368 | for i in range (20): 369 | y0 = 0.1 * random.random() 370 | self.check_L_luminance_inverse_1(y0, verbose) 371 | # Test with random fairly large y values. 372 | for i in range (20): 373 | y0 = 10.0 * random.random() 374 | self.check_L_luminance_inverse_1(y0, verbose) 375 | 376 | def test_L_luminance_inverse_2(self, verbose=False): 377 | ''' Test that L_luminance(L_luminance_inverse(L)) = L. ''' 378 | # Test with specific values on both sides of cutoff value. 379 | vals = [0.1, 0.5, 0.9, 1.1, 2.0, 10.0] 380 | for val in vals: 381 | L0 = val * colormodels.L_LUM_C * colormodels.L_LUM_CUTOFF 382 | self.check_L_luminance_inverse_2(L0, verbose) 383 | # Test with random fairly small L values. 384 | for i in range (20): 385 | L0 = 25.0 * random.random() 386 | self.check_L_luminance_inverse_2(L0, verbose) 387 | # Test with random fairly large L values. 388 | for i in range (20): 389 | L0 = 1000.0 * random.random() 390 | self.check_L_luminance_inverse_2(L0, verbose) 391 | 392 | # Utility function for Lab. 393 | 394 | def check_Lab_f_inverse_1(self, t0, verbose): 395 | ''' Check that Lab_f_inverse() is the inverse of Lab_f() for the given t0. ''' 396 | f0 = colormodels.Lab_f (t0) 397 | t1 = colormodels.Lab_f_inverse (f0) 398 | # Check error. 399 | error = math.fabs (t1 - t0) 400 | tolerance = 1.0e-13 401 | self.assertLessEqual(error, tolerance) 402 | msg = 't0: %g f(t0): %g t(f(t0)): %g Error: %g' % ( 403 | t0, f0, t1, error) 404 | if verbose: 405 | print (msg) 406 | 407 | def check_Lab_f_inverse_2(self, f0, verbose): 408 | ''' Check that Lab_f() is the inverse of Lab_f_inverse() for the given f0. ''' 409 | t0 = colormodels.Lab_f_inverse (f0) 410 | f1 = colormodels.Lab_f (t0) 411 | # Check error. 412 | error = math.fabs (f1 - f0) 413 | tolerance = 1.0e-10 414 | self.assertLessEqual(error, tolerance) 415 | msg = 'f0: %g t(f0): %g f(t(f0)): %g Error: %g' % ( 416 | f0, t0, f1, error) 417 | if verbose: 418 | print (msg) 419 | 420 | def test_Lab_f_inverse_1(self, verbose=False): 421 | ''' Test that Lab_f_inverse(Lab_f(t)) = t. ''' 422 | # Test with specific values on both sides of cutoff value. 423 | vals = [0.1, 0.5, 0.9, 1.1, 2.0, 10.0] 424 | for val in vals: 425 | y0 = val * colormodels.L_LUM_CUTOFF 426 | self.check_Lab_f_inverse_1(y0, verbose) 427 | # Test with fairly small random values. 428 | for i in range (20): 429 | y0 = 0.02 * random.random() 430 | self.check_Lab_f_inverse_1(y0, verbose) 431 | # Test with fairly large random values. 432 | for i in range (20): 433 | y0 = 10.0 * random.random() 434 | self.check_Lab_f_inverse_1(y0, verbose) 435 | 436 | def test_Lab_f_inverse_2(self, verbose=False): 437 | ''' Test that Lab_f(Lab_f_inverse(L)) = L. ''' 438 | # Test with specific values on both sides of cutoff value. 439 | vals = [0.1, 0.5, 0.9, 1.1, 2.0, 10.0] 440 | for val in vals: 441 | L0 = val * (colormodels.LAB_F_A * colormodels.L_LUM_CUTOFF + colormodels.LAB_F_B) 442 | self.check_Lab_f_inverse_2(L0, verbose) 443 | # Test with fairly small random values. 444 | for i in range (20): 445 | L0 = 0.25 * random.random() 446 | self.check_Lab_f_inverse_2(L0, verbose) 447 | # Test with fairly large random values. 448 | for i in range (20): 449 | L0 = 1000.0 * random.random() 450 | self.check_Lab_f_inverse_2(L0, verbose) 451 | 452 | # Utility function for Luv. 453 | 454 | def check_uv_primes_inverse_1(self, xyz0, verbose): 455 | ''' Check that uv_primes() and uv_primes_inverse() are inverses. ''' 456 | up0, vp0 = colormodels.uv_primes (xyz0) 457 | xyz1 = colormodels.uv_primes_inverse (up0, vp0, xyz0[1]) 458 | # Check error. 459 | dxyz = (xyz1 - xyz0) 460 | error = math.sqrt (numpy.dot (dxyz, dxyz)) 461 | tolerance = 1.0e-13 462 | self.assertLessEqual(error, tolerance) 463 | msg = 'xyz0: %s up: %g vp: %g xyz(up,vp): %s Error: %g' % ( 464 | str (xyz0), up0, vp0, str(xyz1), error) 465 | if verbose: 466 | print (msg) 467 | 468 | def check_uv_primes_inverse_2(self, up0, vp0, y0, verbose): 469 | ''' Check that uv_primes() and uv_primes_inverse() are inverses. ''' 470 | xyz0 = colormodels.uv_primes_inverse (up0, vp0, y0) 471 | up1, vp1 = colormodels.uv_primes (xyz0) 472 | # Check error. 473 | error_up = up1 - up0 474 | error_vp = vp1 - vp0 475 | error = numpy.hypot (error_up, error_vp) 476 | tolerance = 1.0e-13 477 | self.assertLessEqual(error, tolerance) 478 | msg = 'up0, vp0, y0: %g, %g, %g xyz(up0,vp0,y0): %s (up,vp)(xyz): %g, %g Error: %g' % ( 479 | up0, vp0, y0, str (xyz0), up1, vp1, error) 480 | if verbose: 481 | print (msg) 482 | 483 | def test_uv_primes_inverse_1(self, verbose=False): 484 | ''' Test that uv_primes() and uv_primes_inverse() are inverses. ''' 485 | # Test some random values. 486 | for i in range (20): 487 | x0 = 10.0 * random.random() 488 | y0 = 10.0 * random.random() 489 | z0 = 10.0 * random.random() 490 | xyz0 = colormodels.xyz_color (x0, y0, z0) 491 | self.check_uv_primes_inverse_1(xyz0, verbose) 492 | # Test black explicitly. 493 | xyz0 = colormodels.xyz_color (0.0, 0.0, 0.0) 494 | self.check_uv_primes_inverse_1(xyz0, verbose) 495 | 496 | def test_uv_primes_inverse_2(self, verbose=False): 497 | ''' Test that uv_primes() and uv_primes_inverse() are inverses. ''' 498 | # Test some random values. 499 | for i in range (20): 500 | up0 = 4.0 * (2.0 * random.random() - 1.0) 501 | vp0 = 9.0 * (2.0 * random.random() - 1.0) 502 | y0 = 10.0 * random.random() 503 | self.check_uv_primes_inverse_2(up0, vp0, y0, verbose) 504 | # Test black explicitly. 505 | self.check_uv_primes_inverse_2(0.0, 0.0, 0.0, verbose) 506 | 507 | 508 | if __name__ == '__main__': 509 | unittest.main() 510 | -------------------------------------------------------------------------------- /colorpy/test_illuminants.py: -------------------------------------------------------------------------------- 1 | ''' 2 | test_illuminants.py - Test module for illuminants.py. 3 | 4 | License: 5 | 6 | Copyright (C) 2008 Mark Kness 7 | 8 | Author - Mark Kness - mkness@alumni.utexas.net 9 | 10 | This file is part of ColorPy. 11 | 12 | ColorPy is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | ColorPy is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public License 23 | along with ColorPy. If not, see . 24 | ''' 25 | from __future__ import print_function 26 | 27 | import unittest 28 | 29 | import illuminants 30 | 31 | 32 | class TestIlluminants(unittest.TestCase): 33 | ''' Test cases for illuminants. ''' 34 | 35 | def test_coverage_1(self, verbose=False): 36 | ''' A coverage test of illuminants. ''' 37 | D65 = illuminants.get_illuminant_D65() 38 | if verbose: 39 | print ('Illuminant D65') 40 | print (str (D65)) 41 | A = illuminants.get_illuminant_A() 42 | if verbose: 43 | print ('Illuminant A') 44 | print (str (A)) 45 | const = illuminants.get_constant_illuminant() 46 | if verbose: 47 | print ('Constant Illuminant') 48 | print (str (const)) 49 | 50 | def test_coverage_2(self, verbose=False): 51 | ''' Another coverage test of illuminants. ''' 52 | T_list = [0.0, 1.0, 100.0, 1000.0, 5778.0, 10000.0, 100000.0] 53 | for T in T_list: 54 | bb = illuminants.get_blackbody_illuminant (T) 55 | if verbose: 56 | print ('Blackbody Illuminant : %g K' % (T)) 57 | print (str (bb)) 58 | 59 | 60 | if __name__ == '__main__': 61 | unittest.main() 62 | -------------------------------------------------------------------------------- /colorpy/test_rayleigh.py: -------------------------------------------------------------------------------- 1 | ''' 2 | test_rayleigh.py - Test module for rayleigh.py. 3 | 4 | License: 5 | 6 | Copyright (C) 2008 Mark Kness 7 | 8 | Author - Mark Kness - mkness@alumni.utexas.net 9 | 10 | This file is part of ColorPy. 11 | 12 | ColorPy is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | ColorPy is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public License 23 | along with ColorPy. If not, see . 24 | ''' 25 | from __future__ import print_function 26 | 27 | import math 28 | import numpy 29 | import random 30 | import unittest 31 | 32 | import ciexyz 33 | import rayleigh 34 | import illuminants 35 | 36 | 37 | class TestRayleigh(unittest.TestCase): 38 | ''' Test cases for Rayleigh scattering. ''' 39 | 40 | def test_wavelength_4(self, verbose=False): 41 | ''' Test that scattering scales as 1/wl^4. ''' 42 | for i in range(20): 43 | # Two random wavelengths, avoiding zero. 44 | wl_1 = 1.0 + 999.0 * random.random() 45 | wl_2 = 1.0 + 999.0 * random.random() 46 | # Scattering. 47 | sc_1 = rayleigh.rayleigh_scattering(wl_1) 48 | sc_2 = rayleigh.rayleigh_scattering(wl_2) 49 | # Ratios, avoiding pow() for more independence from implementation. 50 | r_sc = sc_1 / sc_2 51 | r_wl = wl_2 / wl_1 52 | r4_wl = r_wl * r_wl * r_wl * r_wl 53 | # Check. 54 | actual = r_sc / r4_wl 55 | expect = 1.0 56 | error = math.fabs(actual - expect) 57 | tolerance = 1.0e-12 58 | self.assertLessEqual(error, tolerance) 59 | msg = 'Wavelength: %g, %g Scattering: %g, %g Ratio of Powers: %.8f' % ( 60 | wl_1, wl_2, sc_1, sc_2, actual) 61 | if verbose: 62 | print (msg) 63 | 64 | def test_scattering(self, verbose=False): 65 | ''' Test of scattering calculations. ''' 66 | # Coverage test of rayleigh_scattering_spectrum(). 67 | rayleigh.rayleigh_scattering_spectrum() 68 | illum = illuminants.get_illuminant_D65() 69 | spect = rayleigh.rayleigh_illuminated_spectrum (illum) 70 | # Both color calculations should give the same result. 71 | xyz1 = ciexyz.xyz_from_spectrum (spect) 72 | xyz2 = rayleigh.rayleigh_illuminated_color (illum) 73 | atol = 1.0e-16 74 | ok = numpy.allclose(xyz1, xyz2, atol=atol) 75 | self.assertTrue(ok) 76 | msg = 'D65 Rayleigh scattered xyz: %s, %s' % (str(xyz1), str(xyz2)) 77 | if verbose: 78 | print (msg) 79 | 80 | 81 | if __name__ == '__main__': 82 | unittest.main() 83 | -------------------------------------------------------------------------------- /colorpy/test_thinfilm.py: -------------------------------------------------------------------------------- 1 | ''' 2 | test_thinfilm.py - Test module for thinfilm.py. 3 | 4 | License: 5 | 6 | Copyright (C) 2008 Mark Kness 7 | 8 | Author - Mark Kness - mkness@alumni.utexas.net 9 | 10 | This file is part of ColorPy. 11 | 12 | ColorPy is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | ColorPy is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public License 23 | along with ColorPy. If not, see . 24 | ''' 25 | from __future__ import print_function 26 | 27 | import random 28 | import unittest 29 | 30 | import illuminants 31 | import thinfilm 32 | 33 | 34 | class TestThinFilm(unittest.TestCase): 35 | ''' Test cases for thin film scattering. ''' 36 | 37 | def test_coverage(self): 38 | ''' A coverage test of thin film scattering. ''' 39 | illuminant = illuminants.get_illuminant_D65() 40 | for j in range (20): 41 | n1 = 5.0 * random.random() 42 | n2 = 5.0 * random.random() 43 | n3 = 5.0 * random.random() 44 | thickness_nm = 10000.0 * random.random() 45 | film = thinfilm.thin_film (n1, n2, n3, thickness_nm) 46 | for k in range (20): 47 | wl_nm = 1000.0 * random.random() 48 | film.get_interference_reflection_coefficient (wl_nm) 49 | film.reflection_spectrum () 50 | film.illuminated_spectrum (illuminant) 51 | film.illuminated_color (illuminant) 52 | 53 | 54 | if __name__ == '__main__': 55 | unittest.main() 56 | -------------------------------------------------------------------------------- /colorpy/thinfilm.py: -------------------------------------------------------------------------------- 1 | ''' 2 | thinfilm.py - Thin film interference colors. 3 | 4 | Description: 5 | 6 | Reflection from a thin film, as a function of wavelength, thickness, and index of refraction of materials. 7 | 8 | Note that film thicknesses are given in nm instead of m, as this is a more convenient unit in this case. 9 | 10 | We consider incident light from a medium of index of refraction n1, 11 | striking a thin film of index n2, with a third medium of index n3 behind the film. 12 | 13 | The total reflection from the film, back towards the incident light, is calculated. 14 | 15 | Some sample values of the index of refraction: 16 | air : n = 1.003 17 | water: n = 1.33 18 | glass/plastic: n = 1.5 19 | oil: n = 1.44 (matches Minnaert's color observations) 20 | 21 | Functions: 22 | 23 | class thin_film (n1, n2, n3, thickness_nm) - 24 | Represents a thin film, with the indices of refraction n1,n2,n3 representing: 25 | n1 - index of refraction of infinite region the light comes from 26 | n2 - index of refraction of finite region of the film 27 | n3 - index of refraction of infinite region beyond the film 28 | and thickness_nm being the thickness of the film [nm]. 29 | 30 | On these class objects, the following functions are available: 31 | 32 | get_interference_reflection_coefficient (wl_nm) - 33 | Get the reflection coefficient for the intensity for light 34 | of the given wavelength impinging on the film. 35 | 36 | reflection_spectrum () - 37 | Get the reflection spectrum (independent of illuminant) for the thin film. 38 | 39 | illuminated_spectrum (illuminant) - 40 | Get the spectrum when illuminated by the specified illuminant. 41 | 42 | illuminated_color (illuminant) - 43 | Get the xyz color when illuminated by the specified illuminant. 44 | 45 | Plots: 46 | 47 | thinfilm_patch_plot (n1, n2, n3, thickness_nm_list, illuminant, title, filename) - 48 | Make a patch plot of the color of the film for each thickness [nm]. 49 | 50 | thinfilm_color_vs_thickness_plot (n1, n2, n3, thickness_nm_list, illuminant, title, filename) - 51 | Plot the color of the thin film for the specfied thicknesses [nm]. 52 | 53 | thinfilm_spectrum_plot (n1, n2, n3, thickness_nm, illuminant, title, filename) - 54 | Plot the spectrum of the reflection from a thin film for the given thickness [nm]. 55 | 56 | References: 57 | 58 | Frank S. Crawford, Jr., Waves: Berkeley Physics Course - Volume 3, 59 | McGraw-Hill Book Company, 1968. Library of Congress 64-66016. 60 | 61 | M. Minnaert, The nature of light and color in the open air, 62 | translation H.M. Kremer-Priest, Dover Publications, New York, 1954. ISBN 486-20196-1. p. 208-209. 63 | 64 | License: 65 | 66 | Copyright (C) 2008 Mark Kness 67 | 68 | Author - Mark Kness - mkness@alumni.utexas.net 69 | 70 | This file is part of ColorPy. 71 | 72 | ColorPy is free software: you can redistribute it and/or modify 73 | it under the terms of the GNU Lesser General Public License as 74 | published by the Free Software Foundation, either version 3 of 75 | the License, or (at your option) any later version. 76 | 77 | ColorPy is distributed in the hope that it will be useful, 78 | but WITHOUT ANY WARRANTY; without even the implied warranty of 79 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 80 | GNU Lesser General Public License for more details. 81 | 82 | You should have received a copy of the GNU Lesser General Public License 83 | along with ColorPy. If not, see . 84 | ''' 85 | import math, cmath, numpy 86 | 87 | import colormodels 88 | import ciexyz 89 | import illuminants 90 | import plots 91 | 92 | class thin_film: 93 | '''A thin film of dielectric material.''' 94 | def __init__ (self, n1, n2, n3, thickness_nm): 95 | self.n1 = n1 96 | self.n2 = n2 97 | self.n3 = n3 98 | self.thickness_nm = thickness_nm 99 | self.too_thick = False 100 | 101 | # pre-calculate 102 | def field_reflection_coefficient (n1, n2): 103 | ''' Calculate the reflection coefficient for a light wave traveling from 104 | a region with index of refraction n1 to one having an index of n2. 105 | This is the coefficient for the electric field, not the intensity.''' 106 | return ( (n1 - n2) / (n1 + n2) ) 107 | 108 | # R12 = field reflection coefficient for light traveling from region 1 to 2 109 | # R23 = field reflection coefficient for light traveling from region 2 to 3 110 | self.R12 = field_reflection_coefficient (n1, n2) 111 | self.R23 = field_reflection_coefficient (n2, n3) 112 | self.R12sqd_plus_R23sqd = self.R12*self.R12 + self.R23*self.R23 113 | self.R12_times_R23_times_2 = 2.0 * self.R12 * self.R23 114 | self.phase_factor = -2.0 * self.thickness_nm * 2.0 * math.pi * n2 115 | 116 | # aliasing will occur if the layer is too thick - see if this is true 117 | sample_interval_nm = 1.0 # assuming 1 nm 118 | wavelength_0_nm = 380.0 # shortest wl results in minimum max_thickness 119 | max_thickness_nm = 0.25 * math.pow (wavelength_0_nm, 2) / (n2 * sample_interval_nm) 120 | if self.thickness_nm > max_thickness_nm: 121 | self.too_thick = True 122 | 123 | def get_interference_reflection_coefficient (self, wl_nm): 124 | '''Get the reflection coefficient for the intensity for light 125 | of the given wavelength impinging on the film.''' 126 | if self.too_thick: 127 | # would alias - 128 | # if the layer is too thick, the cos() factor is averaged over multiple periods 129 | # to zero, this is the best we can do 130 | return self.R12sqd_plus_R23sqd 131 | 132 | ## small-reflection approximation 133 | #R = self.R12sqd_plus_R23sqd + self.R12_times_R23_times_2 * math.cos (self.phase_factor / wl_nm) 134 | #return R 135 | 136 | # exact - accounts for multiple reflections, and does not assume a small 137 | # reflection coefficient. Should be correct for complex n1,n2,n3 as well. 138 | phase = cmath.exp (complex (0, 1.0) * (self.phase_factor / wl_nm)) 139 | num = self.R12 + self.R23 * phase 140 | den = 1.0 + self.R12 * self.R23 * phase 141 | Re = num / den 142 | R = Re.real*Re.real + Re.imag*Re.imag 143 | return R 144 | 145 | def reflection_spectrum (self): 146 | '''Get the reflection spectrum (independent of illuminant) for the thin film.''' 147 | spectrum = ciexyz.empty_spectrum() 148 | num_wl = spectrum.shape[0] 149 | for i in range (0, num_wl): 150 | wl_nm = spectrum [i][0] 151 | spectrum [i][1] = self.get_interference_reflection_coefficient (wl_nm) 152 | return spectrum 153 | 154 | def illuminated_spectrum (self, illuminant): 155 | '''Get the spectrum when illuminated by the specified illuminant.''' 156 | spectrum = self.reflection_spectrum() 157 | num_wl = spectrum.shape[0] 158 | for i in range (0, num_wl): 159 | spectrum [i][1] *= illuminant [i][1] 160 | return spectrum 161 | 162 | def illuminated_color (self, illuminant): 163 | '''Get the xyz color when illuminated by the specified illuminant.''' 164 | spectrum = self.illuminated_spectrum (illuminant) 165 | xyz = ciexyz.xyz_from_spectrum (spectrum) 166 | return xyz 167 | 168 | 169 | def create_thin_films (n1, n2, n3, thickness_list): 170 | ''' Create a list of thin films from a list of thicknesses. ''' 171 | films = [] 172 | for thickness in thickness_list: 173 | film = thin_film (n1, n2, n3, thickness) 174 | films.append(film) 175 | return films 176 | 177 | # 178 | # Figures 179 | # 180 | 181 | def thinfilm_patch_plot (n1, n2, n3, thickness_nm_list, illuminant, title, filename): 182 | '''Make a patch plot of the color of the film for each thickness [nm].''' 183 | films = create_thin_films(n1, n2, n3, thickness_nm_list) 184 | xyz_colors = [] 185 | labels = [] 186 | for film in films: 187 | xyz = film.illuminated_color (illuminant) 188 | xyz_colors.append (xyz) 189 | label = '%.1f nm' % (film.thickness_nm) 190 | labels.append(label) 191 | plots.xyz_patch_plot (xyz_colors, labels, title, filename) 192 | 193 | def thinfilm_color_vs_thickness_plot (n1, n2, n3, thickness_nm_list, illuminant, title, filename): 194 | '''Plot the color of the thin film for the specfied thicknesses [nm].''' 195 | films = create_thin_films(n1, n2, n3, thickness_nm_list) 196 | num_films = len (films) 197 | rgb_list = numpy.empty ((num_films, 3)) 198 | for i in range (0, num_films): 199 | film = films[i] 200 | xyz = film.illuminated_color (illuminant) 201 | rgb_list [i] = colormodels.rgb_from_xyz (xyz) 202 | plots.color_vs_param_plot ( 203 | thickness_nm_list, 204 | rgb_list, 205 | title, 206 | filename, 207 | xlabel = r'Thickness (nm)', 208 | ylabel = r'RGB Color') 209 | 210 | def thinfilm_spectrum_plot (n1, n2, n3, thickness_nm, illuminant, title, filename): 211 | '''Plot the spectrum of the reflection from a thin film for the given thickness [nm].''' 212 | film = thin_film (n1, n2, n3, thickness_nm) 213 | illuminated_spectrum = film.illuminated_spectrum (illuminant) 214 | plots.spectrum_plot ( 215 | illuminated_spectrum, 216 | title, 217 | filename, 218 | xlabel = 'Wavelength (nm)', 219 | ylabel = 'Refection Intensity') 220 | 221 | def figures (): 222 | '''Draw some thin film plots.''' 223 | # Simple patch plot. This is not all that interesting. 224 | thickness_nm_list = numpy.linspace(0.0, 750.0, 36) 225 | illuminant = illuminants.get_illuminant_D65() 226 | illuminants.scale_illuminant (illuminant, 9.50) 227 | thinfilm_patch_plot (1.500, 1.003, 1.500, thickness_nm_list, 228 | illuminant, 'ThinFilm Patch Plot', 'ThinFilm-Patch') 229 | 230 | # Plot the colors of films vs thickness. 231 | # Scale the illuminant to get a better range of color. 232 | thickness_nm_list = numpy.linspace(0.0, 1000.0, 800) 233 | # Gap in glass/plastic. 234 | illuminant = illuminants.get_illuminant_D65() 235 | illuminants.scale_illuminant (illuminant, 4.50) 236 | thinfilm_color_vs_thickness_plot ( 237 | 1.500, 1.003, 1.500, thickness_nm_list, illuminant, 238 | 'Thin Film - Gap In Glass/Plastic (n = 1.50)\nIlluminant D65', 239 | 'ThinFilm-GlassGap') 240 | # Soap bubble. 241 | illuminant = illuminants.get_illuminant_D65() 242 | illuminants.scale_illuminant (illuminant, 9.50) 243 | thinfilm_color_vs_thickness_plot ( 244 | 1.003, 1.33, 1.003, thickness_nm_list, illuminant, 245 | 'Thin Film - Soap Bubble (n = 1.33)\nIlluminant D65', 246 | 'ThinFilm-SoapBubble') 247 | # Oil slick on water. 248 | illuminant = illuminants.get_illuminant_D65() 249 | illuminants.scale_illuminant (illuminant, 15.00) 250 | thinfilm_color_vs_thickness_plot ( 251 | 1.003, 1.44, 1.33, thickness_nm_list, illuminant, 252 | 'Thin Film - Oil Slick (n = 1.44) on Water (n = 1.33)\nIlluminant D65', 253 | 'ThinFilm-OilSlick') 254 | # Large index of refraction bubble. 255 | # This has the brightest colors, but is a bit of an artificial example. 256 | illuminant = illuminants.get_illuminant_D65() 257 | illuminants.scale_illuminant (illuminant, 3.33) 258 | thinfilm_color_vs_thickness_plot ( 259 | 1.003, 1.60, 1.003, thickness_nm_list, illuminant, 260 | 'Thin Film - Large Index (n = 1.60) Bubble\nIlluminant D65', 261 | 'ThinFilm-LargeBubble') 262 | 263 | # A very thick film to test the aliasing limits. 264 | # You have to go to very large thicknesses to get much aliasing. 265 | thickness_nm_list = numpy.linspace(0.0, 200000.0, 800) 266 | illuminant = illuminants.get_illuminant_D65() 267 | illuminants.scale_illuminant (illuminant, 9.50) 268 | thinfilm_color_vs_thickness_plot ( 269 | 1.003, 1.33, 1.003, thickness_nm_list, illuminant, 270 | 'Not-so-thin Film - Soap Bubble (n = 1.33)\nIlluminant D65', 271 | 'ThinFilm-Thick') 272 | 273 | # Plot the spectrum of the refection for a couple of thicknesses. 274 | # Use a constant illuminant for a cleaner plot. 275 | # FIXME: Should this really be using an illuminant? 276 | illuminant = illuminants.get_constant_illuminant() 277 | illuminants.scale_illuminant (illuminant, 9.50) 278 | thinfilm_spectrum_plot (1.003, 1.33, 1.003, 400.0, illuminant, 279 | 'Thin Film Interference Spectrum - 400 nm thick\nConstant Illuminant', 280 | 'ThinFilm-Spectrum-400nm') 281 | thinfilm_spectrum_plot (1.003, 1.33, 1.003, 500.0, illuminant, 282 | 'Thin Film Interference Spectrum - 500 nm thick\nConstant Illuminant', 283 | 'ThinFilm-Spectrum-500nm') 284 | 285 | 286 | if __name__ == '__main__': 287 | figures() 288 | --------------------------------------------------------------------------------