962881e87023565f554a6380de59be8ebd8c99c2
[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         if aces_ctl_directory is not None:
498             if os.path.split(aces_ctl_directory)[1] != 'utilities':
499                 ctl_module_path = os.path.join(aces_ctl_directory, 'utilities')
500             else:
501                 ctl_module_path = aces_ctl_directory
502             ctlenv['CTL_MODULE_PATH'] = ctl_module_path
503
504         args = []
505         for ctl in ctl_paths:
506             args += ['-ctl', ctl]
507         args += ['-force']
508         args += ['-input_scale', str(input_scale)]
509         args += ['-output_scale', str(output_scale)]
510         args += ['-global_param1', 'aIn', '1.0']
511         for key, value in global_params.iteritems():
512             args += ['-global_param1', key, str(value)]
513         args += [input_image]
514         args += [output_image]
515
516         ctlp = Process(description='a ctlrender process',
517                        cmd='ctlrender',
518                        args=args, env=ctlenv)
519
520         ctlp.execute()
521
522
523 def convert_bit_depth(input_image, output_image, depth):
524     """
525     Object description.
526
527     Parameters
528     ----------
529     parameter : type
530         Parameter description.
531
532     Returns
533     -------
534     type
535          Return value description.
536     """
537
538     args = [input_image,
539             '-d',
540             depth,
541             '-o',
542             output_image]
543     convert = Process(description='convert image bit depth',
544                       cmd='oiiotool',
545                       args=args)
546     convert.execute()
547
548
549 def generate_1d_LUT_from_CTL(lut_path,
550                              ctl_paths,
551                              lut_resolution=1024,
552                              identity_lut_bit_depth='half',
553                              input_scale=1,
554                              output_scale=1,
555                              global_params=None,
556                              cleanup=True,
557                              aces_ctl_directory=None,
558                              min_value=0,
559                              max_value=1,
560                              channels=3,
561                              format='spi1d'):
562     """
563     Object description.
564
565     Parameters
566     ----------
567     parameter : type
568         Parameter description.
569
570     Returns
571     -------
572     type
573          Return value description.
574     """
575
576     if global_params is None:
577         global_params = {}
578
579     lut_path_base = os.path.splitext(lut_path)[0]
580
581     identity_lut_image_float = '%s.%s.%s' % (lut_path_base, 'float', 'tiff')
582     generate_1d_LUT_image(identity_lut_image_float,
583                           lut_resolution,
584                           min_value,
585                           max_value)
586
587     if identity_lut_bit_depth not in ['half', 'float']:
588         identity_lut_image = '%s.%s.%s' % (lut_path_base, 'uint16', 'tiff')
589         convert_bit_depth(identity_lut_image_float,
590                           identity_lut_image,
591                           identity_lut_bit_depth)
592     else:
593         identity_lut_image = identity_lut_image_float
594
595     transformed_lut_image = '%s.%s.%s' % (lut_path_base, 'transformed', 'exr')
596     apply_CTL_to_image(identity_lut_image,
597                        transformed_lut_image,
598                        ctl_paths,
599                        input_scale,
600                        output_scale,
601                        global_params,
602                        aces_ctl_directory)
603
604     generate_1d_LUT_from_image(transformed_lut_image,
605                                lut_path,
606                                min_value,
607                                max_value,
608                                channels,
609                                format)
610
611     if cleanup:
612         os.remove(identity_lut_image)
613         if identity_lut_image != identity_lut_image_float:
614             os.remove(identity_lut_image_float)
615         os.remove(transformed_lut_image)
616
617
618 def correct_LUT_image(transformed_lut_image,
619                       corrected_lut_image,
620                       lut_resolution):
621     """
622     Object description.
623
624     Parameters
625     ----------
626     parameter : type
627         Parameter description.
628
629     Returns
630     -------
631     type
632          Return value description.
633     """
634
635     transformed = oiio.ImageInput.open(transformed_lut_image)
636
637     transformed_spec = transformed.spec()
638     width = transformed_spec.width
639     height = transformed_spec.height
640     channels = transformed_spec.nchannels
641
642     if width != lut_resolution * lut_resolution or height != lut_resolution:
643         print(('Correcting image as resolution is off. '
644                'Found %d x %d. Expected %d x %d') % (
645                   width,
646                   height,
647                   lut_resolution * lut_resolution,
648                   lut_resolution))
649         print('Generating %s' % corrected_lut_image)
650
651         # Forcibly read data as float, the Python API doesn't handle half-float
652         # well yet.
653         type = oiio.FLOAT
654         source_data = transformed.read_image(type)
655
656         correct = oiio.ImageOutput.create(corrected_lut_image)
657
658         correct_spec = oiio.ImageSpec()
659         correct_spec.set_format(oiio.FLOAT)
660         correct_spec.width = height
661         correct_spec.height = width
662         correct_spec.nchannels = channels
663
664         correct.open(corrected_lut_image, correct_spec, oiio.Create)
665
666         dest_data = array.array('f',
667                                 ('\0' * correct_spec.width *
668                                  correct_spec.height *
669                                  correct_spec.nchannels * 4))
670         for j in range(0, correct_spec.height):
671             for i in range(0, correct_spec.width):
672                 for c in range(0, correct_spec.nchannels):
673                     dest_data[(correct_spec.nchannels *
674                                correct_spec.width * j +
675                                correct_spec.nchannels * i + c)] = (
676                         source_data[correct_spec.nchannels *
677                                     correct_spec.width * j +
678                                     correct_spec.nchannels * i + c])
679
680         correct.write_image(correct_spec.format, dest_data)
681         correct.close()
682     else:
683         # shutil.copy(transformedLUTImage, correctedLUTImage)
684         corrected_lut_image = transformed_lut_image
685
686     transformed.close()
687
688     return corrected_lut_image
689
690
691 def generate_3d_LUT_from_CTL(lut_path,
692                              ctl_paths,
693                              lut_resolution=64,
694                              identity_lut_bit_depth='half',
695                              input_scale=1,
696                              output_scale=1,
697                              global_params=None,
698                              cleanup=True,
699                              aces_ctl_directory=None,
700                              format='spi3d'):
701     """
702     Object description.
703
704     Parameters
705     ----------
706     parameter : type
707         Parameter description.
708
709     Returns
710     -------
711     type
712          Return value description.
713     """
714
715     if global_params is None:
716         global_params = {}
717
718     lut_path_base = os.path.splitext(lut_path)[0]
719
720     identity_lut_image_float = '%s.%s.%s' % (lut_path_base, 'float', 'tiff')
721     generate_3d_LUT_image(identity_lut_image_float, lut_resolution)
722
723     if identity_lut_bit_depth not in ['half', 'float']:
724         identity_lut_image = '%s.%s.%s' % (lut_path_base,
725                                            identity_lut_bit_depth,
726                                            'tiff')
727         convert_bit_depth(identity_lut_image_float,
728                           identity_lut_image,
729                           identity_lut_bit_depth)
730     else:
731         identity_lut_image = identity_lut_image_float
732
733     transformed_lut_image = '%s.%s.%s' % (lut_path_base, 'transformed', 'exr')
734     apply_CTL_to_image(identity_lut_image,
735                        transformed_lut_image,
736                        ctl_paths,
737                        input_scale,
738                        output_scale,
739                        global_params,
740                        aces_ctl_directory)
741
742     corrected_lut_image = '%s.%s.%s' % (lut_path_base, 'correct', 'exr')
743     corrected_lut_image = correct_LUT_image(transformed_lut_image,
744                                             corrected_lut_image,
745                                             lut_resolution)
746
747     generate_3d_LUT_from_image(corrected_lut_image,
748                                lut_path,
749                                lut_resolution,
750                                format)
751
752     if cleanup:
753         os.remove(identity_lut_image)
754         if identity_lut_image != identity_lut_image_float:
755             os.remove(identity_lut_image_float)
756         os.remove(transformed_lut_image)
757         if corrected_lut_image != transformed_lut_image:
758             os.remove(corrected_lut_image)
759         if format != 'spi3d':
760             lut_path_spi3d = '%s.%s' % (lut_path, 'spi3d')
761             os.remove(lut_path_spi3d)
762
763
764 def main():
765     """
766     Object description.
767
768     Parameters
769     ----------
770     parameter : type
771         Parameter description.
772
773     Returns
774     -------
775     type
776          Return value description.
777     """
778
779     import optparse
780
781     p = optparse.OptionParser(
782         description='A utility to generate LUTs from CTL',
783         prog='generateLUT',
784         version='0.01',
785         usage='%prog [options]')
786
787     p.add_option('--lut', '-l', type='string', default='')
788     p.add_option('--format', '-f', type='string', default='')
789     p.add_option('--ctl', '-c', type='string', action='append')
790     p.add_option('--lutResolution1d', '', type='int', default=1024)
791     p.add_option('--lutResolution3d', '', type='int', default=33)
792     p.add_option('--ctlReleasePath', '-r', type='string', default='')
793     p.add_option('--bitDepth', '-b', type='string', default='float')
794     p.add_option('--keepTempImages', '', action='store_true')
795     p.add_option('--minValue', '', type='float', default=0)
796     p.add_option('--maxValue', '', type='float', default=1)
797     p.add_option('--inputScale', '', type='float', default=1)
798     p.add_option('--outputScale', '', type='float', default=1)
799     p.add_option('--ctlRenderParam', '-p', type='string', nargs=2,
800                  action='append')
801
802     p.add_option('--generate1d', '', action='store_true')
803     p.add_option('--generate3d', '', action='store_true')
804
805     options, arguments = p.parse_args()
806
807     lut = options.lut
808     format = options.format
809     ctls = options.ctl
810     lut_resolution_1d = options.lutResolution1d
811     lut_resolution_3d = options.lutResolution3d
812     min_value = options.minValue
813     max_value = options.maxValue
814     input_scale = options.inputScale
815     output_scale = options.outputScale
816     ctl_release_path = options.ctlReleasePath
817     generate_1d = options.generate1d is True
818     generate_3d = options.generate3d is True
819     bit_depth = options.bitDepth
820     cleanup = not options.keepTempImages
821
822     params = {}
823     if options.ctlRenderParam is not None:
824         for param in options.ctlRenderParam:
825             params[param[0]] = float(param[1])
826
827     if generate_1d:
828         print('1D LUT generation options')
829     else:
830         print('3D LUT generation options')
831
832     print('LUT                 : %s' % lut)
833     print('Format              : %s' % format)
834     print('CTLs                : %s' % ctls)
835     print('LUT Res 1d          : %s' % lut_resolution_1d)
836     print('LUT Res 3d          : %s' % lut_resolution_3d)
837     print('Min Value           : %s' % min_value)
838     print('Max Value           : %s' % max_value)
839     print('Input Scale         : %s' % input_scale)
840     print('Output Scale        : %s' % output_scale)
841     print('CTL Render Params   : %s' % params)
842     print('CTL Release Path    : %s' % ctl_release_path)
843     print('Input Bit Depth     : %s' % bit_depth)
844     print('Cleanup Temp Images : %s' % cleanup)
845
846     if generate_1d:
847         generate_1d_LUT_from_CTL(lut,
848                                  ctls,
849                                  lut_resolution_1d,
850                                  bit_depth,
851                                  input_scale,
852                                  output_scale,
853                                  params,
854                                  cleanup,
855                                  ctl_release_path,
856                                  min_value,
857                                  max_value,
858                                  format=format)
859
860     elif generate_3d:
861         generate_3d_LUT_from_CTL(lut,
862                                  ctls,
863                                  lut_resolution_3d,
864                                  bit_depth,
865                                  input_scale,
866                                  output_scale,
867                                  params,
868                                  cleanup,
869                                  ctl_release_path,
870                                  format=format)
871     else:
872         print(('\n\nNo LUT generated! '
873                'You must choose either 1D or 3D LUT generation\n\n'))
874
875
876 if __name__ == '__main__':
877     main()