def XYZ_to_sRGB(XYZ, illuminant=RGB_COLOURSPACES['sRGB'].whitepoint, chromatic_adaptation_transform='CAT02', apply_encoding_cctf=True): """ Converts from *CIE XYZ* tristimulus values to *sRGB* colourspace. Parameters ---------- XYZ : array_like *CIE XYZ* tristimulus values. illuminant : array_like, optional Source illuminant chromaticity coordinates. chromatic_adaptation_transform : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC'}**, *Chromatic adaptation* transform. apply_encoding_cctf : bool, optional Apply *sRGB* encoding colour component transfer function / opto-electronic transfer function. Returns ------- ndarray *sRGB* colour array. Notes ----- - Input *CIE XYZ* tristimulus values are in domain [0, 1]. Examples -------- >>> import numpy as np >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) >>> XYZ_to_sRGB(XYZ) # doctest: +ELLIPSIS array([ 0.1749881..., 0.3881947..., 0.3216031...]) """ sRGB = RGB_COLOURSPACES['sRGB'] return XYZ_to_RGB( XYZ, illuminant, sRGB.whitepoint, sRGB.XYZ_to_RGB_matrix, chromatic_adaptation_transform, sRGB.encoding_cctf if apply_encoding_cctf else None) # yapf: disable
def XYZ_to_sRGB( XYZ, illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65'], chromatic_adaptation_transform='CAT02', apply_encoding_cctf=True): """ Converts from *CIE XYZ* tristimulus values to *sRGB* colourspace. Parameters ---------- XYZ : array_like *CIE XYZ* tristimulus values. illuminant : array_like, optional Source illuminant chromaticity coordinates. chromatic_adaptation_transform : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC'}**, *Chromatic adaptation* transform. apply_encoding_cctf : bool, optional Apply *sRGB* encoding colour component transfer function / opto-electronic transfer function. Returns ------- ndarray *sRGB* colour array. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``RGB`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ Examples -------- >>> import numpy as np >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) >>> XYZ_to_sRGB(XYZ) # doctest: +ELLIPSIS array([ 0.7057393..., 0.1924826..., 0.2235416...]) """ sRGB = RGB_COLOURSPACES['sRGB'] return XYZ_to_RGB( XYZ, illuminant, sRGB.whitepoint, sRGB.XYZ_to_RGB_matrix, chromatic_adaptation_transform, sRGB.encoding_cctf if apply_encoding_cctf else None, )
def sd_to_aces_relative_exposure_values( sd, illuminant=ILLUMINANTS_SDS['D65'], apply_chromatic_adaptation=False, chromatic_adaptation_transform='CAT02'): """ Converts given spectral distribution to *ACES2065-1* colourspace relative exposure values. Parameters ---------- sd : SpectralDistribution Spectral distribution. illuminant : SpectralDistribution, optional *Illuminant* spectral distribution. apply_chromatic_adaptation : bool, optional Whether to apply chromatic adaptation using given transform. chromatic_adaptation_transform : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC'}**, *Chromatic adaptation* transform. Returns ------- ndarray, (3,) *ACES2065-1* colourspace relative exposure values array. Notes ----- +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ`` | [0, 100] | [0, 1] | +------------+-----------------------+---------------+ - The chromatic adaptation method implemented here is a bit unusual as it involves building a new colourspace based on *ACES2065-1* colourspace primaries but using the whitepoint of the illuminant that the spectral distribution was measured under. References ---------- :cite:`Forsythe2018`, :cite:`TheAcademyofMotionPictureArtsandSciences2014q`, :cite:`TheAcademyofMotionPictureArtsandSciences2014r`, :cite:`TheAcademyofMotionPictureArtsandSciencese` Examples -------- >>> from colour import COLOURCHECKERS_SDS >>> sd = COLOURCHECKERS_SDS['ColorChecker N Ohta']['dark skin'] >>> sd_to_aces_relative_exposure_values(sd) # doctest: +ELLIPSIS array([ 0.1171785..., 0.0866347..., 0.0589707...]) >>> sd_to_aces_relative_exposure_values(sd, ... apply_chromatic_adaptation=True) # doctest: +ELLIPSIS array([ 0.1180766..., 0.0869023..., 0.0589104...]) """ shape = ACES_RICD.shape if sd.shape != ACES_RICD.shape: sd = sd.copy().align(shape) if illuminant.shape != ACES_RICD.shape: illuminant = illuminant.copy().align(shape) s_v = sd.values i_v = illuminant.values r_bar, g_bar, b_bar = tsplit(ACES_RICD.values) def k(x, y): """ Computes the :math:`K_r`, :math:`K_g` or :math:`K_b` scale factors. """ return 1 / np.sum(x * y) k_r = k(i_v, r_bar) k_g = k(i_v, g_bar) k_b = k(i_v, b_bar) E_r = k_r * np.sum(i_v * s_v * r_bar) E_g = k_g * np.sum(i_v * s_v * g_bar) E_b = k_b * np.sum(i_v * s_v * b_bar) E_rgb = np.array([E_r, E_g, E_b]) # Accounting for flare. E_rgb += FLARE_PERCENTAGE E_rgb *= S_FLARE_FACTOR if apply_chromatic_adaptation: xy = XYZ_to_xy(sd_to_XYZ(illuminant) / 100) NPM = normalised_primary_matrix(ACES_2065_1_COLOURSPACE.primaries, xy) XYZ = RGB_to_XYZ(E_rgb, xy, ACES_2065_1_COLOURSPACE.whitepoint, NPM, chromatic_adaptation_transform) E_rgb = XYZ_to_RGB(XYZ, ACES_2065_1_COLOURSPACE.whitepoint, ACES_2065_1_COLOURSPACE.whitepoint, ACES_2065_1_COLOURSPACE.XYZ_to_RGB_matrix) return from_range_1(E_rgb)
def XYZ_to_sRGB( XYZ, illuminant=CCS_ILLUMINANTS['CIE 1931 2 Degree Standard Observer'] ['D65'], chromatic_adaptation_transform='CAT02', apply_cctf_encoding=True, **kwargs): """ Converts from *CIE XYZ* tristimulus values to *sRGB* colourspace. Parameters ---------- XYZ : array_like *CIE XYZ* tristimulus values. illuminant : array_like, optional Source illuminant chromaticity coordinates. chromatic_adaptation_transform : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02 Brill 2008', 'Bianco 2010', 'Bianco PC 2010'}**, *Chromatic adaptation* transform. apply_cctf_encoding : bool, optional Apply *sRGB* encoding colour component transfer function / opto-electronic transfer function. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- ndarray *sRGB* colour array. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``RGB`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ Examples -------- >>> import numpy as np >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) >>> XYZ_to_sRGB(XYZ) # doctest: +ELLIPSIS array([ 0.7057393..., 0.1924826..., 0.2235416...]) """ apply_cctf_encoding = handle_arguments_deprecation( { 'ArgumentRenamed': [['apply_encoding_cctf', 'apply_cctf_encoding'] ], }, **kwargs).get('apply_cctf_encoding', apply_cctf_encoding) sRGB = RGB_COLOURSPACES['sRGB'] return XYZ_to_RGB( XYZ, illuminant, sRGB.whitepoint, sRGB.matrix_XYZ_to_RGB, chromatic_adaptation_transform, sRGB.cctf_encoding if apply_cctf_encoding else None, )
def XYZ_to_ICtCp( XYZ: ArrayLike, illuminant=CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"]["D65"], chromatic_adaptation_transform: Union[Literal["Bianco 2010", "Bianco PC 2010", "Bradford", "CAT02 Brill 2008", "CAT02", "CAT16", "CMCCAT2000", "CMCCAT97", "Fairchild", "Sharp", "Von Kries", "XYZ Scaling", ], str, ] = "CAT02", method: Union[Literal["Dolby 2016", "ITU-R BT.2100-1 HLG", "ITU-R BT.2100-1 PQ", "ITU-R BT.2100-2 HLG", "ITU-R BT.2100-2 PQ", ], str, ] = "Dolby 2016", L_p: Floating = 10000, ) -> NDArray: """ Convert from *CIE XYZ* tristimulus values to :math:`IC_TC_P` colour encoding. Parameters ---------- XYZ *CIE XYZ* tristimulus values. illuminant Source illuminant chromaticity coordinates. chromatic_adaptation_transform *Chromatic adaptation* transform. method Computation method. *Recommendation ITU-R BT.2100* defines multiple variants of the :math:`IC_TC_P` colour encoding: - *ITU-R BT.2100-1* - *SMPTE ST 2084:2014* inverse electro-optical transfer function (EOTF) and the :math:`IC_TC_P` matrix from :cite:`Dolby2016a`: *Dolby 2016*, *ITU-R BT.2100-1 PQ*, *ITU-R BT.2100-2 PQ* methods. - *Recommendation ITU-R BT.2100* *Reference HLG* opto-electrical transfer function (OETF) and the :math:`IC_TC_P` matrix from :cite:`Dolby2016a`: *ITU-R BT.2100-1 HLG* method. - *ITU-R BT.2100-2* - *SMPTE ST 2084:2014* inverse electro-optical transfer function (EOTF) and the :math:`IC_TC_P` matrix from :cite:`Dolby2016a`: *Dolby 2016*, *ITU-R BT.2100-1 PQ*, *ITU-R BT.2100-2 PQ* methods. - *Recommendation ITU-R BT.2100* *Reference HLG* opto-electrical transfer function (OETF) and a custom :math:`IC_TC_P` matrix from :cite:`InternationalTelecommunicationUnion2018`: *ITU-R BT.2100-2 HLG* method. L_p Display peak luminance :math:`cd/m^2` for *SMPTE ST 2084:2014* non-linear encoding. This parameter should stay at its default :math:`10000 cd/m^2` value for practical applications. It is exposed so that the definition can be used as a fitting function. Returns ------- :class:`numpy.ndarray` :math:`IC_TC_P` colour encoding array. Warnings -------- The underlying *SMPTE ST 2084:2014* transfer function is an absolute transfer function. Notes ----- - The underlying *SMPTE ST 2084:2014* transfer function is an absolute transfer function, thus the domain and range values for the *Reference* - The *ITU-R BT.2100-1 PQ* and *ITU-R BT.2100-2 PQ* methods are aliases for the *Dolby 2016* method. and *1* scales are only indicative that the data is not affected by scale transformations. The effective domain of *SMPTE ST 2084:2014* inverse electro-optical transfer function (EOTF) is [0.0001, 10000]. +------------+-----------------------+------------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+==================+ | ``XYZ`` | ``UN`` | ``UN`` | +------------+-----------------------+------------------+ +------------+-----------------------+------------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+==================+ | ``ICtCp`` | ``I`` : [0, 1] | ``I`` : [0, 1] | | | | | | | ``CT`` : [-1, 1] | ``CT`` : [-1, 1] | | | | | | | ``CP`` : [-1, 1] | ``CP`` : [-1, 1] | +------------+-----------------------+------------------+ References ---------- :cite:`Dolby2016a`, :cite:`Lu2016c` Examples -------- >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) >>> XYZ_to_ICtCp(XYZ) # doctest: +ELLIPSIS array([ 0.0685809..., -0.0028384..., 0.0602098...]) >>> XYZ_to_ICtCp(XYZ, method='ITU-R BT.2100-2 HLG') # doctest: +ELLIPSIS array([ 0.5924279..., -0.0374073..., 0.2512267...]) """ BT2020 = RGB_COLOURSPACES["ITU-R BT.2020"] RGB = XYZ_to_RGB( XYZ, illuminant, BT2020.whitepoint, BT2020.matrix_XYZ_to_RGB, chromatic_adaptation_transform, ) return RGB_to_ICtCp(RGB, method, L_p)
def XYZ_to_sRGB( XYZ: ArrayLike, illuminant: ArrayLike = CCS_ILLUMINANTS[ "CIE 1931 2 Degree Standard Observer"]["D65"], chromatic_adaptation_transform: Union[Literal["Bianco 2010", "Bianco PC 2010", "Bradford", "CAT02 Brill 2008", "CAT02", "CAT16", "CMCCAT2000", "CMCCAT97", "Fairchild", "Sharp", "Von Kries", "XYZ Scaling", ], str, ] = "CAT02", apply_cctf_encoding: Boolean = True, ) -> NDArray: """ Convert from *CIE XYZ* tristimulus values to *sRGB* colourspace. Parameters ---------- XYZ *CIE XYZ* tristimulus values. illuminant Source illuminant chromaticity coordinates. chromatic_adaptation_transform *Chromatic adaptation* transform. apply_cctf_encoding Whether to apply the *sRGB* encoding colour component transfer function / inverse electro-optical transfer function. Returns ------- :class:`numpy.ndarray` *sRGB* colour array. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``RGB`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ Examples -------- >>> import numpy as np >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) >>> XYZ_to_sRGB(XYZ) # doctest: +ELLIPSIS array([ 0.7057393..., 0.1924826..., 0.2235416...]) """ sRGB = RGB_COLOURSPACES["sRGB"] return XYZ_to_RGB( XYZ, illuminant, sRGB.whitepoint, sRGB.matrix_XYZ_to_RGB, chromatic_adaptation_transform, sRGB.cctf_encoding if apply_cctf_encoding else None, )
def sd_to_aces_relative_exposure_values( sd: SpectralDistribution, illuminant: Optional[SpectralDistribution] = None, apply_chromatic_adaptation: Boolean = False, chromatic_adaptation_transform: Union[Literal["Bianco 2010", "Bianco PC 2010", "Bradford", "CAT02 Brill 2008", "CAT02", "CAT16", "CMCCAT2000", "CMCCAT97", "Fairchild", "Sharp", "Von Kries", "XYZ Scaling", ], str, ] = "CAT02", ) -> NDArray: """ Convert given spectral distribution to *ACES2065-1* colourspace relative exposure values. Parameters ---------- sd Spectral distribution. illuminant *Illuminant* spectral distribution, default to *CIE Standard Illuminant D65*. apply_chromatic_adaptation Whether to apply chromatic adaptation using given transform. chromatic_adaptation_transform *Chromatic adaptation* transform. Returns ------- :class:`numpy.ndarray` *ACES2065-1* colourspace relative exposure values array. Notes ----- +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ`` | [0, 100] | [0, 1] | +------------+-----------------------+---------------+ - The chromatic adaptation method implemented here is a bit unusual as it involves building a new colourspace based on *ACES2065-1* colourspace primaries but using the whitepoint of the illuminant that the spectral distribution was measured under. References ---------- :cite:`Forsythe2018`, :cite:`TheAcademyofMotionPictureArtsandSciences2014q`, :cite:`TheAcademyofMotionPictureArtsandSciences2014r`, :cite:`TheAcademyofMotionPictureArtsandSciencese` Examples -------- >>> from colour import SDS_COLOURCHECKERS >>> sd = SDS_COLOURCHECKERS['ColorChecker N Ohta']['dark skin'] >>> sd_to_aces_relative_exposure_values(sd) # doctest: +ELLIPSIS array([ 0.1171814..., 0.0866360..., 0.0589726...]) >>> sd_to_aces_relative_exposure_values(sd, ... apply_chromatic_adaptation=True) # doctest: +ELLIPSIS array([ 0.1180779..., 0.0869031..., 0.0589125...]) """ illuminant = cast(SpectralDistribution, optional(illuminant, SDS_ILLUMINANTS["D65"])) shape = MSDS_ACES_RICD.shape if sd.shape != MSDS_ACES_RICD.shape: sd = reshape_sd(sd, shape) if illuminant.shape != MSDS_ACES_RICD.shape: illuminant = reshape_sd(illuminant, shape) s_v = sd.values i_v = illuminant.values r_bar, g_bar, b_bar = tsplit(MSDS_ACES_RICD.values) def k(x: NDArray, y: NDArray) -> NDArray: """Compute the :math:`K_r`, :math:`K_g` or :math:`K_b` scale factors.""" return 1 / np.sum(x * y) k_r = k(i_v, r_bar) k_g = k(i_v, g_bar) k_b = k(i_v, b_bar) E_r = k_r * np.sum(i_v * s_v * r_bar) E_g = k_g * np.sum(i_v * s_v * g_bar) E_b = k_b * np.sum(i_v * s_v * b_bar) E_rgb = np.array([E_r, E_g, E_b]) # Accounting for flare. E_rgb += FLARE_PERCENTAGE E_rgb *= S_FLARE_FACTOR if apply_chromatic_adaptation: xy = XYZ_to_xy(sd_to_XYZ(illuminant) / 100) NPM = normalised_primary_matrix(RGB_COLOURSPACE_ACES2065_1.primaries, xy) XYZ = RGB_to_XYZ( E_rgb, xy, RGB_COLOURSPACE_ACES2065_1.whitepoint, NPM, chromatic_adaptation_transform, ) E_rgb = XYZ_to_RGB( XYZ, RGB_COLOURSPACE_ACES2065_1.whitepoint, RGB_COLOURSPACE_ACES2065_1.whitepoint, RGB_COLOURSPACE_ACES2065_1.matrix_XYZ_to_RGB, ) return from_range_1(E_rgb)