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