def read_LUT_UnorderedSonySPI3D(path): title = path_to_title(path) domain_min, domain_max = np.array([0, 0, 0]), np.array([1, 1, 1]) size = 2 indexes = [] table = [] comments = [] with open(path) as spi3d_file: lines = filter(None, (line.strip() for line in spi3d_file.readlines())) for line in lines: if line.startswith('#'): comments.append(line[1:].strip()) continue tokens = line.split() if len(tokens) == 3: assert len(set(tokens)) == 1, ( 'Non-uniform "LUT" shape is unsupported!') size = DEFAULT_INT_DTYPE(tokens[0]) if len(tokens) == 6: indexes.append(as_int_array(tokens[:3])) table.append(as_float_array(tokens[3:])) indexes = as_int_array(indexes) sorting_indexes = np.lexsort((indexes[:, 2], indexes[:, 1], indexes[:, 0])) #print(sorting_indexes) assert np.array_equal( indexes[sorting_indexes], DEFAULT_INT_DTYPE(np.around( LUT3D.linear_table(size) * (size - 1))).reshape( (-1, 3))), 'Indexes do not match expected "LUT3D" indexes!' table = as_float_array(table)[sorting_indexes].reshape( [size, size, size, 3]) return LUT3D(table, title, np.vstack([domain_min, domain_max]), comments=comments)
def test_path_to_title(self): """Test :func:`colour.io.luts.common.path_to_title` definition.""" self.assertEqual( path_to_title( "colour/io/luts/tests/resources/cinespace/RGB_1_0.5_0.25.csp"), "RGB 1 0 5 0 25", )
def test_path_to_title(self): """ Tests :func:`colour.io.luts.common.path_to_title` definition. """ self.assertEqual( path_to_title( 'colour/io/luts/tests/resources/cinespace/RGB_1_0.5_0.25.csp'), 'RGB 1 0 5 0 25')
def read_unordered_LUT_SonySPI3D(path): """ Reads given unordered *.spi3d* *LUT* file. Parameters ---------- path : unicode *LUT* path. Returns ------- LUT3D or LUT3x1D :class:`LUT3D` or :class:`LUT3x1D` class instance. """ title = path_to_title(path) domain_min, domain_max = np.array([0, 0, 0]), np.array([1, 1, 1]) indexes = [] comments = [] table_unordered = [] table_ordered = [] with open(path) as spi3d_file: lines = filter(None, (line.strip() for line in spi3d_file.readlines())) for line in lines: if line.startswith('#'): comments.append(line[1:].strip()) continue tokens = line.split() if len(tokens) == 3: size = DEFAULT_INT_DTYPE(tokens[0]) if len(tokens) == 6: indexes.append(as_int_array(tokens[:3])) table_unordered.append(as_float_array(tokens[3:])) test_indexes = np.around(LUT3D.linear_table(size) * (size - 1)).reshape( (-1, 3)) for i in range(64): for j in range(64): if (np.array_equal(test_indexes[i], indexes[j])): table_ordered.append(table_unordered[j]) table_ordered = as_float_array(table_ordered).reshape( [size, size, size, 3]) return LUT3D(table_ordered, title, np.vstack([domain_min, domain_max]), comments=comments)
def read_LUT_SonySPImtx(path: str) -> LUTOperatorMatrix: """ Read given *Sony* *.spimtx* *LUT* file. Parameters ---------- path *LUT* path. Returns ------- :class:`colour.LUTOperatorMatrix` :class:`colour.io.Matrix` class instance. Examples -------- >>> import os >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'sony_spimtx', ... 'dt.spimtx') >>> print(read_LUT_SonySPImtx(path)) LUTOperatorMatrix - dt ---------------------- <BLANKLINE> Matrix : [[ 0.864274 0. 0. 0. ] [ 0. 0.864274 0. 0. ] [ 0. 0. 0.864274 0. ] [ 0. 0. 0. 1. ]] Offset : [ 0. 0. 0. 0.] """ matrix = np.loadtxt(path, dtype=DEFAULT_FLOAT_DTYPE) matrix = np.reshape(matrix, (3, 4)) offset = matrix[:, 3] / 65535 matrix = matrix[:3, :3] title = path_to_title(path) return LUTOperatorMatrix(matrix, offset, name=title)
def read_LUT_IridasCube(path): """ Reads given *Iridas* *.cube* *LUT* file. Parameters ---------- path : unicode *LUT* path. Returns ------- LUT3x1D or LUT3d :class:`LUT3x1D` or :class:`LUT3D` class instance. References ---------- :cite:`AdobeSystems2013b` Examples -------- Reading a 3x1D *Iridas* *.cube* *LUT*: >>> import os >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'iridas_cube', ... 'ACES_Proxy_10_to_ACES.cube') >>> print(read_LUT_IridasCube(path)) LUT3x1D - ACES Proxy 10 to ACES ------------------------------- <BLANKLINE> Dimensions : 2 Domain : [[ 0. 0. 0.] [ 1. 1. 1.]] Size : (32, 3) Reading a 3D *Iridas* *.cube* *LUT*: >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'iridas_cube', ... 'ColourCorrect.cube') >>> print(read_LUT_IridasCube(path)) LUT3D - Generated by Foundry::LUT --------------------------------- <BLANKLINE> Dimensions : 3 Domain : [[ 0. 0. 0.] [ 1. 1. 1.]] Size : (4, 4, 4, 3) Reading a 3D *Iridas* *.cube* *LUT* with comments: >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'iridas_cube', ... 'Demo.cube') >>> print(read_LUT_IridasCube(path)) LUT3x1D - Demo -------------- <BLANKLINE> Dimensions : 2 Domain : [[ 0. 0. 0.] [ 1. 2. 3.]] Size : (3, 3) Comment 01 : Comments can go anywhere """ title = path_to_title(path) domain_min, domain_max = np.array([0, 0, 0]), np.array([1, 1, 1]) dimensions = 3 size = 2 table = [] comments = [] with open(path) as cube_file: lines = cube_file.readlines() for line in lines: line = line.strip() if len(line) == 0: continue if line.startswith('#'): comments.append(line[1:].strip()) continue tokens = line.split() if tokens[0] == 'TITLE': title = ' '.join(tokens[1:])[1:-1] elif tokens[0] == 'DOMAIN_MIN': domain_min = parse_array(tokens[1:]) elif tokens[0] == 'DOMAIN_MAX': domain_max = parse_array(tokens[1:]) elif tokens[0] == 'LUT_1D_SIZE': dimensions = 2 size = DEFAULT_INT_DTYPE(tokens[1]) elif tokens[0] == 'LUT_3D_SIZE': dimensions = 3 size = DEFAULT_INT_DTYPE(tokens[1]) else: table.append(parse_array(tokens)) table = as_float_array(table) if dimensions == 2: return LUT3x1D(table, title, np.vstack([domain_min, domain_max]), comments=comments) elif dimensions == 3: # The lines of table data shall be in ascending index order, # with the first component index (Red) changing most rapidly, # and the last component index (Blue) changing least rapidly. table = table.reshape([size, size, size, 3], order='F') return LUT3D(table, title, np.vstack([domain_min, domain_max]), comments=comments)
def read_LUT_SonySPI3D(path): """ Reads given *Sony* *.spi3d* *LUT* file. Parameters ---------- path : unicode *LUT* path. Returns ------- LUT3D or LUT3x1D :class:`LUT3D` or :class:`LUT3x1D` class instance. Examples -------- Reading a 3D *Sony* *.spi3d* *LUT*: >>> import os >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'sony_spi3d', ... 'ColourCorrect.spi3d') >>> print(read_LUT_SonySPI3D(path)) LUT3D - ColourCorrect --------------------- <BLANKLINE> Dimensions : 3 Domain : [[ 0. 0. 0.] [ 1. 1. 1.]] Size : (4, 4, 4, 3) Comment 01 : Adapted from a LUT generated by Foundry::LUT. """ title = path_to_title(path) domain_min, domain_max = np.array([0, 0, 0]), np.array([1, 1, 1]) size = 2 indexes = [] table = [] comments = [] with open(path) as spi3d_file: lines = spi3d_file.readlines() for line in lines: line = line.strip() if len(line) == 0: continue if line.startswith('#'): comments.append(line[1:].strip()) continue tokens = line.split() if len(tokens) == 3: assert len(set(tokens)) == 1, ( 'Non-uniform "LUT" shape is unsupported!') size = DEFAULT_INT_DTYPE(tokens[0]) if len(tokens) == 6: indexes.append(parse_array(tokens[:3])) table.append(parse_array(tokens[3:])) assert np.array_equal( indexes, DEFAULT_INT_DTYPE(LUT3D.linear_table(size) * (size - 1)).reshape( (-1, 3))), 'Indexes do not match expected "LUT3D" indexes!' table = as_float_array(table).reshape([size, size, size, 3]) return LUT3D(table, title, np.vstack([domain_min, domain_max]), comments=comments)
def read_LUT_ResolveCube(path): """ Reads given *Resolve* *.cube* *LUT* file. Parameters ---------- path : unicode *LUT* path. Returns ------- LUT3x1D or LUT3D or LUTSequence :class:`LUT3x1D` or :class:`LUT3D` or :class:`LUTSequence` class instance. References ---------- :cite:`Chamberlain2015` Examples -------- Reading a 3x1D *Resolve* *.cube* *LUT*: >>> import os >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'resolve_cube', ... 'ACES_Proxy_10_to_ACES.cube') >>> print(read_LUT_ResolveCube(path)) LUT3x1D - ACES Proxy 10 to ACES ------------------------------- <BLANKLINE> Dimensions : 2 Domain : [[ 0. 0. 0.] [ 1. 1. 1.]] Size : (32, 3) Reading a 3D *Resolve* *.cube* *LUT*: >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'resolve_cube', ... 'Colour_Correct.cube') >>> print(read_LUT_ResolveCube(path)) LUT3D - Generated by Foundry::LUT --------------------------------- <BLANKLINE> Dimensions : 3 Domain : [[ 0. 0. 0.] [ 1. 1. 1.]] Size : (4, 4, 4, 3) Reading a 3D *Resolve* *.cube* *LUT* with comments: >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'resolve_cube', ... 'Demo.cube') >>> print(read_LUT_ResolveCube(path)) LUT3x1D - Demo -------------- <BLANKLINE> Dimensions : 2 Domain : [[ 0. 0. 0.] [ 3. 3. 3.]] Size : (3, 3) Comment 01 : Comments can't go anywhere Reading a 3x1D + 3D *Resolve* *.cube* *LUT*: >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'resolve_cube', ... 'Three_Dimensional_Table_With_Shaper.cube') >>> print(read_LUT_ResolveCube(path)) LUT Sequence ------------ <BLANKLINE> Overview <BLANKLINE> LUT3x1D ---> LUT3D <BLANKLINE> Operations <BLANKLINE> LUT3x1D - LUT3D with My Shaper - Shaper --------------------------------------- <BLANKLINE> Dimensions : 2 Domain : [[-0.1 -0.1 -0.1] [ 3. 3. 3. ]] Size : (10, 3) <BLANKLINE> LUT3D - LUT3D with My Shaper - Cube ----------------------------------- <BLANKLINE> Dimensions : 3 Domain : [[-0.1 -0.1 -0.1] [ 3. 3. 3. ]] Size : (3, 3, 3, 3) Comment 01 : A first "Shaper" comment. Comment 02 : A second "Shaper" comment. Comment 03 : A first "LUT3D" comment. Comment 04 : A second "LUT3D" comment. """ title = path_to_title(path) size_3x1D = size_3D = 2 table = [] comments = [] has_3x1D, has_3D = False, False with open(path) as cube_file: lines = cube_file.readlines() LUT = LUTSequence(LUT3x1D(), LUT3D()) for line in lines: line = line.strip() if len(line) == 0: continue if line.startswith('#'): comments.append(line[1:].strip()) continue tokens = line.split() if tokens[0] == 'TITLE': title = ' '.join(tokens[1:])[1:-1] elif tokens[0] == 'LUT_1D_INPUT_RANGE': domain = parse_array(tokens[1:]) LUT[0].domain = tstack([domain, domain, domain]) elif tokens[0] == 'LUT_3D_INPUT_RANGE': domain = parse_array(tokens[1:]) LUT[1].domain = tstack([domain, domain, domain]) elif tokens[0] == 'LUT_1D_SIZE': has_3x1D = True size_3x1D = np.int_(tokens[1]) elif tokens[0] == 'LUT_3D_SIZE': has_3D = True size_3D = np.int_(tokens[1]) else: table.append(parse_array(tokens)) table = as_float_array(table) if has_3x1D and has_3D: LUT[0].name = '{0} - Shaper'.format(title) LUT[1].name = '{0} - Cube'.format(title) LUT[1].comments = comments LUT[0].table = table[:size_3x1D] # The lines of table data shall be in ascending index order, # with the first component index (Red) changing most rapidly, # and the last component index (Blue) changing least rapidly. LUT[1].table = table[size_3x1D:].reshape( (size_3D, size_3D, size_3D, 3), order='F') return LUT elif has_3x1D: LUT[0].name = title LUT[0].comments = comments LUT[0].table = table return LUT[0] elif has_3D: LUT[1].name = title LUT[1].comments = comments # The lines of table data shall be in ascending index order, # with the first component index (Red) changing most rapidly, # and the last component index (Blue) changing least rapidly. table = table.reshape([size_3D, size_3D, size_3D, 3], order='F') LUT[1].table = table return LUT[1]
def read_LUT_ResolveCube(path): """ Reads given *Resolve* *.cube* *LUT* file. Parameters ---------- path : unicode *LUT* path. Returns ------- LUT3x1D or LUT3D or LUTSequence :class:`LUT3x1D` or :class:`LUT3D` or :class:`LUTSequence` class instance. References ---------- :cite:`Chamberlain2015` Examples -------- Reading a 3x1D *Resolve* *.cube* *LUT*: >>> import os >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'resolve_cube', ... 'ACES_Proxy_10_to_ACES.cube') >>> print(read_LUT_ResolveCube(path)) LUT3x1D - ACES Proxy 10 to ACES ------------------------------- <BLANKLINE> Dimensions : 2 Domain : [[ 0. 0. 0.] [ 1. 1. 1.]] Size : (32, 3) Reading a 3D *Resolve* *.cube* *LUT*: >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'resolve_cube', ... 'ColourCorrect.cube') >>> print(read_LUT_ResolveCube(path)) LUT3D - Generated by Foundry::LUT --------------------------------- <BLANKLINE> Dimensions : 3 Domain : [[ 0. 0. 0.] [ 1. 1. 1.]] Size : (4, 4, 4, 3) Reading a 3D *Resolve* *.cube* *LUT* with comments: >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'resolve_cube', ... 'Demo.cube') >>> print(read_LUT_ResolveCube(path)) LUT3x1D - Demo -------------- <BLANKLINE> Dimensions : 2 Domain : [[ 0. 0. 0.] [ 3. 3. 3.]] Size : (3, 3) Comment 01 : Comments can't go anywhere """ title = path_to_title(path) size_3x1D = size_3D = 2 table = [] comments = [] has_3x1D, has_3D = False, False with open(path) as cube_file: lines = cube_file.readlines() LUT = LUTSequence(LUT3x1D(), LUT3D()) for line in lines: line = line.strip() if len(line) == 0: continue if line.startswith('#'): comments.append(line[1:].strip()) continue tokens = line.split() if tokens[0] == 'TITLE': title = ' '.join(tokens[1:])[1:-1] elif tokens[0] == 'LUT_1D_INPUT_RANGE': domain = parse_array(tokens[1:]) LUT[0].domain = tstack([domain, domain, domain]) elif tokens[0] == 'LUT_3D_INPUT_RANGE': domain = parse_array(tokens[1:]) LUT[1].domain = tstack([domain, domain, domain]) elif tokens[0] == 'LUT_1D_SIZE': has_3x1D = True size_3x1D = np.int_(tokens[1]) elif tokens[0] == 'LUT_3D_SIZE': has_3D = True size_3D = np.int_(tokens[1]) else: table.append(parse_array(tokens)) table = as_float_array(table) if has_3x1D and has_3D: LUT[0].name = '{0} - Shaper'.format(title) LUT[1].name = '{0} - Cube'.format(title) LUT[1].comments = comments LUT[0].table = table[:size_3x1D] # The lines of table data shall be in ascending index order, # with the first component index (Red) changing most rapidly, # and the last component index (Blue) changing least rapidly. LUT[1].table = table[size_3x1D:].reshape( (size_3D, size_3D, size_3D, 3), order='F') return LUT elif has_3x1D: LUT[0].name = title LUT[0].comments = comments LUT[0].table = table return LUT[0] elif has_3D: LUT[1].name = title LUT[1].comments = comments # The lines of table data shall be in ascending index order, # with the first component index (Red) changing most rapidly, # and the last component index (Blue) changing least rapidly. table = table.reshape([size_3D, size_3D, size_3D, 3], order='F') LUT[1].table = table return LUT[1]
def read_LUT_SonySPI3D(path): """ Reads given *Sony* *.spi3d* *LUT* file. Parameters ---------- path : unicode *LUT* path. Returns ------- LUT3D or LUT3x1D :class:`LUT3D` or :class:`LUT3x1D` class instance. Examples -------- Reading a 3D *Sony* *.spi3d* *LUT*: >>> import os >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'sony_spi3d', ... 'ColourCorrect.spi3d') >>> print(read_LUT_SonySPI3D(path)) LUT3D - ColourCorrect --------------------- <BLANKLINE> Dimensions : 3 Domain : [[ 0. 0. 0.] [ 1. 1. 1.]] Size : (4, 4, 4, 3) Comment 01 : Adapted from a LUT generated by Foundry::LUT. """ title = path_to_title(path) domain_min, domain_max = np.array([0, 0, 0]), np.array([1, 1, 1]) size = 2 indexes = [] table = [] comments = [] with open(path) as spi3d_file: lines = spi3d_file.readlines() for line in lines: line = line.strip() if len(line) == 0: continue if line.startswith('#'): comments.append(line[1:].strip()) continue tokens = line.split() if len(tokens) == 3: assert len(set(tokens)) == 1, ( 'Non-uniform "LUT" shape is unsupported!') size = DEFAULT_INT_DTYPE(tokens[0]) if len(tokens) == 6: indexes.append(parse_array(tokens[:3])) table.append(parse_array(tokens[3:])) assert np.array_equal( indexes, DEFAULT_INT_DTYPE(LUT3D.linear_table(size) * (size - 1)).reshape( (-1, 3))), 'Indexes do not match expected "LUT3D" indexes!' table = as_float_array(table).reshape([size, size, size, 3]) return LUT3D( table, title, np.vstack([domain_min, domain_max]), comments=comments)
def read_LUT_SonySPI1D(path): """ Reads given *Sony* *.spi1d* *LUT* file. Parameters ---------- path : unicode *LUT* path. Returns ------- LUT1D or LUT2D :class:`LUT1D` or :class:`LUT2D` class instance. Examples -------- Reading a 1D *Sony* *.spi1d* *LUT*: >>> import os >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'sony_spi1d', ... 'oetf_reverse_sRGB_1D.spi1d') >>> print(read_LUT_SonySPI1D(path)) LUT1D - oetf reverse sRGB 1D ---------------------------- <BLANKLINE> Dimensions : 1 Domain : [-0.1 1.5] Size : (16,) Comment 01 : Generated by "Colour 0.3.11". Comment 02 : "colour.models.oetf_reverse_sRGB". Reading a 2D *Sony* *.spi1d* *LUT*: >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'sony_spi1d', ... 'oetf_reverse_sRGB_2D.spi1d') >>> print(read_LUT_SonySPI1D(path)) LUT2D - oetf reverse sRGB 2D ---------------------------- <BLANKLINE> Dimensions : 2 Domain : [[-0.1 -0.1 -0.1] [ 1.5 1.5 1.5]] Size : (16, 3) Comment 01 : Generated by "Colour 0.3.11". Comment 02 : "colour.models.oetf_reverse_sRGB". """ title = path_to_title(path) domain_min, domain_max = np.array([0, 1]) dimensions = 1 table = [] comments = [] with open(path) as spi1d_file: lines = spi1d_file.readlines() for line in lines: line = line.strip() if len(line) == 0: continue if line.startswith('#'): comments.append(line[1:].strip()) continue tokens = line.split() if tokens[0] == 'Version': continue if tokens[0] == 'From': domain_min, domain_max = parse_array(tokens[1:]) elif tokens[0] == 'Length': continue elif tokens[0] == 'Components': component = DEFAULT_INT_DTYPE(tokens[1]) assert component in (1, 3), ( 'Only 1 or 3 components are supported!') dimensions = 1 if component == 1 else 2 elif tokens[0] in ('{', '}'): continue else: table.append(parse_array(tokens)) table = as_float_array(table) if dimensions == 1: return LUT1D(np.squeeze(table), title, np.array([domain_min, domain_max]), comments=comments) elif dimensions == 2: return LUT2D(table, title, np.array([[domain_min, domain_min, domain_min], [domain_max, domain_max, domain_max]]), comments=comments)
def read_LUT_SonySPI1D(path: str) -> Union[LUT1D, LUT3x1D]: """ Read given *Sony* *.spi1d* *LUT* file. Parameters ---------- path *LUT* path. Returns ------- :class:`colour.LUT1D` or :class:`colour.LUT3x1D` :class:`LUT1D` or :class:`LUT3x1D` class instance. Examples -------- Reading a 1D *Sony* *.spi1d* *LUT*: >>> import os >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'sony_spi1d', ... 'eotf_sRGB_1D.spi1d') >>> print(read_LUT_SonySPI1D(path)) LUT1D - eotf sRGB 1D -------------------- <BLANKLINE> Dimensions : 1 Domain : [-0.1 1.5] Size : (16,) Comment 01 : Generated by "Colour 0.3.11". Comment 02 : "colour.models.eotf_sRGB". Reading a 3x1D *Sony* *.spi1d* *LUT*: >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'sony_spi1d', ... 'eotf_sRGB_3x1D.spi1d') >>> print(read_LUT_SonySPI1D(path)) LUT3x1D - eotf sRGB 3x1D ------------------------ <BLANKLINE> Dimensions : 2 Domain : [[-0.1 -0.1 -0.1] [ 1.5 1.5 1.5]] Size : (16, 3) Comment 01 : Generated by "Colour 0.3.11". Comment 02 : "colour.models.eotf_sRGB". """ title = path_to_title(path) domain_min, domain_max = np.array([0, 1]) dimensions = 1 data = [] comments = [] with open(path) as spi1d_file: lines = filter(None, (line.strip() for line in spi1d_file.readlines())) for line in lines: if line.startswith("#"): comments.append(line[1:].strip()) continue tokens = line.split() if tokens[0] == "Version": continue if tokens[0] == "From": domain_min, domain_max = as_float_array(tokens[1:]) elif tokens[0] == "Length": continue elif tokens[0] == "Components": component = as_int_scalar(tokens[1]) attest( component in (1, 3), "Only 1 or 3 components are supported!", ) dimensions = 1 if component == 1 else 2 elif tokens[0] in ("{", "}"): continue else: data.append(tokens) table = as_float_array(data) LUT: Union[LUT1D, LUT3x1D] if dimensions == 1: LUT = LUT1D( np.squeeze(table), title, np.array([domain_min, domain_max]), comments=comments, ) elif dimensions == 2: LUT = LUT3x1D( table, title, np.array([ [domain_min, domain_min, domain_min], [domain_max, domain_max, domain_max], ]), comments=comments, ) return LUT
def read_LUT_IridasCube(path): """ Reads given *Iridas* *.cube* *LUT* file. Parameters ---------- path : unicode *LUT* path. Returns ------- LUT3x1D or LUT3d :class:`LUT3x1D` or :class:`LUT3D` class instance. References ---------- :cite:`AdobeSystems2013b` Examples -------- Reading a 3x1D *Iridas* *.cube* *LUT*: >>> import os >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'iridas_cube', ... 'ACES_Proxy_10_to_ACES.cube') >>> print(read_LUT_IridasCube(path)) LUT3x1D - ACES Proxy 10 to ACES ------------------------------- <BLANKLINE> Dimensions : 2 Domain : [[ 0. 0. 0.] [ 1. 1. 1.]] Size : (32, 3) Reading a 3D *Iridas* *.cube* *LUT*: >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'iridas_cube', ... 'ColourCorrect.cube') >>> print(read_LUT_IridasCube(path)) LUT3D - Generated by Foundry::LUT --------------------------------- <BLANKLINE> Dimensions : 3 Domain : [[ 0. 0. 0.] [ 1. 1. 1.]] Size : (4, 4, 4, 3) Reading a 3D *Iridas* *.cube* *LUT* with comments: >>> path = os.path.join( ... os.path.dirname(__file__), 'tests', 'resources', 'iridas_cube', ... 'Demo.cube') >>> print(read_LUT_IridasCube(path)) LUT3x1D - Demo -------------- <BLANKLINE> Dimensions : 2 Domain : [[ 0. 0. 0.] [ 1. 2. 3.]] Size : (3, 3) Comment 01 : Comments can go anywhere """ title = path_to_title(path) domain_min, domain_max = np.array([0, 0, 0]), np.array([1, 1, 1]) dimensions = 3 size = 2 table = [] comments = [] with open(path) as cube_file: lines = cube_file.readlines() for line in lines: line = line.strip() if len(line) == 0: continue if line.startswith('#'): comments.append(line[1:].strip()) continue tokens = line.split() if tokens[0] == 'TITLE': title = ' '.join(tokens[1:])[1:-1] elif tokens[0] == 'DOMAIN_MIN': domain_min = parse_array(tokens[1:]) elif tokens[0] == 'DOMAIN_MAX': domain_max = parse_array(tokens[1:]) elif tokens[0] == 'LUT_1D_SIZE': dimensions = 2 size = DEFAULT_INT_DTYPE(tokens[1]) elif tokens[0] == 'LUT_3D_SIZE': dimensions = 3 size = DEFAULT_INT_DTYPE(tokens[1]) else: table.append(parse_array(tokens)) table = as_float_array(table) if dimensions == 2: return LUT3x1D( table, title, np.vstack([domain_min, domain_max]), comments=comments) elif dimensions == 3: # The lines of table data shall be in ascending index order, # with the first component index (Red) changing most rapidly, # and the last component index (Blue) changing least rapidly. table = table.reshape([size, size, size, 3], order='F') return LUT3D( table, title, np.vstack([domain_min, domain_max]), comments=comments)