2 # -*- coding: utf-8 -*-
5 Implements support for general colorspaces conversions and transfer functions.
8 from __future__ import division
13 import PyOpenColorIO as ocio
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
19 __author__ = 'ACES Developers'
20 __copyright__ = 'Copyright (C) 2014 - 2015 - ACES Developers'
22 __maintainer__ = 'ACES Developers'
23 __email__ = 'aces@oscars.org'
24 __status__ = 'Production'
26 __all__ = ['create_matrix_colorspace',
27 'create_transfer_colorspace',
28 'create_matrix_plus_transfer_colorspace',
29 'transfer_function_sRGB_to_linear',
30 'transfer_function_Rec709_to_linear',
31 'transfer_function_Rec2020_10bit_to_linear',
32 'transfer_function_Rec2020_12bit_to_linear',
33 'transfer_function_Rec1886_to_linear',
38 # -------------------------------------------------------------------------
40 # -------------------------------------------------------------------------
41 def create_matrix_colorspace(name='matrix',
42 from_reference_values=None,
43 to_reference_values=None,
51 Parameter description.
56 Return value description.
59 if from_reference_values is None:
60 from_reference_values = []
62 if to_reference_values is None:
63 to_reference_values = []
69 cs.description = 'The %s color space' % name
71 cs.equality_group = name
75 # A linear space needs allocation variables.
76 cs.allocation_type = ocio.Constants.ALLOCATION_UNIFORM
77 cs.allocation_vars = [0, 1]
79 cs.to_reference_transforms = []
80 if to_reference_values:
81 for matrix in to_reference_values:
82 cs.to_reference_transforms.append({
84 'matrix': mat44_from_mat33(matrix),
85 'direction': 'forward'})
87 cs.from_reference_transforms = []
88 if from_reference_values:
89 for matrix in from_reference_values:
90 cs.from_reference_transforms.append({
92 'matrix': mat44_from_mat33(matrix),
93 'direction': 'forward'})
98 # -------------------------------------------------------------------------
99 # *Transfer Function Transform*
100 # -------------------------------------------------------------------------
101 def create_transfer_colorspace(name='transfer',
102 transfer_function_name='transfer_function',
103 transfer_function=lambda x: x,
104 lut_directory='/tmp',
105 lut_resolution_1d=1024,
113 Parameter description.
118 Return value description.
124 cs = ColorSpace(name)
125 cs.description = 'The %s color space' % name
127 cs.equality_group = name
128 cs.family = 'Utility'
131 # A linear space needs allocation variables.
132 cs.allocation_type = ocio.Constants.ALLOCATION_UNIFORM
133 cs.allocation_vars = [0, 1]
135 # Sampling the transfer function.
136 data = array.array('f', '\0' * lut_resolution_1d * 4)
137 for c in range(lut_resolution_1d):
138 data[c] = transfer_function(c / (lut_resolution_1d - 1))
140 # Writing the sampled data to a *LUT*.
141 lut = '%s_to_linear.spi1d' % transfer_function_name
143 os.path.join(lut_directory, lut),
150 # Creating the *to_reference* transforms.
151 cs.to_reference_transforms = []
152 cs.to_reference_transforms.append({
155 'interpolation': 'linear',
156 'direction': 'forward'})
158 # Creating the *from_reference* transforms.
159 cs.from_reference_transforms = []
164 # -------------------------------------------------------------------------
165 # *Transfer Function + Matrix Transform*
166 # -------------------------------------------------------------------------
167 def create_matrix_plus_transfer_colorspace(
168 name='matrix_plus_transfer',
169 transfer_function_name='transfer_function',
170 transfer_function=lambda x: x,
171 lut_directory='/tmp',
172 lut_resolution_1d=1024,
173 from_reference_values=None,
174 to_reference_values=None,
182 Parameter description.
187 Return value description.
190 if from_reference_values is None:
191 from_reference_values = []
193 if to_reference_values is None:
194 to_reference_values = []
199 cs = ColorSpace(name)
200 cs.description = 'The %s color space' % name
202 cs.equality_group = name
203 cs.family = 'Utility'
206 # A linear space needs allocation variables.
207 cs.allocation_type = ocio.Constants.ALLOCATION_UNIFORM
208 cs.allocation_vars = [0, 1]
210 # Sampling the transfer function.
211 data = array.array('f', '\0' * lut_resolution_1d * 4)
212 for c in range(lut_resolution_1d):
213 data[c] = transfer_function(c / (lut_resolution_1d - 1))
215 # Writing the sampled data to a *LUT*.
216 lut = '%s_to_linear.spi1d' % transfer_function_name
218 os.path.join(lut_directory, lut),
225 # Creating the *to_reference* transforms.
226 cs.to_reference_transforms = []
227 if to_reference_values:
228 cs.to_reference_transforms.append({
231 'interpolation': 'linear',
232 'direction': 'forward'})
234 for matrix in to_reference_values:
235 cs.to_reference_transforms.append({
237 'matrix': mat44_from_mat33(matrix),
238 'direction': 'forward'})
240 # Creating the *from_reference* transforms.
241 cs.from_reference_transforms = []
242 if from_reference_values:
243 for matrix in from_reference_values:
244 cs.from_reference_transforms.append({
246 'matrix': mat44_from_mat33(matrix),
247 'direction': 'forward'})
249 cs.from_reference_transforms.append({
252 'interpolation': 'linear',
253 'direction': 'inverse'})
258 # Transfer functions for standard colorspaces.
259 def transfer_function_sRGB_to_linear(v):
267 return pow(((v + (a - 1)) / a), g)
270 def transfer_function_Rec709_to_linear(v):
279 return pow(((v + (a - 1)) / a), g)
282 def transfer_function_Rec2020_10bit_to_linear(v):
291 return pow(((v + (a - 1)) / a), g)
294 def transfer_function_Rec2020_12bit_to_linear(v):
303 return pow(((v + (a - 1)) / a), g)
306 def transfer_function_Rec1886_to_linear(v):
311 # Ignoring legal to full scaling for now.
312 # v = (1023.0*v - 64.0)/876.0
314 t = pow(Lw, 1.0 / g) - pow(Lb, 1.0 / g)
316 b = pow(Lb, 1.0 / g) / t
318 return a * pow(max((v + b), 0.0), g)
321 def create_colorspaces(lut_directory,
324 Generates the colorspace conversions.
329 Parameter description.
334 Return value description.
339 # -------------------------------------------------------------------------
341 # -------------------------------------------------------------------------
342 cs = create_matrix_colorspace('XYZ-D60',
343 to_reference_values=[aces.ACES_XYZ_TO_AP0],
344 from_reference_values=[aces.ACES_AP0_TO_XYZ],
345 aliases=['lin_xyz_d60'])
346 colorspaces.append(cs)
348 # -------------------------------------------------------------------------
350 # -------------------------------------------------------------------------
351 # *ACES* to *Linear*, *P3D60* primaries
352 XYZ_to_P3D60 = [2.4027414142, -0.8974841639, -0.3880533700,
353 -0.8325796487, 1.7692317536, 0.0237127115,
354 0.0388233815, -0.0824996856, 1.0363685997]
356 cs = create_matrix_colorspace(
358 from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_P3D60],
359 aliases=['lin_p3d60'])
360 colorspaces.append(cs)
362 # -------------------------------------------------------------------------
364 # -------------------------------------------------------------------------
365 # *ACES* to *Linear*, *P3DCI* primaries
366 XYZ_to_P3DCI = [2.7253940305, -1.0180030062, -0.4401631952,
367 -0.7951680258, 1.6897320548, 0.0226471906,
368 0.0412418914, -0.0876390192, 1.1009293786]
370 cs = create_matrix_colorspace(
372 from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_P3DCI],
373 aliases=['lin_p3dci'])
374 colorspaces.append(cs)
376 # -------------------------------------------------------------------------
378 # -------------------------------------------------------------------------
379 # *ACES* to *Linear*, *Rec. 709* primaries.
380 # *sRGB* and *Rec 709* use the same gamut.
381 XYZ_to_Rec709 = [3.2409699419, -1.5373831776, -0.4986107603,
382 -0.9692436363, 1.8759675015, 0.0415550574,
383 0.0556300797, -0.2039769589, 1.0569715142]
385 cs = create_matrix_colorspace(
387 from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec709],
388 aliases=['lin_srgb'])
389 colorspaces.append(cs)
391 # *Linear* to *sRGB* Transfer Function*
392 cs = create_transfer_colorspace(
395 transfer_function_sRGB_to_linear,
398 aliases=['crv_srgb'])
399 colorspaces.append(cs)
401 # *ACES* to *sRGB* Primaries + Transfer Function*
402 cs = create_matrix_plus_transfer_colorspace(
405 transfer_function_sRGB_to_linear,
408 from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec709],
410 colorspaces.append(cs)
412 # -------------------------------------------------------------------------
414 # -------------------------------------------------------------------------
415 # *ACES* to *Linear*, *Rec. 709* primaries
416 XYZ_to_Rec709 = [3.2409699419, -1.5373831776, -0.4986107603,
417 -0.9692436363, 1.8759675015, 0.0415550574,
418 0.0556300797, -0.2039769589, 1.0569715142]
420 cs = create_matrix_colorspace(
422 from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec709],
423 aliases=['lin_rec709'])
424 colorspaces.append(cs)
426 # *Linear* to *Rec. 709* Transfer Function*
427 cs = create_transfer_colorspace(
430 transfer_function_Rec709_to_linear,
433 aliases=['crv_rec709'])
434 colorspaces.append(cs)
436 # *ACES* to *Rec. 709* Primaries + Transfer Function*
437 cs = create_matrix_plus_transfer_colorspace(
440 transfer_function_Rec709_to_linear,
443 from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec709],
444 aliases=['rec709_camera'])
445 colorspaces.append(cs)
447 # -------------------------------------------------------------------------
449 # -------------------------------------------------------------------------
450 # *ACES* to *Linear*, *Rec. 2020* primaries
451 XYZ_to_Rec2020 = [1.7166511880, -0.3556707838, -0.2533662814,
452 -0.6666843518, 1.6164812366, 0.0157685458,
453 0.0176398574, -0.0427706133, 0.9421031212]
455 cs = create_matrix_colorspace(
457 from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec2020],
458 aliases=['lin_rec2020'])
459 colorspaces.append(cs)
461 # *Linear* to *Rec. 2020 10 bit* Transfer Function*
462 cs = create_transfer_colorspace(
465 transfer_function_Rec2020_10bit_to_linear,
468 aliases=['crv_rec2020'])
469 colorspaces.append(cs)
471 # *ACES* to *Rec. 2020 10 bit* Primaries + Transfer Function*
472 cs = create_matrix_plus_transfer_colorspace(
475 transfer_function_Rec2020_10bit_to_linear,
478 from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec2020],
479 aliases=['rec2020_camera'])
480 colorspaces.append(cs)
482 # -------------------------------------------------------------------------
484 # -------------------------------------------------------------------------
485 # *Linear* to *Rec.1886* Transfer Function*
486 cs = create_transfer_colorspace(
489 transfer_function_Rec1886_to_linear,
492 aliases=['crv_rec1886'])
493 colorspaces.append(cs)
495 # *ACES* to *sRGB* Primaries + Transfer Function*
496 cs = create_matrix_plus_transfer_colorspace(
499 transfer_function_Rec1886_to_linear,
502 from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec709],
503 aliases=['rec709_display'])
504 colorspaces.append(cs)
506 # *ACES* to *sRGB* Primaries + Transfer Function*
507 cs = create_matrix_plus_transfer_colorspace(
508 'Rec.2020 - Display',
510 transfer_function_Rec1886_to_linear,
513 from_reference_values=[aces.ACES_AP0_TO_XYZ, XYZ_to_Rec2020],
514 aliases=['rec2020_display'])
515 colorspaces.append(cs)
517 # -------------------------------------------------------------------------
519 # -------------------------------------------------------------------------
520 # *ACES* to *Linear*, *Pro Photo* primaries
521 AP0_to_RIMM = [1.2412367771, -0.1685692287, -0.0726675484,
522 0.0061203066, 1.083151174, -0.0892714806,
523 -0.0032853314, 0.0099796402, 0.9933056912]
525 cs = create_matrix_colorspace(
526 'Linear - RIMM ROMM (ProPhoto)',
527 from_reference_values=[AP0_to_RIMM],
528 aliases=['lin_prophoto', 'lin_rimm'])
529 colorspaces.append(cs)
531 # -------------------------------------------------------------------------
533 # -------------------------------------------------------------------------
534 # *ACES* to *Linear*, *Adobe RGB* primaries
535 AP0_to_ADOBERGB = [1.7245603168, -0.4199935942, -0.3045667227,
536 -0.2764799142, 1.3727190877, -0.0962391734,
537 -0.0261255258, -0.0901747807, 1.1163003065]
539 cs = create_matrix_colorspace(
540 'Linear - Adobe RGB',
541 from_reference_values=[AP0_to_ADOBERGB],
542 aliases=['lin_adobergb'])
543 colorspaces.append(cs)
545 # -------------------------------------------------------------------------
546 # Adobe Wide Gamut RGB
547 # -------------------------------------------------------------------------
548 # *ACES* to *Linear*, *Adobe Wide Gamut RGB* primaries
549 AP0_to_ADOBERGB = [1.3809814778, -0.1158594573, -0.2651220205,
550 0.0057015535, 1.0402949043, -0.0459964578,
551 -0.0038908746, -0.0597091815, 1.0636000561]
553 cs = create_matrix_colorspace(
554 'Linear - Adobe Wide Gamut RGB',
555 from_reference_values=[AP0_to_ADOBERGB],
556 aliases=['lin_adobewidegamutrgb'])
557 colorspaces.append(cs)
563 # *Raw* utility space
565 raw = ColorSpace(name)
566 raw.description = 'The %s color space' % name
567 raw.aliases = ['raw']
568 raw.equality_group = name
569 raw.family = 'Utility'