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