From 1ef6829d081edc2cdb9e7610f33ae52a0a7f0ee7 Mon Sep 17 00:00:00 2001 From: Haarm-Pieter Duiker Date: Thu, 5 Feb 2015 12:17:33 -0800 Subject: [PATCH] Add support to generate_lut for writing CSP Add link to CTL fork that includes for Dolby PQ transforms Add thank you to Robert Molholm Add link to Panasonic IDT --- aces_1.0.0/README.md | 8 + aces_1.0.0/python/aces_ocio/generate_lut.py | 211 +++++++++++++++++++++++---- 2 files changed, 194 insertions(+), 25 deletions(-) diff --git a/aces_1.0.0/README.md b/aces_1.0.0/README.md index 2ab0e19..8ec631c 100644 --- a/aces_1.0.0/README.md +++ b/aces_1.0.0/README.md @@ -29,6 +29,10 @@ The **ACES CTL** code used as source for the configuration is available here: - https://github.com/ampas/aces-dev/tree/v1.0 - https://github.com/ampas/aces-dev/releases/tag/v1.0 +The current configuration depends on a **fork of the 1.0 ACES CTL** that is available here: +- https://github.com/hpd/aces-dev/tree/master/transforms/ctl +- The fork contains a few additional scripts in the utilities folder but is otherwise the same. + Transforms ---------- Transforms generated based on the following sources: @@ -49,6 +53,9 @@ Transforms generated based on the following sources: - http://www.usa.canon.com/cusa/professional/products/professional_cameras/cinema_eos_cameras/eos_c100#DriversAndSoftware - Choose *OSX Mountain Lion v10.8* to download the IDTs +### Panasonic +- http://pro-av.panasonic.net/en/varicam/35/dl.html + ### RED - http://www.red.com/learn/red-101/redlogfilm-redgamma - Conversations with Graeme Nattress of RED @@ -72,6 +79,7 @@ The script used to generate these transforms and the transforms themselves were - Joseph Goldstone - Jim Houston - Thomas Mansencal +- Robert Molholm - Will McCown - Graeme Nattress - Doug Walker diff --git a/aces_1.0.0/python/aces_ocio/generate_lut.py b/aces_1.0.0/python/aces_ocio/generate_lut.py index 107698b..6059636 100755 --- a/aces_1.0.0/python/aces_ocio/generate_lut.py +++ b/aces_1.0.0/python/aces_ocio/generate_lut.py @@ -120,11 +120,119 @@ def write_SPI_1d(filename, fp.write('}\n') +def write_CSP_1d(filename, + from_min, + from_max, + data, + entries, + channels, + components=3): + """ + Object description. + + Parameters + ---------- + parameter : type + Parameter description. + + Returns + ------- + type + Return value description. + """ + + # May want to use fewer components than there are channels in the data + # Most commonly used for single channel LUTs + components = min(3, components, channels) + + with open(filename, 'w') as fp: + fp.write('CSPLUTV100\n') + fp.write('1D\n') + fp.write('\n') + fp.write('BEGIN METADATA') + fp.write('END METADATA') + + fp.write('\n') + + fp.write('2\n') + fp.write('%f %f\n' % (from_min, from_max)) + fp.write('0.0 1.0\n') + fp.write('2\n') + fp.write('%f %f\n' % (from_min, from_max)) + fp.write('0.0 1.0\n') + fp.write('2\n') + fp.write('%f %f\n' % (from_min, from_max)) + fp.write('0.0 1.0\n') + + fp.write('\n') + + fp.write('%d\n' % entries) + if components == 1: + for i in range(0, entries): + entry = '' + for j in range(3): + entry = '%s %s' % (entry, data[i * channels]) + fp.write('%s\n' % entry) + else: + for i in range(entries): + entry = '' + for j in range(components): + entry = '%s %s' % (entry, data[i * channels + j]) + fp.write('%s\n' % entry) + fp.write('\n') + +def write_1d(filename, + from_min, + from_max, + data, + data_entries, + data_channels, + lut_components=3, + format='spi1d'): + """ + Object description. + + Parameters + ---------- + parameter : type + Parameter description. + + Returns + ------- + type + Return value description. + """ + + ocioFormatsToExtensions = {'cinespace' : 'csp', + 'flame' : '3dl', + 'icc' : 'icc', + 'houdini' : 'lut', + 'lustre' : '3dl'} + + if format in ocioFormatsToExtensions: + if ocioFormatsToExtensions[format] == 'csp': + write_CSP_1d(filename, + from_min, + from_max, + data, + data_entries, + data_channels, + lut_components) + else: + write_SPI_1d(filename, + from_min, + from_max, + data, + data_entries, + data_channels, + lut_components) + def generate_1d_LUT_from_image(ramp_1d_path, output_path=None, min_value=0, max_value=1, - channels=3): + channels=3, + format='spi1d'): """ Object description. @@ -153,8 +261,8 @@ def generate_1d_LUT_from_image(ramp_1d_path, type = oiio.FLOAT ramp_data = ramp.read_image(type) - write_SPI_1d(output_path, min_value, max_value, - ramp_data, ramp_width, ramp_channels, channels) + write_1d(output_path, min_value, max_value, + ramp_data, ramp_width, ramp_channels, channels, format) def generate_3d_LUT_image(ramp_3d_path, resolution=32): @@ -185,7 +293,10 @@ def generate_3d_LUT_image(ramp_3d_path, resolution=32): lut_extract.execute() -def generate_3d_LUT_from_image(ramp_3d_path, output_path=None, resolution=32): +def generate_3d_LUT_from_image(ramp_3d_path, + output_path=None, + resolution=32, + format='spi3d'): """ Object description. @@ -201,21 +312,58 @@ def generate_3d_LUT_from_image(ramp_3d_path, output_path=None, resolution=32): """ if output_path is None: - output_path = '%s.%s' % (ramp_3d_path, 'spi1d') + output_path = '%s.%s' % (ramp_3d_path, 'spi3d') + + ocioFormatsToExtensions = {'cinespace' : 'csp', + 'flame' : '3dl', + 'icc' : 'icc', + 'houdini' : 'lut', + 'lustre' : '3dl'} + + if format == 'spi3d' or not (format in ocioFormatsToExtensions): + # Extract a spi3d LUT + args = ['--extract', + '--cubesize', + str(resolution), + '--maxwidth', + str(resolution * resolution), + '--input', + ramp_3d_path, + '--output', + output_path] + lut_extract = Process(description='extract a 3d LUT', + cmd='ociolutimage', + args=args) + lut_extract.execute() - args = ['--extract', - '--cubesize', - str(resolution), - '--maxwidth', - str(resolution * resolution), - '--input', - ramp_3d_path, - '--output', - output_path] - lut_extract = Process(description='extract a 3d LUT', - cmd='ociolutimage', - args=args) - lut_extract.execute() + else: + output_path_spi3d = '%s.%s' % (output_path, 'spi3d') + + # Extract a spi3d LUT + args = ['--extract', + '--cubesize', + str(resolution), + '--maxwidth', + str(resolution * resolution), + '--input', + ramp_3d_path, + '--output', + output_path_spi3d] + lut_extract = Process(description='extract a 3d LUT', + cmd='ociolutimage', + args=args) + lut_extract.execute() + + # Convert to a different format + args = ['--lut', + output_path_spi3d, + '--format', + format, + output_path] + lut_convert = Process(description='convert a 3d LUT', + cmd='ociobakelut', + args=args) + lut_convert.execute() def apply_CTL_to_image(input_image, @@ -309,7 +457,8 @@ def generate_1d_LUT_from_CTL(lut_path, aces_ctl_directory=None, min_value=0, max_value=1, - channels=3): + channels=3, + format='spi1d'): """ Object description. @@ -356,7 +505,8 @@ def generate_1d_LUT_from_CTL(lut_path, lut_path, min_value, max_value, - channels) + channels, + format) if cleanup: os.remove(identity_LUT_image) @@ -446,7 +596,8 @@ def generate_3d_LUT_from_CTL(lut_path, output_scale=1, global_params=None, cleanup=True, - aces_ctl_directory=None): + aces_ctl_directory=None, + format='spi3d'): """ Object description. @@ -493,7 +644,10 @@ def generate_3d_LUT_from_CTL(lut_path, corrected_LUT_image, lut_resolution) - generate_3d_LUT_from_image(corrected_LUT_image, lut_path, lut_resolution) + generate_3d_LUT_from_image(corrected_LUT_image, + lut_path, + lut_resolution, + format) if cleanup: os.remove(identity_LUT_image) @@ -502,7 +656,9 @@ def generate_3d_LUT_from_CTL(lut_path, os.remove(transformed_LUT_image) if corrected_LUT_image != transformed_LUT_image: os.remove(corrected_LUT_image) - + if format != 'spi3d': + lut_path_spi3d = '%s.%s' % (lut_path, 'spi3d') + os.remove(lut_path_spi3d) def main(): """ @@ -528,6 +684,7 @@ def main(): usage='%prog [options]') p.add_option('--lut', '-l', type='string', default='') + p.add_option('--format', '-f', type='string', default='') p.add_option('--ctl', '-c', type='string', action='append') p.add_option('--lutResolution1d', '', type='int', default=1024) p.add_option('--lutResolution3d', '', type='int', default=33) @@ -547,6 +704,7 @@ def main(): options, arguments = p.parse_args() lut = options.lut + format = options.format ctls = options.ctl lut_resolution_1d = options.lutResolution1d lut_resolution_3d = options.lutResolution3d @@ -578,6 +736,7 @@ def main(): print('3D LUT generation options') print('lut : %s' % lut) + print('format : %s' % format) print('ctls : %s' % ctls) print('lut res 1d : %s' % lut_resolution_1d) print('lut res 3d : %s' % lut_resolution_3d) @@ -601,7 +760,8 @@ def main(): cleanup, ctl_release_path, min_value, - max_value) + max_value, + format=format) elif generate_3d: generate_3d_LUT_from_CTL(lut, @@ -612,7 +772,8 @@ def main(): output_scale, params, cleanup, - ctl_release_path) + ctl_release_path, + format=format) else: print(('\n\nNo LUT generated. ' 'You must choose either 1D or 3D LUT generation\n\n')) -- 1.7.10.4