Add main module attributes.
[OpenColorIO-Configs.git] / aces_1.0.0 / python / aces_ocio / createARRIColorSpaces.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 import array
5 import math
6
7 import aces_ocio.generateLUT as genlut
8 from aces_ocio.util import ColorSpace, mat44FromMat33
9
10
11 __author__ = 'ACES Developers'
12 __copyright__ = 'Copyright (C) 2014 - 2015 - ACES Developers'
13 __license__ = ''
14 __maintainer__ = 'ACES Developers'
15 __email__ = 'aces@oscars.org'
16 __status__ = 'Production'
17
18 __all__ = ['createLogC',
19            'createColorSpaces']
20
21 #
22 # LogC to ACES
23 #
24 def createLogC(gamut,
25                transferFunction,
26                exposureIndex,
27                name,
28                lutDir,
29                lutResolution1d):
30     name = "%s (EI%s) - %s" % (transferFunction, exposureIndex, gamut)
31     if transferFunction == "":
32         name = "Linear - %s" % gamut
33     if gamut == "":
34         name = "%s (EI%s)" % (transferFunction, exposureIndex)
35
36     cs = ColorSpace(name)
37     cs.description = name
38     cs.equalityGroup = ''
39     cs.family = 'ARRI'
40     cs.isData = False
41
42     # Globals
43     IDT_maker_version = "0.08"
44
45     nominalEI = 400.0
46     blackSignal = 0.003907
47     midGraySignal = 0.01
48     encodingGain = 0.256598
49     encodingOffset = 0.391007
50
51     def gainForEI(EI):
52         return (math.log(EI / nominalEI) / math.log(2) * (
53             0.89 - 1) / 3 + 1) * encodingGain
54
55     def LogCInverseParametersForEI(EI):
56         cut = 1.0 / 9.0
57         slope = 1.0 / (cut * math.log(10))
58         offset = math.log10(cut) - slope * cut
59         gain = EI / nominalEI
60         gray = midGraySignal / gain
61         # The higher the EI, the lower the gamma
62         encGain = gainForEI(EI)
63         encOffset = encodingOffset
64         for i in range(0, 3):
65             nz = ((95.0 / 1023.0 - encOffset) / encGain - offset) / slope
66             encOffset = encodingOffset - math.log10(1 + nz) * encGain
67         # Calculate some intermediate values
68         a = 1.0 / gray
69         b = nz - blackSignal / gray
70         e = slope * a * encGain
71         f = encGain * (slope * b + offset) + encOffset
72         # Manipulations so we can return relative exposure
73         s = 4 / (0.18 * EI)
74         t = blackSignal
75         b = b + a * t
76         a = a * s
77         f = f + e * t
78         e = e * s
79         return {'a': a,
80                 'b': b,
81                 'cut': (cut - b) / a,
82                 'c': encGain,
83                 'd': encOffset,
84                 'e': e,
85                 'f': f}
86
87     def logCtoLinear(codeValue, exposureIndex):
88         p = LogCInverseParametersForEI(exposureIndex)
89         breakpoint = p['e'] * p['cut'] + p['f']
90         if (codeValue > breakpoint):
91             linear = ((pow(10, (codeValue / 1023.0 - p['d']) / p['c']) -
92                        p['b']) / p['a'])
93         else:
94             linear = (codeValue / 1023.0 - p['f']) / p['e']
95
96         # print(codeValue, linear)
97         return linear
98
99
100     cs.toReferenceTransforms = []
101
102     if transferFunction == "V3 LogC":
103         data = array.array('f', "\0" * lutResolution1d * 4)
104         for c in range(lutResolution1d):
105             data[c] = logCtoLinear(1023.0 * c / (lutResolution1d - 1),
106                                    int(exposureIndex))
107
108         lut = "%s_to_linear.spi1d" % (
109             "%s_%s" % (transferFunction, exposureIndex))
110
111         # Remove spaces and parentheses
112         lut = lut.replace(' ', '_').replace(')', '_').replace('(', '_')
113
114         genlut.writeSPI1D(lutDir + "/" + lut,
115                           0.0,
116                           1.0,
117                           data,
118                           lutResolution1d,
119                           1)
120
121         # print("Writing %s" % lut)
122         cs.toReferenceTransforms.append({
123             'type': 'lutFile',
124             'path': lut,
125             'interpolation': 'linear',
126             'direction': 'forward'
127         })
128
129     if gamut == 'Wide Gamut':
130         cs.toReferenceTransforms.append({
131             'type': 'matrix',
132             'matrix': mat44FromMat33([0.680206, 0.236137, 0.083658,
133                                       0.085415, 1.017471, -0.102886,
134                                       0.002057, -0.062563, 1.060506]),
135             'direction': 'forward'
136         })
137
138     cs.fromReferenceTransforms = []
139     return cs
140
141
142 def createColorSpaces(lutDir, lutResolution1d):
143     colorspaces = []
144
145     transferFunction = "V3 LogC"
146     gamut = "Wide Gamut"
147     # EIs = [160.0, 200.0, 250.0, 320.0, 400.0, 500.0, 640.0, 800.0,
148     # 1000.0, 1280.0, 1600.0, 2000.0, 2560.0, 3200.0]
149     EIs = [160, 200, 250, 320, 400, 500, 640, 800,
150            1000, 1280, 1600, 2000, 2560, 3200]
151     defaultEI = 800
152
153     # Full conversion
154     for EI in EIs:
155         LogCEIfull = createLogC(
156             gamut, transferFunction, EI, "LogC", lutDir, lutResolution1d)
157         colorspaces.append(LogCEIfull)
158
159     # Linearization only
160     for EI in [800]:
161         LogCEIlinearization = createLogC(
162             "", transferFunction, EI, "LogC", lutDir, lutResolution1d)
163         colorspaces.append(LogCEIlinearization)
164
165     # Primaries
166     LogCEIprimaries = createLogC(
167         gamut, "", defaultEI, "LogC", lutDir, lutResolution1d)
168     colorspaces.append(LogCEIprimaries)
169
170     return colorspaces