-
Notifications
You must be signed in to change notification settings - Fork 1
/
AgX.py
324 lines (249 loc) · 8.27 KB
/
AgX.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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
import colour
import numpy
import PyOpenColorIO
def shape_OCIO_matrix(numpy_matrix):
# Shape the RGB to XYZ array for OpenColorIO
ocio_matrix = numpy.pad(
numpy_matrix,
[(0, 1), (0, 1)],
mode='constant'
)
ocio_matrix = ocio_matrix.flatten()
ocio_matrix[-1] = 1.
return ocio_matrix
def AgX_compressed_matrix(compression=0.20):
sRGB_Colourspace = colour.RGB_COLOURSPACES["sRGB"]
# Individual attenuation channel compressions. There Be Dragons.
compression_red = 0.00
compression_green = 0.00
compression_blue = 0.00
compressions = numpy.asarray(
[compression_red, compression_green, compression_blue]
)
# Global attenuation compression. Will be applied equally to
# all three channels.
scale_factor = numpy.ma.divide(
1.0,
(1.0 - compressions) * (1.0 - compression)
).filled(fill_value=0.0)[..., numpy.newaxis]
adjusted_primaries = (
(sRGB_Colourspace.primaries - sRGB_Colourspace.whitepoint)
* scale_factor
) + sRGB_Colourspace.whitepoint
adjusted_Colourspace = sRGB_Colourspace.copy()
adjusted_Colourspace.primaries = adjusted_primaries
adjusted_Colourspace.name = "Adjusted Colourspace"
adjusted_Colourspace.use_derived_matrix_RGB_to_XYZ = True
adjusted_Colourspace.use_derived_matrix_XYZ_to_RGB = True
adjusted_Colourspace.use_derived_transformation_matrices = True
adjusted_Colourspace.matrix_RGB_to_XYZ = adjusted_Colourspace.matrix_RGB_to_XYZ
adjusted_Colourspace.matrix_XYZ_to_RGB = adjusted_Colourspace.matrix_XYZ_to_RGB
return colour.matrix_RGB_to_RGB(sRGB_Colourspace, adjusted_Colourspace)
def as_numeric(obj, as_type=numpy.float64):
try:
return as_type(obj)
except TypeError:
return obj
# Calculate OpenColorIO allocation for log2 from open domain tristimulus value.
def calculate_OCIO_log2(in_ev, od_middle_grey=0.18):
return numpy.log2(
numpy.power(2.0, in_ev) * od_middle_grey
)
# Convert relative exposure values open domain tristimulus values.
def calculate_ev_to_od(
in_ev,
od_middle_grey=0.18
):
in_ev = numpy.asarray(in_ev)
return as_numeric(numpy.power(2.0, in_ev) * od_middle_grey)
# Convert open domain tristimulus values to relative expsoure values.
def calculate_od_to_ev(
in_od,
od_middle_grey=0.18
):
in_od = numpy.asarray(in_od)
return as_numeric(numpy.log2(in_od) - numpy.log2(od_middle_grey))
def adjust_exposure(RGB_input, exposure_adjustment):
return numpy.power(2.0, exposure_adjustment) * RGB_input
def open_domain_to_normalized_log2(
in_od,
in_middle_grey=0.18,
minimum_ev=-7.0,
maximum_ev=+7.0
):
total_exposure = maximum_ev - minimum_ev
in_od = numpy.asarray(in_od)
in_od[in_od <= 0.0] = numpy.finfo(float).eps
output_log = numpy.clip(
numpy.log2(in_od / in_middle_grey),
minimum_ev,
maximum_ev
)
return as_numeric((output_log - minimum_ev) / total_exposure)
def normalized_log2_to_open_domain(
in_norm_log2,
od_middle_grey=0.18,
minimum_ev=-7.0,
maximum_ev=+7.0
):
in_norm_log2 = numpy.asarray(in_norm_log2)
in_norm_log2 = numpy.clip(in_norm_log2, 0.0, 1.0) * (
maximum_ev - minimum_ev) + minimum_ev
return as_numeric(numpy.power(2.0, in_norm_log2) * od_middle_grey)
# The following is a completely tunable sigmoid function compliments
# of the incredible hard work of Jed Smith. He's an incredible peep,
# but don't let anyone know that I said that.
def equation_scale(x_pivot, y_pivot, slope_pivot, power):
x_pivot = numpy.asarray(x_pivot)
y_pivot = numpy.asarray(y_pivot)
slope_pivot = numpy.asarray(slope_pivot)
power = numpy.asarray(power)
return (
((slope_pivot * x_pivot)**-power) *
(((slope_pivot * (x_pivot / y_pivot))**power) - 1.0)
)**(-1.0 / power)
def equation_hyperbolic(x, power):
x = numpy.asarray(x)
power = numpy.asarray(power)
return x / ((1.0 + x**power)**(1.0 / power))
def equation_term(x, x_pivot, slope_pivot, scale):
x = numpy.asarray(x)
x_pivot = numpy.asarray(x_pivot)
slope_pivot = numpy.asarray(slope_pivot)
scale = numpy.asarray(scale)
return (slope_pivot * (x - x_pivot)) / scale
def equation_curve(x, x_pivot, y_pivot, slope_pivot, power, scale):
x = numpy.asarray(x)
x_pivot = numpy.asarray(x_pivot)
y_pivot = numpy.asarray(y_pivot)
slope_pivot = numpy.asarray(slope_pivot)
power = numpy.asarray(power)
scale = numpy.asarray(scale)
curve = numpy.where(
scale < 0.0,
scale * equation_hyperbolic(
equation_term(
x,
x_pivot,
slope_pivot,
scale
),
power[..., 0]
) + y_pivot,
scale * equation_hyperbolic(
equation_term(
x,
x_pivot,
slope_pivot,
scale
),
power[..., 1]
) + y_pivot
)
return curve
def equation_full_curve(x, x_pivot, y_pivot, slope_pivot, power):
x = numpy.asarray(x)
x_pivot = numpy.tile(numpy.asarray(x_pivot), len(x))
y_pivot = numpy.tile(numpy.asarray(y_pivot), len(x))
slope_pivot = numpy.tile(numpy.asarray(slope_pivot), len(x))
power = numpy.tile(numpy.asarray(power), len(x))
scale_x_pivot = numpy.where(
x >= x_pivot, 1.0 - x_pivot, x_pivot
)
scale_y_pivot = numpy.where(
x >= x_pivot, 1.0 - y_pivot, y_pivot
)
toe_scale = equation_scale(
scale_x_pivot, scale_y_pivot, slope_pivot, power[..., 0]
)
shoulder_scale = equation_scale(
scale_x_pivot, scale_y_pivot, slope_pivot, power[..., 1]
)
scale = numpy.where(
x >= x_pivot, shoulder_scale, -toe_scale
)
return equation_curve(x, x_pivot, y_pivot, slope_pivot, power, scale)
def add_view(in_dict, display, view_name, view_transform):
if display not in in_dict:
in_dict[display] = {}
in_dict[display][view_name] = view_transform
return in_dict
def add_colourspace(
config,
family,
name,
description,
transforms=None,
aliases=[],
direction=PyOpenColorIO.ColorSpaceDirection.COLORSPACE_DIR_FROM_REFERENCE,
referencespace=PyOpenColorIO.ReferenceSpaceType.REFERENCE_SPACE_SCENE,
isdata=False,
debug=False
):
colourspace_family = family
colourspace_name = name
colourspace_description = description
colourspace = PyOpenColorIO.ColorSpace(
referenceSpace=referencespace,
family=colourspace_family,
name=colourspace_name,
aliases=aliases,
isData=isdata
)
colourspace.setDescription(
colourspace_description
)
if transforms is not None:
if len(transforms) > 1:
transforms = PyOpenColorIO.GroupTransform(transforms)
else:
transforms = transforms[0]
colourspace.setTransform(transforms, direction)
if debug is True:
# DEBUG
shader_desc = PyOpenColorIO.GpuShaderDesc.CreateShaderDesc(
language=PyOpenColorIO.GPU_LANGUAGE_GLSL_4_0
)
processor = config.getProcessor(transforms).getDefaultGPUProcessor()
processor.extractGpuShaderInfo(shader_desc)
print("*****[{}]:\n{}".format(name, shader_desc.getShaderText()))
config.addColorSpace(colourspace)
return config, colourspace
def add_named_transform(
config,
family,
name,
description,
transforms,
aliases=None
):
if isinstance(transforms, list):
transform = PyOpenColorIO.GroupTransform(transforms)
named_transform = PyOpenColorIO.NamedTransform(
name=name,
aliases=aliases,
family=family,
forwardTransform=transform
)
named_transform.setDescription(description)
config.addNamedTransform(named_transform)
return config, named_transform
def add_look(
config,
name,
transforms,
description,
processSpace="AgX Base",
):
if len(transforms) > 1:
transforms = PyOpenColorIO.GroupTransform(transforms)
else:
transforms = transforms[0]
look = PyOpenColorIO.Look(
name=name,
processSpace=processSpace,
transform=transforms,
description=description
)
config.addLook(look)
return config, look