forked from hellothisistim/blackbody
/
__init__.py
226 lines (172 loc) · 7.07 KB
/
__init__.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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# -*- coding: utf-8 -*-
#from pprint import pprint
# blackbody.py
#
# Tim BOWMAN [puffy@netherlogic.com]
"""
Mapping hotness to color values.
Build ColorLookups in Nuke that map degrees Kelvin to useable color values.
Data sourced from this excellent datafile:
http://www.vendian.org/mncharity/dir3/blackbody/
"""
import nuke
def load_data():
#data_file = 'bbr_color.txt'
data_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'bbr_color.txt')
fields = ('kelvin', 'kelvin_abbr', 'cmf', 'chromaticity_x',
'chromaticity_y', 'power', 'log_r', 'log_g', 'log_b', 'r',
'g', 'b', 'hex')
data = []
count = 0
for line in open(data_file).readlines():
#print count, line
count += 1
#if count % 10 == 1:
# print "Reading line", count
if line.startswith('#'):
# it's a comment
pass
else:
one_entry = {}
chunks = line.split()
#print "there are", len(chunks), "chunks"
for index, field in enumerate(fields):
#print index, field, chunks[index]
one_entry[field] = chunks[index]
data.append(one_entry)
#pprint(one_entry)
return data
def filter_yxy(data, cmf='2deg'):
"""Take data dictionary and return tuples of floats for Kelvin, power,
X chromaticity and Y chromaticity. Use only the requested color matching
function.
Note: The stunningly high power values are unruly in Nuke.
data: list of dicts from load_data method
cmf: color matching function. either '2deg' (default) or '10deg'
"""
assert type(data) == list
assert type(cmf) == str
assert cmf in ['2deg', '10deg']
kxy = []
for data_point in data:
if data_point['cmf'] == cmf:
kxy.append((float(data_point['kelvin']),
float(data_point['power']),
float(data_point['chromaticity_x']),
float(data_point['chromaticity_y'])))
return kxy
def filter_logrgb(data):
"""Accept dictionary of data and return tuples of floats for Kelvin, log
red, log green, and log blue.
data: list of dicts from load_data method
"""
assert type(data) == list
logrgb = []
for data_point in data:
logrgb.append((float(data_point['kelvin']),
float(data_point['log_r']),
float(data_point['log_g']),
float(data_point['log_b'])))
return logrgb
def filter_srgb(data):
"""Accept dictionary of data and return tuples of floats for Kelvin, sRGB
red, sRGB green, and sRGB blue.
data: list of dicts from load_data method
"""
assert type(data) == list
logrgb = []
for data_point in data:
logrgb.append((float(data_point['kelvin']),
float(data_point['r']) / 255.0,
float(data_point['g']) / 255.0,
float(data_point['b']) / 255.0))
return logrgb
def build_lookup(filtered_data):
"""Accept filtered data (list of tuples) from one of the filter methods
and create a ColorLookup Node in Nuke using the filtered data Kelvin input
mapped to whatever the filter provides."""
lookup = nuke.createNode('ColorLookup')
# Keys at 0 and 1 in red, green, and blue are problematic. Get rid of them.
for channel in range(1,4):
lookup.knob('lut').clearAnimated(channel)
lookup.knob('source').setSingleValue(True)
for point in filtered_data:
#print point
source, dest_r, dest_g, dest_b = point
lookup.knob('source').setValue(source, 0)
lookup.knob('target').setValue(dest_r, 0)
lookup.knob('target').setValue(dest_g, 1)
lookup.knob('target').setValue(dest_b, 2)
lookup.knob('setRGB').execute()
return lookup
def yxy_lookup():
"""Build a ColorLookup using the chromaticity and power data."""
note_message = """
Blackbody color lookup with input in degrees Kelvin (data ranges from 1000
to 40000 degrees) mapped to chromaticity data (Y is power in semi-arbitrary
units, x and y are chromaticity coordinates.
Note: This lookup requires a bit of massaging pre- and post-lookup. Your
input heat map (which is probably in the 0-1 range) will need to be
remapped to your desired heat level in Kelvin. The lookup outputs in the
CIE-Yxy colorspace and will need to be converted back to your working
colorspace. It is also likely to be massively overexposed (50 stops or so --
yikes!)
Data sourced from this excellent datafile:
http://www.vendian.org/mncharity/dir3/blackbody/
"""
data = load_data()
yxy = build_lookup(filter_yxy(data))
yxy.setName('Blackbody_Yxy_Lookup')
a = nuke.Text_Knob('note', 'Note')
yxy.addKnob(a)
yxy.knob('note').setValue(note_message)
return yxy
def srgb_lookup():
"""Build a ColorLookup using the srgb data."""
note_message = """
Blackbody color lookup with input in degrees Kelvin (data ranges from 1000
to 40000 degrees) mapped to sRGB color values.
Note: This lookup requires a bit of massaging pre- and post-lookup. Your
input heat map (which is probably in the 0-1 range) will need to be
remapped to your desired heat level in Kelvin. The lookup outputs in
sRGB colorspace and will need to be converted back to your working
colorspace.
Data sourced from this excellent datafile:
http://www.vendian.org/mncharity/dir3/blackbody/
"""
data = load_data()
srgb = build_lookup(filter_srgb(data))
srgb.setName('Blackbody_sRGB_Lookup')
a = nuke.Text_Knob('note', 'Note')
srgb.addKnob(a)
srgb.knob('note').setValue(note_message)
return srgb
def logrgb_lookup():
"""Build a ColorLookup using the logrgb data."""
note_message = """
Blackbody color lookup with input in degrees Kelvin (data ranges from 1000
to 40000 degrees) mapped to logrithmic RGB color values.
Note: This lookup requires a bit of massaging pre- and post-lookup. Your
input heat map (which is probably in the 0-1 range) will need to be
remapped to your desired heat level in Kelvin. The lookup outputs in some
weird logrithmic RGB colorspace, so you may need to do some massaging to
make things look right.
Data sourced from this excellent datafile:
http://www.vendian.org/mncharity/dir3/blackbody/
"""
data = load_data()
logrgb = build_lookup(filter_logrgb(data))
logrgb.setName('Blackbody_logRGB_Lookup')
a = nuke.Text_Knob('note', 'Note')
logrgb.addKnob(a)
logrgb.knob('note').setValue(note_message)
return logrgb
def addMenu(dest = nuke.menu('Nodes')):
"""
Add a "Blackbody" menu to the desired destination (default: Nodes) menu
which allows access to the lookups in the Nuke GUI.
"""
bb_menu = dest.addMenu('Blackbody')
bb_menu.addCommand('Yxy Lookup', "blackbody.yxy_lookup()")
bb_menu.addCommand('sRGB Lookup', "blackbody.srgb_lookup()")
bb_menu.addCommand('log RGB Lookup', "blackbody.logrgb_lookup()")