Consolidated config.ocio and nuke_config.ocio into a single config.ocio.
[OpenColorIO-Configs.git] / aces_1.0.0 / python / aces_ocio / colorspaces / general.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 """
5 Implements support for general colorspaces conversions and transfer functions.
6 """
7
8 from __future__ import division
9
10 import array
11 import os
12
13 import PyOpenColorIO as ocio
14
15 import aces_ocio.generate_lut as genlut
16 from aces_ocio.colorspaces import aces
17 from aces_ocio.utilities import ColorSpace, mat44_from_mat33
18
19
20 __author__ = 'ACES Developers'
21 __copyright__ = 'Copyright (C) 2014 - 2015 - ACES Developers'
22 __license__ = ''
23 __maintainer__ = 'ACES Developers'
24 __email__ = 'aces@oscars.org'
25 __status__ = 'Production'
26
27 __all__ = ['create_matrix_colorspace',
28            'create_colorspaces']
29
30 # -------------------------------------------------------------------------
31 # *Matrix Transform*
32 # -------------------------------------------------------------------------
33 def create_matrix_colorspace(name='matrix',
34                              from_reference_values=None,
35                              to_reference_values=None,
36                              aliases=[]):
37     """
38     Object description.
39
40     Parameters
41     ----------
42     parameter : type
43         Parameter description.
44
45     Returns
46     -------
47     type
48          Return value description.
49     """
50
51     if from_reference_values is None:
52         from_reference_values = []
53
54     if to_reference_values is None:
55         to_reference_values = []
56
57     cs = ColorSpace(name)
58     cs.description = 'The %s color space' % name
59     cs.aliases = aliases
60     cs.equality_group = name
61     cs.family = 'Utility'
62     cs.is_data = False
63
64     # A linear space needs allocation variables
65     cs.allocation_type = ocio.Constants.ALLOCATION_LG2
66     cs.allocation_vars = [-8, 5, 0.00390625]
67
68     cs.to_reference_transforms = []
69     if to_reference_values:
70         for matrix in to_reference_values:
71             cs.to_reference_transforms.append({
72                 'type': 'matrix',
73                 'matrix': mat44_from_mat33(matrix),
74                 'direction': 'forward'})
75
76     cs.from_reference_transforms = []
77     if from_reference_values:
78         for matrix in from_reference_values:
79             cs.from_reference_transforms.append({
80                 'type': 'matrix',
81                 'matrix': mat44_from_mat33(matrix),
82                 'direction': 'forward'})
83
84     return cs
85
86 # -------------------------------------------------------------------------
87 # *Matrix Transform*
88 # -------------------------------------------------------------------------
89 def create_matrix_plus_transfer_colorspace(name='matrix_plus_transfer',
90                                            transfer_function_name='transfer_function',
91                                            transfer_function=lambda x: x,
92                                            lut_directory='/tmp',
93                                            lut_resolution_1d=1024,
94                                            from_reference_values=None,
95                                            to_reference_values=None,
96                                            aliases=[]):
97     """
98     Object description.
99
100     Parameters
101     ----------
102     parameter : type
103         Parameter description.
104
105     Returns
106     -------
107     type
108          Return value description.
109     """
110
111     if from_reference_values is None:
112         from_reference_values = []
113
114     if to_reference_values is None:
115         to_reference_values = []
116
117     cs = ColorSpace(name)
118     cs.description = 'The %s color space' % name
119     cs.aliases = aliases
120     cs.equality_group = name
121     cs.family = 'Utility'
122     cs.is_data = False
123
124     # A linear space needs allocation variables
125     cs.allocation_type = ocio.Constants.ALLOCATION_LG2
126     cs.allocation_vars = [-8, 5, 0.00390625]
127
128     # Sample the transfer function
129     data = array.array('f', '\0' * lut_resolution_1d * 4)
130     for c in range(lut_resolution_1d):
131         data[c] = transfer_function(c / (lut_resolution_1d - 1))
132
133     # Write the sampled data to a LUT
134     lut = '%s_to_linear.spi1d' % transfer_function_name
135     genlut.write_SPI_1d(
136         os.path.join(lut_directory, lut),
137         0,
138         1,
139         data,
140         lut_resolution_1d,
141         1)
142
143     # Create the 'to_reference' transforms
144     cs.to_reference_transforms = []
145     cs.to_reference_transforms.append({
146         'type': 'lutFile',
147         'path': lut,
148         'interpolation': 'linear',
149         'direction': 'forward'})
150
151     if to_reference_values:
152         for matrix in to_reference_values:
153             cs.to_reference_transforms.append({
154                 'type': 'matrix',
155                 'matrix': mat44_from_mat33(matrix),
156                 'direction': 'forward'})
157
158     # Create the 'from_reference' transforms
159     cs.from_reference_transforms = []
160     if from_reference_values:
161         for matrix in from_reference_values:
162             cs.from_reference_transforms.append({
163                 'type': 'matrix',
164                 'matrix': mat44_from_mat33(matrix),
165                 'direction': 'forward'})
166
167     cs.from_reference_transforms.append({
168         'type': 'lutFile',
169         'path': lut,
170         'interpolation': 'linear',
171         'direction': 'inverse'})
172
173     return cs
174
175 # Transfer functions for standard color spaces
176 def transfer_function_sRGB_to_linear(v):
177     a = 1.055
178     b = 0.04045
179     d = 12.92
180     g = 2.4
181
182     if v < b:
183         return v/d
184     return pow(((v + (a - 1)) / a), g)
185
186 def transfer_function_Rec709_to_linear(v):
187     a = 1.099
188     b = 0.018
189     d = 4.5
190     g = (1.0/0.45)
191
192     if v < b:
193         return v/d
194
195     return pow(((v + (a - 1)) / a), g)
196
197 def transfer_function_Rec2020_10bit_to_linear(v):
198     a = 1.099
199     b = 0.018
200     d = 4.5
201     g = (1.0/0.45)
202
203     if v < b:
204         return v/d
205
206     return pow(((v + (a - 1)) / a), g)
207
208 def transfer_function_Rec2020_12bit_to_linear(v):
209     a = 1.0993
210     b = 0.0181
211     d = 4.5
212     g = (1.0/0.45)
213
214     if v < b:
215         return v/d
216
217     return pow(((v + (a - 1)) / a), g)
218
219 def transfer_function_Rec1886_to_linear(v):
220     g = 2.4
221     Lw = 1
222     Lb = 0
223
224     # Ignoring legal to full scaling for now
225     #v = (1023.0*v - 64.0)/876.0
226
227     t = pow(Lw, 1.0/g) - pow(Lb, 1.0/g)
228     a = pow(t, g)
229     b = pow(Lb, 1.0/g)/t
230
231     return a*pow(max((v + b), 0.0), g)
232
233 def create_colorspaces(lut_directory,
234                        lut_resolution_1d,
235                        lut_resolution_3d):
236     """
237     Generates the colorspace conversions.
238
239     Parameters
240     ----------
241     parameter : type
242         Parameter description.
243
244     Returns
245     -------
246     type
247          Return value description.
248     """
249
250     colorspaces = []
251
252     #
253     # XYZ
254     #
255     cs = create_matrix_colorspace('XYZ',
256                                to_reference_values=[aces.ACES_XYZ_TO_AP0],
257                                from_reference_values=[aces.ACES_AP0_TO_XYZ],
258                                aliases=["lin_xyz"])
259     colorspaces.append(cs)
260
261     #
262     # AP1
263     #
264     cs = create_matrix_colorspace(
265         'Linear - AP1',
266         to_reference_values=[aces.ACES_AP1_TO_AP0],
267         from_reference_values=[aces.ACES_AP0_TO_AP1],
268         aliases=["lin_ap1"])
269     colorspaces.append(cs)
270
271     #
272     # P3-D60
273     #
274     # *ACES* to *Linear*, *P3D60* primaries.
275     XYZ_to_P3D60 = [2.4027414142, -0.8974841639, -0.3880533700,
276                     -0.8325796487, 1.7692317536, 0.0237127115,
277                     0.0388233815, -0.0824996856, 1.0363685997]
278
279     cs = create_matrix_colorspace(
280         'Linear - P3-D60',
281         from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_P3D60],
282         aliases=["lin_p3d60"])
283     colorspaces.append(cs)
284
285     #
286     # P3-DCI
287     #
288     # *ACES* to *Linear*, *P3DCI* primaries.
289     XYZ_to_P3DCI = [2.7253940305, -1.0180030062, -0.4401631952,
290                     -0.7951680258, 1.6897320548, 0.0226471906,
291                     0.0412418914, -0.0876390192, 1.1009293786]
292
293     cs = create_matrix_colorspace(
294         'Linear - P3-DCI',
295         from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_P3DCI],
296         aliases=["lin_p3dci"])
297     colorspaces.append(cs)
298
299     #
300     # Rec 709
301     #
302     # *ACES* to *Linear*, *Rec. 709* primaries.
303     XYZ_to_Rec709 = [3.2409699419, -1.5373831776, -0.4986107603,
304                      -0.9692436363, 1.8759675015, 0.0415550574,
305                      0.0556300797, -0.2039769589, 1.0569715142]
306
307     cs = create_matrix_colorspace(
308         'Linear - Rec.709',
309         from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec709],
310         aliases=["lin_rec709"])
311     colorspaces.append(cs)
312
313     # *Linear* to *Rec. 709* Transfer Function*
314     cs = create_matrix_plus_transfer_colorspace(
315         'Curve - Rec.709',
316         'rec709',
317         transfer_function_Rec709_to_linear,
318         lut_directory,
319         lut_resolution_1d,
320         aliases=["crv_rec709"])
321     colorspaces.append(cs)
322
323     # *ACES* to *Rec. 709* Primaries + Transfer Function*
324     cs = create_matrix_plus_transfer_colorspace(
325         'Rec.709',
326         'rec709',
327         transfer_function_Rec709_to_linear,
328         lut_directory,
329         lut_resolution_1d,
330         from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec709],
331         aliases=["rec709"])
332     colorspaces.append(cs)
333
334     #
335     # sRGB
336     #
337     # *ACES* to *Linear*, *Rec. 709* primaries.
338     # sRGB and Rec 709 use the same gamut
339     XYZ_to_Rec709 = [3.2409699419, -1.5373831776, -0.4986107603,
340                      -0.9692436363, 1.8759675015, 0.0415550574,
341                      0.0556300797, -0.2039769589, 1.0569715142]
342
343     cs = create_matrix_colorspace(
344         'Linear - sRGB',
345         from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec709],
346         aliases=["lin_sRGB"])
347     colorspaces.append(cs)
348
349     # *Linear* to *sRGB* Transfer Function*
350     cs = create_matrix_plus_transfer_colorspace(
351         'Curve - sRGB',
352         'sRGB',
353         transfer_function_sRGB_to_linear,
354         lut_directory,
355         lut_resolution_1d,
356         aliases=["crv_sRGB"])
357     colorspaces.append(cs)
358
359     # *ACES* to *sRGB* Primaries + Transfer Function*
360     cs = create_matrix_plus_transfer_colorspace(
361         'sRGB',
362         'sRGB',
363         transfer_function_sRGB_to_linear,
364         lut_directory,
365         lut_resolution_1d,
366         from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec709],
367         aliases=["sRGB"])
368     colorspaces.append(cs)
369
370     #
371     # Rec 1886
372     #
373     # *ACES* to *Linear*, *Rec. 709* primaries.
374     # Rec 1886 and Rec 709 use the same gamut
375     XYZ_to_Rec709 = [3.2409699419, -1.5373831776, -0.4986107603,
376                      -0.9692436363, 1.8759675015, 0.0415550574,
377                      0.0556300797, -0.2039769589, 1.0569715142]
378
379     cs = create_matrix_colorspace(
380         'Linear - Rec.1886',
381         from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec709],
382         aliases=["lin_rec1886"])
383     colorspaces.append(cs)
384
385     # *Linear* to *sRGB* Transfer Function*
386     cs = create_matrix_plus_transfer_colorspace(
387         'Curve - Rec.1886',
388         'rec1886',
389         transfer_function_Rec1886_to_linear,
390         lut_directory,
391         lut_resolution_1d,
392         aliases=["crv_rec1886"])
393     colorspaces.append(cs)
394
395     # *ACES* to *sRGB* Primaries + Transfer Function*
396     cs = create_matrix_plus_transfer_colorspace(
397         'Rec.1886',
398         'rec1886',
399         transfer_function_Rec1886_to_linear,
400         lut_directory,
401         lut_resolution_1d,
402         from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec709],
403         aliases=["rec1886"])
404     colorspaces.append(cs)
405
406     #
407     # Rec 2020
408     #
409     # *ACES* to *Linear*, *Rec. 2020* primaries.
410     XYZ_to_Rec2020 = [1.7166511880, -0.3556707838, -0.2533662814,
411                       -0.6666843518, 1.6164812366, 0.0157685458,
412                       0.0176398574, -0.0427706133, 0.9421031212]
413
414     cs = create_matrix_colorspace(
415         'Linear - Rec.2020',
416         from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec2020],
417         aliases=["lin_rec2020"])
418     colorspaces.append(cs)
419
420     # *Linear* to *Rec. 2020 10 bit* Transfer Function*
421     cs = create_matrix_plus_transfer_colorspace(
422         'Curve - Rec.2020 - 10 bit',
423         'rec2020',
424         transfer_function_Rec2020_10bit_to_linear,
425         lut_directory,
426         lut_resolution_1d,
427         aliases=["crv_rec202010bit"])
428     colorspaces.append(cs)
429
430     # *ACES* to *Rec. 2020 10 bit* Primaries + Transfer Function*
431     cs = create_matrix_plus_transfer_colorspace(
432         'Rec.2020 10 bit - Rec.2020',
433         'rec2020',
434         transfer_function_Rec2020_10bit_to_linear,
435         lut_directory,
436         lut_resolution_1d,
437         from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec2020],
438         aliases=["rec202010bit"])
439     colorspaces.append(cs)
440
441     # *Linear* to *Rec. 2020 10 bit* Transfer Function*
442     cs = create_matrix_plus_transfer_colorspace(
443         'Curve - Rec.2020 - 12 bit',
444         'rec2020',
445         transfer_function_Rec2020_12bit_to_linear,
446         lut_directory,
447         lut_resolution_1d,
448         aliases=["crv_rec202012bit"])
449     colorspaces.append(cs)
450
451     # *ACES* to *Rec. 2020 10 bit* Primaries + Transfer Function*
452     cs = create_matrix_plus_transfer_colorspace(
453         'Rec.2020 12 bit - Rec.2020',
454         'rec2020',
455         transfer_function_Rec2020_12bit_to_linear,
456         lut_directory,
457         lut_resolution_1d,
458         from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec2020],
459         aliases=["rec202012bit"])
460     colorspaces.append(cs)
461
462     #
463     # ProPhoto
464     #
465     # *ACES* to *Linear*, *Pro Photo* primaries.
466     AP0_to_RIMM = [1.2412367771, -0.1685692287, -0.0726675484,
467                    0.0061203066, 1.083151174, -0.0892714806,
468                    -0.0032853314, 0.0099796402, 0.9933056912]
469
470     cs = create_matrix_colorspace(
471         'Linear - RIMM ROMM (ProPhoto)',
472         from_reference_values=[AP0_to_RIMM],
473         aliases=["lin_prophoto", "lin_rimm"])
474     colorspaces.append(cs)
475
476     #
477     # Adobe RGB
478     #
479     # *ACES* to *Linear*, *Adobe RGB* primaries.
480     AP0_to_ADOBERGB = [1.7245603168, -0.4199935942, -0.3045667227,
481                        -0.2764799142, 1.3727190877, -0.0962391734,
482                        -0.0261255258, -0.0901747807, 1.1163003065]
483
484     cs = create_matrix_colorspace(
485         'Linear - Adobe RGB',
486         from_reference_values=[AP0_to_ADOBERGB],
487         aliases=["lin_adobergb"])
488     colorspaces.append(cs)
489
490     #
491     # Adobe Wide Gamut RGB
492     #
493
494     # *ACES* to *Linear*, *Adobe Wide Gamut RGB* primaries.
495     AP0_to_ADOBERGB = [1.3809814778, -0.1158594573, -0.2651220205,
496                        0.0057015535, 1.0402949043, -0.0459964578,
497                        -0.0038908746, -0.0597091815, 1.0636000561]
498
499     cs = create_matrix_colorspace(
500         'Linear - Adobe Wide Gamut RGB',
501         from_reference_values=[AP0_to_ADOBERGB],
502         aliases=["lin_adobewidegamutrgb"])
503     colorspaces.append(cs)
504
505     return colorspaces
506
507
508 def create_raw():
509     # *Raw* utility space
510     name = "Raw"
511     raw = ColorSpace(name)
512     raw.description = 'The %s color space' % name
513     raw.aliases = []
514     raw.equality_group = name
515     raw.family = 'Utility'
516     raw.is_data = True
517
518     return raw
519
520