def sRGB_to_XYZ(RGB, illuminant=RGB_COLOURSPACES['sRGB'].whitepoint, chromatic_adaptation_method='CAT02', apply_decoding_cctf=True): """ Converts from *sRGB* colourspace to *CIE XYZ* tristimulus values. Parameters ---------- RGB : array_like *sRGB* colourspace array. illuminant : array_like, optional Source illuminant chromaticity coordinates. chromatic_adaptation_method : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC'}**, *Chromatic adaptation* method. apply_decoding_cctf : bool, optional Apply *sRGB* decoding colour component transfer function / electro-optical transfer function. Returns ------- ndarray *CIE XYZ* tristimulus values. Notes ----- - Input *RGB* colourspace array is in domain [0, 1]. Examples -------- >>> import numpy as np >>> RGB = np.array([0.17498172, 0.38818743, 0.32159978]) >>> sRGB_to_XYZ(RGB) # doctest: +ELLIPSIS array([ 0.0704953..., 0.1008..., 0.0955831...]) """ sRGB = RGB_COLOURSPACES['sRGB'] return RGB_to_XYZ( RGB, sRGB.whitepoint, illuminant, sRGB.RGB_to_XYZ_matrix, chromatic_adaptation_method, sRGB.decoding_cctf if apply_decoding_cctf else None) # yapf: disable
def sRGB_to_XYZ( RGB, illuminant=ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D65'], chromatic_adaptation_method='CAT02', apply_decoding_cctf=True): """ Converts from *sRGB* colourspace to *CIE XYZ* tristimulus values. Parameters ---------- RGB : array_like *sRGB* colourspace array. illuminant : array_like, optional Source illuminant chromaticity coordinates. chromatic_adaptation_method : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC'}**, *Chromatic adaptation* method. apply_decoding_cctf : bool, optional Apply *sRGB* decoding colour component transfer function / electro-optical transfer function. Returns ------- ndarray *CIE XYZ* tristimulus values. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``RGB`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ Examples -------- >>> import numpy as np >>> RGB = np.array([0.70573936, 0.19248266, 0.22354169]) >>> sRGB_to_XYZ(RGB) # doctest: +ELLIPSIS array([ 0.2065429..., 0.1219794..., 0.0513714...]) """ sRGB = RGB_COLOURSPACES['sRGB'] return RGB_to_XYZ( RGB, sRGB.whitepoint, illuminant, sRGB.RGB_to_XYZ_matrix, chromatic_adaptation_method, sRGB.decoding_cctf if apply_decoding_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 sRGB_to_XYZ( RGB, illuminant=CCS_ILLUMINANTS['CIE 1931 2 Degree Standard Observer'] ['D65'], chromatic_adaptation_method='CAT02', apply_cctf_decoding=True, **kwargs): """ Converts from *sRGB* colourspace to *CIE XYZ* tristimulus values. Parameters ---------- RGB : array_like *sRGB* colourspace array. illuminant : array_like, optional Source illuminant chromaticity coordinates. chromatic_adaptation_method : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02 Brill 2008', 'Bianco 2010', 'Bianco PC 2010'}**, *Chromatic adaptation* method. apply_cctf_decoding : bool, optional Apply *sRGB* decoding colour component transfer function / electro-optical transfer function. Other Parameters ---------------- \\**kwargs : dict, optional Keywords arguments for deprecation management. Returns ------- ndarray *CIE XYZ* tristimulus values. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``RGB`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ Examples -------- >>> import numpy as np >>> RGB = np.array([0.70573936, 0.19248266, 0.22354169]) >>> sRGB_to_XYZ(RGB) # doctest: +ELLIPSIS array([ 0.2065429..., 0.1219794..., 0.0513714...]) """ apply_cctf_decoding = handle_arguments_deprecation( { 'ArgumentRenamed': [['apply_decoding_cctf', 'apply_cctf_decoding'] ], }, **kwargs).get('apply_cctf_decoding', apply_cctf_decoding) sRGB = RGB_COLOURSPACES['sRGB'] return RGB_to_XYZ( RGB, sRGB.whitepoint, illuminant, sRGB.matrix_RGB_to_XYZ, chromatic_adaptation_method, sRGB.cctf_decoding if apply_cctf_decoding else None, )
def ICtCp_to_XYZ( ICtCp: 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 :math:`IC_TC_P` colour encoding to *CIE XYZ* tristimulus values. Parameters ---------- ICtCp :math:`IC_TC_P` colour encoding array. 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` *CIE XYZ* tristimulus values. Warnings -------- The underlying *SMPTE ST 2084:2014* transfer function is an absolute transfer function. Notes ----- - The *ITU-R BT.2100-1 PQ* and *ITU-R BT.2100-2 PQ* methods are aliases for the *Dolby 2016* method. - The underlying *SMPTE ST 2084:2014* transfer function is an absolute transfer function, thus the domain and range values for the *Reference* and *1* scales are only indicative that the data is not affected by scale transformations. +------------+-----------------------+------------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+==================+ | ``ICtCp`` | ``I`` : [0, 1] | ``I`` : [0, 1] | | | | | | | ``CT`` : [-1, 1] | ``CT`` : [-1, 1] | | | | | | | ``CP`` : [-1, 1] | ``CP`` : [-1, 1] | +------------+-----------------------+------------------+ +------------+-----------------------+------------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+==================+ | ``XYZ`` | ``UN`` | ``UN`` | +------------+-----------------------+------------------+ References ---------- :cite:`Dolby2016a`, :cite:`Lu2016c` Examples -------- >>> ICtCp = np.array([0.06858097, -0.00283842, 0.06020983]) >>> ICtCp_to_XYZ(ICtCp) # doctest: +ELLIPSIS array([ 0.2065400..., 0.1219722..., 0.0513695...]) >>> ICtCp = np.array([0.59242792, -0.03740730, 0.25122675]) >>> ICtCp_to_XYZ(ICtCp, method='ITU-R BT.2100-2 HLG') # doctest: +ELLIPSIS array([ 0.2065400..., 0.1219722..., 0.0513695...]) """ RGB = ICtCp_to_RGB(ICtCp, method, L_p) BT2020 = RGB_COLOURSPACES["ITU-R BT.2020"] XYZ = RGB_to_XYZ( RGB, BT2020.whitepoint, illuminant, BT2020.matrix_RGB_to_XYZ, chromatic_adaptation_transform, ) return XYZ
def sRGB_to_XYZ( RGB: 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_decoding: Boolean = True, ) -> NDArray: """ Convert from *sRGB* colourspace to *CIE XYZ* tristimulus values. Parameters ---------- RGB *sRGB* colourspace array. illuminant Source illuminant chromaticity coordinates. chromatic_adaptation_transform *Chromatic adaptation* transform. apply_cctf_decoding Whether to apply the *sRGB* decoding colour component transfer function / electro-optical transfer function. Returns ------- :class:`numpy.ndarray` *CIE XYZ* tristimulus values. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``RGB`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ Examples -------- >>> import numpy as np >>> RGB = np.array([0.70573936, 0.19248266, 0.22354169]) >>> sRGB_to_XYZ(RGB) # doctest: +ELLIPSIS array([ 0.2065429..., 0.1219794..., 0.0513714...]) """ sRGB = RGB_COLOURSPACES["sRGB"] return RGB_to_XYZ( RGB, sRGB.whitepoint, illuminant, sRGB.matrix_RGB_to_XYZ, chromatic_adaptation_transform, sRGB.cctf_decoding if apply_cctf_decoding 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)