2 # -*- coding: utf-8 -*-
5 Implements support for *Panasonic GH4* colorspaces conversions and transfer
6 functions based on empirical data.
8 from panasonic_gh4_data import *
11 from scipy import interpolate
12 import matplotlib.pyplot as plt
18 import PyOpenColorIO as ocio
20 import aces_ocio.generate_lut as genlut
21 from aces_ocio.utilities import ColorSpace
23 __author__ = 'Martin Schitter'
24 __copyright__ = 'Copyright (C) 2015 - Martin Schitter'
25 __license__ = 'GNU General Public License'
26 __maintainer__ = 'Martin Schitter'
27 __email__ = 'ms+aces@mur.at'
28 __status__ = 'Experimental'
30 __all__ = ['create_gh4_style',
33 'Scenery': [0.0079310344827586213, 0.017241379310344827,
34 0.053448275862068968, 0.27517241379310342, 0.7501724137931034,
35 1.3010344827586207, 2.1315517241379309, 3.0501724137931037,
36 4.3113793103448277, 5.8546551724137927, 7.9153448275862068,
37 10.296551724137931, 13.276896551724137, 16.769310344827588,
38 21.641896551724138, 27.386034482758621, 34.62258620689655,
39 43.353448275862071, 53.682931034482756, 65.670000000000002,
40 80.268275862068961, 102.43344827586206, 116.53896551724138,
41 134.62586206896552, 156.84931034482759, 170.11293103448276,
42 184.20775862068965, 196.58258620689656, 207.89155172413794,
43 217.53241379310344, 227.18224137931034, 236.08120689655172,
44 244.85396551724139, 252.55293103448275, 254.95758620689656,
45 255.0, 255.0, 255.0, 255.0, 255.0],
47 'Natural': [0.032758620689655175, 0.048275862068965517,
48 0.16224137931034482, 0.4613793103448276, 1.0034482758620689,
49 1.7708620689655172, 2.6732758620689654, 3.9575862068965519,
50 5.5139655172413793, 7.4403448275862072, 9.6510344827586199,
51 12.639310344827587, 16.452758620689654, 20.901551724137931,
52 26.867241379310343, 34.115862068965519, 43.008448275862072,
53 52.998448275862067, 64.548103448275867, 76.758448275862065,
54 90.370862068965522, 109.64431034482759, 121.71120689655173,
55 137.56103448275863, 157.60396551724139, 169.77672413793104,
56 182.39965517241379, 194.02293103448275, 205.00258620689655,
57 214.89431034482757, 224.41034482758621, 233.6396551724138,
58 242.20258620689654, 250.67862068965516, 254.0, 254.0, 254.0,
61 'Vivid': [0.0013793103448275861, 0.0025862068965517241,
62 0.024482758620689656, 0.11120689655172414, 0.16810344827586207,
63 0.79741379310344829, 1.2001724137931034, 1.9437931034482758,
64 2.9256896551724139, 4.0244827586206897, 5.4912068965517244,
65 7.490344827586207, 10.088448275862069, 13.246379310344828,
66 17.292586206896551, 22.015862068965518, 28.217068965517242,
67 35.784310344827588, 44.731379310344828, 56.00931034482759,
68 70.820689655172416, 93.825344827586207, 108.79879310344828,
69 128.2251724137931, 152.32620689655172, 166.44137931034481,
70 181.00758620689655, 193.65810344827585, 205.37741379310344,
71 215.1153448275862, 224.87586206896552, 234.14637931034483,
72 242.44327586206896, 250.86465517241379, 254.98724137931035,
73 255.0, 255.0, 255.0, 255.0, 255.0],
75 'Cinelike-D': [0.21293103448275863, 0.27379310344827584,
76 0.55500000000000005, 1.0448275862068965, 1.5686206896551724,
77 2.7260344827586205, 3.9756896551724137, 5.5051724137931037,
78 7.6129310344827585, 10.310344827586206, 13.517931034482759,
79 17.027586206896551, 21.260862068965519, 25.73741379310345,
80 30.967241379310344, 37.214310344827588, 44.142931034482757,
81 51.230689655172412, 58.622068965517244, 66.37155172413793,
82 75.241034482758621, 88.354310344827582, 96.904655172413797,
83 108.34051724137932, 125.1453448275862, 136.35637931034483,
84 150.76827586206898, 168.86913793103449, 185.40758620689655,
85 200.0305172413793, 213.47120689655173, 227.06482758620689,
86 242.42689655172413, 253.55879310344827, 254.97620689655173,
87 255.0, 255.0, 255.0, 255.0, 255.0],
89 'V-Log': [31.429137931034482, 31.752758620689654,
90 31.977413793103448, 32.531551724137934, 32.976551724137934,
91 33.822586206896553, 34.706206896551727, 36.100344827586206,
92 37.966551724137929, 40.231724137931032, 42.8301724137931,
93 46.389482758620687, 50.373103448275863, 54.91965517241379,
94 60.101724137931036, 65.1351724137931, 70.557586206896545,
95 76.224827586206899, 81.544655172413798, 87.275517241379305,
96 93.204999999999998, 100.89396551724138, 105.2244827586207,
97 111.05396551724138, 118.80051724137931, 123.33396551724138,
98 129.31517241379311, 135.62620689655174, 141.68793103448274,
99 148.09086206896552, 154.73741379310346, 160.67603448275861,
100 167.00999999999999, 173.17275862068965, 179.17706896551724,
101 185.62896551724137, 190.93706896551726, 191.0, 191.0, 191.0],
103 'Standard': [0.019827586206896553, 0.030344827586206897,
104 0.1296551724137931, 0.39862068965517239, 0.84431034482758616,
105 1.5265517241379309, 2.3403448275862071, 3.3762068965517242,
106 4.9127586206896554, 6.6224137931034486, 8.8127586206896549,
107 11.51948275862069, 14.727241379310344, 18.599482758620688,
108 23.895862068965517, 30.157413793103448, 38.333275862068966,
109 47.146724137931038, 57.659999999999997, 68.3953448275862,
110 81.231034482758616, 99.765517241379314, 111.80913793103448,
111 127.22586206896551, 147.36137931034483, 160.73448275862069,
112 174.77620689655171, 188.09258620689656, 200.56137931034482,
113 212.24275862068964, 222.05310344827586, 231.96775862068966,
114 240.85534482758621, 250.1894827586207, 255.0, 255.0, 255.0,
115 255.0, 255.0, 255.0],
117 'BW': [0.012068965517241379, 0.03017241379310345,
118 0.15879310344827585, 0.40379310344827585, 1.039655172413793,
119 1.5532758620689655, 2.5448275862068965, 3.6275862068965519,
120 5.1298275862068969, 7.1593103448275865, 9.1227586206896554,
121 12.219482758620689, 15.602413793103448, 19.667068965517242,
122 25.558793103448277, 32.138103448275864, 40.762413793103448,
123 50.295862068965519, 61.059655172413791, 72.762758620689652,
124 86.235172413793109, 105.61879310344827, 118.42362068965517,
125 134.05362068965516, 155.23034482758621, 168.7403448275862,
126 182.65913793103448, 195.72913793103447, 208.67896551724138,
127 220.05086206896553, 229.83293103448275, 238.34137931034482,
128 246.78810344827585, 254.53086206896552, 255.0, 255.0, 255.0,
129 255.0, 255.0, 255.0],
131 'Cinelike-V': [0.0, 0.0, 0.00034482758620689653,
132 0.017586206896551725, 0.16534482758620689, 0.71965517241379307,
133 1.0924137931034483, 1.8994827586206897, 2.7312068965517242,
134 3.7174137931034483, 5.0798275862068962, 7.0439655172413795,
135 9.4998275862068962, 12.756379310344828, 17.174827586206895,
136 22.375, 29.295000000000002, 37.235344827586204,
137 47.138448275862068, 58.181034482758619, 71.008103448275861,
138 89.295000000000002, 101.09810344827586, 117.49913793103448,
139 138.71793103448275, 152.10293103448276, 166.64051724137931,
140 181.39448275862068, 194.29568965517242, 206.1453448275862,
141 218.05224137931035, 229.84310344827585, 243.2646551724138,
142 254.25103448275863, 254.99310344827586, 255.0, 255.0, 255.0,
145 'Portrait': [0.044999999999999998, 0.10706896551724138,
146 0.21482758620689654, 0.61827586206896556, 1.258448275862069,
147 1.9755172413793103, 2.8977586206896553, 4.243620689655172,
148 5.7982758620689658, 7.8572413793103451, 10.573620689655172,
149 13.566896551724138, 17.62396551724138, 22.091724137931035,
150 28.537068965517243, 36.138103448275864, 45.346551724137932,
151 55.862241379310348, 67.451379310344834, 79.880689655172418,
152 94.139827586206891, 113.69862068965517, 126.13396551724138,
153 141.94724137931036, 161.84068965517241, 173.89344827586206,
154 186.02206896551724, 196.99051724137931, 207.93103448275863,
155 217.54758620689654, 227.05655172413793, 235.96586206896552,
156 245.08810344827586, 253.00948275862069, 253.97603448275862,
157 254.0, 254.0, 254.0, 254.0, 254.0],
159 'Custom': [0.039310344827586205, 0.1, 0.31086206896551727,
160 0.73482758620689659, 1.3484482758620691, 2.046551724137931,
161 3.1565517241379308, 4.5710344827586207, 6.1872413793103451,
162 8.3953448275862073, 10.947068965517241, 14.126724137931035,
163 18.054827586206898, 22.778965517241378, 29.185689655172414,
164 36.938448275862072, 45.952931034482759, 56.380000000000003,
165 67.094310344827591, 79.601724137931029, 93.560000000000002,
166 113.16017241379311, 125.54551724137932, 141.44189655172414,
167 162.21155172413793, 174.12517241379311, 186.3755172413793,
168 199.36862068965516, 211.13103448275862, 221.01068965517243,
169 230.70120689655172, 239.67758620689656, 249.01879310344827,
170 254.96413793103449, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0]
173 def prepare_photostyle_to_linear(style, corr=None, debug_plot=False):
175 # 18% gray card correction
179 # if style == 'V-Log':
185 exp = np.linspace( (corr-39)/3.0, corr/3.0, 40)
186 l = np.power(2, exp) * 0.18
187 vals = np.array(styles[style])
190 # remove visible edges at some exposure values
192 for n in [24, 21, 4]:
194 plt.semilogy(vals[n], l[n], 'bx' )
195 vals = np.delete(vals, n)
198 # modify equal values to get an invertable monotone function
199 force_monotone = np.linspace(0,0.00001,len(vals))
200 vals = vals+force_monotone
202 #interp = interpolate.Akima1DInterpolator(vals, l)
203 interp = interpolate.PchipInterpolator(vals, l, extrapolate=False)
206 plt.semilogy(vals, l, 'b+' )
207 x = np.linspace(0., 1.0, 4096)
209 plt.semilogy(x, y, 'r.', ms=1 )
210 x = np.linspace(0., 1.0, 256)
212 plt.semilogy(x, y, 'bo', ms=2 )
218 def create_gh4_style(gamut,
225 Creates colorspace covering the conversion from GH4 picture styles
226 to ACES based on empirical data
231 The name of the encoding gamut to use.
232 transfer_function : str
233 The name of the transfer function to use
234 lut_directory : str or unicode
235 The directory to use when generating LUTs
236 lut_resolution_1d : int
237 The resolution of generated 1D LUTs
238 aliases : list of str
239 Aliases for this colorspace
244 A ColorSpace container class referencing the LUTs, matrices
245 and identifying information for the requested colorspace.
248 name = 'GH4-%s - GH4-%s-Gamut' % (transfer_function, gamut)
249 if transfer_function == '':
250 name = 'Linear - GH4-%s-Gamut' % gamut
252 name = 'Curve - GH4-%s' % transfer_function
254 cs = ColorSpace(name)
255 cs.description = name
257 cs.equality_group = ''
258 cs.family = 'Input/Panasonic/GH4'
261 # A linear space needs allocation variables
262 if transfer_function == '':
263 cs.allocation_type = ocio.Constants.ALLOCATION_LG2
264 cs.allocation_vars = [-8, 6, 0.00390625]
266 cs.to_reference_transforms = []
268 if transfer_function != '':
269 f = prepare_photostyle_to_linear(transfer_function)
271 #data = array.array('f', '\0' * lut_resolution_1d * 4)
272 #for c in range(lut_resolution_1d):
273 # data[c] = v_log_to_linear(float(c) / (lut_resolution_1d - 1))
274 dom = np.linspace(0.0, 1.0, lut_resolution_1d)
277 # constant extrapolation
278 data_min = np.nanmin(data)
279 data_max = np.nanmax(data)
280 inds = np.where(np.isnan(data))
282 if i < lut_resolution_1d/2:
288 lut = 'gh4_%s_to_linear.spi1d' % transfer_function
290 os.path.join(lut_directory, lut),
297 cs.to_reference_transforms.append({
300 'interpolation': 'linear',
301 'direction': 'forward'})
304 # matrix calculations based on:
305 # http://www.colour-science.org
313 cs.to_reference_transforms.append({
315 # colour.V_GAMUT_COLOURSPACE.RGB_to_XYZ_matrix
316 'matrix': [0.679644, 0.152211, 0.1186 , 0.,
317 0.260686, 0.774894, -0.03558, 0.,
318 -0.00931 , -0.004612, 1.10298, 0.,
320 'direction': 'forward'})
322 cs.to_reference_transforms.append({
324 # colour.sRGB_COLOURSPACE.RGB_to_XYZ_matrix
325 'matrix': [0.41238656, 0.35759149, 0.18045049, 0.0,
326 0.21263682, 0.71518298, 0.0721802 , 0.0,
327 0.01933062, 0.11919716, 0.95037259, 0.0,
329 'direction': 'forward'})
331 # D65 -> D50 adaption
333 # colour.chromatic_adaptation_matrix_VonKries(
334 # colour.xy_to_XYZ(c.sRGB_COLOURSPACE.whitepoint),
335 # colour.xy_to_XYZ(colour.ILLUMINANTS[
336 # 'CIE 1931 2 Degree Standard Observer']['D50']), 'CAT02')
339 cs.to_reference_transforms.append({
341 'matrix': [1.04251352, 0.03083262, -0.05276445, 0.0,
342 0.0221519 , 1.00187227, -0.02105432, 0.0,
343 -0.00116356, -0.00341802, 0.76197255, 0.0,
345 'direction': 'forward'})
347 if gamut.endswith('XYZ'):
348 cs.from_reference_transforms = []
351 if gamut.endswith('Calibrated'):
353 wb[0] = calibration_wb[style][0]
354 wb[5] = calibration_wb[style][1]
355 wb[10] = calibration_wb[style][2]
357 cs.to_reference_transforms.append({
360 'direction': 'forward'})
361 cs.to_reference_transforms.append({
363 'matrix': (calibration_matrices[style][0] + [0.0] +
364 calibration_matrices[style][1] + [0.0] +
365 calibration_matrices[style][2] + [0.0] +
367 'direction': 'forward'})
369 # D50 -> ACES WP (~D60)
371 # colour.chromatic_adaptation_matrix_VonKries(
372 # colour.xy_to_XYZ(colour.ILLUMINANTS[
373 # 'CIE 1931 2 Degree Standard Observer']['D50']),
374 # colour.xy_to_XYZ(colour.V_GAMUT_COLOURSPACE.whitepoint),
377 cs.to_reference_transforms.append({
379 'matrix': [ 0.95991641, -0.02931741, 0.06566143, 0.0,
380 -0.02119542, 0.99887268, 0.02613247, 0.0,
381 0.00137075, 0.00443593, 1.31260073, 0.0,
383 'direction': 'forward'})
388 # colour.ACES_2065_1_COLOURSPACE.XYZ_to_RGB_matrix
389 cs.to_reference_transforms.append({
391 'matrix': [1.04981102e+00, 0.00000000e+00, -9.74845410e-05, 0.,
392 -4.95903023e-01, 1.37331305e+00, 9.82400365e-02, 0.,
393 0.00000000e+00, 0.00000000e+00, 9.91252022e-01, 0.,
395 'direction': 'forward'})
398 # matrix given py panasonic / calculated by nuke
399 # for one step transformation:
402 # if gamut == 'V-Log':
403 # cs.to_reference_transforms.append({
405 # 'matrix': [0.724383 , 0.166748 , 0.108497, 0.,
406 # 0.021354 , 0.985138 , -0.006319, 0.,
407 # -0.009234 , -0.001043 , 1.010273, 0.,
409 # 'direction': 'forward'})
411 # cs.to_reference_transforms.append({
413 # 'matrix': [0.43964687, 0.38298151, 0.17737158, 0.0,
414 # 0.08978026, 0.81343973, 0.09677973, 0.0,
415 # 0.01754464, 0.11155707, 0.87089837, 0.0,
417 # 'direction': 'forward'})
419 cs.from_reference_transforms = []
423 def create_colorspaces(lut_directory, lut_resolution_1d):
425 Generates the colorspace conversions.
429 lut_directory : str or unicode
430 The directory to use when generating LUTs
431 lut_resolution_1d : int
432 The resolution of generated 1D LUTs
437 A list of colorspaces for Panasonic cameras and encodings
442 styles_sort = styles.keys()
445 for style in styles_sort:
448 style_1 = create_gh4_style(
453 ['gh4_%s_gh4_gamut' % style.lower().replace('-','_')])
454 colorspaces.append(style_1)
457 style_2 = create_gh4_style(
462 ['crv_gh4_%s' % style.lower().replace('-','_')])
463 colorspaces.append(style_2)
465 # Linearization and XYZ conversion
466 style_3 = create_gh4_style(
471 ['gh4_%s_xyz' % style.lower().replace('-','_')])
472 colorspaces.append(style_3)
475 style_4 = create_gh4_style(
480 ['lin_gh4_%s_gamut' % style.lower().replace('-','_')])
481 colorspaces.append(style_4)
485 # Full conversion calibrated
486 style_5 = create_gh4_style(
487 '%s-Calibrated' % style,
491 ['gh4_%s_gh4_calibrated_gamut'% style.lower().replace('-','_')],
493 colorspaces.append(style_5)
495 # Primaries Only calibrated
496 style_6 = create_gh4_style(
497 '%s-Calibrated' % style,
501 ['lin_gh4_%s_calibrated_gamut'%style.lower().replace('-','_')],
503 colorspaces.append(style_6)