-
Notifications
You must be signed in to change notification settings - Fork 0
/
wavelen2rgb.py
210 lines (151 loc) · 6.25 KB
/
wavelen2rgb.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#!/usr/bin/python -tt
#=======================================================================
# General Documentation
"""Single-function module.
Function and module names are the same. See function docstring for
description.
"""
#-----------------------------------------------------------------------
# Additional Documentation
#
# RCS Revision Code:
# $Id: wavelen2rgb.py,v 1.2 2003/12/20 21:26:35 jlin Exp $
#
# Modification History:
# - 4 Dec 2003: Original by Johnny Lin, Computation Institute,
# University of Chicago. Passed passably reasonable tests.
#
# Notes:
# - Written for Python 2.2.
# - Module docstrings can be tested using the doctest module. To
# test, execute "python wavelen2rgb.py".
# - No non-"built-in" packages and modules required.
#
# Copyright (c) 2003 by Johnny Lin. For licensing, distribution
# conditions, contact information, and additional documentation see
# the URL http://www.johnny-lin.com/pylib.html.
#=======================================================================
#-------------------- Overall Function Declaration ---------------------
def wavelen2rgb(Wavelength, MaxIntensity=100):
"""Calculate RGB values given the wavelength of visible light.
Arguments:
* Wavelength: Wavelength in nm. Scalar floating.
* MaxIntensity: The RGB value for maximum intensity. Scalar
integer.
Returns:
* 3-element list of RGB values for the input wavelength. The
values are scaled from 0 to MaxIntensity, where 0 is the
lowest intensity and MaxIntensity is the highest. Integer
list.
Visible light is in the range of 380-780 nm. Outside of this
range the returned RGB triple is [0,0,0].
Based on code by Earl F. Glynn II at:
http://www.efg2.com/Lab/ScienceAndEngineering/Spectra.htm
See also:
http://www.physics.sfasu.edu/astro/color/spectra.html
whose code is what Glynn's code is based on.
Example:
>>> from wavelen2rgb import wavelen2rgb
>>> waves = [300.0, 400.0, 600.0]
>>> rgb = [wavelen2rgb(waves[i], MaxIntensity=255) for i in range(3)]
>>> print (rgb)
[[0, 0, 0], [131, 0, 181], [255, 190, 0]]
"""
#--------------------------- Helper Function ---------------------------
def Adjust_and_Scale(Color, Factor, Highest=100):
"""Gamma adjustment.
Arguments:
* Color: Value of R, G, or B, on a scale from 0 to 1, inclusive,
with 0 being lowest intensity and 1 being highest. Floating
point value.
* Factor: Factor obtained to have intensity fall off at limits
of human vision. Floating point value.
* Highest: Maximum intensity of output, scaled value. The
lowest intensity is 0. Scalar integer.
Returns an adjusted and scaled value of R, G, or B, on a scale
from 0 to Highest, inclusive, as an integer, with 0 as the lowest
and Highest as highest intensity.
Since this is a helper function I keep its existence hidden.
See http://www.efg2.com/Lab/ScienceAndEngineering/Spectra.htm and
http://www.physics.sfasu.edu/astro/color/spectra.html for details.
"""
Gamma = 0.80
if Color == 0.0:
result = 0
else:
result = int( round(pow(Color * Factor, Gamma) * round(Highest)) )
if result < 0: result = 0
if result > Highest: result = Highest
return result
#------------------------ Overall Function Code ------------------------
#- Set RGB values (normalized in range 0 to 1) depending on
# heuristic wavelength intervals:
if (Wavelength >= 380.0) and (Wavelength < 440.0):
Red = -(Wavelength - 440.) / (440. - 380.)
Green = 0.0
Blue = 1.0
elif (Wavelength >= 440.0) and (Wavelength < 490.0):
Red = 0.0
Green = (Wavelength - 440.) / (490. - 440.)
Blue = 1.0
elif (Wavelength >= 490.0) and (Wavelength < 510.0):
Red = 0.0
Green = 1.0
Blue = -(Wavelength - 510.) / (510. - 490.)
elif (Wavelength >= 510.0) and (Wavelength < 580.0):
Red = (Wavelength - 510.) / (580. - 510.)
Green = 1.0
Blue = 0.0
elif (Wavelength >= 580.0) and (Wavelength < 645.0):
Red = 1.0
Green = -(Wavelength - 645.) / (645. - 580.)
Blue = 0.0
elif (Wavelength >= 645.0) and (Wavelength <= 780.0):
Red = 1.0
Green = 0.0
Blue = 0.0
else:
Red = 0.0
Green = 0.0
Blue = 0.0
#- Let the intensity fall off near the vision limits:
if (Wavelength >= 380.0) and (Wavelength < 420.0):
Factor = 0.3 + 0.7*(Wavelength - 380.) / (420. - 380.)
elif (Wavelength >= 420.0) and (Wavelength < 701.0):
Factor = 1.0
elif (Wavelength >= 701.0) and (Wavelength <= 780.0):
Factor = 0.3 + 0.7*(780. - Wavelength) / (780. - 700.)
else:
Factor = 0.0
#- Adjust and scale RGB values to 0 to MaxIntensity integer range:
R = Adjust_and_Scale(Red, Factor, MaxIntensity)
G = Adjust_and_Scale(Green, Factor, MaxIntensity)
B = Adjust_and_Scale(Blue, Factor, MaxIntensity)
#- Return 3-element list value:
return [R, G, B]
#-------------------------- Main: Test Module -------------------------
#- Define additional examples for doctest to use:
__test__ = { 'Additional Example 1':
"""
>>> from wavelen2rgb import wavelen2rgb
>>> waves = [450.0, 550.0, 800.0]
>>> rgb = [wavelen2rgb(waves[i], MaxIntensity=255) for i in range(3)]
>>> print (rgb)
[[0, 70, 255], [163, 255, 0], [0, 0, 0]]
>>> rgb = [wavelen2rgb(waves[i]) for i in range(3)]
>>> print (rgb)
[[0, 28, 100], [64, 100, 0], [0, 0, 0]]
""" }
#- Execute doctest if module is run from command line:
if __name__ == "__main__":
"""Test the module.
Tests the examples in all the module documentation strings, plus
__test__.
Note: In case this is distributed as a package, we add the parent
directory to to sys.path for this module testing case to enable
doctest to work in more circumstances.
"""
import doctest, sys, os
sys.path.append(os.pardir)
doctest.testmod(sys.modules[__name__])
# ===== end file =====