def test_XYZ_to_RGB(self): """ Tests :func:`colour.models.rgb.rgb_colourspace.XYZ_to_RGB` definition. """ np.testing.assert_almost_equal( XYZ_to_RGB( np.array([0.21638819, 0.12570000, 0.03847493]), np.array([0.34570, 0.35850]), np.array([0.31270, 0.32900]), np.array([ [3.24062548, -1.53720797, -0.49862860], [-0.96893071, 1.87575606, 0.04151752], [0.05571012, -0.20402105, 1.05699594], ]), 'Bradford', oetf_sRGB), np.array([0.70556599, 0.19109268, 0.22340812]), decimal=7) np.testing.assert_almost_equal( XYZ_to_RGB( np.array([0.21638819, 0.12570000, 0.03847493]), np.array([0.34570, 0.35850]), np.array([0.31270, 0.32900]), np.array([ [3.24062548, -1.53720797, -0.49862860], [-0.96893071, 1.87575606, 0.04151752], [0.05571012, -0.20402105, 1.05699594], ]), None, oetf_sRGB), np.array([0.72794579, 0.18180021, 0.17951580]), decimal=7) np.testing.assert_almost_equal( XYZ_to_RGB( np.array([0.21638819, 0.12570000, 0.03847493]), np.array([0.34570, 0.35850]), np.array([0.32168, 0.33767]), np.array([ [1.04981102, 0.00000000, -0.00009748], [-0.49590302, 1.37331305, 0.09824004], [0.00000000, 0.00000000, 0.99125202], ])), np.array([0.21959099, 0.06985815, 0.04703704]), decimal=7) np.testing.assert_almost_equal( XYZ_to_RGB( np.array([0.21638819, 0.12570000, 0.03847493]), np.array([0.34570, 0.35850]), np.array([0.31270, 0.32900, 1.00000]), np.array([ [3.24062548, -1.53720797, -0.49862860], [-0.96893071, 1.87575606, 0.04151752], [0.05571012, -0.20402105, 1.05699594], ])), np.array([0.45620801, 0.03079991, 0.04091883]), decimal=7)
def XYZ_to_RGB_Smits1999(XYZ: ArrayLike) -> NDArray: """ Convert from *CIE XYZ* tristimulus values to *RGB* colourspace with conditions required by the current *Smits (1999)* method implementation. Parameters ---------- XYZ *CIE XYZ* tristimulus values. Returns ------- :class:`numpy.ndarray` *RGB* colour array. Examples -------- >>> XYZ = np.array([0.21781186, 0.12541048, 0.04697113]) >>> XYZ_to_RGB_Smits1999(XYZ) # doctest: +ELLIPSIS array([ 0.4063959..., 0.0275289..., 0.0398219...]) """ return XYZ_to_RGB( XYZ, CCS_WHITEPOINT_SMITS1999, CCS_WHITEPOINT_SMITS1999, MATRIX_XYZ_TO_RGB_SMITS1999, )
def XYZ_to_RGB_Smits1999(XYZ): """ Convenient object to convert from *CIE XYZ* tristimulus values to *RGB* colourspace in conditions required by the current *Smits (1999)* method implementation. Parameters ---------- XYZ : array_like *CIE XYZ* tristimulus values. Returns ------- ndarray *RGB* colour array. Notes ----- - Input *CIE XYZ* tristimulus values are in domain [0, 1]. Examples -------- >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) >>> XYZ_to_RGB_Smits1999(XYZ) # doctest: +ELLIPSIS array([ 0.0214496..., 0.1315460..., 0.0928760...]) """ return XYZ_to_RGB(XYZ, SMITS1999_WHITEPOINT, SMITS1999_WHITEPOINT, SMITS1999_XYZ_TO_RGB_MATRIX, encoding_cctf=None)
def XYZ_to_RGB_Smits1999(XYZ): """ Convenient object to convert from *CIE XYZ* tristimulus values to *RGB* colourspace in conditions required by the current *Smits (1999)* method implementation. Parameters ---------- XYZ : array_like *CIE XYZ* tristimulus values. Returns ------- ndarray *RGB* colour array. Examples -------- >>> XYZ = np.array([0.21781186, 0.12541048, 0.04697113]) >>> XYZ_to_RGB_Smits1999(XYZ) # doctest: +ELLIPSIS array([ 0.4063959..., 0.0275289..., 0.0398219...]) """ return XYZ_to_RGB(XYZ, SMITS1999_WHITEPOINT, SMITS1999_WHITEPOINT, SMITS1999_XYZ_TO_RGB_MATRIX, cctf_encoding=None)
def RGB_colourspace_volume_coverage_MonteCarlo( colourspace, coverage_sampler, samples=10e6, random_generator=random_triplet_generator, random_state=None): """ Returns given *RGB* colourspace percentage coverage of an arbitrary volume. Parameters ---------- colourspace : RGB_Colourspace *RGB* colourspace to compute the volume coverage percentage. coverage_sampler : object Python object responsible for checking the volume coverage. samples : numeric, optional Samples count. random_generator : generator, optional Random triplet generator providing the random samples. random_state : RandomState, optional Mersenne Twister pseudo-random number generator to use in the random number generator. Returns ------- float Percentage coverage of volume. Examples -------- >>> from colour import sRGB_COLOURSPACE as sRGB >>> prng = np.random.RandomState(2) >>> RGB_colourspace_volume_coverage_MonteCarlo( # doctest: +ELLIPSIS ... sRGB, ... is_within_pointer_gamut, ... 10e3, ... random_state=prng) 83... """ random_state = (random_state if random_state is not None else np.random.RandomState()) # TODO: Investigate for generator yielding directly a ndarray. XYZ = np.asarray(list(random_generator( samples, random_state=random_state))) XYZ_vs = XYZ[coverage_sampler(XYZ)] RGB = XYZ_to_RGB(XYZ_vs, colourspace.whitepoint, colourspace.whitepoint, colourspace.XYZ_to_RGB_matrix) RGB_c = RGB[np.logical_and(np.min(RGB, axis=-1) >= 0, np.max(RGB, axis=-1) <= 1)] return 100 * RGB_c.size / XYZ_vs.size
def RGB_colourspace_volume_coverage_MonteCarlo( colourspace: RGB_Colourspace, coverage_sampler: Callable, samples: Integer = 1000000, random_generator: Callable = random_triplet_generator, random_state: np.random.RandomState = None, ) -> Floating: """ Return given *RGB* colourspace percentage coverage of an arbitrary volume. Parameters ---------- colourspace *RGB* colourspace to compute the volume coverage percentage. coverage_sampler Python object responsible for checking the volume coverage. samples Samples count. random_generator Random triplet generator providing the random samples. random_state Mersenne Twister pseudo-random number generator to use in the random number generator. Returns ------- :class:`numpy.floating` Percentage coverage of volume. Examples -------- >>> from colour.models import RGB_COLOURSPACE_sRGB as sRGB >>> prng = np.random.RandomState(2) >>> RGB_colourspace_volume_coverage_MonteCarlo( ... sRGB, is_within_pointer_gamut, 10e3, random_state=prng) ... # doctest: +ELLIPSIS 81... """ random_state = (random_state if random_state is not None else np.random.RandomState()) XYZ = random_generator(DEFAULT_INT_DTYPE(samples), random_state=random_state) XYZ_vs = XYZ[coverage_sampler(XYZ)] RGB = XYZ_to_RGB( XYZ_vs, colourspace.whitepoint, colourspace.whitepoint, colourspace.matrix_XYZ_to_RGB, ) RGB_c = RGB[np.logical_and( np.min(RGB, axis=-1) >= 0, np.max(RGB, axis=-1) <= 1)] return 100 * RGB_c.size / XYZ_vs.size
def test_XYZ_to_RGB(self): """ Tests :func:`colour.models.rgb.rgb_colourspace.XYZ_to_RGB` definition. """ np.testing.assert_almost_equal( XYZ_to_RGB( np.array([0.11518475, 0.10080000, 0.05089373]), np.array([0.34570, 0.35850]), np.array([0.31270, 0.32900]), np.array([ [3.24062548, -1.53720797, -0.49862860], [-0.96893071, 1.87575606, 0.04151752], [0.05571012, -0.20402105, 1.05699594], ]), 'Bradford', oetf_sRGB), np.array([0.45286611, 0.31735742, 0.26418007]), decimal=7) np.testing.assert_almost_equal( XYZ_to_RGB( np.array([0.11518475, 0.10080000, 0.05089373]), np.array([0.34570, 0.35850]), np.array([0.32168, 0.33767]), np.array([ [1.04981102, 0.00000000, -0.00009748], [-0.49590302, 1.37331305, 0.09824004], [0.00000000, 0.00000000, 0.99125202], ])), np.array([0.11757966, 0.08781514, 0.06185473]), decimal=7) np.testing.assert_almost_equal( XYZ_to_RGB( np.array([0.07049534, 0.10080000, 0.09558313]), np.array([0.34570, 0.35850]), np.array([0.31270, 0.32900, 0.10080]), np.array([ [3.24062548, -1.53720797, -0.49862860], [-0.96893071, 1.87575606, 0.04151752], [0.05571012, -0.20402105, 1.05699594], ])), np.array([0.00109657, 0.01282168, 0.01173596]), decimal=7)
def test_n_dimensional_XYZ_to_RGB(self): """ Tests :func:`colour.models.rgb.rgb_colourspace.XYZ_to_RGB` definition n-dimensions support. """ XYZ = np.array([0.21638819, 0.12570000, 0.03847493]) W_R = np.array([0.34570, 0.35850]) W_T = np.array([0.31270, 0.32900]) M = np.array([ [3.24062548, -1.53720797, -0.49862860], [-0.96893071, 1.87575606, 0.04151752], [0.05571012, -0.20402105, 1.05699594], ]) RGB = np.array([0.70556599, 0.19109268, 0.22340812]) np.testing.assert_almost_equal(XYZ_to_RGB(XYZ, W_R, W_T, M, 'Bradford', oetf_sRGB), RGB, decimal=7) XYZ = np.tile(XYZ, (6, 1)) RGB = np.tile(RGB, (6, 1)) np.testing.assert_almost_equal(XYZ_to_RGB(XYZ, W_R, W_T, M, 'Bradford', oetf_sRGB), RGB, decimal=7) W_R = np.tile(W_R, (6, 1)) W_T = np.tile(W_T, (6, 1)) np.testing.assert_almost_equal(XYZ_to_RGB(XYZ, W_R, W_T, M, 'Bradford', oetf_sRGB), RGB, decimal=7) XYZ = np.reshape(XYZ, (2, 3, 3)) W_R = np.reshape(W_R, (2, 3, 2)) W_T = np.reshape(W_T, (2, 3, 2)) RGB = np.reshape(RGB, (2, 3, 3)) np.testing.assert_almost_equal(XYZ_to_RGB(XYZ, W_R, W_T, M, 'Bradford', oetf_sRGB), RGB, decimal=7)
def test_n_dimensional_XYZ_to_RGB(self): """ Tests :func:`colour.models.rgb.rgb_colourspace.XYZ_to_RGB` definition n-dimensions support. """ XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) W_R = np.array([0.34570, 0.35850]) W_T = np.array([0.31270, 0.32900]) M = np.array([[3.24062548, -1.53720797, -0.49862860], [-0.96893071, 1.87575606, 0.04151752], [0.05571012, -0.20402105, 1.05699594]]) RGB = np.array([0.01087863, 0.12719923, 0.11642816]) np.testing.assert_almost_equal( XYZ_to_RGB(XYZ, W_R, W_T, M), RGB, decimal=7) XYZ = np.tile(XYZ, (6, 1)) RGB = np.tile(RGB, (6, 1)) np.testing.assert_almost_equal( XYZ_to_RGB(XYZ, W_R, W_T, M), RGB, decimal=7) W_R = np.tile(W_R, (6, 1)) W_T = np.tile(W_T, (6, 1)) np.testing.assert_almost_equal( XYZ_to_RGB(XYZ, W_R, W_T, M), RGB, decimal=7) XYZ = np.reshape(XYZ, (2, 3, 3)) W_R = np.reshape(W_R, (2, 3, 2)) W_T = np.reshape(W_T, (2, 3, 2)) RGB = np.reshape(RGB, (2, 3, 3)) np.testing.assert_almost_equal( XYZ_to_RGB(XYZ, W_R, W_T, M), RGB, decimal=7)
def test_nan_XYZ_to_RGB(self): """ Tests :func:`colour.models.rgb.XYZ_to_RGB` definition nan support. """ cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan] cases = set(permutations(cases * 3, r=3)) for case in cases: XYZ = np.array(case) W_R = np.array(case[0:2]) W_T = np.array(case[0:2]) M = np.vstack((case, case, case)).reshape((3, 3)) XYZ_to_RGB(XYZ, W_R, W_T, M)
def XYZ_to_plotting_colourspace( XYZ: ArrayLike, illuminant: ArrayLike = RGB_COLOURSPACES["sRGB"].whitepoint, 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 the default plotting colourspace. Parameters ---------- XYZ *CIE XYZ* tristimulus values. illuminant Source illuminant chromaticity coordinates. chromatic_adaptation_transform *Chromatic adaptation* transform. apply_cctf_encoding Apply the default plotting colourspace encoding colour component transfer function / opto-electronic transfer function. Returns ------- :class:`numpy.ndarray` Default plotting colourspace colour array. Examples -------- >>> import numpy as np >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) >>> XYZ_to_plotting_colourspace(XYZ) # doctest: +ELLIPSIS array([ 0.7057393..., 0.1924826..., 0.2235416...]) """ return XYZ_to_RGB( XYZ, illuminant, CONSTANTS_COLOUR_STYLE.colour.colourspace.whitepoint, CONSTANTS_COLOUR_STYLE.colour.colourspace.matrix_XYZ_to_RGB, chromatic_adaptation_transform, CONSTANTS_COLOUR_STYLE.colour.colourspace.cctf_encoding if apply_cctf_encoding else None, )
def test_domain_range_scale_XYZ_to_RGB(self): """ Tests :func:`colour.models.rgb.rgb_colourspace.XYZ_to_RGB` definition domain and range scale support. """ XYZ = np.array([0.21638819, 0.12570000, 0.03847493]) W_R = np.array([0.34570, 0.35850]) W_T = np.array([0.31270, 0.32900]) M = np.array([ [3.24062548, -1.53720797, -0.49862860], [-0.96893071, 1.87575606, 0.04151752], [0.05571012, -0.20402105, 1.05699594], ]) RGB = XYZ_to_RGB(XYZ, W_R, W_T, M) d_r = (('reference', 1), (1, 1), (100, 100)) for scale, factor in d_r: with domain_range_scale(scale): np.testing.assert_almost_equal(XYZ_to_RGB( XYZ * factor, W_R, W_T, M), RGB * factor, decimal=7)
def xy_to_rgb(xy, name='ITU-R BT.2020', normalize='maximum', specific=None): """ xy値からRGB値を算出する。 いい感じに正規化もしておく。 Parameters ---------- xy : array_like xy value. name : string color space name. normalize : string normalize method. You can select 'maximum', 'specific' or None. Returns ------- array_like rgb value. the value is normalized. """ illuminant_XYZ = D65_WHITE illuminant_RGB = D65_WHITE chromatic_adaptation_transform = 'CAT02' large_xyz_to_rgb_matrix = get_xyz_to_rgb_matrix(name) if normalize == 'specific': xyY = xy_to_xyY(xy) xyY[..., 2] = specific large_xyz = xyY_to_XYZ(xyY) else: large_xyz = xy_to_XYZ(xy) rgb = XYZ_to_RGB(large_xyz, illuminant_XYZ, illuminant_RGB, large_xyz_to_rgb_matrix, chromatic_adaptation_transform) """ そのままだとビデオレベルが低かったりするので、 各ドット毎にRGB値を正規化&最大化する。必要であれば。 """ if normalize == 'maximum': rgb = normalise_maximum(rgb, axis=-1) else: if(np.sum(rgb > 1.0) > 0): print("warning: over flow has occured at xy_to_rgb") if(np.sum(rgb < 0.0) > 0): print("warning: under flow has occured at xy_to_rgb") rgb[rgb < 0] = 0 rgb[rgb > 1.0] = 1.0 return rgb
def test_n_dimensional_XYZ_to_RGB(self): """ Tests :func:`colour.models.rgb.XYZ_to_RGB` definition n-dimensions support. """ XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) W_R = np.array([0.34567, 0.35850]) W_T = np.array([0.31271, 0.32902]) M = np.array([[3.24100326, -1.53739899, -0.49861587], [-0.96922426, 1.87592999, 0.04155422], [0.05563942, -0.20401120, 1.05714897]]) RGB = np.array([0.01091381, 0.12719366, 0.11641136]) np.testing.assert_almost_equal(XYZ_to_RGB(XYZ, W_R, W_T, M), RGB, decimal=7) XYZ = np.tile(XYZ, (6, 1)) RGB = np.tile(RGB, (6, 1)) np.testing.assert_almost_equal(XYZ_to_RGB(XYZ, W_R, W_T, M), RGB, decimal=7) W_R = np.tile(W_R, (6, 1)) W_T = np.tile(W_T, (6, 1)) np.testing.assert_almost_equal(XYZ_to_RGB(XYZ, W_R, W_T, M), RGB, decimal=7) XYZ = np.reshape(XYZ, (2, 3, 3)) W_R = np.reshape(W_R, (2, 3, 2)) W_T = np.reshape(W_T, (2, 3, 2)) RGB = np.reshape(RGB, (2, 3, 3)) np.testing.assert_almost_equal(XYZ_to_RGB(XYZ, W_R, W_T, M), RGB, decimal=7)
def test_XYZ_to_RGB(self): """ Tests :func:`colour.models.rgb.XYZ_to_RGB` definition. """ for _xyY, XYZ, RGB in sRGB_LINEAR_COLORCHECKER_2005: np.testing.assert_almost_equal(XYZ_to_RGB( np.array(XYZ), np.array([0.34567, 0.35850]), np.array([0.31271, 0.32902]), np.array([[3.24100326, -1.53739899, -0.49861587], [-0.96922426, 1.87592999, 0.04155422], [0.05563942, -0.20401120, 1.05714897]]), 'Bradford', sRGB_OECF), RGB, decimal=7) for _xyY, XYZ, RGB in ACES_COLORCHECKER_2005: np.testing.assert_almost_equal(XYZ_to_RGB( np.array(XYZ), np.array([0.34567, 0.35850]), np.array([0.32168, 0.33767]), np.array([[1.04981102e+00, 0.00000000e+00, -9.74845410e-05], [-4.95903023e-01, 1.37331305e+00, 9.82400365e-02], [0.00000000e+00, 0.00000000e+00, 9.91252022e-01]])), RGB, decimal=7) XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) W_R = np.array([0.34567, 0.35850]) W_T = np.array([0.31271, 0.32902, 0.10080]) M = np.array([[3.24100326, -1.53739899, -0.49861587], [-0.96922426, 1.87592999, 0.04155422], [0.05563942, -0.20401120, 1.05714897]]) np.testing.assert_almost_equal( XYZ_to_RGB(XYZ, W_R, W_T, M), np.array([0.00110011, 0.01282112, 0.01173427]), decimal=7)
def XYZ_to_plotting_colourspace(XYZ, illuminant=RGB_COLOURSPACES['sRGB'].whitepoint, chromatic_adaptation_transform='CAT02', apply_encoding_cctf=True): """ Converts from *CIE XYZ* tristimulus values to :attr:`colour.plotting.DEFAULT_PLOTTING_COLOURSPACE` 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 :attr:`colour.plotting.DEFAULT_PLOTTING_COLOURSPACE` colourspace encoding colour component transfer function / opto-electronic transfer function. Returns ------- ndarray :attr:`colour.plotting.DEFAULT_PLOTTING_COLOURSPACE` colourspace colour array. Examples -------- >>> import numpy as np >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) >>> XYZ_to_plotting_colourspace(XYZ) # doctest: +ELLIPSIS array([ 0.7057393..., 0.1924826..., 0.2235416...]) """ return XYZ_to_RGB( XYZ, illuminant, COLOUR_STYLE_CONSTANTS.colour.colourspace.whitepoint, COLOUR_STYLE_CONSTANTS.colour.colourspace.XYZ_to_RGB_matrix, chromatic_adaptation_transform, COLOUR_STYLE_CONSTANTS.colour.colourspace.encoding_cctf if apply_encoding_cctf else None)
def check_basis_functions(self): """ Test :func:`colour.recovery.RGB_to_sd_Mallett2019` definition or the more specialised :func:`colour.recovery.RGB_to_sd_Mallett2019` definition. """ # Make sure the white point is reconstructed as a perfectly flat # spectrum. RGB = np.full(3, 1.0) sd = RGB_to_sd_Mallett2019(RGB, self._basis) self.assertLess(np.var(sd.values), 1e-5) # Check if the primaries or their combination exceeds the [0, 1] range. lower = np.zeros_like(sd.values) - 1e-12 upper = np.ones_like(sd.values) + 1e12 for RGB in [[1, 1, 1], [1, 0, 0], [0, 1, 0], [0, 0, 1]]: sd = RGB_to_sd_Mallett2019(RGB, self._basis) np.testing.assert_array_less(sd.values, upper) np.testing.assert_array_less(lower, sd.values) # Check Delta E's using a colour checker. for name, sd in SDS_COLOURCHECKERS["ColorChecker N Ohta"].items(): XYZ = sd_to_XYZ(sd, self._cmfs, self._sd_D65) / 100 Lab = XYZ_to_Lab(XYZ, self._xy_D65) RGB = XYZ_to_RGB( XYZ, self._RGB_colourspace.whitepoint, self._xy_D65, self._RGB_colourspace.matrix_XYZ_to_RGB, ) recovered_sd = RGB_to_sd_Mallett2019(RGB, self._basis) recovered_XYZ = ( sd_to_XYZ(recovered_sd, self._cmfs, self._sd_D65) / 100 ) recovered_Lab = XYZ_to_Lab(recovered_XYZ, self._xy_D65) error = delta_E_CIE1976(Lab, recovered_Lab) if error > 4 * JND_CIE1976 / 100: # pragma: no cover self.fail(f'Delta E for "{name}" is {error}!')
def highlights_recovery_LCHab(RGB, threshold=None, RGB_colourspace=sRGB_COLOURSPACE): """ Performs highlights recovery in *CIE L\\*C\\*Hab* colourspace. Parameters ---------- RGB : array_like *RGB* colourspace array. threshold : numeric, optional Threshold for highlights selection, automatically computed if not given. RGB_colourspace : RGB_Colourspace, optional Working *RGB* colourspace to perform the *CIE L\\*C\\*Hab* to and from. Returns ------- ndarray Highlights recovered *RGB* colourspace array. """ L, _C, H = tsplit( Lab_to_LCHab( XYZ_to_Lab( RGB_to_XYZ(RGB, RGB_colourspace.whitepoint, RGB_colourspace.whitepoint, RGB_colourspace.RGB_to_XYZ_matrix), RGB_colourspace.whitepoint))) _L_c, C_c, _H_c = tsplit( Lab_to_LCHab( XYZ_to_Lab( RGB_to_XYZ(np.clip(RGB, 0, threshold), RGB_colourspace.whitepoint, RGB_colourspace.whitepoint, RGB_colourspace.RGB_to_XYZ_matrix), RGB_colourspace.whitepoint))) return XYZ_to_RGB( Lab_to_XYZ(LCHab_to_Lab(tstack([L, C_c, H])), RGB_colourspace.whitepoint), RGB_colourspace.whitepoint, RGB_colourspace.whitepoint, RGB_colourspace.XYZ_to_RGB_matrix)
def XYZ_to_sRGB(XYZ, illuminant=RGB_COLOURSPACES.get('sRGB').whitepoint, chromatic_adaptation_transform='CAT02', apply_OECF=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_OECF : bool, optional Apply *sRGB* *opto-electronic conversion 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.1750135..., 0.3881879..., 0.3216195...]) """ sRGB = RGB_COLOURSPACES.get('sRGB') return XYZ_to_RGB(XYZ, illuminant, sRGB.whitepoint, sRGB.XYZ_to_RGB_matrix, chromatic_adaptation_transform, sRGB.OECF if apply_OECF else None)
def XYZ_to_sRGB(XYZ, illuminant=RGB_COLOURSPACES.get('sRGB').whitepoint, chromatic_adaptation_method='CAT02', transfer_function=True): """ Converts from *CIE XYZ* colourspace to *sRGB* colourspace. Parameters ---------- XYZ : array_like, (3,) *CIE XYZ* colourspace matrix. illuminant : array_like, optional Source illuminant chromaticity coordinates. chromatic_adaptation_method : unicode, optional ('XYZ Scaling', 'Bradford', 'Von Kries', 'Fairchild', 'CAT02') *Chromatic adaptation* method. transfer_function : bool, optional Apply *sRGB* *transfer function*. Returns ------- ndarray, (3,) *sRGB* colour matrix. Notes ----- - Input *CIE XYZ* colourspace matrix is in domain [0, 1]. Examples -------- >>> XYZ = np.array([0.1180583421, 0.1034, 0.0515089229]) >>> XYZ_to_sRGB(XYZ) # doctest: +ELLIPSIS array([ 0.4822488..., 0.3165197..., 0.2207051...]) """ sRGB = RGB_COLOURSPACES.get('sRGB') return XYZ_to_RGB(XYZ, illuminant, sRGB.whitepoint, sRGB.to_RGB, chromatic_adaptation_method, sRGB.transfer_function if transfer_function else None)
def XYZ_to_RGB_Smits1999(XYZ, chromatic_adaptation_transform='Bradford'): """ Convenient object to convert from *CIE XYZ* tristimulus values to *RGB* colourspace in conditions required by the current *Smits (1999)* method implementation. Parameters ---------- XYZ : array_like *CIE XYZ* tristimulus values. chromatic_adaptation_transform : unicode, optional **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC'}**, *Chromatic adaptation* method. Returns ------- ndarray *RGB* colour array. Notes ----- - Input *CIE XYZ* tristimulus values are in domain [0, 1]. Examples -------- >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) >>> XYZ_to_RGB_Smits1999(XYZ) # doctest: +ELLIPSIS array([ 0.0214496..., 0.1315460..., 0.0928760...]) """ return XYZ_to_RGB( XYZ, SMITS1999_WHITEPOINT, SMITS1999_WHITEPOINT, SMITS1999_XYZ_TO_RGB_MATRIX, chromatic_adaptation_transform, encoding_cctf=None)
def sample_RGB_colourspace_volume_MonteCarlo( colourspace, samples=10e6, limits=np.array([[0, 100], [-150, 150], [-150, 150]]), illuminant_Lab=ILLUMINANTS['CIE 1931 2 Degree Standard Observer'] ['D65'], chromatic_adaptation_method='CAT02', random_generator=random_triplet_generator, random_state=None): """ Randomly samples the *Lab* colourspace volume and returns the ratio of samples within the given *RGB* colourspace volume. Parameters ---------- colourspace : RGB_Colourspace *RGB* colourspace to compute the volume of. samples : numeric, optional Samples count. limits : array_like, optional *Lab* colourspace volume. illuminant_Lab : array_like, optional *Lab* colourspace *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. random_generator : generator, optional Random triplet generator providing the random samples within the *Lab* colourspace volume. random_state : RandomState, optional Mersenne Twister pseudo-random number generator to use in the random number generator. Returns ------- integer Within *RGB* colourspace volume samples count. Notes ----- - The doctest is assuming that :func:`np.random.RandomState` definition will return the same sequence no matter which *OS* or *Python* version is used. There is however no formal promise about the *prng* sequence reproducibility of either *Python* or *Numpy* implementations: Laurent. (2012). Reproducibility of python pseudo-random numbers across systems and versions? Retrieved January 20, 2015, from http://stackoverflow.com/questions/8786084/\ reproducibility-of-python-pseudo-random-numbers-across-systems-and-versions Examples -------- >>> from colour.models import sRGB_COLOURSPACE as sRGB >>> prng = np.random.RandomState(2) >>> sample_RGB_colourspace_volume_MonteCarlo(sRGB, 10e3, random_state=prng) ... # doctest: +ELLIPSIS 9... """ random_state = (random_state if random_state is not None else np.random.RandomState()) Lab = as_float_array(list(random_generator(samples, limits, random_state))) RGB = XYZ_to_RGB( Lab_to_XYZ(Lab, illuminant_Lab), illuminant_Lab, colourspace.whitepoint, colourspace.XYZ_to_RGB_matrix, chromatic_adaptation_transform=chromatic_adaptation_method) RGB_w = RGB[np.logical_and( np.min(RGB, axis=-1) >= 0, np.max(RGB, axis=-1) <= 1)] return len(RGB_w)
def plot_xyY_color_space(name='ITU-R BT.2020', samples=1024, antialiasing=True): """ SONY の HDR説明資料にあるような xyY の図を作る。 Parameters ---------- name : str name of the target color space. Returns ------- None """ # 馬蹄の領域判別用データ作成 # -------------------------- primary_xy, _ = get_primaries(name=name) triangulation = Delaunay(primary_xy) xx, yy\ = np.meshgrid(np.linspace(0, 1, samples), np.linspace(1, 0, samples)) xy = np.dstack((xx, yy)) mask = (triangulation.find_simplex(xy) < 0).astype(np.float) # アンチエイリアシングしてアルファチャンネルを滑らかに # ------------------------------------------------ if antialiasing: kernel = np.array([ [0, 1, 0], [1, 2, 1], [0, 1, 0], ]).astype(np.float) kernel /= np.sum(kernel) mask = convolve(mask, kernel) # ネガポジ反転 # -------------------------------- mask = 1 - mask[:, :, np.newaxis] # xy のメッシュから色を復元 # ------------------------ illuminant_XYZ = D65_WHITE illuminant_RGB = RGB_COLOURSPACES[name].whitepoint chromatic_adaptation_transform = 'CAT02' large_xyz_to_rgb_matrix = get_xyz_to_rgb_matrix(name) rgb_to_large_xyz_matrix = get_rgb_to_xyz_matrix(name) large_xyz = xy_to_XYZ(xy) rgb = XYZ_to_RGB(large_xyz, illuminant_XYZ, illuminant_RGB, large_xyz_to_rgb_matrix, chromatic_adaptation_transform) """ そのままだとビデオレベルが低かったりするので、 各ドット毎にRGB値を正規化&最大化する。 """ rgb_org = normalise_maximum(rgb, axis=-1) # mask 適用 # ------------------------------------- mask_rgb = np.dstack((mask, mask, mask)) rgb = rgb_org * mask_rgb rgba = np.dstack((rgb, mask)) # こっからもういちど XYZ に変換。Yを求めるために。 # --------------------------------------------- large_xyz2 = RGB_to_XYZ(rgb, illuminant_RGB, illuminant_XYZ, rgb_to_large_xyz_matrix, chromatic_adaptation_transform) # ログスケールに変換する準備 # -------------------------- large_y = large_xyz2[..., 1] * 1000 large_y[large_y < 1] = 1.0 fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # ax.plot_wireframe(xy[..., 0], xy[..., 1], np.log10(large_y), # rcount=100, ccount=100) ax.plot_surface(xy[..., 0], xy[..., 1], np.log10(large_y), rcount=64, ccount=64, facecolors=rgb_org) ax.set_xlabel("x") ax.set_ylabel("y") ax.set_zlabel("Y") ax.set_zticks([0, 1, 2, 3]) ax.set_zticklabels([1, 10, 100, 1000]) # chromatcity_image の取得。z=0 の位置に貼り付ける # ---------------------------------------------- cie1931_rgb = get_chromaticity_image(samples=samples, bg_color=0.0) alpha = np.zeros_like(cie1931_rgb[..., 0]) rgb_sum = np.sum(cie1931_rgb, axis=-1) alpha[rgb_sum > 0.00001] = 1 cie1931_rgb = np.dstack((cie1931_rgb[..., 0], cie1931_rgb[..., 1], cie1931_rgb[..., 2], alpha)) zz = np.zeros_like(xy[..., 0]) ax.plot_surface(xy[..., 0], xy[..., 1], zz, facecolors=cie1931_rgb) plt.show()
def get_chromaticity_image(samples=1024, antialiasing=True, bg_color=0.9, xmin=0.0, xmax=1.0, ymin=0.0, ymax=1.0): """ xy色度図の馬蹄形の画像を生成する Returns ------- ndarray rgb image. """ """ 色域設定。sRGBだと狭くて少し変だったのでBT.2020に設定。 若干色が薄くなるのが難点。暇があれば改良したい。 """ # color_space = models.BT2020_COLOURSPACE # color_space = models.S_GAMUT3_COLOURSPACE color_space = models.ACES_CG_COLOURSPACE # 馬蹄形のxy値を算出 # -------------------------- cmf_xy = _get_cmfs_xy() """ 馬蹄の内外の判別をするために三角形で領域分割する(ドロネー図を作成)。 ドロネー図を作れば後は外積計算で領域の内外を判別できる(たぶん)。 なお、作成したドロネー図は以下のコードでプロット可能。 1点補足しておくと、```plt.triplot``` の第三引数は、 第一、第二引数から三角形を作成するための **インデックス** のリスト になっている。[[0, 1, 2], [2, 4, 3], ...]的な。 ```python plt.figure() plt.triplot(xy[:, 0], xy[:, 1], triangulation.simplices.copy(), '-o') plt.title('triplot of Delaunay triangulation') plt.show() ``` """ triangulation = Delaunay(cmf_xy) """ ```triangulation.find_simplex()``` で xy がどのインデックスの領域か 調べることができる。戻り値が ```-1``` の場合は領域に含まれないため、 0以下のリストで領域判定の mask を作ることができる。 """ xx, yy\ = np.meshgrid(np.linspace(xmin, xmax, samples), np.linspace(ymax, ymin, samples)) xy = np.dstack((xx, yy)) mask = (triangulation.find_simplex(xy) < 0).astype(np.float) # アンチエイリアシングしてアルファチャンネルを滑らかに # ------------------------------------------------ if antialiasing: kernel = np.array([ [0, 1, 0], [1, 2, 1], [0, 1, 0], ]).astype(np.float) kernel /= np.sum(kernel) mask = convolve(mask, kernel) # ネガポジ反転 # -------------------------------- mask = 1 - mask[:, :, np.newaxis] # xy のメッシュから色を復元 # ------------------------ illuminant_XYZ = D65_WHITE illuminant_RGB = color_space.whitepoint chromatic_adaptation_transform = 'XYZ Scaling' large_xyz_to_rgb_matrix = color_space.XYZ_to_RGB_matrix large_xyz = xy_to_XYZ(xy) rgb = XYZ_to_RGB(large_xyz, illuminant_XYZ, illuminant_RGB, large_xyz_to_rgb_matrix, chromatic_adaptation_transform) """ そのままだとビデオレベルが低かったりするので、 各ドット毎にRGB値を正規化&最大化する。 """ rgb = normalise_maximum(rgb, axis=-1) # mask 適用 # ------------------------------------- mask_rgb = np.dstack((mask, mask, mask)) rgb *= mask_rgb # 背景色をグレーに変更 # ------------------------------------- bg_rgb = np.ones_like(rgb) bg_rgb *= (1 - mask_rgb) * bg_color rgb += bg_rgb rgb = rgb ** (1/2.2) return rgb
def sample_RGB_colourspace_volume_MonteCarlo( colourspace: RGB_Colourspace, samples: Integer = 1000000, limits: ArrayLike = np.array([[0, 100], [-150, 150], [-150, 150]]), illuminant_Lab: 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", random_generator: Callable = random_triplet_generator, random_state: np.random.RandomState = None, ) -> Integer: """ Randomly sample the *CIE L\\*a\\*b\\** colourspace volume and returns the ratio of samples within the given *RGB* colourspace volume. Parameters ---------- colourspace *RGB* colourspace to compute the volume of. samples Samples count. limits *CIE L\\*a\\*b\\** colourspace volume. illuminant_Lab *CIE L\\*a\\*b\\** colourspace *illuminant* chromaticity coordinates. chromatic_adaptation_transform *Chromatic adaptation* transform. random_generator Random triplet generator providing the random samples within the *CIE L\\*a\\*b\\** colourspace volume. random_state Mersenne Twister pseudo-random number generator to use in the random number generator. Returns ------- :class:`numpy.integer` Within *RGB* colourspace volume samples count. Notes ----- - The doctest is assuming that :func:`np.random.RandomState` definition will return the same sequence no matter which *OS* or *Python* version is used. There is however no formal promise about the *prng* sequence reproducibility of either *Python* or *Numpy* implementations: Laurent. (2012). Reproducibility of python pseudo-random numbers across systems and versions? Retrieved January 20, 2015, from http://stackoverflow.com/questions/8786084/\ reproducibility-of-python-pseudo-random-numbers-across-systems-and-versions Examples -------- >>> from colour.models import RGB_COLOURSPACE_sRGB as sRGB >>> prng = np.random.RandomState(2) >>> sample_RGB_colourspace_volume_MonteCarlo(sRGB, 10e3, random_state=prng) ... # doctest: +ELLIPSIS 9... """ random_state = (random_state if random_state is not None else np.random.RandomState()) Lab = random_generator(DEFAULT_INT_DTYPE(samples), limits, random_state) RGB = XYZ_to_RGB( Lab_to_XYZ(Lab, illuminant_Lab), illuminant_Lab, colourspace.whitepoint, colourspace.matrix_XYZ_to_RGB, chromatic_adaptation_transform=chromatic_adaptation_transform, ) RGB_w = RGB[np.logical_and( np.min(RGB, axis=-1) >= 0, np.max(RGB, axis=-1) <= 1)] return len(RGB_w)