Minor updates and bug fixes.
[OpenColorIO-Configs.git] / aces_1.0.0 / python / aces_ocio / generate_lut.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 """
5 Defines objects to generate various kind of 1d, 2d and 3d LUTs in various file
6 formats.
7 """
8
9 from __future__ import division
10
11 import array
12 import os
13
14 import OpenImageIO as oiio
15
16 from aces_ocio.process import Process
17
18 __author__ = 'ACES Developers'
19 __copyright__ = 'Copyright (C) 2014 - 2015 - ACES Developers'
20 __license__ = ''
21 __maintainer__ = 'ACES Developers'
22 __email__ = 'aces@oscars.org'
23 __status__ = 'Production'
24
25 __all__ = ['generate_1d_LUT_image',
26            'write_SPI_1d',
27            'write_CSP_1d',
28            'write_CTL_1d',
29            'write_1d',
30            'generate_1d_LUT_from_image',
31            'generate_3d_LUT_image',
32            'generate_3d_LUT_from_image',
33            'apply_CTL_to_image',
34            'convert_bit_depth',
35            'generate_1d_LUT_from_CTL',
36            'correct_LUT_image',
37            'generate_3d_LUT_from_CTL',
38            'main']
39
40
41 def generate_1d_LUT_image(ramp_1d_path,
42                           resolution=1024,
43                           min_value=0,
44                           max_value=1):
45     """
46     Object description.
47
48     Parameters
49     ----------
50     parameter : type
51         Parameter description.
52
53     Returns
54     -------
55     type
56          Return value description.
57     """
58
59     ramp = oiio.ImageOutput.create(ramp_1d_path)
60
61     spec = oiio.ImageSpec()
62     spec.set_format(oiio.FLOAT)
63     # spec.format.basetype = oiio.FLOAT
64     spec.width = resolution
65     spec.height = 1
66     spec.nchannels = 3
67
68     ramp.open(ramp_1d_path, spec, oiio.Create)
69
70     data = array.array('f',
71                        '\0' * spec.width * spec.height * spec.nchannels * 4)
72     for i in range(resolution):
73         value = float(i) / (resolution - 1) * (
74             max_value - min_value) + min_value
75         data[i * spec.nchannels + 0] = value
76         data[i * spec.nchannels + 1] = value
77         data[i * spec.nchannels + 2] = value
78
79     ramp.write_image(spec.format, data)
80     ramp.close()
81
82
83 def write_SPI_1d(filename,
84                  from_min,
85                  from_max,
86                  data,
87                  entries,
88                  channels,
89                  components=3):
90     """
91     Object description.
92
93     Credit to *Alex Fry* for the original single channel version of the spi1d
94     writer.
95
96     Parameters
97     ----------
98     parameter : type
99         Parameter description.
100
101     Returns
102     -------
103     type
104          Return value description.
105     """
106
107     # May want to use fewer components than there are channels in the data
108     # Most commonly used for single channel LUTs
109     components = min(3, components, channels)
110
111     with open(filename, 'w') as fp:
112         fp.write('Version 1\n')
113         fp.write('From %f %f\n' % (from_min, from_max))
114         fp.write('Length %d\n' % entries)
115         fp.write('Components %d\n' % components)
116         fp.write('{\n')
117         for i in range(0, entries):
118             entry = ''
119             for j in range(0, components):
120                 entry = '%s %s' % (entry, data[i * channels + j])
121             fp.write('        %s\n' % entry)
122         fp.write('}\n')
123
124
125 def write_CSP_1d(filename,
126                  from_min,
127                  from_max,
128                  data,
129                  entries,
130                  channels,
131                  components=3):
132     """
133     Object description.
134
135     Parameters
136     ----------
137     parameter : type
138         Parameter description.
139
140     Returns
141     -------
142     type
143          Return value description.
144     """
145
146     # May want to use fewer components than there are channels in the data
147     # Most commonly used for single channel LUTs
148     components = min(3, components, channels)
149
150     with open(filename, 'w') as fp:
151         fp.write('CSPLUTV100\n')
152         fp.write('1D\n')
153         fp.write('\n')
154         fp.write('BEGIN METADATA\n')
155         fp.write('END METADATA\n')
156
157         fp.write('\n')
158
159         fp.write('2\n')
160         fp.write('%f %f\n' % (from_min, from_max))
161         fp.write('0.0 1.0\n')
162         fp.write('2\n')
163         fp.write('%f %f\n' % (from_min, from_max))
164         fp.write('0.0 1.0\n')
165         fp.write('2\n')
166         fp.write('%f %f\n' % (from_min, from_max))
167         fp.write('0.0 1.0\n')
168
169         fp.write('\n')
170
171         fp.write('%d\n' % entries)
172         if components == 1:
173             for i in range(0, entries):
174                 entry = ''
175                 for j in range(3):
176                     entry = '%s %s' % (entry, data[i * channels])
177                 fp.write('%s\n' % entry)
178         else:
179             for i in range(entries):
180                 entry = ''
181                 for j in range(components):
182                     entry = '%s %s' % (entry, data[i * channels + j])
183                 fp.write('%s\n' % entry)
184         fp.write('\n')
185
186
187 def write_CTL_1d(filename,
188                  from_min,
189                  from_max,
190                  data,
191                  entries,
192                  channels,
193                  components=3):
194     """
195     Object description.
196
197     Parameters
198     ----------
199     parameter : type
200         Parameter description.
201
202     Returns
203     -------
204     type
205          Return value description.
206     """
207
208     # May want to use fewer components than there are channels in the data
209     # Most commonly used for single channel LUTs
210     components = min(3, components, channels)
211
212     with open(filename, 'w') as fp:
213         fp.write('// %d x %d LUT generated by "generate_lut"\n' % (
214             entries, components))
215         fp.write('\n')
216         fp.write('const float min1d = %3.9f;\n' % from_min)
217         fp.write('const float max1d = %3.9f;\n' % from_max)
218         fp.write('\n')
219
220         # Write LUT
221         if components == 1:
222             fp.write('const float lut[] = {\n')
223             for i in range(0, entries):
224                 fp.write('%s' % data[i * channels])
225                 if i != (entries - 1):
226                     fp.write(',')
227                 fp.write('\n')
228             fp.write('};\n')
229             fp.write('\n')
230         else:
231             for j in range(components):
232                 fp.write('const float lut%d[] = {\n' % j)
233                 for i in range(0, entries):
234                     fp.write('%s' % data[i * channels])
235                     if i != (entries - 1):
236                         fp.write(',')
237                     fp.write('\n')
238                 fp.write('};\n')
239                 fp.write('\n')
240
241         fp.write('void main\n')
242         fp.write('(\n')
243         fp.write('  input varying float rIn,\n')
244         fp.write('  input varying float gIn,\n')
245         fp.write('  input varying float bIn,\n')
246         fp.write('  input varying float aIn,\n')
247         fp.write('  output varying float rOut,\n')
248         fp.write('  output varying float gOut,\n')
249         fp.write('  output varying float bOut,\n')
250         fp.write('  output varying float aOut\n')
251         fp.write(')\n')
252         fp.write('{\n')
253         fp.write('  float r = rIn;\n')
254         fp.write('  float g = gIn;\n')
255         fp.write('  float b = bIn;\n')
256         fp.write('\n')
257         fp.write('  // Apply LUT\n')
258         if components == 1:
259             fp.write('  r = lookup1D(lut, min1d, max1d, r);\n')
260             fp.write('  g = lookup1D(lut, min1d, max1d, g);\n')
261             fp.write('  b = lookup1D(lut, min1d, max1d, b);\n')
262         elif components == 3:
263             fp.write('  r = lookup1D(lut0, min1d, max1d, r);\n')
264             fp.write('  g = lookup1D(lut1, min1d, max1d, g);\n')
265             fp.write('  b = lookup1D(lut2, min1d, max1d, b);\n')
266         fp.write('\n')
267         fp.write('  rOut = r;\n')
268         fp.write('  gOut = g;\n')
269         fp.write('  bOut = b;\n')
270         fp.write('  aOut = aIn;\n')
271         fp.write('}\n')
272
273
274 def write_1d(filename,
275              from_min,
276              from_max,
277              data,
278              data_entries,
279              data_channels,
280              lut_components=3,
281              format='spi1d'):
282     """
283     Object description.
284
285     Parameters
286     ----------
287     parameter : type
288         Parameter description.
289
290     Returns
291     -------
292     type
293          Return value description.
294     """
295
296     ocio_formats_to_extensions = {'cinespace': 'csp',
297                                   'flame': '3dl',
298                                   'icc': 'icc',
299                                   'houdini': 'lut',
300                                   'lustre': '3dl',
301                                   'ctl': 'ctl'}
302
303     if format in ocio_formats_to_extensions:
304         if ocio_formats_to_extensions[format] == 'csp':
305             write_CSP_1d(filename,
306                          from_min,
307                          from_max,
308                          data,
309                          data_entries,
310                          data_channels,
311                          lut_components)
312         elif ocio_formats_to_extensions[format] == 'ctl':
313             write_CTL_1d(filename,
314                          from_min,
315                          from_max,
316                          data,
317                          data_entries,
318                          data_channels,
319                          lut_components)
320     else:
321         write_SPI_1d(filename,
322                      from_min,
323                      from_max,
324                      data,
325                      data_entries,
326                      data_channels,
327                      lut_components)
328
329
330 def generate_1d_LUT_from_image(ramp_1d_path,
331                                output_path=None,
332                                min_value=0,
333                                max_value=1,
334                                channels=3,
335                                format='spi1d'):
336     """
337     Object description.
338
339     Parameters
340     ----------
341     parameter : type
342         Parameter description.
343
344     Returns
345     -------
346     type
347          Return value description.
348     """
349
350     if output_path is None:
351         output_path = '%s.%s' % (ramp_1d_path, 'spi1d')
352
353     ramp = oiio.ImageInput.open(ramp_1d_path)
354
355     ramp_spec = ramp.spec()
356     ramp_width = ramp_spec.width
357     ramp_channels = ramp_spec.nchannels
358
359     # Forcibly read data as float, the Python API doesn't handle half-float
360     # well yet.
361     type = oiio.FLOAT
362     ramp_data = ramp.read_image(type)
363
364     write_1d(output_path, min_value, max_value,
365              ramp_data, ramp_width, ramp_channels, channels, format)
366
367
368 def generate_3d_LUT_image(ramp_3d_path, resolution=32):
369     """
370     Object description.
371
372     Parameters
373     ----------
374     parameter : type
375         Parameter description.
376
377     Returns
378     -------
379     type
380          Return value description.
381     """
382
383     args = ['--generate',
384             '--cubesize',
385             str(resolution),
386             '--maxwidth',
387             str(resolution * resolution),
388             '--output',
389             ramp_3d_path]
390     lut_extract = Process(description='generate a 3d LUT image',
391                           cmd='ociolutimage',
392                           args=args)
393     lut_extract.execute()
394
395
396 def generate_3d_LUT_from_image(ramp_3d_path,
397                                output_path=None,
398                                resolution=32,
399                                format='spi3d'):
400     """
401     Object description.
402
403     Parameters
404     ----------
405     parameter : type
406         Parameter description.
407
408     Returns
409     -------
410     type
411          Return value description.
412     """
413
414     if output_path is None:
415         output_path = '%s.%s' % (ramp_3d_path, 'spi3d')
416
417     ocio_formats_to_extensions = {'cinespace': 'csp',
418                                   'flame': '3dl',
419                                   'icc': 'icc',
420                                   'houdini': 'lut',
421                                   'lustre': '3dl'}
422
423     if format == 'spi3d' or not (format in ocio_formats_to_extensions):
424         # Extract a spi3d LUT
425         args = ['--extract',
426                 '--cubesize',
427                 str(resolution),
428                 '--maxwidth',
429                 str(resolution * resolution),
430                 '--input',
431                 ramp_3d_path,
432                 '--output',
433                 output_path]
434         lut_extract = Process(description='extract a 3d LUT',
435                               cmd='ociolutimage',
436                               args=args)
437         lut_extract.execute()
438
439     else:
440         output_path_spi3d = '%s.%s' % (output_path, 'spi3d')
441
442         # Extract a spi3d LUT
443         args = ['--extract',
444                 '--cubesize',
445                 str(resolution),
446                 '--maxwidth',
447                 str(resolution * resolution),
448                 '--input',
449                 ramp_3d_path,
450                 '--output',
451                 output_path_spi3d]
452         lut_extract = Process(description='extract a 3d LUT',
453                               cmd='ociolutimage',
454                               args=args)
455         lut_extract.execute()
456
457         # Convert to a different format
458         args = ['--lut',
459                 output_path_spi3d,
460                 '--format',
461                 format,
462                 output_path]
463         lut_convert = Process(description='convert a 3d LUT',
464                               cmd='ociobakelut',
465                               args=args)
466         lut_convert.execute()
467
468
469 def apply_CTL_to_image(input_image,
470                        output_image,
471                        ctl_paths=None,
472                        input_scale=1,
473                        output_scale=1,
474                        global_params=None,
475                        aces_ctl_directory=None):
476     """
477     Object description.
478
479     Parameters
480     ----------
481     parameter : type
482         Parameter description.
483
484     Returns
485     -------
486     type
487          Return value description.
488     """
489
490     if ctl_paths is None:
491         ctl_paths = []
492     if global_params is None:
493         global_params = {}
494
495     if len(ctl_paths) > 0:
496         ctlenv = os.environ
497
498         if "/usr/local/bin" not in ctlenv['PATH'].split(':'):
499             ctlenv['PATH'] = "%s:/usr/local/bin" % ctlenv['PATH']
500
501         if aces_ctl_directory is not None:
502             if os.path.split(aces_ctl_directory)[1] != 'utilities':
503                 ctl_module_path = os.path.join(aces_ctl_directory, 'utilities')
504             else:
505                 ctl_module_path = aces_ctl_directory
506             ctlenv['CTL_MODULE_PATH'] = ctl_module_path
507
508         args = []
509         for ctl in ctl_paths:
510             args += ['-ctl', ctl]
511         args += ['-force']
512         args += ['-input_scale', str(input_scale)]
513         args += ['-output_scale', str(output_scale)]
514         args += ['-global_param1', 'aIn', '1.0']
515         for key, value in global_params.iteritems():
516             args += ['-global_param1', key, str(value)]
517         args += [input_image]
518         args += [output_image]
519
520         ctlp = Process(description='a ctlrender process',
521                        cmd='ctlrender',
522                        args=args, env=ctlenv)
523
524         ctlp.execute()
525
526
527 def convert_bit_depth(input_image, output_image, depth):
528     """
529     Object description.
530
531     Parameters
532     ----------
533     parameter : type
534         Parameter description.
535
536     Returns
537     -------
538     type
539          Return value description.
540     """
541
542     args = [input_image,
543             '-d',
544             depth,
545             '-o',
546             output_image]
547     convert = Process(description='convert image bit depth',
548                       cmd='oiiotool',
549                       args=args)
550     convert.execute()
551
552
553 def generate_1d_LUT_from_CTL(lut_path,
554                              ctl_paths,
555                              lut_resolution=1024,
556                              identity_lut_bit_depth='half',
557                              input_scale=1,
558                              output_scale=1,
559                              global_params=None,
560                              cleanup=True,
561                              aces_ctl_directory=None,
562                              min_value=0,
563                              max_value=1,
564                              channels=3,
565                              format='spi1d'):
566     """
567     Object description.
568
569     Parameters
570     ----------
571     parameter : type
572         Parameter description.
573
574     Returns
575     -------
576     type
577          Return value description.
578     """
579
580     if global_params is None:
581         global_params = {}
582
583     lut_path_base = os.path.splitext(lut_path)[0]
584
585     identity_lut_image_float = '%s.%s.%s' % (lut_path_base, 'float', 'tiff')
586     generate_1d_LUT_image(identity_lut_image_float,
587                           lut_resolution,
588                           min_value,
589                           max_value)
590
591     if identity_lut_bit_depth not in ['half', 'float']:
592         identity_lut_image = '%s.%s.%s' % (lut_path_base, 'uint16', 'tiff')
593         convert_bit_depth(identity_lut_image_float,
594                           identity_lut_image,
595                           identity_lut_bit_depth)
596     else:
597         identity_lut_image = identity_lut_image_float
598
599     transformed_lut_image = '%s.%s.%s' % (lut_path_base, 'transformed', 'exr')
600     apply_CTL_to_image(identity_lut_image,
601                        transformed_lut_image,
602                        ctl_paths,
603                        input_scale,
604                        output_scale,
605                        global_params,
606                        aces_ctl_directory)
607
608     generate_1d_LUT_from_image(transformed_lut_image,
609                                lut_path,
610                                min_value,
611                                max_value,
612                                channels,
613                                format)
614
615     if cleanup:
616         os.remove(identity_lut_image)
617         if identity_lut_image != identity_lut_image_float:
618             os.remove(identity_lut_image_float)
619         os.remove(transformed_lut_image)
620
621
622 def correct_LUT_image(transformed_lut_image,
623                       corrected_lut_image,
624                       lut_resolution):
625     """
626     Object description.
627
628     Parameters
629     ----------
630     parameter : type
631         Parameter description.
632
633     Returns
634     -------
635     type
636          Return value description.
637     """
638
639     transformed = oiio.ImageInput.open(transformed_lut_image)
640
641     transformed_spec = transformed.spec()
642     width = transformed_spec.width
643     height = transformed_spec.height
644     channels = transformed_spec.nchannels
645
646     if width != lut_resolution * lut_resolution or height != lut_resolution:
647         print(('Correcting image as resolution is off. '
648                'Found %d x %d. Expected %d x %d') % (
649                   width,
650                   height,
651                   lut_resolution * lut_resolution,
652                   lut_resolution))
653         print('Generating %s' % corrected_lut_image)
654
655         # Forcibly read data as float, the Python API doesn't handle half-float
656         # well yet.
657         type = oiio.FLOAT
658         source_data = transformed.read_image(type)
659
660         correct = oiio.ImageOutput.create(corrected_lut_image)
661
662         correct_spec = oiio.ImageSpec()
663         correct_spec.set_format(oiio.FLOAT)
664         correct_spec.width = height
665         correct_spec.height = width
666         correct_spec.nchannels = channels
667
668         correct.open(corrected_lut_image, correct_spec, oiio.Create)
669
670         dest_data = array.array('f',
671                                 ('\0' * correct_spec.width *
672                                  correct_spec.height *
673                                  correct_spec.nchannels * 4))
674         for j in range(0, correct_spec.height):
675             for i in range(0, correct_spec.width):
676                 for c in range(0, correct_spec.nchannels):
677                     dest_data[(correct_spec.nchannels *
678                                correct_spec.width * j +
679                                correct_spec.nchannels * i + c)] = (
680                         source_data[correct_spec.nchannels *
681                                     correct_spec.width * j +
682                                     correct_spec.nchannels * i + c])
683
684         correct.write_image(correct_spec.format, dest_data)
685         correct.close()
686     else:
687         # shutil.copy(transformedLUTImage, correctedLUTImage)
688         corrected_lut_image = transformed_lut_image
689
690     transformed.close()
691
692     return corrected_lut_image
693
694
695 def generate_3d_LUT_from_CTL(lut_path,
696                              ctl_paths,
697                              lut_resolution=64,
698                              identity_lut_bit_depth='half',
699                              input_scale=1,
700                              output_scale=1,
701                              global_params=None,
702                              cleanup=True,
703                              aces_ctl_directory=None,
704                              format='spi3d'):
705     """
706     Object description.
707
708     Parameters
709     ----------
710     parameter : type
711         Parameter description.
712
713     Returns
714     -------
715     type
716          Return value description.
717     """
718
719     if global_params is None:
720         global_params = {}
721
722     lut_path_base = os.path.splitext(lut_path)[0]
723
724     identity_lut_image_float = '%s.%s.%s' % (lut_path_base, 'float', 'tiff')
725     generate_3d_LUT_image(identity_lut_image_float, lut_resolution)
726
727     if identity_lut_bit_depth not in ['half', 'float']:
728         identity_lut_image = '%s.%s.%s' % (lut_path_base,
729                                            identity_lut_bit_depth,
730                                            'tiff')
731         convert_bit_depth(identity_lut_image_float,
732                           identity_lut_image,
733                           identity_lut_bit_depth)
734     else:
735         identity_lut_image = identity_lut_image_float
736
737     transformed_lut_image = '%s.%s.%s' % (lut_path_base, 'transformed', 'exr')
738     apply_CTL_to_image(identity_lut_image,
739                        transformed_lut_image,
740                        ctl_paths,
741                        input_scale,
742                        output_scale,
743                        global_params,
744                        aces_ctl_directory)
745
746     corrected_lut_image = '%s.%s.%s' % (lut_path_base, 'correct', 'exr')
747     corrected_lut_image = correct_LUT_image(transformed_lut_image,
748                                             corrected_lut_image,
749                                             lut_resolution)
750
751     generate_3d_LUT_from_image(corrected_lut_image,
752                                lut_path,
753                                lut_resolution,
754                                format)
755
756     if cleanup:
757         os.remove(identity_lut_image)
758         if identity_lut_image != identity_lut_image_float:
759             os.remove(identity_lut_image_float)
760         os.remove(transformed_lut_image)
761         if corrected_lut_image != transformed_lut_image:
762             os.remove(corrected_lut_image)
763         if format != 'spi3d':
764             lut_path_spi3d = '%s.%s' % (lut_path, 'spi3d')
765             os.remove(lut_path_spi3d)
766
767
768 def main():
769     """
770     Object description.
771
772     Parameters
773     ----------
774     parameter : type
775         Parameter description.
776
777     Returns
778     -------
779     type
780          Return value description.
781     """
782
783     import optparse
784
785     p = optparse.OptionParser(
786         description='A utility to generate LUTs from CTL',
787         prog='generateLUT',
788         version='0.01',
789         usage='%prog [options]')
790
791     p.add_option('--lut', '-l', type='string', default='')
792     p.add_option('--format', '-f', type='string', default='')
793     p.add_option('--ctl', '-c', type='string', action='append')
794     p.add_option('--lutResolution1d', '', type='int', default=1024)
795     p.add_option('--lutResolution3d', '', type='int', default=33)
796     p.add_option('--ctlReleasePath', '-r', type='string', default='')
797     p.add_option('--bitDepth', '-b', type='string', default='float')
798     p.add_option('--keepTempImages', '', action='store_true')
799     p.add_option('--minValue', '', type='float', default=0)
800     p.add_option('--maxValue', '', type='float', default=1)
801     p.add_option('--inputScale', '', type='float', default=1)
802     p.add_option('--outputScale', '', type='float', default=1)
803     p.add_option('--ctlRenderParam', '-p', type='string', nargs=2,
804                  action='append')
805
806     p.add_option('--generate1d', '', action='store_true')
807     p.add_option('--generate3d', '', action='store_true')
808
809     options, arguments = p.parse_args()
810
811     lut = options.lut
812     format = options.format
813     ctls = options.ctl
814     lut_resolution_1d = options.lutResolution1d
815     lut_resolution_3d = options.lutResolution3d
816     min_value = options.minValue
817     max_value = options.maxValue
818     input_scale = options.inputScale
819     output_scale = options.outputScale
820     ctl_release_path = options.ctlReleasePath
821     generate_1d = options.generate1d is True
822     generate_3d = options.generate3d is True
823     bit_depth = options.bitDepth
824     cleanup = not options.keepTempImages
825
826     params = {}
827     if options.ctlRenderParam is not None:
828         for param in options.ctlRenderParam:
829             params[param[0]] = float(param[1])
830
831     if generate_1d:
832         print('1D LUT generation options')
833     else:
834         print('3D LUT generation options')
835
836     print('LUT                 : %s' % lut)
837     print('Format              : %s' % format)
838     print('CTLs                : %s' % ctls)
839     print('LUT Res 1d          : %s' % lut_resolution_1d)
840     print('LUT Res 3d          : %s' % lut_resolution_3d)
841     print('Min Value           : %s' % min_value)
842     print('Max Value           : %s' % max_value)
843     print('Input Scale         : %s' % input_scale)
844     print('Output Scale        : %s' % output_scale)
845     print('CTL Render Params   : %s' % params)
846     print('CTL Release Path    : %s' % ctl_release_path)
847     print('Input Bit Depth     : %s' % bit_depth)
848     print('Cleanup Temp Images : %s' % cleanup)
849
850     if generate_1d:
851         generate_1d_LUT_from_CTL(lut,
852                                  ctls,
853                                  lut_resolution_1d,
854                                  bit_depth,
855                                  input_scale,
856                                  output_scale,
857                                  params,
858                                  cleanup,
859                                  ctl_release_path,
860                                  min_value,
861                                  max_value,
862                                  format=format)
863
864     elif generate_3d:
865         generate_3d_LUT_from_CTL(lut,
866                                  ctls,
867                                  lut_resolution_3d,
868                                  bit_depth,
869                                  input_scale,
870                                  output_scale,
871                                  params,
872                                  cleanup,
873                                  ctl_release_path,
874                                  format=format)
875     else:
876         print(('\n\nNo LUT generated! '
877                'You must choose either 1D or 3D LUT generation\n\n'))
878
879
880 if __name__ == '__main__':
881     main()