def create_transfer_colorspace(name='transfer', transfer_function_name='transfer_function', transfer_function=lambda x: x, lut_directory='/tmp', lut_resolution_1d=1024, aliases=[]): """ Object description. Parameters ---------- parameter : type Parameter description. Returns ------- type Return value description. """ cs = ColorSpace(name) cs.description = 'The %s color space' % name cs.aliases = aliases cs.equality_group = name cs.family = 'Utility' cs.is_data = False # A linear space needs allocation variables cs.allocation_type = ocio.Constants.ALLOCATION_UNIFORM cs.allocation_vars = [0, 1] # Sample the transfer function data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = transfer_function(c / (lut_resolution_1d - 1)) # Write the sampled data to a LUT lut = '%s_to_linear.spi1d' % transfer_function_name genlut.write_SPI_1d( os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) # Create the 'to_reference' transforms cs.to_reference_transforms = [] cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) # Create the 'from_reference' transforms cs.from_reference_transforms = [] return cs
def create_matrix_colorspace(name='matrix', from_reference_values=None, to_reference_values=None, aliases=None): """ Object description. Parameters ---------- parameter : type Parameter description. Returns ------- type Return value description. """ if from_reference_values is None: from_reference_values = [] if to_reference_values is None: to_reference_values = [] if aliases is None: aliases = [] cs = ColorSpace(name) cs.description = 'The %s color space' % name cs.aliases = aliases cs.equality_group = name cs.family = 'Utility' cs.is_data = False # A linear space needs allocation variables. cs.allocation_type = ocio.Constants.ALLOCATION_UNIFORM cs.allocation_vars = [0, 1] cs.to_reference_transforms = [] if to_reference_values: for matrix in to_reference_values: cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(matrix), 'direction': 'forward'}) cs.from_reference_transforms = [] if from_reference_values: for matrix in from_reference_values: cs.from_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(matrix), 'direction': 'forward'}) return cs
def create_ACES(): """ Object description. Parameters ---------- parameter : type Parameter description. Returns ------- type Return value description. """ # Defining the reference colorspace. aces2065_1 = ColorSpace('ACES2065-1') aces2065_1.description = ( 'The Academy Color Encoding System reference color space') aces2065_1.equality_group = '' aces2065_1.aliases = ['lin_ap0', 'aces'] aces2065_1.family = 'ACES' aces2065_1.is_data = False aces2065_1.allocation_type = ocio.Constants.ALLOCATION_LG2 aces2065_1.allocation_vars = [-8, 5, 0.00390625] return aces2065_1
def create_Dolby_PQ_scaled(aces_ctl_directory, lut_directory, lut_resolution_1d, cleanup, name='pq', aliases=None, min_value=0.0, max_value=1.0, input_scale=1.0, middle_grey=0.18, min_exposure=-6.0, max_exposure=6.5): if aliases is None: aliases = [] cs = ColorSpace(name) cs.description = 'The %s color space' % name cs.aliases = aliases cs.equality_group = name cs.family = 'Utility' cs.is_data = False ctls = [os.path.join( aces_ctl_directory, 'utilities', 'ACESlib.OCIOShaper_to_lin_param.a1.0.0.ctl')] lut = '%s_to_linear.spi1d' % name lut = sanitize(lut) generate_1d_LUT_from_CTL( os.path.join(lut_directory, lut), ctls, lut_resolution_1d, 'float', input_scale, 1.0, {'middleGrey': middle_grey, 'minExposure': min_exposure, 'maxExposure': max_exposure}, cleanup, aces_ctl_directory, min_value, max_value) cs.to_reference_transforms = [] cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) cs.from_reference_transforms = [] return cs
def create_ACEScg(aces_ctl_directory, lut_directory, lut_resolution_1d, cleanup, name='ACEScg'): """ Creates the *ACEScg* colorspace. Parameters ---------- parameter : type Parameter description. Returns ------- Colorspace *ACEScg* colorspace. """ cs = ColorSpace(name) cs.description = 'The %s color space' % name cs.aliases = ["lin_ap1"] cs.equality_group = '' cs.family = 'ACES' cs.is_data = False cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] cs.to_reference_transforms = [] # *AP1* primaries to *AP0* primaries. cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(ACES_AP1_TO_AP0), 'direction': 'forward'}) cs.from_reference_transforms = [] return cs
def create_dolbypq_scaled( aces_CTL_directory, lut_directory, lut_resolution_1d, cleanup, name="pq", aliases=[], min_value=0.0, max_value=1.0, input_scale=1.0, middle_grey=0.18, min_exposure=-6.0, max_exposure=6.5, ): cs = ColorSpace(name) cs.description = "The %s color space" % name cs.aliases = aliases cs.equality_group = name cs.family = "Utility" cs.is_data = False ctls = [os.path.join(aces_CTL_directory, "utilities", "ACESlib.DolbyPQ_to_lin_param.a1.0.0.ctl")] lut = "%s_to_linear.spi1d" % name lut = sanitize(lut) generate_1d_LUT_from_CTL( os.path.join(lut_directory, lut), ctls, lut_resolution_1d, "float", input_scale, 1.0, {"middleGrey": middle_grey, "minExposure": min_exposure, "maxExposure": max_exposure}, cleanup, aces_CTL_directory, min_value, max_value, ) cs.to_reference_transforms = [] cs.to_reference_transforms.append( {"type": "lutFile", "path": lut, "interpolation": "linear", "direction": "forward"} ) cs.from_reference_transforms = [] return cs
def create_dolbypq(aces_CTL_directory, lut_directory, lut_resolution_1d, cleanup, name='pq', aliases=[], min_value=0.0, max_value=1.0, input_scale=1.0): cs = ColorSpace(name) cs.description = 'The %s color space' % name cs.aliases = aliases cs.equality_group = name cs.family = 'Utility' cs.is_data = False ctls = [os.path.join( aces_CTL_directory, 'utilities', 'ACESlib.OCIO_shaper_dolbypq_to_lin.a1.0.0.ctl')] lut = '%s_to_linear.spi1d' % name lut = sanitize(lut) generate_1d_LUT_from_CTL( os.path.join(lut_directory, lut), ctls, lut_resolution_1d, 'float', input_scale, 1.0, {}, cleanup, aces_CTL_directory, min_value, max_value) cs.to_reference_transforms = [] cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) cs.from_reference_transforms = [] return cs
def create_raw(): # *Raw* utility space name = "Raw" raw = ColorSpace(name) raw.description = 'The %s color space' % name raw.aliases = [] raw.equality_group = name raw.family = 'Utility' raw.is_data = True return raw
def create_raw(): """ Creates the *raw* colorspace. Returns ------- ColorSpace *raw* and all its identifying information. """ # *Raw* utility space name = 'Raw' raw = ColorSpace(name) raw.description = 'The {0} color space'.format(name) raw.aliases = ['raw'] raw.equality_group = name raw.family = 'Utility' raw.is_data = True return raw
def create_raw(): """ Creates the *raw* color space Parameters ---------- None Returns ------- ColorSpace *raw* and all its identifying information """ # *Raw* utility space name = 'Raw' raw = ColorSpace(name) raw.description = 'The %s color space' % name raw.aliases = ['raw'] raw.equality_group = name raw.family = 'Utility' raw.is_data = True return raw
def create_c_log(gamut, transfer_function, lut_directory, lut_resolution_1d, aliases): """ Object description. Canon-Log to ACES. Parameters ---------- parameter : type Parameter description. Returns ------- type Return value description. """ name = '%s - %s' % (transfer_function, gamut) if transfer_function == '': name = 'Linear - Canon %s' % gamut if gamut == '': name = 'Curve - %s' % transfer_function cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/Canon' cs.is_data = False # A linear space needs allocation variables. if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] def legal_to_full(code_value): return (code_value - 64) / (940 - 64) def c_log_to_linear(code_value): # log = fullToLegal(c1 * log10(c2*linear + 1) + c3) # linear = (pow(10, (legalToFul(log) - c3)/c1) - 1)/c2 c1 = 0.529136 c2 = 10.1596 c3 = 0.0730597 linear = (pow(10, (legal_to_full(code_value) - c3) / c1) - 1) / c2 linear *= 0.9 return linear cs.to_reference_transforms = [] if transfer_function == 'Canon-Log': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = c_log_to_linear(1023 * c / (lut_resolution_1d - 1)) lut = '%s_to_linear.spi1d' % transfer_function genlut.write_SPI_1d( os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) if gamut == 'Rec. 709 Daylight': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.561538969, 0.402060105, 0.036400926, 0, 0.092739623, 0.924121198, -0.016860821, 0, 0.084812961, 0.006373835, 0.908813204, 0, 0, 0, 0, 1], 'direction': 'forward'}) elif gamut == 'Rec. 709 Tungsten': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.566996399, 0.365079418, 0.067924183, 0, 0.070901044, 0.880331008, 0.048767948, 0, 0.073013542, -0.066540862, 0.99352732, 0, 0, 0, 0, 1], 'direction': 'forward'}) elif gamut == 'DCI-P3 Daylight': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.607160575, 0.299507286, 0.093332140, 0, 0.004968120, 1.050982224, -0.055950343, 0, -0.007839939, 0.000809127, 1.007030813, 0, 0, 0, 0, 1], 'direction': 'forward'}) elif gamut == 'DCI-P3 Tungsten': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.650279125, 0.253880169, 0.095840706, 0, -0.026137986, 1.017900530, 0.008237456, 0, 0.007757558, -0.063081669, 1.055324110, 0, 0, 0, 0, 1], 'direction': 'forward'}) elif gamut == 'Cinema Gamut Daylight': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.763064455, 0.149021161, 0.087914384, 0, 0.003657457, 1.10696038, -0.110617837, 0, -0.009407794, -0.218383305, 1.227791099, 0, 0, 0, 0, 1], 'direction': 'forward'}) elif gamut == 'Cinema Gamut Tungsten': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.817416293, 0.090755698, 0.091828009, 0, -0.035361374, 1.065690585, -0.030329211, 0, 0.010390366, -0.299271107, 1.288880741, 0, 0, 0, 0, 1], 'direction': 'forward'}) cs.from_reference_transforms = [] return cs
def create_matrix_colorspace(name='matrix', from_reference_values=None, to_reference_values=None, aliases=None): """ Creates a ColorSpace that only uses *Matrix Transforms* Parameters ---------- name : str, optional Aliases for this colorspace from_reference_values : list of matrices List of matrices to convert from the reference colorspace to this space to_reference_values : list of matrices List of matrices to convert to the reference colorspace from this space aliases : list of str, optional Aliases for this colorspace Returns ------- ColorSpace A *Matrix Transform*-based ColorSpace """ if from_reference_values is None: from_reference_values = [] if to_reference_values is None: to_reference_values = [] if aliases is None: aliases = [] cs = ColorSpace(name) cs.description = 'The %s color space' % name cs.aliases = aliases cs.equality_group = name cs.family = 'Utility' cs.is_data = False # A linear space needs allocation variables. cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] cs.to_reference_transforms = [] if to_reference_values: for matrix in to_reference_values: cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(matrix), 'direction': 'forward'}) cs.from_reference_transforms = [] if from_reference_values: for matrix in from_reference_values: cs.from_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(matrix), 'direction': 'forward'}) return cs
def create_red_log_film(gamut, transfer_function, lut_directory, lut_resolution_1d, aliases=None): """ Creates colorspace covering the conversion from RED spaces to ACES, with various transfer functions and encoding gamuts covered Parameters ---------- gamut : str The name of the encoding gamut to use. transfer_function : str The name of the transfer function to use lut_directory : str or unicode The directory to use when generating LUTs lut_resolution_1d : int The resolution of generated 1D LUTs aliases : list of str Aliases for this colorspace Returns ------- ColorSpace A ColorSpace container class referencing the LUTs, matrices and identifying information for the requested colorspace. """ if aliases is None: aliases = [] name = '%s - %s' % (transfer_function, gamut) if transfer_function == '': name = 'Linear - %s' % gamut if gamut == '': name = 'Curve - %s' % transfer_function cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/RED' cs.is_data = False # A linear space needs allocation variables if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] def cineon_to_linear(code_value): n_gamma = 0.6 black_point = 95 white_point = 685 code_value_to_density = 0.002 black_linear = pow(10, (black_point - white_point) * ( code_value_to_density / n_gamma)) code_linear = pow(10, (code_value - white_point) * ( code_value_to_density / n_gamma)) return (code_linear - black_linear) / (1 - black_linear) cs.to_reference_transforms = [] if transfer_function == 'REDlogFilm': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = cineon_to_linear(1023 * c / (lut_resolution_1d - 1)) lut = 'CineonLog_to_linear.spi1d' genlut.write_SPI_1d( os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) if gamut == 'DRAGONcolor': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([0.532279, 0.376648, 0.091073, 0.046344, 0.974513, -0.020860, -0.053976, -0.000320, 1.054267]), 'direction': 'forward'}) elif gamut == 'DRAGONcolor2': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([0.468452, 0.331484, 0.200064, 0.040787, 0.857658, 0.101553, -0.047504, -0.000282, 1.047756]), 'direction': 'forward'}) elif gamut == 'REDcolor': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([0.451464, 0.388498, 0.160038, 0.062716, 0.866790, 0.070491, -0.017541, 0.086921, 0.930590]), 'direction': 'forward'}) elif gamut == 'REDcolor2': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([0.480997, 0.402289, 0.116714, -0.004938, 1.000154, 0.004781, -0.105257, 0.025320, 1.079907]), 'direction': 'forward'}) elif gamut == 'REDcolor3': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([0.512136, 0.360370, 0.127494, 0.070377, 0.903884, 0.025737, -0.020824, 0.017671, 1.003123]), 'direction': 'forward'}) elif gamut == 'REDcolor4': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([0.474202, 0.333677, 0.192121, 0.065164, 0.836932, 0.097901, -0.019281, 0.016362, 1.002889]), 'direction': 'forward'}) cs.from_reference_transforms = [] return cs
def create_log_c(gamut, transfer_function, exposure_index, name, lut_directory, lut_resolution_1d, aliases): """ Object description. LogC to ACES. Parameters ---------- parameter : type Parameter description. Returns ------- type Return value description. """ name = '%s (EI%s) - %s' % (transfer_function, exposure_index, gamut) if transfer_function == '': name = 'Linear - ARRI %s' % gamut if gamut == '': name = '%s (EI%s)' % (transfer_function, exposure_index) cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/ARRI' cs.is_data = False # A linear space needs allocation variables if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] # Globals. IDT_maker_version = '0.08' nominal_EI = 400 black_signal = 0.003907 mid_gray_signal = 0.01 encoding_gain = 0.256598 encoding_offset = 0.391007 def gain_for_EI(EI): return (math.log(EI / nominal_EI) / math.log(2) * ( 0.89 - 1) / 3 + 1) * encoding_gain def log_c_inverse_parameters_for_EI(EI): cut = 1 / 9 slope = 1 / (cut * math.log(10)) offset = math.log10(cut) - slope * cut gain = EI / nominal_EI gray = mid_gray_signal / gain # The higher the EI, the lower the gamma. enc_gain = gain_for_EI(EI) enc_offset = encoding_offset for i in range(0, 3): nz = ((95 / 1023 - enc_offset) / enc_gain - offset) / slope enc_offset = encoding_offset - math.log10(1 + nz) * enc_gain a = 1 / gray b = nz - black_signal / gray e = slope * a * enc_gain f = enc_gain * (slope * b + offset) + enc_offset # Ensuring we can return relative exposure. s = 4 / (0.18 * EI) t = black_signal b += a * t a *= s f += e * t e *= s return {'a': a, 'b': b, 'cut': (cut - b) / a, 'c': enc_gain, 'd': enc_offset, 'e': e, 'f': f} def log_c_to_linear(code_value, exposure_index): p = log_c_inverse_parameters_for_EI(exposure_index) breakpoint = p['e'] * p['cut'] + p['f'] if code_value > breakpoint: linear = ((pow(10, (code_value / 1023 - p['d']) / p['c']) - p['b']) / p['a']) else: linear = (code_value / 1023 - p['f']) / p['e'] return linear cs.to_reference_transforms = [] if transfer_function == 'V3 LogC': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = log_c_to_linear(1023 * c / (lut_resolution_1d - 1), int(exposure_index)) lut = '%s_to_linear.spi1d' % ( '%s_%s' % (transfer_function, exposure_index)) lut = sanitize(lut) genlut.write_SPI_1d( os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward' }) if gamut == 'Wide Gamut': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([0.680206, 0.236137, 0.083658, 0.085415, 1.017471, -0.102886, 0.002057, -0.062563, 1.060506]), 'direction': 'forward' }) cs.from_reference_transforms = [] return cs
def create_ACES_RRT_plus_ODT(odt_name, odt_values, shaper_info, aces_ctl_directory, lut_directory, lut_resolution_3d=64, cleanup=True, aliases=None): """ Object description. Parameters ---------- parameter : type Parameter description. Returns ------- type Return value description. """ if aliases is None: aliases = [] cs = ColorSpace('%s' % odt_name) cs.description = '%s - %s Output Transform' % ( odt_values['transformUserNamePrefix'], odt_name) cs.aliases = aliases cs.equality_group = '' cs.family = 'Output' cs.is_data = False cs.aces_transform_id = odt_values['transformID'] pprint.pprint(odt_values) # Generating the *shaper* transform. (shaper_name, shaper_to_aces_ctl, shaper_from_aces_ctl, shaper_input_scale, shaper_params) = shaper_info if 'legalRange' in odt_values: shaper_params['legalRange'] = odt_values['legalRange'] else: shaper_params['legalRange'] = 0 shaper_lut = '%s_to_linear.spi1d' % shaper_name shaper_lut = sanitize(shaper_lut) shaper_ocio_transform = { 'type': 'lutFile', 'path': shaper_lut, 'interpolation': 'linear', 'direction': 'inverse'} # Generating the *forward* transform. cs.from_reference_transforms = [] if 'transformLUT' in odt_values: transform_lut_file_name = os.path.basename( odt_values['transformLUT']) lut = os.path.join(lut_directory, transform_lut_file_name) shutil.copy(odt_values['transformLUT'], lut) cs.from_reference_transforms.append(shaper_ocio_transform) cs.from_reference_transforms.append({ 'type': 'lutFile', 'path': transform_lut_file_name, 'interpolation': 'tetrahedral', 'direction': 'forward'}) elif 'transformCTL' in odt_values: ctls = [ shaper_to_aces_ctl % aces_ctl_directory, os.path.join(aces_ctl_directory, 'rrt', 'RRT.a1.0.0.ctl'), os.path.join(aces_ctl_directory, 'odt', odt_values['transformCTL'])] lut = '%s.RRT.a1.0.0.%s.spi3d' % (shaper_name, odt_name) lut = sanitize(lut) generate_3d_LUT_from_CTL( os.path.join(lut_directory, lut), ctls, lut_resolution_3d, 'float', 1 / shaper_input_scale, 1, shaper_params, cleanup, aces_ctl_directory) cs.from_reference_transforms.append(shaper_ocio_transform) cs.from_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'tetrahedral', 'direction': 'forward'}) # Generating the *inverse* transform. cs.to_reference_transforms = [] if 'transformLUTInverse' in odt_values: transform_lut_inverse_file_name = os.path.basename( odt_values['transformLUTInverse']) lut = os.path.join(lut_directory, transform_lut_inverse_file_name) shutil.copy(odt_values['transformLUTInverse'], lut) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': transform_lut_inverse_file_name, 'interpolation': 'tetrahedral', 'direction': 'forward'}) shaper_inverse = shaper_ocio_transform.copy() shaper_inverse['direction'] = 'forward' cs.to_reference_transforms.append(shaper_inverse) elif 'transformCTLInverse' in odt_values: ctls = [os.path.join(aces_ctl_directory, 'odt', odt_values['transformCTLInverse']), os.path.join(aces_ctl_directory, 'rrt', 'InvRRT.a1.0.0.ctl'), shaper_from_aces_ctl % aces_ctl_directory] lut = 'InvRRT.a1.0.0.%s.%s.spi3d' % (odt_name, shaper_name) lut = sanitize(lut) generate_3d_LUT_from_CTL( os.path.join(lut_directory, lut), ctls, lut_resolution_3d, 'half', 1, shaper_input_scale, shaper_params, cleanup, aces_ctl_directory) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'tetrahedral', 'direction': 'forward'}) shaper_inverse = shaper_ocio_transform.copy() shaper_inverse['direction'] = 'forward' cs.to_reference_transforms.append(shaper_inverse) return cs
def create_v_log(gamut, transfer_function, lut_directory, lut_resolution_1d, aliases): """ Object description. Panasonic V-Log to ACES. Parameters ---------- parameter : type Parameter description. Returns ------- type Return value description. """ name = '%s - %s' % (transfer_function, gamut) if transfer_function == '': name = 'Linear - %s' % gamut if gamut == '': name = 'Curve - %s' % transfer_function cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/Panasonic' cs.is_data = False # A linear space needs allocation variables if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] def v_log_to_linear(x): cut_inv = 0.181 b = 0.00873 c = 0.241514 d = 0.598206 if x <= cut_inv: return (x - 0.125) / 5.6 else: return pow(10, (x - d) / c) - b cs.to_reference_transforms = [] if transfer_function == 'V-Log': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = v_log_to_linear(float(c) / (lut_resolution_1d - 1)) lut = '%s_to_linear.spi1d' % transfer_function genlut.write_SPI_1d( os.path.join(lut_directory, lut), 0.0, 1.0, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) if gamut == 'V-Gamut': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.724382758, 0.166748484, 0.108497411, 0.0, 0.021354009, 0.985138372, -0.006319092, 0.0, -0.009234278, -0.00104295, 1.010272625, 0.0, 0, 0, 0, 1.0], 'direction': 'forward'}) cs.from_reference_transforms = [] return cs
def create_VLog(gamut, transfer_function, lut_directory, lut_resolution_1D, aliases): """ Creates colorspace covering the conversion from *VLog* to *ACES*, with various transfer functions and encoding gamuts covered. Parameters ---------- gamut : str The name of the encoding gamut to use. transfer_function : str The name of the transfer function to use. lut_directory : str or unicode The directory to use when generating LUTs. lut_resolution_1D : int The resolution of generated 1D LUTs. aliases : list of str Aliases for this colorspace. Returns ------- ColorSpace A ColorSpace container class referencing the LUTs, matrices and identifying information for the requested colorspace. """ name = '{0} - {1}'.format(transfer_function, gamut) if transfer_function == '': name = 'Linear - {0}'.format(gamut) if gamut == '': name = 'Curve - {0}'.format(transfer_function) cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/Panasonic' cs.is_data = False # A linear space needs allocation variables if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] def VLog_to_linear(x): cut_inv = 0.181 b = 0.00873 c = 0.241514 d = 0.598206 if x <= cut_inv: return (x - 0.125) / 5.6 else: return pow(10, (x - d) / c) - b cs.to_reference_transforms = [] if transfer_function == 'V-Log': data = array.array('f', b'\0' * lut_resolution_1D * 4) for c in range(lut_resolution_1D): data[c] = VLog_to_linear(float(c) / (lut_resolution_1D - 1)) lut = '{0}_to_linear.spi1d'.format(transfer_function) genlut.write_SPI_1D(os.path.join(lut_directory, lut), 0.0, 1.0, data, lut_resolution_1D, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward' }) if gamut == 'V-Gamut': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [ 0.724382758, 0.166748484, 0.108497411, 0.0, 0.021354009, 0.985138372, -0.006319092, 0.0, -0.009234278, -0.00104295, 1.010272625, 0.0, 0, 0, 0, 1.0 ], 'direction': 'forward' }) cs.from_reference_transforms = [] return cs
def create_ACES_LMT(lmt_name, lmt_values, shaper_info, aces_ctl_directory, lut_directory, lut_resolution_3d=64, cleanup=True, aliases=None): """ Creates the *ACES LMT* colorspace. Parameters ---------- parameter : type Parameter description. Returns ------- Colorspace *ACES LMT* colorspace. """ if aliases is None: aliases = [] cs = ColorSpace('%s' % lmt_name) cs.description = 'The ACES Look Transform: %s' % lmt_name cs.aliases = aliases cs.equality_group = '' cs.family = 'Look' cs.is_data = False cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] cs.aces_transform_id = lmt_values['transformID'] pprint.pprint(lmt_values) # Generating the *shaper* transform. (shaper_name, shaper_to_aces_ctl, shaper_from_aces_ctl, shaper_input_scale, shaper_params) = shaper_info shaper_lut = '%s_to_linear.spi1d' % shaper_name shaper_lut = sanitize(shaper_lut) shaper_ocio_transform = { 'type': 'lutFile', 'path': shaper_lut, 'interpolation': 'linear', 'direction': 'inverse'} # Generating the forward transform. cs.from_reference_transforms = [] if 'transformCTL' in lmt_values: ctls = [shaper_to_aces_ctl % aces_ctl_directory, os.path.join(aces_ctl_directory, lmt_values['transformCTL'])] lut = '%s.%s.spi3d' % (shaper_name, lmt_name) lut = sanitize(lut) generate_3d_LUT_from_CTL( os.path.join(lut_directory, lut), ctls, lut_resolution_3d, 'float', 1 / shaper_input_scale, 1, shaper_params, cleanup, aces_ctl_directory) cs.from_reference_transforms.append(shaper_ocio_transform) cs.from_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'tetrahedral', 'direction': 'forward'}) # Generating the inverse transform. cs.to_reference_transforms = [] if 'transformCTLInverse' in lmt_values: ctls = [os.path.join(aces_ctl_directory, lmt_values['transformCTLInverse']), shaper_from_aces_ctl % aces_ctl_directory] lut = 'Inverse.%s.%s.spi3d' % (lmt_name, shaper_name) lut = sanitize(lut) generate_3d_LUT_from_CTL( os.path.join(lut_directory, lut), ctls, lut_resolution_3d, 'half', 1, shaper_input_scale, shaper_params, cleanup, aces_ctl_directory, 0) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'tetrahedral', 'direction': 'forward'}) shaper_inverse = shaper_ocio_transform.copy() shaper_inverse['direction'] = 'forward' cs.to_reference_transforms.append(shaper_inverse) return cs
def create_c_log(gamut, transfer_function, lut_directory, lut_resolution_1d, aliases): """ Creates a colorspace covering the conversion from CLog to ACES, with various transfer functions and encoding gamuts covered. Parameters ---------- gamut : str The name of the encoding gamut to use. transfer_function : str The name of the transfer function to use lut_directory : str or unicode The directory to use when generating LUTs lut_resolution_1d : int The resolution of generated 1D LUTs aliases : list of str Aliases for this colorspace. Returns ------- ColorSpace A ColorSpace container class referencing the LUTs, matrices and identifying information for the requested colorspace. """ name = '%s - %s' % (transfer_function, gamut) if transfer_function == '': name = 'Linear - Canon %s' % gamut if gamut == '': name = 'Curve - %s' % transfer_function cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/Canon' cs.is_data = False # A linear space needs allocation variables. if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] def legal_to_full(code_value): return (code_value - 64) / (940 - 64) def c_log_to_linear(code_value): # log = fullToLegal(c1 * log10(c2*linear + 1) + c3) # linear = (pow(10, (legalToFul(log) - c3)/c1) - 1)/c2 c1 = 0.529136 c2 = 10.1596 c3 = 0.0730597 linear = (pow(10, (legal_to_full(code_value) - c3) / c1) - 1) / c2 linear *= 0.9 return linear def c_log2_to_linear(code_value): # log = fullToLegal(c1 * log10(c2*linear + 1) + c3) # linear = (pow(10, (legalToFul(log) - c3)/c1) - 1)/c2 c1 = 0.281863093 c2 = 87.09937546 c3 = 0.035388128 linear = (pow(10, (legal_to_full(code_value) - c3) / c1) - 1) / c2 linear *= 0.9 return linear def c_log3_to_linear(code_value): # if(clog3_ire < 0.04076162) # out = -( pow( 10, ( 0.07623209 - clog3_ire ) / 0.42889912 ) # - 1 ) / 14.98325; # else if(clog3_ire <= 0.105357102) # out = ( clog3_ire - 0.073059361 ) / 2.3069815; # else # out = ( pow( 10, ( clog3_ire - 0.069886632 ) / 0.42889912 ) # - 1 ) / 14.98325; c1 = 0.42889912 c2 = 14.98325 c3 = 0.069886632 c4 = 0.04076162 c5 = 0.07623209 c6 = 0.105357102 c7 = 0.073059361 c8 = 2.3069815 clog3_ire = legal_to_full(code_value) if clog3_ire < c4: linear = -(pow(10, (c5 - clog3_ire) / c1) - 1) / c2 elif clog3_ire <= c6: linear = (clog3_ire - c7) / c8 else: linear = (pow(10, (clog3_ire - c3) / c1) - 1) / c2 linear *= 0.9 return linear cs.to_reference_transforms = [] if transfer_function: if transfer_function == 'Canon-Log': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = c_log_to_linear(1023 * c / (lut_resolution_1d - 1)) elif transfer_function == 'Canon-Log2': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = c_log2_to_linear(1023 * c / (lut_resolution_1d - 1)) elif transfer_function == 'Canon-Log3': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = c_log3_to_linear(1023 * c / (lut_resolution_1d - 1)) lut = '%s_to_linear.spi1d' % transfer_function genlut.write_SPI_1d(os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward' }) if gamut == 'Rec. 709 Daylight': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [ 0.561538969, 0.402060105, 0.036400926, 0, 0.092739623, 0.924121198, -0.016860821, 0, 0.084812961, 0.006373835, 0.908813204, 0, 0, 0, 0, 1 ], 'direction': 'forward' }) elif gamut == 'Rec. 709 Tungsten': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [ 0.566996399, 0.365079418, 0.067924183, 0, 0.070901044, 0.880331008, 0.048767948, 0, 0.073013542, -0.066540862, 0.99352732, 0, 0, 0, 0, 1 ], 'direction': 'forward' }) elif gamut == 'DCI-P3 Daylight': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [ 0.607160575, 0.299507286, 0.093332140, 0, 0.004968120, 1.050982224, -0.055950343, 0, -0.007839939, 0.000809127, 1.007030813, 0, 0, 0, 0, 1 ], 'direction': 'forward' }) elif gamut == 'DCI-P3 Tungsten': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [ 0.650279125, 0.253880169, 0.095840706, 0, -0.026137986, 1.017900530, 0.008237456, 0, 0.007757558, -0.063081669, 1.055324110, 0, 0, 0, 0, 1 ], 'direction': 'forward' }) elif gamut == 'Cinema Gamut Daylight': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [ 0.763064455, 0.149021161, 0.087914384, 0, 0.003657457, 1.10696038, -0.110617837, 0, -0.009407794, -0.218383305, 1.227791099, 0, 0, 0, 0, 1 ], 'direction': 'forward' }) elif gamut == 'Cinema Gamut Tungsten': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [ 0.817416293, 0.090755698, 0.091828009, 0, -0.035361374, 1.065690585, -0.030329211, 0, 0.010390366, -0.299271107, 1.288880741, 0, 0, 0, 0, 1 ], 'direction': 'forward' }) elif gamut == 'Rec. 2020 Daylight': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [ 0.678891151, 0.158868422, 0.162240427, 0, 0.045570831, 0.860712772, 0.093716397, 0, -0.000485710, 0.025060196, 0.975425515, 0, 0, 0, 0, 1 ], 'direction': 'forward' }) elif gamut == 'Rec. 2020 Tungsten': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [ 0.724488568, 0.115140904, 0.160370529, 0, 0.010659276, 0.839605344, 0.149735380, 0, 0.014560161, 0.028562057, 1.014001897, 0, 0, 0, 0, 1 ], 'direction': 'forward' }) cs.from_reference_transforms = [] return cs
def create_log_c(gamut, transfer_function, exposure_index, lut_directory, lut_resolution_1d, aliases): """ Creates a colorspace covering the conversion from LogC to ACES, with various transfer functions and encoding gamuts covered. Parameters ---------- gamut : str The name of the encoding gamut to use. transfer_function : str The name of the transfer function to use. exposure_index : str The exposure index to use. lut_directory : str or unicode The directory to use when generating LUTs. lut_resolution_1d : int The resolution of generated 1D LUTs. aliases : list of str Aliases for this colorspace. Returns ------- ColorSpace A ColorSpace container class referencing the LUTs, matrices and identifying information for the requested colorspace. """ name = '%s (EI%s) - %s' % (transfer_function, exposure_index, gamut) if transfer_function == '': name = 'Linear - ALEXA %s' % gamut if gamut == '': name = 'Curve - %s (EI%s)' % (transfer_function, exposure_index) cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/ARRI' cs.is_data = False if gamut and transfer_function: cs.aces_transform_id = ('IDT.ARRI.Alexa-v3-logC-EI%s.a1.v1' % exposure_index) # A linear space needs allocation variables. if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] IDT_maker_version = '0.09' nominal_exposure_index = 400 black_signal = 16 / 4095 # 0.003907 mid_gray_signal = 0.01 encoding_gain = 500 / 1023 * 0.525 # 0.256598 encoding_offset = 400 / 1023 # 0.391007 def gain_for_EI(ei): return (math.log(ei / nominal_exposure_index) / math.log(2) * (0.89 - 1) / 3 + 1) * encoding_gain def hermite_weights(x, x1, x2): d = x2 - x1 s = (x - x1) / d s2 = 1 - s return [(1 + 2 * s) * s2 * s2, (3 - 2 * s) * s * s, d * s * s2 * s2, -d * s * s * s2] def normalized_sensor_to_relative_exposure(ns, ei): return (ns - black_signal) * ( 0.18 / (mid_gray_signal * nominal_exposure_index / ei)) def normalized_log_c_to_linear(code_value, exposure_index): cut = 1 / 9 slope = 1 / (cut * math.log(10)) offset = math.log10(cut) - slope * cut gain = exposure_index / nominal_exposure_index gray = mid_gray_signal / gain # The higher the EI, the lower the gamma. enc_gain = (math.log(gain) / math.log(2) * (0.89 - 1) / 3 + 1) * encoding_gain enc_offset = encoding_offset for i in range(0, 3): nz = ((95 / 1023 - enc_offset) / enc_gain - offset) / slope enc_offset = encoding_offset - math.log10(1 + nz) * enc_gain # see if we need to bring the hermite spline into play xm = math.log10((1 - black_signal) / gray + nz) * enc_gain + enc_offset if xm > 1.0: if code_value > 0.8: hw = hermite_weights(code_value, 0.8, 1) d = 0.2 / (xm - 0.8) v = [0.8, xm, 1.0, 1 / (d * d)] # reconstruct code value from spline code_value = 0 for i in range(0, 4): code_value += (hw[i] * v[i]) code_value = (code_value - enc_offset) / enc_gain # compute normalized sensor value ns = pow(10, code_value) if (code_value - offset) / slope > cut else ( code_value - offset) / slope ns = (ns - nz) * gray + black_signal return normalized_sensor_to_relative_exposure(ns, exposure_index) cs.to_reference_transforms = [] if transfer_function == 'V3 LogC': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = normalized_log_c_to_linear(c / (lut_resolution_1d - 1), int(exposure_index)) lut = '%s_to_linear.spi1d' % ('%s_%s' % (transfer_function, exposure_index)) lut = sanitize(lut) genlut.write_SPI_1d(os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward' }) if gamut == 'Wide Gamut': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([ 0.680206, 0.236137, 0.083658, 0.085415, 1.017471, -0.102886, 0.002057, -0.062563, 1.060506 ]), 'direction': 'forward' }) cs.from_reference_transforms = [] return cs
def create_s_log(gamut, transfer_function, lut_directory, lut_resolution_1d, aliases): """ Creates colorspace covering the conversion from Sony spaces to ACES, with various transfer functions and encoding gamuts covered Parameters ---------- gamut : str The name of the encoding gamut to use. transfer_function : str The name of the transfer function to use lut_directory : str or unicode The directory to use when generating LUTs lut_resolution_1d : int The resolution of generated 1D LUTs aliases : list of str Aliases for this colorspace Returns ------- ColorSpace A ColorSpace container class referencing the LUTs, matrices and identifying information for the requested colorspace. """ name = '%s - %s' % (transfer_function, gamut) if transfer_function == '': name = 'Linear - %s' % gamut if gamut == '': name = 'Curve - %s' % transfer_function cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/Sony' cs.is_data = False if gamut and transfer_function: cs.aces_transform_id = 'IDT.Sony.%s_%s_10i.a1.v1' % ( transfer_function.replace('-', ''), gamut.replace('-', '').replace( ' ', '_')) # A linear space needs allocation variables. if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] def s_log1_to_linear(s_log): b = 64. ab = 90. w = 940. if s_log >= ab: linear = ((pow(10., ( ((s_log - b) / (w - b) - 0.616596 - 0.03) / 0.432699)) - 0.037584) * 0.9) else: linear = (((s_log - b) / (w - b) - 0.030001222851889303) / 5.) * 0.9 return linear def s_log2_to_linear(s_log): b = 64. ab = 90. w = 940. if s_log >= ab: linear = ((219. * (pow(10., ( ((s_log - b) / (w - b) - 0.616596 - 0.03) / 0.432699)) - 0.037584) / 155.) * 0.9) else: linear = ( ((s_log - b) / (w - b) - 0.030001222851889303) / 3.53881278538813) * 0.9 return linear def s_log3_to_linear(code_value): if code_value >= 171.2102946929: linear = (pow(10, ((code_value - 420) / 261.5)) * (0.18 + 0.01) - 0.01) else: linear = (code_value - 95) * 0.01125000 / (171.2102946929 - 95) return linear cs.to_reference_transforms = [] if transfer_function == 'S-Log1': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = s_log1_to_linear(1023 * c / (lut_resolution_1d - 1)) lut = '%s_to_linear.spi1d' % transfer_function genlut.write_SPI_1d(os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward' }) elif transfer_function == 'S-Log2': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = s_log2_to_linear(1023 * c / (lut_resolution_1d - 1)) lut = '%s_to_linear.spi1d' % transfer_function genlut.write_SPI_1d(os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward' }) elif transfer_function == 'S-Log3': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = s_log3_to_linear(1023 * c / (lut_resolution_1d - 1)) lut = '%s_to_linear.spi1d' % transfer_function genlut.write_SPI_1d(os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward' }) if gamut == 'S-Gamut': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([ 0.754338638, 0.133697046, 0.111968437, 0.021198141, 1.005410934, -0.026610548, -0.009756991, 0.004508563, 1.005253201 ]), 'direction': 'forward' }) elif gamut == 'S-Gamut Daylight': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([ 0.8764457030, 0.0145411681, 0.1090131290, 0.0774075345, 0.9529571767, -0.0303647111, 0.0573564351, -0.1151066335, 1.0577501984 ]), 'direction': 'forward' }) elif gamut == 'S-Gamut Tungsten': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([ 1.0110238740, -0.1362526051, 0.1252287310, 0.1011994504, 0.9562196265, -0.0574190769, 0.0600766530, -0.1010185315, 1.0409418785 ]), 'direction': 'forward' }) elif gamut == 'S-Gamut3.Cine': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([ 0.6387886672, 0.2723514337, 0.0888598992, -0.0039159061, 1.0880732308, -0.0841573249, -0.0299072021, -0.0264325799, 1.0563397820 ]), 'direction': 'forward' }) elif gamut == 'S-Gamut3': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([ 0.7529825954, 0.1433702162, 0.1036471884, 0.0217076974, 1.0153188355, -0.0370265329, -0.0094160528, 0.0033704179, 1.0060456349 ]), 'direction': 'forward' }) cs.from_reference_transforms = [] return cs
def create_matrix_colorspace(name='matrix', from_reference_values=None, to_reference_values=None, aliases=None): """ Creates a ColorSpace that only uses *Matrix Transforms* Parameters ---------- name : str, optional Aliases for this colorspace from_reference_values : list of matrices List of matrices to convert from the reference colorspace to this space to_reference_values : list of matrices List of matrices to convert to the reference colorspace from this space aliases : list of str, optional Aliases for this colorspace Returns ------- ColorSpace A *Matrix Transform*-based ColorSpace """ if from_reference_values is None: from_reference_values = [] if to_reference_values is None: to_reference_values = [] if aliases is None: aliases = [] cs = ColorSpace(name) cs.description = 'The %s color space' % name cs.aliases = aliases cs.equality_group = name cs.family = 'Utility' cs.is_data = False # A linear space needs allocation variables. cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] cs.to_reference_transforms = [] if to_reference_values: for matrix in to_reference_values: cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(matrix), 'direction': 'forward' }) cs.from_reference_transforms = [] if from_reference_values: for matrix in from_reference_values: cs.from_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(matrix), 'direction': 'forward' }) return cs
def create_matrix_plus_transfer_colorspace( name='matrix_plus_transfer', transfer_function_name='transfer_function', transfer_function=lambda x: x, lut_directory='/tmp', lut_resolution_1d=1024, from_reference_values=None, to_reference_values=None, aliases=None): """ Creates a ColorSpace that uses transfer functions encoded as 1D LUTs and matrice Parameters ---------- name : str, optional Aliases for this colorspace transfer_function_name : str, optional The name of the transfer function transfer_function : function, optional The transfer function to be evaluated lut_directory : str or unicode The directory to use when generating LUTs lut_resolution_1d : int The resolution of generated 1D LUTs from_reference_values : list of matrices List of matrices to convert from the reference colorspace to this space to_reference_values : list of matrices List of matrices to convert to the reference colorspace from this space aliases : list of str Aliases for this colorspace Returns ------- ColorSpace A *Matrx and LUT1D Transform*-based ColorSpace representing a transfer function and matrix """ if from_reference_values is None: from_reference_values = [] if to_reference_values is None: to_reference_values = [] if aliases is None: aliases = [] cs = ColorSpace(name) cs.description = 'The %s color space' % name cs.aliases = aliases cs.equality_group = name cs.family = 'Utility' cs.is_data = False # A linear space needs allocation variables. cs.allocation_type = ocio.Constants.ALLOCATION_UNIFORM cs.allocation_vars = [0, 1] # Sampling the transfer function. data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = transfer_function(c / (lut_resolution_1d - 1)) # Writing the sampled data to a *LUT*. lut = '%s_to_linear.spi1d' % transfer_function_name genlut.write_SPI_1d(os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) # Creating the *to_reference* transforms. cs.to_reference_transforms = [] if to_reference_values: cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward' }) for matrix in to_reference_values: cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(matrix), 'direction': 'forward' }) # Creating the *from_reference* transforms. cs.from_reference_transforms = [] if from_reference_values: for matrix in from_reference_values: cs.from_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(matrix), 'direction': 'forward' }) cs.from_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'inverse' }) return cs
def create_ODTs( aces_ctl_directory, lut_directory, lut_resolution_1d, lut_resolution_3d, odt_info, shaper_name, cleanup, linear_display_space, log_display_space, ): """ Object description. Parameters ---------- parameter : type Parameter description. Returns ------- type Return value description. """ colorspaces = [] displays = {} # ------------------------------------------------------------------------- # *RRT / ODT* Shaper Options # ------------------------------------------------------------------------- shaper_data = {} # Defining the *Log 2* shaper. log2_shaper_name = shaper_name log2_shaper_name_aliases = ["crv_%s" % compact(log2_shaper_name)] log2_params = {"middleGrey": 0.18, "minExposure": -6, "maxExposure": 6.5} log2_shaper_colorspace = create_generic_log( aces_ctl_directory, lut_directory, lut_resolution_1d, cleanup, name=log2_shaper_name, middle_grey=log2_params["middleGrey"], min_exposure=log2_params["minExposure"], max_exposure=log2_params["maxExposure"], aliases=log2_shaper_name_aliases, ) colorspaces.append(log2_shaper_colorspace) shaper_input_scale_generic_log2 = 1 # *Log 2* shaper name and *CTL* transforms bundled up. log2_shaper_data = [ log2_shaper_name, os.path.join("%s", "utilities", "ACESlib.Log2_to_Lin_param.a1.0.0.ctl"), os.path.join("%s", "utilities", "ACESlib.Lin_to_Log2_param.a1.0.0.ctl"), shaper_input_scale_generic_log2, log2_params, ] shaper_data[log2_shaper_name] = log2_shaper_data # Space with a more user-friendly name. Direct copy otherwise. log2_shaper_copy_name = "Log2 Shaper" log2_shaper_copy_colorspace = ColorSpace(log2_shaper_copy_name) log2_shaper_copy_colorspace.description = "The %s color space" % log2_shaper_copy_name log2_shaper_copy_colorspace.aliases = ["crv_%s" % compact(log2_shaper_copy_name)] log2_shaper_copy_colorspace.equality_group = log2_shaper_copy_name log2_shaper_copy_colorspace.family = log2_shaper_colorspace.family log2_shaper_copy_colorspace.is_data = log2_shaper_colorspace.is_data log2_shaper_copy_colorspace.to_reference_transforms = list(log2_shaper_colorspace.to_reference_transforms) log2_shaper_copy_colorspace.from_reference_transforms = list(log2_shaper_colorspace.from_reference_transforms) colorspaces.append(log2_shaper_copy_colorspace) # Defining the *Log2 shaper that includes the AP1* primaries. log2_shaper_api1_name = "%s - AP1" % "Log2 Shaper" log2_shaper_api1_colorspace = ColorSpace(log2_shaper_api1_name) log2_shaper_api1_colorspace.description = "The %s color space" % log2_shaper_api1_name log2_shaper_api1_colorspace.aliases = ["%s_ap1" % compact(log2_shaper_copy_name)] log2_shaper_api1_colorspace.equality_group = log2_shaper_api1_name log2_shaper_api1_colorspace.family = log2_shaper_colorspace.family log2_shaper_api1_colorspace.is_data = log2_shaper_colorspace.is_data log2_shaper_api1_colorspace.to_reference_transforms = list(log2_shaper_colorspace.to_reference_transforms) log2_shaper_api1_colorspace.from_reference_transforms = list(log2_shaper_colorspace.from_reference_transforms) # *AP1* primaries to *AP0* primaries. log2_shaper_api1_colorspace.to_reference_transforms.append( {"type": "matrix", "matrix": mat44_from_mat33(ACES_AP1_TO_AP0), "direction": "forward"} ) colorspaces.append(log2_shaper_api1_colorspace) # Defining the *Log2 shaper that includes the AP1* primaries. # Named with 'shaper_name' variable. Needed for some LUT baking steps. shaper_api1_name = "%s - AP1" % shaper_name shaper_api1_colorspace = ColorSpace(shaper_api1_name) shaper_api1_colorspace.description = "The %s color space" % shaper_api1_name shaper_api1_colorspace.aliases = ["%s_ap1" % compact(shaper_name)] shaper_api1_colorspace.equality_group = shaper_api1_name shaper_api1_colorspace.family = log2_shaper_colorspace.family shaper_api1_colorspace.is_data = log2_shaper_colorspace.is_data shaper_api1_colorspace.to_reference_transforms = list(log2_shaper_api1_colorspace.to_reference_transforms) shaper_api1_colorspace.from_reference_transforms = list(log2_shaper_api1_colorspace.from_reference_transforms) colorspaces.append(shaper_api1_colorspace) # Define the base *Dolby PQ Shaper* # dolbypq_shaper_name = "Dolby PQ 10000" dolbypq_shaper_name_aliases = ["crv_%s" % "dolbypq_10000"] dolbypq_shaper_colorspace = create_dolbypq( aces_ctl_directory, lut_directory, lut_resolution_1d, cleanup, name=dolbypq_shaper_name, aliases=dolbypq_shaper_name_aliases, ) colorspaces.append(dolbypq_shaper_colorspace) # *Dolby PQ* shaper name and *CTL* transforms bundled up. dolbypq_shaper_data = [ dolbypq_shaper_name, os.path.join("%s", "utilities", "ACESlib.DolbyPQ_to_Lin.a1.0.0.ctl"), os.path.join("%s", "utilities", "ACESlib.Lin_to_DolbyPQ.a1.0.0.ctl"), 1.0, {}, ] shaper_data[dolbypq_shaper_name] = dolbypq_shaper_data # Define the *Dolby PQ Shaper that considers a fixed linear range* # dolbypq_scaled_shaper_name = "Dolby PQ Scaled" dolbypq_scaled_shaper_name_aliases = ["crv_%s" % "dolbypq_scaled"] dolbypq_scaled_shaper_colorspace = create_dolbypq_scaled( aces_ctl_directory, lut_directory, lut_resolution_1d, cleanup, name=dolbypq_scaled_shaper_name, aliases=dolbypq_scaled_shaper_name_aliases, ) colorspaces.append(dolbypq_scaled_shaper_colorspace) # *Dolby PQ* shaper name and *CTL* transforms bundled up. dolbypq_scaled_shaper_data = [ dolbypq_scaled_shaper_name, os.path.join("%s", "utilities", "ACESlib.DolbyPQ_to_Lin_param.a1.0.0.ctl"), os.path.join("%s", "utilities", "ACESlib.Lin_to_DolbyPQ_param.a1.0.0.ctl"), 1.0, log2_params, ] shaper_data[dolbypq_scaled_shaper_name] = dolbypq_scaled_shaper_data # # Pick a specific shaper # rrt_shaper = log2_shaper_data # rrt_shaper = dolbypq_scaled_shaper_data # *RRT + ODT* combinations. sorted_odts = sorted(odt_info.iteritems(), key=lambda x: x[1]) print(sorted_odts) for odt in sorted_odts: (odt_name, odt_values) = odt # Generating only full range transform for *ODTs* that can generate # either *legal* or *full* output. # Uncomment these lines and the lower section and flip the 'legalRange' value to 1 # to recover the old behavior, where both legal and full range LUTs were generated if odt_values["transformHasFullLegalSwitch"]: # odt_name_legal = '%s - Legal' % odt_values['transformUserName'] odt_legal["legalRange"] = 0 # else: # odt_name_legal = odt_values['transformUserName'] odt_name_legal = odt_values["transformUserName"] odt_legal = odt_values.copy() odt_aliases = ["out_%s" % compact(odt_name_legal)] cs = create_ACES_RRT_plus_ODT( odt_name_legal, odt_legal, rrt_shaper, aces_ctl_directory, lut_directory, lut_resolution_1d, lut_resolution_3d, cleanup, odt_aliases, ) colorspaces.append(cs) displays[odt_name_legal] = {"Raw": linear_display_space, "Log": log_display_space, "Output Transform": cs} """ # Generating full range transform for *ODTs* that can generate # either *legal* or *full* output. if odt_values['transformHasFullLegalSwitch']: print('Generating full range ODT for %s' % odt_name) odt_name_full = '%s - Full' % odt_values['transformUserName'] odt_full = odt_values.copy() odt_full['legalRange'] = 0 odt_full_aliases = ["out_%s" % compact(odt_name_full)] cs_full = create_ACES_RRT_plus_ODT( odt_name_full, odt_full, rrt_shaper, aces_ctl_directory, lut_directory, lut_resolution_1d, lut_resolution_3d, cleanup, odt_full_aliases) colorspaces.append(cs_full) displays[odt_name_full] = { 'Raw': linear_display_space, 'Log': log_display_space, 'Output Transform': cs_full} """ return (colorspaces, displays)
def create_ACEScc(aces_ctl_directory, lut_directory, lut_resolution_1d, cleanup, name='ACEScc', min_value=0, max_value=1, input_scale=1): """ Creates the *ACEScc* colorspace. Parameters ---------- parameter : type Parameter description. Returns ------- Colorspace *ACEScc* colorspace. """ cs = ColorSpace(name) cs.description = 'The %s color space' % name cs.aliases = ["acescc_ap1"] cs.equality_group = '' cs.family = 'ACES' cs.is_data = False cs.allocation_type = ocio.Constants.ALLOCATION_UNIFORM cs.allocation_vars = [min_value, max_value] ctls = [os.path.join(aces_ctl_directory, 'ACEScc', 'ACEScsc.ACEScc_to_ACES.a1.0.0.ctl')] lut = '%s_to_linear.spi1d' % name lut = sanitize(lut) generate_1d_LUT_from_CTL( os.path.join(lut_directory, lut), ctls, lut_resolution_1d, 'float', input_scale, 1, {'transferFunctionOnly':1}, cleanup, aces_ctl_directory, min_value, max_value, 1) cs.to_reference_transforms = [] cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) # *AP1* primaries to *AP0* primaries. cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(ACES_AP1_TO_AP0), 'direction': 'forward'}) cs.from_reference_transforms = [] return cs
def create_matrix_plus_gamma_colorspace(name='matrix_plus_gamma', gamma_value=1.0, from_reference_values=None, to_reference_values=None, aliases=None): """ Creates a colorspace expressed as a single or multiple *MatrixTransform* and an *ExponentTransform* transformations. Parameters ---------- name : str, optional Aliases for this colorspace. gamma_value : function, optional The gamma value. from_reference_values : list of matrices List of matrices to convert from the reference colorspace to this colorspace. to_reference_values : list of matrices List of matrices to convert to the reference colorspace from this colorspace. aliases : list of str Aliases for this colorspace. Returns ------- ColorSpace A colorspace expressed as a single or multiple *MatrixTransform* and an *ExponentTransform* transformations. """ if from_reference_values is None: from_reference_values = [] if to_reference_values is None: to_reference_values = [] if aliases is None: aliases = [] cs = ColorSpace(name) cs.description = 'The {0} color space'.format(name) cs.aliases = aliases cs.equality_group = name cs.family = 'Utility' cs.is_data = False cs.allocation_type = ocio.Constants.ALLOCATION_UNIFORM cs.allocation_vars = [0, 1] # Creating the *to_reference* transforms. cs.to_reference_transforms = [] if to_reference_values: cs.to_reference_transforms.append({ 'type': 'exponent', 'value': [gamma_value, gamma_value, gamma_value, 1] }) for matrix in to_reference_values: cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(matrix), 'direction': 'forward' }) # Creating the *from_reference* transforms. cs.from_reference_transforms = [] if from_reference_values: for matrix in from_reference_values: cs.from_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(matrix), 'direction': 'forward' }) cs.from_reference_transforms.append({ 'type': 'exponent', 'value': [1.0 / gamma_value, 1.0 / gamma_value, 1.0 / gamma_value, 1] }) return cs
def create_ACES_LMT( lmt_name, lmt_values, shaper_info, aces_ctl_directory, lut_directory, lut_resolution_1d=1024, lut_resolution_3d=64, cleanup=True, aliases=None, ): """ Creates the *ACES LMT* colorspace. Parameters ---------- parameter : type Parameter description. Returns ------- Colorspace *ACES LMT* colorspace. """ if aliases is None: aliases = [] cs = ColorSpace("%s" % lmt_name) cs.description = "The ACES Look Transform: %s" % lmt_name cs.aliases = aliases cs.equality_group = "" cs.family = "Look" cs.is_data = False cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] cs.aces_transform_id = lmt_values["transformID"] pprint.pprint(lmt_values) # Generating the *shaper* transform. (shaper_name, shaper_to_ACES_CTL, shaper_from_ACES_CTL, shaper_input_scale, shaper_params) = shaper_info # Add the shaper transform shaper_lut = "%s_to_linear.spi1d" % shaper_name shaper_lut = sanitize(shaper_lut) shaper_OCIO_transform = {"type": "lutFile", "path": shaper_lut, "interpolation": "linear", "direction": "inverse"} # Generating the forward transform. cs.from_reference_transforms = [] if "transformCTL" in lmt_values: ctls = [shaper_to_ACES_CTL % aces_ctl_directory, os.path.join(aces_ctl_directory, lmt_values["transformCTL"])] lut = "%s.%s.spi3d" % (shaper_name, lmt_name) lut = sanitize(lut) generate_3d_LUT_from_CTL( os.path.join(lut_directory, lut), ctls, lut_resolution_3d, "float", 1 / shaper_input_scale, 1, shaper_params, cleanup, aces_ctl_directory, ) cs.from_reference_transforms.append(shaper_OCIO_transform) cs.from_reference_transforms.append( {"type": "lutFile", "path": lut, "interpolation": "tetrahedral", "direction": "forward"} ) # Generating the inverse transform. cs.to_reference_transforms = [] if "transformCTLInverse" in lmt_values: ctls = [ os.path.join(aces_ctl_directory, lmt_values["transformCTLInverse"]), shaper_from_ACES_CTL % aces_ctl_directory, ] lut = "Inverse.%s.%s.spi3d" % (odt_name, shaper_name) lut = sanitize(lut) generate_3d_LUT_from_CTL( os.path.join(lut_directory, lut), ctls, lut_resolution_3d, "half", 1, shaper_input_scale, shaper_params, cleanup, aces_ctl_directory, 0, 1, 1, ) cs.to_reference_transforms.append( {"type": "lutFile", "path": lut, "interpolation": "tetrahedral", "direction": "forward"} ) shaper_inverse = shaper_OCIO_transform.copy() shaper_inverse["direction"] = "forward" cs.to_reference_transforms.append(shaper_inverse) return cs
def create_gamma_colorspace(name='gamma', gamma_value=1.0, aliases=None): """ Creates a colorspace expressed as an *ExponentTransform* transformation. Parameters ---------- name : str, optional Aliases for this colorspace. gamma_value : function, optional The gamma value. aliases : list of str Aliases for this colorspace. Returns ------- ColorSpace A colorspace expressed as an *ExponentTransform* transformation. """ if aliases is None: aliases = [] cs = ColorSpace(name) cs.description = 'The {0} color space'.format(name) cs.aliases = aliases cs.equality_group = name cs.family = 'Utility' cs.is_data = False # A linear space needs allocation variables. cs.allocation_type = ocio.Constants.ALLOCATION_UNIFORM cs.allocation_vars = [0, 1] # Creating the *to_reference* transforms. cs.to_reference_transforms = [] cs.to_reference_transforms.append({ 'type': 'exponent', 'value': [gamma_value, gamma_value, gamma_value, 1] }) # Creating the *from_reference* transforms. cs.from_reference_transforms = [] return cs
def create_s_log(gamut, transfer_function, lut_directory, lut_resolution_1d, aliases): """ Creates colorspace covering the conversion from Sony spaces to ACES, with various transfer functions and encoding gamuts covered Parameters ---------- gamut : str The name of the encoding gamut to use. transfer_function : str The name of the transfer function to use lut_directory : str or unicode The directory to use when generating LUTs lut_resolution_1d : int The resolution of generated 1D LUTs aliases : list of str Aliases for this colorspace Returns ------- ColorSpace A ColorSpace container class referencing the LUTs, matrices and identifying information for the requested colorspace. """ name = '%s - %s' % (transfer_function, gamut) if transfer_function == '': name = 'Linear - %s' % gamut if gamut == '': name = 'Curve - %s' % transfer_function cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/Sony' cs.is_data = False if gamut and transfer_function: cs.aces_transform_id = 'IDT.Sony.%s_%s_10i.a1.v1' % ( transfer_function.replace('-', ''), gamut.replace('-', '').replace(' ', '_')) # A linear space needs allocation variables. if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] def s_log1_to_linear(s_log): b = 64. ab = 90. w = 940. if s_log >= ab: linear = ((pow(10., (((s_log - b) / (w - b) - 0.616596 - 0.03) / 0.432699)) - 0.037584) * 0.9) else: linear = (((s_log - b) / ( w - b) - 0.030001222851889303) / 5.) * 0.9 return linear def s_log2_to_linear(s_log): b = 64. ab = 90. w = 940. if s_log >= ab: linear = ((219. * (pow(10., (((s_log - b) / (w - b) - 0.616596 - 0.03) / 0.432699)) - 0.037584) / 155.) * 0.9) else: linear = (((s_log - b) / ( w - b) - 0.030001222851889303) / 3.53881278538813) * 0.9 return linear def s_log3_to_linear(code_value): if code_value >= 171.2102946929: linear = (pow(10, ((code_value - 420) / 261.5)) * (0.18 + 0.01) - 0.01) else: linear = (code_value - 95) * 0.01125000 / (171.2102946929 - 95) return linear cs.to_reference_transforms = [] if transfer_function == 'S-Log1': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = s_log1_to_linear(1023 * c / (lut_resolution_1d - 1)) lut = '%s_to_linear.spi1d' % transfer_function genlut.write_SPI_1d( os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) elif transfer_function == 'S-Log2': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = s_log2_to_linear(1023 * c / (lut_resolution_1d - 1)) lut = '%s_to_linear.spi1d' % transfer_function genlut.write_SPI_1d( os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) elif transfer_function == 'S-Log3': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = s_log3_to_linear(1023 * c / (lut_resolution_1d - 1)) lut = '%s_to_linear.spi1d' % transfer_function genlut.write_SPI_1d( os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) if gamut == 'S-Gamut': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33( [0.754338638, 0.133697046, 0.111968437, 0.021198141, 1.005410934, -0.026610548, -0.009756991, 0.004508563, 1.005253201]), 'direction': 'forward'}) elif gamut == 'S-Gamut Daylight': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33( [0.8764457030, 0.0145411681, 0.1090131290, 0.0774075345, 0.9529571767, -0.0303647111, 0.0573564351, -0.1151066335, 1.0577501984]), 'direction': 'forward'}) elif gamut == 'S-Gamut Tungsten': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33( [1.0110238740, -0.1362526051, 0.1252287310, 0.1011994504, 0.9562196265, -0.0574190769, 0.0600766530, -0.1010185315, 1.0409418785]), 'direction': 'forward'}) elif gamut == 'S-Gamut3.Cine': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33( [0.6387886672, 0.2723514337, 0.0888598992, -0.0039159061, 1.0880732308, -0.0841573249, -0.0299072021, -0.0264325799, 1.0563397820]), 'direction': 'forward'}) elif gamut == 'S-Gamut3': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33( [0.7529825954, 0.1433702162, 0.1036471884, 0.0217076974, 1.0153188355, -0.0370265329, -0.0094160528, 0.0033704179, 1.0060456349]), 'direction': 'forward'}) cs.from_reference_transforms = [] return cs
def create_c_log(gamut, transfer_function, lut_directory, lut_resolution_1d, aliases): """ Creates colorspace covering the conversion from CLog to ACES, with various transfer functions and encoding gamuts covered Parameters ---------- gamut : str The name of the encoding gamut to use. transfer_function : str The name of the transfer function to use lut_directory : str or unicode The directory to use when generating LUTs lut_resolution_1d : int The resolution of generated 1D LUTs aliases : list of str Aliases for this colorspace Returns ------- ColorSpace A ColorSpace container class referencing the LUTs, matrices and identifying information for the requested colorspace. """ name = '%s - %s' % (transfer_function, gamut) if transfer_function == '': name = 'Linear - Canon %s' % gamut if gamut == '': name = 'Curve - %s' % transfer_function cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/Canon' cs.is_data = False # A linear space needs allocation variables. if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] def legal_to_full(code_value): return (code_value - 64) / (940 - 64) def c_log_to_linear(code_value): # log = fullToLegal(c1 * log10(c2*linear + 1) + c3) # linear = (pow(10, (legalToFul(log) - c3)/c1) - 1)/c2 c1 = 0.529136 c2 = 10.1596 c3 = 0.0730597 linear = (pow(10, (legal_to_full(code_value) - c3) / c1) - 1) / c2 linear *= 0.9 return linear def c_log2_to_linear(code_value): # log = fullToLegal(c1 * log10(c2*linear + 1) + c3) # linear = (pow(10, (legalToFul(log) - c3)/c1) - 1)/c2 c1 = 0.281863093 c2 = 87.09937546 c3 = 0.035388128 linear = (pow(10, (legal_to_full(code_value) - c3) / c1) - 1) / c2 linear *= 0.9 return linear cs.to_reference_transforms = [] if transfer_function: if transfer_function == 'Canon-Log': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = c_log_to_linear(1023 * c / (lut_resolution_1d - 1)) elif transfer_function == 'Canon-Log2': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = c_log2_to_linear(1023 * c / (lut_resolution_1d - 1)) lut = '%s_to_linear.spi1d' % transfer_function genlut.write_SPI_1d( os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) if gamut == 'Rec. 709 Daylight': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.561538969, 0.402060105, 0.036400926, 0, 0.092739623, 0.924121198, -0.016860821, 0, 0.084812961, 0.006373835, 0.908813204, 0, 0, 0, 0, 1], 'direction': 'forward'}) elif gamut == 'Rec. 709 Tungsten': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.566996399, 0.365079418, 0.067924183, 0, 0.070901044, 0.880331008, 0.048767948, 0, 0.073013542, -0.066540862, 0.99352732, 0, 0, 0, 0, 1], 'direction': 'forward'}) elif gamut == 'DCI-P3 Daylight': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.607160575, 0.299507286, 0.093332140, 0, 0.004968120, 1.050982224, -0.055950343, 0, -0.007839939, 0.000809127, 1.007030813, 0, 0, 0, 0, 1], 'direction': 'forward'}) elif gamut == 'DCI-P3 Tungsten': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.650279125, 0.253880169, 0.095840706, 0, -0.026137986, 1.017900530, 0.008237456, 0, 0.007757558, -0.063081669, 1.055324110, 0, 0, 0, 0, 1], 'direction': 'forward'}) elif gamut == 'Cinema Gamut Daylight': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.763064455, 0.149021161, 0.087914384, 0, 0.003657457, 1.10696038, -0.110617837, 0, -0.009407794, -0.218383305, 1.227791099, 0, 0, 0, 0, 1], 'direction': 'forward'}) elif gamut == 'Cinema Gamut Tungsten': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.817416293, 0.090755698, 0.091828009, 0, -0.035361374, 1.065690585, -0.030329211, 0, 0.010390366, -0.299271107, 1.288880741, 0, 0, 0, 0, 1], 'direction': 'forward'}) elif gamut == 'Rec. 2020 Daylight': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.678891151, 0.158868422, 0.162240427, 0, 0.045570831, 0.860712772, 0.093716397, 0, -0.000485710, 0.025060196, 0.975425515, 0, 0, 0, 0, 1], 'direction': 'forward'}) elif gamut == 'Rec. 2020 Tungsten': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.724488568, 0.115140904, 0.160370529, 0, 0.010659276, 0.839605344, 0.149735380, 0, 0.014560161, 0.028562057, 1.014001897, 0, 0, 0, 0, 1], 'direction': 'forward'}) cs.from_reference_transforms = [] return cs
def create_REDLog_film(gamut, transfer_function, lut_directory, lut_resolution_1D, aliases=None): """ Creates colorspace covering the conversion from *RED* spaces to *ACES*, with various transfer functions and encoding gamuts covered. Parameters ---------- gamut : str The name of the encoding gamut to use. transfer_function : str The name of the transfer function to use. lut_directory : str or unicode The directory to use when generating LUTs. lut_resolution_1D : int The resolution of generated 1D LUTs. aliases : list of str Aliases for this colorspace. Returns ------- ColorSpace A ColorSpace container class referencing the LUTs, matrices and identifying information for the requested colorspace. """ if aliases is None: aliases = [] name = '{0} - {1}'.format(transfer_function, gamut) if transfer_function == '': name = 'Linear - {0}'.format(gamut) if gamut == '': name = 'Curve - {0}'.format(transfer_function) cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/RED' cs.is_data = False # A linear space needs allocation variables if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] def Cineon_to_linear(code_value): n_gamma = 0.6 black_point = 95 white_point = 685 code_value_to_density = 0.002 black_linear = pow(10, (black_point - white_point) * (code_value_to_density / n_gamma)) code_linear = pow(10, (code_value - white_point) * (code_value_to_density / n_gamma)) return (code_linear - black_linear) / (1 - black_linear) def Log3G10_to_linear(code_value): a = 0.224282 b = 155.975327 c = 0.01 normalized_log = code_value / 1023.0 mirror = 1.0 if normalized_log < 0.0: mirror = -1.0 normalized_log = -normalized_log linear = (pow(10.0, normalized_log / a) - 1) / b linear = linear * mirror - c return linear cs.to_reference_transforms = [] if transfer_function: if transfer_function == 'REDlogFilm': lut_name = "CineonLog" data = array.array('f', b'\0' * lut_resolution_1D * 4) for c in range(lut_resolution_1D): data[c] = Cineon_to_linear(1023 * c / (lut_resolution_1D - 1)) elif transfer_function == 'REDLog3G10': lut_name = "REDLog3G10" data = array.array('f', b'\0' * lut_resolution_1D * 4) for c in range(lut_resolution_1D): data[c] = Log3G10_to_linear(1023 * c / (lut_resolution_1D - 1)) lut = '{0}_to_linear.spi1d'.format(lut_name) genlut.write_SPI_1D(os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1D, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward' }) if gamut == 'DRAGONcolor': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([ 0.532279, 0.376648, 0.091073, 0.046344, 0.974513, -0.020860, -0.053976, -0.000320, 1.054267 ]), 'direction': 'forward' }) elif gamut == 'DRAGONcolor2': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([ 0.468452, 0.331484, 0.200064, 0.040787, 0.857658, 0.101553, -0.047504, -0.000282, 1.047756 ]), 'direction': 'forward' }) elif gamut == 'REDcolor': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([ 0.451464, 0.388498, 0.160038, 0.062716, 0.866790, 0.070491, -0.017541, 0.086921, 0.930590 ]), 'direction': 'forward' }) elif gamut == 'REDcolor2': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([ 0.480997, 0.402289, 0.116714, -0.004938, 1.000154, 0.004781, -0.105257, 0.025320, 1.079907 ]), 'direction': 'forward' }) elif gamut == 'REDcolor3': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([ 0.512136, 0.360370, 0.127494, 0.070377, 0.903884, 0.025737, -0.020824, 0.017671, 1.003123 ]), 'direction': 'forward' }) elif gamut == 'REDcolor4': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([ 0.474202, 0.333677, 0.192121, 0.065164, 0.836932, 0.097901, -0.019281, 0.016362, 1.002889 ]), 'direction': 'forward' }) elif gamut == 'REDWideGamutRGB': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([ 0.785043, 0.083844, 0.131118, 0.023172, 1.087892, -0.111055, -0.073769, -0.314639, 1.388537 ]), 'direction': 'forward' }) cs.from_reference_transforms = [] return cs
def create_protune(gamut, transfer_function, lut_directory, lut_resolution_1d, aliases): """ Creates colorspace covering the conversion from ProTune to ACES, with various transfer functions and encoding gamuts covered Parameters ---------- gamut : str The name of the encoding gamut to use. transfer_function : str The name of the transfer function to use lut_directory : str or unicode The directory to use when generating LUTs lut_resolution_1d : int The resolution of generated 1D LUTs aliases : list of str Aliases for this colorspace Returns ------- ColorSpace A ColorSpace container class referencing the LUTs, matrices and identifying information for the requested colorspace. """ # The gamut should be marked as experimental until matrices are fully # verified. name = '%s - %s - Experimental' % (transfer_function, gamut) if transfer_function == '': name = 'Linear - %s - Experimental' % gamut if gamut == '': name = 'Curve - %s' % transfer_function cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/GoPro' cs.is_data = False # A linear space needs allocation variables. if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] def protune_to_linear(normalized_code_value): c1 = 113.0 c2 = 1.0 c3 = 112.0 linear = ((pow(c1, normalized_code_value) - c2) / c3) return linear cs.to_reference_transforms = [] if transfer_function == 'Protune Flat': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = protune_to_linear(float(c) / (lut_resolution_1d - 1)) lut = '%s_to_linear.spi1d' % transfer_function lut = sanitize(lut) genlut.write_SPI_1d( os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) if gamut == 'Protune Native': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.533448429, 0.32413911, 0.142412421, 0, -0.050729924, 1.07572006, -0.024990416, 0, 0.071419661, -0.290521962, 1.219102381, 0, 0, 0, 0, 1], 'direction': 'forward'}) cs.from_reference_transforms = [] return cs
def create_ODTs(aces_ctl_directory, lut_directory, lut_resolution_1d, lut_resolution_3d, odt_info, shaper_name, cleanup, linear_display_space, log_display_space): """ Object description. Parameters ---------- parameter : type Parameter description. Returns ------- type Return value description. """ colorspaces = [] displays = {} # ------------------------------------------------------------------------- # *RRT / ODT* Shaper Options # ------------------------------------------------------------------------- shaper_data = {} # Defining the *Log 2* shaper. log2_shaper_name = shaper_name log2_shaper_name_aliases = ['crv_%s' % compact(log2_shaper_name)] log2_params = { 'middleGrey': 0.18, 'minExposure': -6, 'maxExposure': 6.5} log2_shaper_colorspace = create_generic_log( aces_ctl_directory, lut_directory, lut_resolution_1d, cleanup, name=log2_shaper_name, middle_grey=log2_params['middleGrey'], min_exposure=log2_params['minExposure'], max_exposure=log2_params['maxExposure'], aliases=log2_shaper_name_aliases) colorspaces.append(log2_shaper_colorspace) shaper_input_scale_generic_log2 = 1 # *Log 2* shaper name and *CTL* transforms bundled up. log2_shaper_data = [ log2_shaper_name, os.path.join('%s', 'utilities', 'ACESlib.Log2_to_Lin_param.a1.0.0.ctl'), os.path.join('%s', 'utilities', 'ACESlib.Lin_to_Log2_param.a1.0.0.ctl'), shaper_input_scale_generic_log2, log2_params] shaper_data[log2_shaper_name] = log2_shaper_data # Space with a more user-friendly name. Direct copy otherwise. log2_shaper_copy_name = 'Log2 Shaper' log2_shaper_copy_colorspace = ColorSpace(log2_shaper_copy_name) log2_shaper_copy_colorspace.description = ( 'The %s color space' % log2_shaper_copy_name) log2_shaper_copy_colorspace.aliases = [ 'crv_%s' % compact(log2_shaper_copy_name)] log2_shaper_copy_colorspace.equality_group = log2_shaper_copy_name log2_shaper_copy_colorspace.family = log2_shaper_colorspace.family log2_shaper_copy_colorspace.is_data = log2_shaper_colorspace.is_data log2_shaper_copy_colorspace.to_reference_transforms = list( log2_shaper_colorspace.to_reference_transforms) log2_shaper_copy_colorspace.from_reference_transforms = list( log2_shaper_colorspace.from_reference_transforms) colorspaces.append(log2_shaper_copy_colorspace) # Defining the *Log2 shaper that includes the AP1* primaries. log2_shaper_api1_name = '%s - AP1' % 'Log2 Shaper' log2_shaper_api1_colorspace = ColorSpace(log2_shaper_api1_name) log2_shaper_api1_colorspace.description = ( 'The %s color space' % log2_shaper_api1_name) log2_shaper_api1_colorspace.aliases = [ '%s_ap1' % compact(log2_shaper_copy_name)] log2_shaper_api1_colorspace.equality_group = log2_shaper_api1_name log2_shaper_api1_colorspace.family = log2_shaper_colorspace.family log2_shaper_api1_colorspace.is_data = log2_shaper_colorspace.is_data log2_shaper_api1_colorspace.to_reference_transforms = list( log2_shaper_colorspace.to_reference_transforms) log2_shaper_api1_colorspace.from_reference_transforms = list( log2_shaper_colorspace.from_reference_transforms) # *AP1* primaries to *AP0* primaries log2_shaper_api1_colorspace.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(ACES_AP1_TO_AP0), 'direction': 'forward' }) colorspaces.append(log2_shaper_api1_colorspace) # Defining the *Log2* shaper that includes the *AP1* primaries. # Named with `shaper_name` variable and needed for some *LUT* baking steps. shaper_api1_name = '%s - AP1' % shaper_name shaper_api1_colorspace = ColorSpace(shaper_api1_name) shaper_api1_colorspace.description = ( 'The %s color space' % shaper_api1_name) shaper_api1_colorspace.aliases = ['%s_ap1' % compact(shaper_name)] shaper_api1_colorspace.equality_group = shaper_api1_name shaper_api1_colorspace.family = log2_shaper_colorspace.family shaper_api1_colorspace.is_data = log2_shaper_colorspace.is_data shaper_api1_colorspace.to_reference_transforms = list( log2_shaper_api1_colorspace.to_reference_transforms) shaper_api1_colorspace.from_reference_transforms = list( log2_shaper_api1_colorspace.from_reference_transforms) colorspaces.append(shaper_api1_colorspace) # Define the base *Dolby PQ Shaper* # dolby_pq_shaper_name = 'Dolby PQ 10000' dolby_pq_shaper_name_aliases = ['crv_%s' % 'dolbypq_10000'] dolby_pq_shaper_colorspace = create_Dolby_PQ( aces_ctl_directory, lut_directory, lut_resolution_1d, cleanup, name=dolby_pq_shaper_name, aliases=dolby_pq_shaper_name_aliases) colorspaces.append(dolby_pq_shaper_colorspace) # *Dolby PQ* shaper name and *CTL* transforms bundled up. dolby_pq_shaper_data = [ dolby_pq_shaper_name, os.path.join('%s', 'utilities', 'ACESlib.DolbyPQ_to_Lin.a1.0.0.ctl'), os.path.join('%s', 'utilities', 'ACESlib.Lin_to_DolbyPQ.a1.0.0.ctl'), 1.0, {}] shaper_data[dolby_pq_shaper_name] = dolby_pq_shaper_data # Define the *Dolby PQ Shaper that considers a fixed linear range* dolby_pq_scaled_shaper_name = 'Dolby PQ Scaled' dolby_pq_scaled_shaper_name_aliases = ['crv_%s' % 'dolbypq_scaled'] dolby_pq_scaled_shaper_colorspace = create_Dolby_PQ_scaled( aces_ctl_directory, lut_directory, lut_resolution_1d, cleanup, name=dolby_pq_scaled_shaper_name, aliases=dolby_pq_scaled_shaper_name_aliases) colorspaces.append(dolby_pq_scaled_shaper_colorspace) # *Dolby PQ* shaper name and *CTL* transforms bundled up. dolby_pq_scaled_shaper_data = [ dolby_pq_scaled_shaper_name, os.path.join('%s', 'utilities', 'ACESlib.OCIOShaper_to_Lin_param.a1.0.0.ctl'), os.path.join('%s', 'utilities', 'ACESlib.Lin_to_OCIOShaper_param.a1.0.0.ctl'), 1.0, log2_params] shaper_data[dolby_pq_scaled_shaper_name] = dolby_pq_scaled_shaper_data rrt_shaper = log2_shaper_data # rrt_shaper = dolby_pq_scaled_shaper_data # *RRT + ODT* combinations. sorted_odts = sorted(odt_info.iteritems(), key=lambda x: x[1]) print(sorted_odts) for odt in sorted_odts: (odt_name, odt_values) = odt # Defining full range transform for *ODTs* that can generate either # *legal* or *full* output. # Uncomment these lines and the lower section and # flip the `legalRange` value to 1 to restore the old behavior, # where both *legal* or *full* range *LUTs* were generated. if odt_values['transformHasFullLegalSwitch']: # odt_name_legal = '%s - Legal' % odt_values['transformUserName'] odt_legal['legalRange'] = 0 # else: # odt_name_legal = odt_values['transformUserName'] odt_name_legal = odt_values['transformUserName'] odt_legal = odt_values.copy() odt_aliases = ['out_%s' % compact(odt_name_legal)] cs = create_ACES_RRT_plus_ODT( odt_name_legal, odt_legal, rrt_shaper, aces_ctl_directory, lut_directory, lut_resolution_3d, cleanup, odt_aliases) colorspaces.append(cs) displays[odt_name_legal] = { 'Raw': linear_display_space, 'Log': log_display_space, 'Output Transform': cs} """ # Generating full range transform for *ODTs* that can generate # either *legal* or *full* output. if odt_values['transformHasFullLegalSwitch']: print('Generating full range ODT for %s' % odt_name) odt_name_full = '%s - Full' % odt_values['transformUserName'] odt_full = odt_values.copy() odt_full['legalRange'] = 0 odt_full_aliases = ['out_%s' % compact(odt_name_full)] cs_full = create_ACES_RRT_plus_ODT( odt_name_full, odt_full, rrt_shaper, aces_ctl_directory, lut_directory, lut_resolution_1d, lut_resolution_3d, cleanup, odt_full_aliases) colorspaces.append(cs_full) displays[odt_name_full] = { 'Raw': linear_display_space, 'Log': log_display_space, 'Output Transform': cs_full} """ return colorspaces, displays
def create_matrix_plus_transfer_colorspace( name='matrix_plus_transfer', transfer_function_name='transfer_function', transfer_function=lambda x: x, lut_directory='/tmp', lut_resolution_1D=1024, from_reference_values=None, to_reference_values=None, aliases=None): """ Creates a colorspace expressed as a single or multiple *MatrixTransform* and 1D LUT *FileTransform* transformations. Parameters ---------- name : str, optional Aliases for this colorspace. transfer_function_name : str, optional The name of the transfer function. transfer_function : function, optional The transfer function to be evaluated. lut_directory : str or unicode The directory to use when generating LUTs. lut_resolution_1D : int The resolution of generated 1D LUTs. from_reference_values : list of matrices List of matrices to convert from the reference colorspace to this colorspace. to_reference_values : list of matrices List of matrices to convert to the reference colorspace from this colorspace. aliases : list of str Aliases for this colorspace. Returns ------- ColorSpace A colorspace expressed as a single or multiple *MatrixTransform* and 1D LUT *FileTransform* transformations. """ if from_reference_values is None: from_reference_values = [] if to_reference_values is None: to_reference_values = [] if aliases is None: aliases = [] cs = ColorSpace(name) cs.description = 'The {0} color space'.format(name) cs.aliases = aliases cs.equality_group = name cs.family = 'Utility' cs.is_data = False # A linear space needs allocation variables. cs.allocation_type = ocio.Constants.ALLOCATION_UNIFORM cs.allocation_vars = [0, 1] # Sampling the transfer function. data = array.array('f', b'\0' * lut_resolution_1D * 4) for c in range(lut_resolution_1D): data[c] = transfer_function(c / (lut_resolution_1D - 1)) # Writing the sampled data to a *LUT*. lut = 'linear_to_{0}.spi1d'.format(transfer_function_name) genlut.write_SPI_1D(os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1D, 1) # Creating the *to_reference* transforms. cs.to_reference_transforms = [] if to_reference_values: cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'inverse' }) for matrix in to_reference_values: cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(matrix), 'direction': 'forward' }) # Creating the *from_reference* transforms. cs.from_reference_transforms = [] if from_reference_values: for matrix in from_reference_values: cs.from_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(matrix), 'direction': 'forward' }) cs.from_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward' }) return cs
def create_ACESproxy(aces_ctl_directory, lut_directory, lut_resolution_1d, cleanup, name='ACESproxy'): """ Creates the *ACESproxy* colorspace. Parameters ---------- parameter : type Parameter description. Returns ------- Colorspace *ACESproxy* colorspace. """ cs = ColorSpace(name) cs.description = 'The %s color space' % name cs.aliases = ['acesproxy', 'acesproxy_ap1'] cs.equality_group = '' cs.family = 'ACES' cs.is_data = False cs.aces_transform_id = 'ACEScsc.ACESproxy10i_to_ACES.a1.0.0' ctls = [os.path.join(aces_ctl_directory, 'ACESproxy', 'ACEScsc.ACESproxy10i_to_ACES.a1.0.0.ctl'), # This transform gets back to the *AP1* primaries. # Useful as the 1d LUT is only covering the transfer function. # The primaries switch is covered by the matrix below: os.path.join(aces_ctl_directory, 'ACEScg', 'ACEScsc.ACES_to_ACEScg.a1.0.0.ctl')] lut = '%s_to_linear.spi1d' % name lut = sanitize(lut) generate_1d_LUT_from_CTL( os.path.join(lut_directory, lut), ctls, lut_resolution_1d, 'float', 1, 1, {}, cleanup, aces_ctl_directory, 0, 1, 1) cs.to_reference_transforms = [] cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) # *AP1* primaries to *AP0* primaries cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(ACES_AP1_TO_AP0), 'direction': 'forward'}) cs.from_reference_transforms = [] return cs
def create_protune(gamut, transfer_function, lut_directory, lut_resolution_1d, aliases): """ Creates colorspace covering the conversion from ProTune to ACES, with various transfer functions and encoding gamuts covered Parameters ---------- gamut : str The name of the encoding gamut to use. transfer_function : str The name of the transfer function to use lut_directory : str or unicode The directory to use when generating LUTs lut_resolution_1d : int The resolution of generated 1D LUTs aliases : list of str Aliases for this colorspace Returns ------- ColorSpace A ColorSpace container class referencing the LUTs, matrices and identifying information for the requested colorspace. """ # The gamut should be marked as experimental until matrices are fully # verified. name = '%s - %s - Experimental' % (transfer_function, gamut) if transfer_function == '': name = 'Linear - %s - Experimental' % gamut if gamut == '': name = 'Curve - %s' % transfer_function cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/GoPro' cs.is_data = False # A linear space needs allocation variables. if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] def protune_to_linear(normalized_code_value): c1 = 113.0 c2 = 1.0 c3 = 112.0 linear = ((pow(c1, normalized_code_value) - c2) / c3) return linear cs.to_reference_transforms = [] if transfer_function == 'Protune Flat': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = protune_to_linear(float(c) / (lut_resolution_1d - 1)) lut = '%s_to_linear.spi1d' % transfer_function lut = sanitize(lut) genlut.write_SPI_1d(os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward' }) if gamut == 'Protune Native': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [ 0.533448429, 0.32413911, 0.142412421, 0, -0.050729924, 1.07572006, -0.024990416, 0, 0.071419661, -0.290521962, 1.219102381, 0, 0, 0, 0, 1 ], 'direction': 'forward' }) cs.from_reference_transforms = [] return cs
def create_ACEScg(): """ Creates the *ACEScg* colorspace. Parameters ---------- parameter : type Parameter description. Returns ------- Colorspace *ACEScg* colorspace. """ name = 'ACEScg' cs = ColorSpace(name) cs.description = 'The %s color space' % name cs.aliases = ['acescg', 'lin_ap1'] cs.equality_group = '' cs.family = 'ACES' cs.is_data = False cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] cs.aces_transform_id = 'ACEScsc.ACEScg_to_ACES.a1.0.0' cs.to_reference_transforms = [] # *AP1* primaries to *AP0* primaries cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(ACES_AP1_TO_AP0), 'direction': 'forward'}) cs.from_reference_transforms = [] # *AP1* primaries to *AP0* primaries cs.from_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(ACES_AP0_TO_AP1), 'direction': 'forward'}) return cs
def create_matrix_plus_transfer_colorspace( name='matrix_plus_transfer', transfer_function_name='transfer_function', transfer_function=lambda x: x, lut_directory='/tmp', lut_resolution_1d=1024, from_reference_values=None, to_reference_values=None, aliases=None): """ Creates a ColorSpace that uses transfer functions encoded as 1D LUTs and matrice Parameters ---------- name : str, optional Aliases for this colorspace transfer_function_name : str, optional The name of the transfer function transfer_function : function, optional The transfer function to be evaluated lut_directory : str or unicode The directory to use when generating LUTs lut_resolution_1d : int The resolution of generated 1D LUTs from_reference_values : list of matrices List of matrices to convert from the reference colorspace to this space to_reference_values : list of matrices List of matrices to convert to the reference colorspace from this space aliases : list of str Aliases for this colorspace Returns ------- ColorSpace A *Matrx and LUT1D Transform*-based ColorSpace representing a transfer function and matrix """ if from_reference_values is None: from_reference_values = [] if to_reference_values is None: to_reference_values = [] if aliases is None: aliases = [] cs = ColorSpace(name) cs.description = 'The %s color space' % name cs.aliases = aliases cs.equality_group = name cs.family = 'Utility' cs.is_data = False # A linear space needs allocation variables. cs.allocation_type = ocio.Constants.ALLOCATION_UNIFORM cs.allocation_vars = [0, 1] # Sampling the transfer function. data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = transfer_function(c / (lut_resolution_1d - 1)) # Writing the sampled data to a *LUT*. lut = '%s_to_linear.spi1d' % transfer_function_name genlut.write_SPI_1d( os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) # Creating the *to_reference* transforms. cs.to_reference_transforms = [] if to_reference_values: cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) for matrix in to_reference_values: cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(matrix), 'direction': 'forward'}) # Creating the *from_reference* transforms. cs.from_reference_transforms = [] if from_reference_values: for matrix in from_reference_values: cs.from_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33(matrix), 'direction': 'forward'}) cs.from_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'inverse'}) return cs
def create_ADX(lut_directory, bit_depth=10, name='ADX'): """ Creates the *ADX* colorspace. Parameters ---------- parameter : type Parameter description. Returns ------- Colorspace *ADX* colorspace. """ name = '%s%s' % (name, bit_depth) cs = ColorSpace(name) cs.description = '%s color space - used for film scans' % name cs.aliases = ['adx%s' % str(bit_depth)] cs.equality_group = '' cs.family = 'ADX' cs.is_data = False if bit_depth == 10: cs.aces_transform_id = 'ACEScsc.ADX10_to_ACES.a1.0.0' cs.bit_depth = ocio.Constants.BIT_DEPTH_UINT10 ADX_to_CDD = [1023 / 500, 0, 0, 0, 0, 1023 / 500, 0, 0, 0, 0, 1023 / 500, 0, 0, 0, 0, 1] offset = [-95 / 500, -95 / 500, -95 / 500, 0] elif bit_depth == 16: cs.aces_transform_id = 'ACEScsc.ADX16_to_ACES.a1.0.0' cs.bit_depth = ocio.Constants.BIT_DEPTH_UINT16 ADX_to_CDD = [65535 / 8000, 0, 0, 0, 0, 65535 / 8000, 0, 0, 0, 0, 65535 / 8000, 0, 0, 0, 0, 1] offset = [-1520 / 8000, -1520 / 8000, -1520 / 8000, 0] cs.to_reference_transforms = [] # Converting from *ADX* to *Channel-Dependent Density*. cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': ADX_to_CDD, 'offset': offset, 'direction': 'forward'}) # Converting from *Channel-Dependent Density* to # *Channel-Independent Density*. cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.75573, 0.22197, 0.02230, 0, 0.05901, 0.96928, -0.02829, 0, 0.16134, 0.07406, 0.76460, 0, 0, 0, 0, 1], 'direction': 'forward'}) # Copied from *Alex Fry*'s *adx_cid_to_rle.py* def create_CID_to_RLE_LUT(): def interpolate_1d(x, xp, fp): return numpy.interp(x, xp, fp) LUT_1D_XP = [-0.190000000000000, 0.010000000000000, 0.028000000000000, 0.054000000000000, 0.095000000000000, 0.145000000000000, 0.220000000000000, 0.300000000000000, 0.400000000000000, 0.500000000000000, 0.600000000000000] LUT_1D_FP = [-6.000000000000000, -2.721718645000000, -2.521718645000000, -2.321718645000000, -2.121718645000000, -1.921718645000000, -1.721718645000000, -1.521718645000000, -1.321718645000000, -1.121718645000000, -0.926545676714876] REF_PT = ((7120 - 1520) / 8000 * (100 / 55) - math.log(0.18, 10)) def cid_to_rle(x): if x <= 0.6: return interpolate_1d(x, LUT_1D_XP, LUT_1D_FP) return (100 / 55) * x - REF_PT def fit(value, from_min, from_max, to_min, to_max): if from_min == from_max: raise ValueError('from_min == from_max') return (value - from_min) / (from_max - from_min) * ( to_max - to_min) + to_min num_samples = 2 ** 12 domain = (-0.19, 3) data = [] for i in xrange(num_samples): x = i / (num_samples - 1) x = fit(x, 0, 1, domain[0], domain[1]) data.append(cid_to_rle(x)) lut = 'ADX_CID_to_RLE.spi1d' write_SPI_1d(os.path.join(lut_directory, lut), domain[0], domain[1], data, num_samples, 1) return lut # Converting *Channel Independent Density* values to # *Relative Log Exposure* values. lut = create_CID_to_RLE_LUT() cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) # Converting *Relative Log Exposure* values to # *Relative Exposure* values. cs.to_reference_transforms.append({ 'type': 'log', 'base': 10, 'direction': 'inverse'}) # Convert *Relative Exposure* values to *ACES* values. cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.72286, 0.12630, 0.15084, 0, 0.11923, 0.76418, 0.11659, 0, 0.01427, 0.08213, 0.90359, 0, 0, 0, 0, 1], 'direction': 'forward'}) cs.from_reference_transforms = [] return cs
def create_generic_log(aces_ctl_directory, lut_directory, lut_resolution_1d, cleanup, name='log', aliases=[], min_value=0, max_value=1, input_scale=1, middle_grey=0.18, min_exposure=-6, max_exposure=6.5): """ Creates the *Generic Log* colorspace. Parameters ---------- parameter : type Parameter description. Returns ------- Colorspace *Generic Log* colorspace. """ cs = ColorSpace(name) cs.description = 'The %s color space' % name cs.aliases = aliases cs.equality_group = name cs.family = 'Utility' cs.is_data = False ctls = [os.path.join( aces_ctl_directory, 'utilities', 'ACESlib.OCIO_shaper_log2_to_lin_param.a1.0.0.ctl')] lut = '%s_to_linear.spi1d' % name lut = sanitize(lut) generate_1d_LUT_from_CTL( os.path.join(lut_directory, lut), ctls, lut_resolution_1d, 'float', input_scale, 1, {'middleGrey': middle_grey, 'minExposure': min_exposure, 'maxExposure': max_exposure}, cleanup, aces_ctl_directory, min_value, max_value, 1) cs.to_reference_transforms = [] cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) cs.from_reference_transforms = [] return cs
def create_ACES_RRT_plus_ODT( odt_name, odt_values, shaper_info, aces_ctl_directory, lut_directory, lut_resolution_1d=1024, lut_resolution_3d=64, cleanup=True, aliases=None, ): """ Object description. Parameters ---------- parameter : type Parameter description. Returns ------- type Return value description. """ if aliases is None: aliases = [] cs = ColorSpace("%s" % odt_name) cs.description = "%s - %s Output Transform" % (odt_values["transformUserNamePrefix"], odt_name) cs.aliases = aliases cs.equality_group = "" cs.family = "Output" cs.is_data = False cs.aces_transform_id = odt_values["transformID"] pprint.pprint(odt_values) # Generating the *shaper* transform. (shaper_name, shaper_to_ACES_CTL, shaper_from_ACES_CTL, shaper_input_scale, shaper_params) = shaper_info if "legalRange" in odt_values: shaper_params["legalRange"] = odt_values["legalRange"] else: shaper_params["legalRange"] = 0 # Add the shaper transform shaper_lut = "%s_to_linear.spi1d" % shaper_name shaper_lut = sanitize(shaper_lut) shaper_OCIO_transform = {"type": "lutFile", "path": shaper_lut, "interpolation": "linear", "direction": "inverse"} # Generating the *forward* transform. cs.from_reference_transforms = [] if "transformLUT" in odt_values: transform_LUT_file_name = os.path.basename(odt_values["transformLUT"]) lut = os.path.join(lut_directory, transform_LUT_file_name) shutil.copy(odt_values["transformLUT"], lut) cs.from_reference_transforms.append(shaper_OCIO_transform) cs.from_reference_transforms.append( {"type": "lutFile", "path": transform_LUT_file_name, "interpolation": "tetrahedral", "direction": "forward"} ) elif "transformCTL" in odt_values: ctls = [ shaper_to_ACES_CTL % aces_ctl_directory, os.path.join(aces_ctl_directory, "rrt", "RRT.a1.0.0.ctl"), os.path.join(aces_ctl_directory, "odt", odt_values["transformCTL"]), ] lut = "%s.RRT.a1.0.0.%s.spi3d" % (shaper_name, odt_name) lut = sanitize(lut) generate_3d_LUT_from_CTL( os.path.join(lut_directory, lut), # shaperLUT, ctls, lut_resolution_3d, "float", 1 / shaper_input_scale, 1, shaper_params, cleanup, aces_ctl_directory, ) cs.from_reference_transforms.append(shaper_OCIO_transform) cs.from_reference_transforms.append( {"type": "lutFile", "path": lut, "interpolation": "tetrahedral", "direction": "forward"} ) # Generating the *inverse* transform. cs.to_reference_transforms = [] if "transformLUTInverse" in odt_values: transform_LUT_inverse_file_name = os.path.basename(odt_values["transformLUTInverse"]) lut = os.path.join(lut_directory, transform_LUT_inverse_file_name) shutil.copy(odt_values["transformLUTInverse"], lut) cs.to_reference_transforms.append( { "type": "lutFile", "path": transform_LUT_inverse_file_name, "interpolation": "tetrahedral", "direction": "forward", } ) shaper_inverse = shaper_OCIO_transform.copy() shaper_inverse["direction"] = "forward" cs.to_reference_transforms.append(shaper_inverse) elif "transformCTLInverse" in odt_values: ctls = [ os.path.join(aces_ctl_directory, "odt", odt_values["transformCTLInverse"]), os.path.join(aces_ctl_directory, "rrt", "InvRRT.a1.0.0.ctl"), shaper_from_ACES_CTL % aces_ctl_directory, ] lut = "InvRRT.a1.0.0.%s.%s.spi3d" % (odt_name, shaper_name) lut = sanitize(lut) generate_3d_LUT_from_CTL( os.path.join(lut_directory, lut), # None, ctls, lut_resolution_3d, "half", 1, shaper_input_scale, shaper_params, cleanup, aces_ctl_directory, ) cs.to_reference_transforms.append( {"type": "lutFile", "path": lut, "interpolation": "tetrahedral", "direction": "forward"} ) shaper_inverse = shaper_OCIO_transform.copy() shaper_inverse["direction"] = "forward" cs.to_reference_transforms.append(shaper_inverse) return cs
def create_protune(gamut, transfer_function, lut_directory, lut_resolution_1d, aliases): """ Object description. Protune to ACES. Parameters ---------- parameter : type Parameter description. Returns ------- type Return value description. """ # The gamut should be marked as experimental until matrices are fully # verified. name = '%s - %s - Experimental' % (transfer_function, gamut) if transfer_function == '': name = 'Linear - %s - Experimental' % gamut if gamut == '': name = 'Curve - %s' % transfer_function cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/GoPro' cs.is_data = False # A linear space needs allocation variables. if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] def protune_to_linear(normalized_code_value): c1 = 113.0 c2 = 1.0 c3 = 112.0 linear = ((pow(c1, normalized_code_value) - c2) / c3) return linear cs.to_reference_transforms = [] if transfer_function == 'Protune Flat': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = protune_to_linear(float(c) / (lut_resolution_1d - 1)) lut = '%s_to_linear.spi1d' % transfer_function lut = sanitize(lut) genlut.write_SPI_1d( os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward'}) if gamut == 'Protune Native': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': [0.533448429, 0.32413911, 0.142412421, 0, -0.050729924, 1.07572006, -0.024990416, 0, 0.071419661, -0.290521962, 1.219102381, 0, 0, 0, 0, 1], 'direction': 'forward'}) cs.from_reference_transforms = [] return cs
def create_log_c(gamut, transfer_function, exposure_index, lut_directory, lut_resolution_1d, aliases): """ Creates colorspace covering the conversion from LogC to ACES, with various transfer functions and encoding gamuts covered Parameters ---------- gamut : str The name of the encoding gamut to use. transfer_function : str The name of the transfer function to use exposure_index : str The exposure index to use lut_directory : str or unicode The directory to use when generating LUTs lut_resolution_1d : int The resolution of generated 1D LUTs aliases : list of str Aliases for this colorspace Returns ------- ColorSpace A ColorSpace container class referencing the LUTs, matrices and identifying information for the requested colorspace. """ name = '%s (EI%s) - %s' % (transfer_function, exposure_index, gamut) if transfer_function == '': name = 'Linear - ARRI %s' % gamut if gamut == '': name = 'Curve - %s (EI%s)' % (transfer_function, exposure_index) cs = ColorSpace(name) cs.description = name cs.aliases = aliases cs.equality_group = '' cs.family = 'Input/ARRI' cs.is_data = False if gamut and transfer_function: cs.aces_transform_id = ('IDT.ARRI.Alexa-v3-logC-EI%s.a1.v1' % exposure_index) # A linear space needs allocation variables. if transfer_function == '': cs.allocation_type = ocio.Constants.ALLOCATION_LG2 cs.allocation_vars = [-8, 5, 0.00390625] IDT_maker_version = '0.08' nominal_EI = 400 black_signal = 0.003907 mid_gray_signal = 0.01 encoding_gain = 0.256598 encoding_offset = 0.391007 def gain_for_EI(EI): return (math.log(EI / nominal_EI) / math.log(2) * (0.89 - 1) / 3 + 1) * encoding_gain def log_c_inverse_parameters_for_EI(EI): cut = 1 / 9 slope = 1 / (cut * math.log(10)) offset = math.log10(cut) - slope * cut gain = EI / nominal_EI gray = mid_gray_signal / gain # The higher the EI, the lower the gamma. enc_gain = gain_for_EI(EI) enc_offset = encoding_offset for i in range(0, 3): nz = ((95 / 1023 - enc_offset) / enc_gain - offset) / slope enc_offset = encoding_offset - math.log10(1 + nz) * enc_gain a = 1 / gray b = nz - black_signal / gray e = slope * a * enc_gain f = enc_gain * (slope * b + offset) + enc_offset # Ensuring we can return relative exposure. s = 4 / (0.18 * EI) t = black_signal b += a * t a *= s f += e * t e *= s return { 'a': a, 'b': b, 'cut': (cut - b) / a, 'c': enc_gain, 'd': enc_offset, 'e': e, 'f': f } def normalized_log_c_to_linear(code_value, exposure_index): p = log_c_inverse_parameters_for_EI(exposure_index) breakpoint = p['e'] * p['cut'] + p['f'] if code_value > breakpoint: linear = ((pow(10, (code_value - p['d']) / p['c']) - p['b']) / p['a']) else: linear = (code_value - p['f']) / p['e'] return linear cs.to_reference_transforms = [] if transfer_function == 'V3 LogC': data = array.array('f', '\0' * lut_resolution_1d * 4) for c in range(lut_resolution_1d): data[c] = normalized_log_c_to_linear(c / (lut_resolution_1d - 1), int(exposure_index)) lut = '%s_to_linear.spi1d' % ('%s_%s' % (transfer_function, exposure_index)) lut = sanitize(lut) genlut.write_SPI_1d(os.path.join(lut_directory, lut), 0, 1, data, lut_resolution_1d, 1) cs.to_reference_transforms.append({ 'type': 'lutFile', 'path': lut, 'interpolation': 'linear', 'direction': 'forward' }) if gamut == 'Wide Gamut': cs.to_reference_transforms.append({ 'type': 'matrix', 'matrix': mat44_from_mat33([ 0.680206, 0.236137, 0.083658, 0.085415, 1.017471, -0.102886, 0.002057, -0.062563, 1.060506 ]), 'direction': 'forward' }) cs.from_reference_transforms = [] return cs