def test_n_dimensional_Lab_to_XYZ(self): """ Tests :func:`colour.models.cie_lab.Lab_to_XYZ` definition n-dimensions support. """ Lab = np.array([41.52787529, 52.63858304, 26.92317922]) illuminant = np.array([0.31270, 0.32900]) XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) np.testing.assert_almost_equal(Lab_to_XYZ(Lab, illuminant), XYZ, decimal=7) Lab = np.tile(Lab, (6, 1)) XYZ = np.tile(XYZ, (6, 1)) np.testing.assert_almost_equal(Lab_to_XYZ(Lab, illuminant), XYZ, decimal=7) illuminant = np.tile(illuminant, (6, 1)) np.testing.assert_almost_equal(Lab_to_XYZ(Lab, illuminant), XYZ, decimal=7) Lab = np.reshape(Lab, (2, 3, 3)) illuminant = np.reshape(illuminant, (2, 3, 2)) XYZ = np.reshape(XYZ, (2, 3, 3)) np.testing.assert_almost_equal(Lab_to_XYZ(Lab, illuminant), XYZ, decimal=7)
def test_n_dimensional_Lab_to_XYZ(self): """ Tests :func:`colour.models.cie_lab.Lab_to_XYZ` definition n-dimensions support. """ Lab = np.array([37.98562910, -23.62907688, -4.41746615]) illuminant = np.array([0.34570, 0.35850]) XYZ = np.array([0.07049534, 0.10080000, 0.09558313]) np.testing.assert_almost_equal(Lab_to_XYZ(Lab, illuminant), XYZ, decimal=7) Lab = np.tile(Lab, (6, 1)) XYZ = np.tile(XYZ, (6, 1)) np.testing.assert_almost_equal(Lab_to_XYZ(Lab, illuminant), XYZ, decimal=7) illuminant = np.tile(illuminant, (6, 1)) np.testing.assert_almost_equal(Lab_to_XYZ(Lab, illuminant), XYZ, decimal=7) Lab = np.reshape(Lab, (2, 3, 3)) illuminant = np.reshape(illuminant, (2, 3, 2)) XYZ = np.reshape(XYZ, (2, 3, 3)) np.testing.assert_almost_equal(Lab_to_XYZ(Lab, illuminant), XYZ, decimal=7)
def is_within_pointer_gamut(XYZ, tolerance=None): """ Returns if given *CIE XYZ* tristimulus values are within Pointer's Gamut volume. Parameters ---------- XYZ : array_like *CIE XYZ* tristimulus values. tolerance : numeric, optional Tolerance allowed in the inside-triangle check. Returns ------- bool Is within Pointer's Gamut. Notes ----- - Input *CIE XYZ* tristimulus values are in domain [0, 1]. Examples -------- >>> import numpy as np >>> is_within_pointer_gamut(np.array([0.3205, 0.4131, 0.5100])) array(True, dtype=bool) >>> a = np.array([[0.3205, 0.4131, 0.5100], [0.0005, 0.0031, 0.0010]]) >>> is_within_pointer_gamut(a) array([ True, False], dtype=bool) """ XYZ_p = Lab_to_XYZ( LCHab_to_Lab(POINTER_GAMUT_DATA), POINTER_GAMUT_ILLUMINANT) return is_within_mesh_volume(XYZ, XYZ_p, tolerance)
def test_domain_range_scale_Lab_to_XYZ(self): """ Tests :func:`colour.models.cie_lab.Lab_to_XYZ` definition domain and range scale support. """ Lab = np.array([41.52787529, 52.63858304, 26.92317922]) illuminant = np.array([0.31270, 0.32900]) XYZ = Lab_to_XYZ(Lab, illuminant) d_r = (('reference', 1, 1), (1, 0.01, 1), (100, 1, 100)) for scale, factor_a, factor_b in d_r: with domain_range_scale(scale): np.testing.assert_almost_equal( Lab_to_XYZ(Lab * factor_a, illuminant), XYZ * factor_b, decimal=7)
def test_nan_Lab_to_XYZ(self): """Test :func:`colour.models.cie_lab.Lab_to_XYZ` 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: Lab = np.array(case) illuminant = np.array(case[0:2]) Lab_to_XYZ(Lab, illuminant)
def test_Lab_to_XYZ(self): """ Tests :func:`colour.models.cie_lab.Lab_to_XYZ` definition. """ np.testing.assert_almost_equal(Lab_to_XYZ( np.array([100, 0.83871284, -21.55579303])), np.array([0.96907232, 1., 1.12179215]), decimal=7) np.testing.assert_almost_equal(Lab_to_XYZ( np.array([100, 129.04406346, 406.69765889])), np.array([1.92001986, 1., -0.1241347]), decimal=7) np.testing.assert_almost_equal(Lab_to_XYZ( np.array([100, 8.32281957, -73.58297716])), np.array([1.0131677, 1., 2.11217686]), decimal=7) np.testing.assert_almost_equal(Lab_to_XYZ( np.array([100, -13.29228089, -162.12804888]), (0.44757, 0.40745)), np.array([1.0131677, 1., 2.11217686]), decimal=7) np.testing.assert_almost_equal(Lab_to_XYZ( np.array([100, 2.18505384, -56.60990888]), (1 / 3, 1 / 3)), np.array([1.0131677, 1., 2.11217686]), decimal=7) np.testing.assert_almost_equal(Lab_to_XYZ( np.array([100, 10.76832763, -49.42733157]), (0.31271, 0.32902)), np.array([1.0131677, 1., 2.11217686]), decimal=7)
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 is_within_pointer_gamut(XYZ: ArrayLike, tolerance: Optional[Floating] = None) -> NDArray: """ Return whether given *CIE XYZ* tristimulus values are within Pointer's Gamut volume. Parameters ---------- XYZ *CIE XYZ* tristimulus values. tolerance Tolerance allowed in the inside-triangle check. Returns ------- :class:`numpy.ndarray` Wether given *CIE XYZ* tristimulus values are within Pointer's Gamut volume. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``XYZ`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ Examples -------- >>> import numpy as np >>> is_within_pointer_gamut(np.array([0.3205, 0.4131, 0.5100])) array(True, dtype=bool) >>> a = np.array([[0.3205, 0.4131, 0.5100], [0.0005, 0.0031, 0.0010]]) >>> is_within_pointer_gamut(a) array([ True, False], dtype=bool) """ XYZ_p = Lab_to_XYZ(LCHab_to_Lab(DATA_POINTER_GAMUT_VOLUME), CCS_ILLUMINANT_POINTER_GAMUT) return is_within_mesh_volume(XYZ, XYZ_p, tolerance)
def test_Lab_to_XYZ(self): """ Tests :func:`colour.models.cie_lab.Lab_to_XYZ` definition. """ np.testing.assert_almost_equal( Lab_to_XYZ(np.array([37.98562910, -23.62907688, -4.41746615])), np.array([0.07049534, 0.10080000, 0.09558313]), decimal=7) np.testing.assert_almost_equal( Lab_to_XYZ(np.array([65.70971880, 41.56438554, 37.78303554])), np.array([0.47097710, 0.34950000, 0.11301649]), decimal=7) np.testing.assert_almost_equal( Lab_to_XYZ(np.array([50.86223896, 32.76150086, 20.25483590])), np.array([0.25506814, 0.19150000, 0.08849752]), decimal=7) np.testing.assert_almost_equal( Lab_to_XYZ(np.array([37.98562910, -32.51333979, -35.96770745]), np.array([0.44757, 0.40745])), np.array([0.07049534, 0.10080000, 0.09558313]), decimal=7) np.testing.assert_almost_equal( Lab_to_XYZ(np.array([37.98562910, -22.61920654, 4.19811236]), np.array([0.31270, 0.32900])), np.array([0.07049534, 0.10080000, 0.09558313]), decimal=7) np.testing.assert_almost_equal( Lab_to_XYZ(np.array([37.98562910, -25.55521883, -11.26139386]), np.array([0.37208, 0.37529])), np.array([0.07049534, 0.10080000, 0.09558313]), decimal=7) np.testing.assert_almost_equal( Lab_to_XYZ(np.array([37.98562910, -25.55521883, -11.26139386]), np.array([0.37208, 0.37529, 0.10080])), np.array([0.00710593, 0.01016064, 0.00963478]), decimal=7)
def test_Lab_to_XYZ(self): """ Tests :func:`colour.models.cie_lab.Lab_to_XYZ` definition. """ np.testing.assert_almost_equal( Lab_to_XYZ(np.array([37.98562910, -23.62302887, -4.41417036])), np.array([0.07049534, 0.10080000, 0.09558313]), decimal=7) np.testing.assert_almost_equal( Lab_to_XYZ(np.array([65.70971880, 41.57577646, 37.78652063])), np.array([0.47097710, 0.34950000, 0.11301649]), decimal=7) np.testing.assert_almost_equal( Lab_to_XYZ(np.array([50.86223896, 32.77078577, 20.25804815])), np.array([0.25506814, 0.19150000, 0.08849752]), decimal=7) np.testing.assert_almost_equal( Lab_to_XYZ(np.array([37.98562910, -32.51333979, -35.96770745]), np.array([0.44757, 0.40745])), np.array([0.07049534, 0.10080000, 0.09558313]), decimal=7) np.testing.assert_almost_equal( Lab_to_XYZ(np.array([37.98562910, -22.61718913, 4.19383056]), np.array([0.31271, 0.32902])), np.array([0.07049534, 0.10080000, 0.09558313]), decimal=7) np.testing.assert_almost_equal( Lab_to_XYZ(np.array([37.98562910, -25.55521883, -11.26139386]), np.array([0.37208, 0.37529])), np.array([0.07049534, 0.10080000, 0.09558313]), decimal=7) np.testing.assert_almost_equal( Lab_to_XYZ(np.array([37.98562910, -25.55521883, -11.26139386]), np.array([0.37208, 0.37529, 0.10080])), np.array([0.00710593, 0.01016064, 0.00963478]), decimal=7)
def test_Lab_to_XYZ(self): """Test :func:`colour.models.cie_lab.Lab_to_XYZ` definition.""" np.testing.assert_almost_equal( Lab_to_XYZ(np.array([41.52787529, 52.63858304, 26.92317922])), np.array([0.20654008, 0.12197225, 0.05136952]), decimal=7, ) np.testing.assert_almost_equal( Lab_to_XYZ(np.array([55.11636304, -41.08791787, 30.91825778])), np.array([0.14222010, 0.23042768, 0.10495772]), decimal=7, ) np.testing.assert_almost_equal( Lab_to_XYZ(np.array([29.80565520, 20.01830466, -48.34913874])), np.array([0.07818780, 0.06157201, 0.28099326]), decimal=7, ) np.testing.assert_almost_equal( Lab_to_XYZ( np.array([41.52787529, 38.48089305, -5.73295122]), np.array([0.44757, 0.40745]), ), np.array([0.20654008, 0.12197225, 0.05136952]), decimal=7, ) np.testing.assert_almost_equal( Lab_to_XYZ( np.array([41.52787529, 51.19354174, 19.91843098]), np.array([0.34570, 0.35850]), ), np.array([0.20654008, 0.12197225, 0.05136952]), decimal=7, ) np.testing.assert_almost_equal( Lab_to_XYZ( np.array([41.52787529, 51.19354174, 19.91843098]), np.array([0.34570, 0.35850, 1.00000]), ), np.array([0.20654008, 0.12197225, 0.05136952]), decimal=7, )
Notes ----- - *X-Rite* data is given as *CIE L\\*a\\*b\\** colourspace values under *CIE Illuminant D Series D50* for the *CIE 1931 2 Degree Standard Observer*. COLORCHECKER24_BEFORE_NOV2014_LAB_DATA : ndarray """ COLORCHECKER24_BEFORE_NOV2014_DATA = OrderedDict( zip( COLORCHECKER24_BEFORE_NOV2014_LAB_DATA.keys(), XYZ_to_xyY( Lab_to_XYZ( list(COLORCHECKER24_BEFORE_NOV2014_LAB_DATA.values()), ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D50'])))) COLORCHECKER24_BEFORE_NOV2014_ILLUMINANT = ( ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['D50']) """ *ColorChecker24 - Before November 2014* illuminant. COLORCHECKER24_BEFORE_NOV2014_ILLUMINANT : ndarray """ COLORCHECKER24_BEFORE_NOV2014 = ColourChecker( 'ColorChecker24 - Before November 2014', COLORCHECKER24_BEFORE_NOV2014_DATA, COLORCHECKER24_BEFORE_NOV2014_ILLUMINANT) """
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 RGB_colourspaces_CIE_1931_chromaticity_diagram_plot( colourspaces=None, cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots given *RGB* colourspaces in *CIE 1931 Chromaticity Diagram*. Parameters ---------- colourspaces : array_like, optional *RGB* colourspaces to plot. cmfs : unicode, optional Standard observer colour matching functions used for diagram bounds. Other Parameters ---------------- \**kwargs : dict, optional {:func:`boundaries`, :func:`canvas`, :func:`decorate`, :func:`display`}, Please refer to the documentation of the previously listed definitions. show_diagram_colours : bool, optional {:func:`CIE_1931_chromaticity_diagram_plot`}, Whether to display the chromaticity diagram background colours. Returns ------- Figure Current figure or None. Examples -------- >>> c = ['Rec. 709', 'ACEScg', 'S-Gamut'] >>> RGB_colourspaces_CIE_1931_chromaticity_diagram_plot( ... c) # doctest: +SKIP """ settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)} settings.update(kwargs) canvas(**settings) if colourspaces is None: colourspaces = ('Rec. 709', 'ACEScg', 'S-Gamut', 'Pointer Gamut') cmfs, name = get_cmfs(cmfs), cmfs settings = { 'title': '{0} - {1} - CIE 1931 Chromaticity Diagram'.format( ', '.join(colourspaces), name), 'standalone': False } settings.update(kwargs) CIE_1931_chromaticity_diagram_plot(**settings) x_limit_min, x_limit_max = [-0.1], [0.9] y_limit_min, y_limit_max = [-0.1], [0.9] settings = { 'colour_cycle_map': 'rainbow', 'colour_cycle_count': len(colourspaces) } settings.update(kwargs) cycle = colour_cycle(**settings) for colourspace in colourspaces: if colourspace == 'Pointer Gamut': xy = np.asarray(POINTER_GAMUT_BOUNDARIES) alpha_p, colour_p = 0.85, '0.95' pylab.plot(xy[..., 0], xy[..., 1], label='Pointer\'s Gamut', color=colour_p, alpha=alpha_p, linewidth=2) pylab.plot((xy[-1][0], xy[0][0]), (xy[-1][1], xy[0][1]), color=colour_p, alpha=alpha_p, linewidth=2) XYZ = Lab_to_XYZ(LCHab_to_Lab(POINTER_GAMUT_DATA), POINTER_GAMUT_ILLUMINANT) xy = XYZ_to_xy(XYZ, POINTER_GAMUT_ILLUMINANT) pylab.scatter(xy[..., 0], xy[..., 1], alpha=alpha_p / 2, color=colour_p, marker='+') else: colourspace, name = get_RGB_colourspace(colourspace), colourspace r, g, b, _a = next(cycle) primaries = colourspace.primaries whitepoint = colourspace.whitepoint pylab.plot((whitepoint[0], whitepoint[0]), (whitepoint[1], whitepoint[1]), color=(r, g, b), label=colourspace.name, linewidth=2) pylab.plot((whitepoint[0], whitepoint[0]), (whitepoint[1], whitepoint[1]), 'o', color=(r, g, b), linewidth=2) pylab.plot((primaries[0, 0], primaries[1, 0]), (primaries[0, 1], primaries[1, 1]), 'o-', color=(r, g, b), linewidth=2) pylab.plot((primaries[1, 0], primaries[2, 0]), (primaries[1, 1], primaries[2, 1]), 'o-', color=(r, g, b), linewidth=2) pylab.plot((primaries[2, 0], primaries[0, 0]), (primaries[2, 1], primaries[0, 1]), 'o-', color=(r, g, b), linewidth=2) x_limit_min.append(np.amin(primaries[..., 0]) - 0.1) y_limit_min.append(np.amin(primaries[..., 1]) - 0.1) x_limit_max.append(np.amax(primaries[..., 0]) + 0.1) y_limit_max.append(np.amax(primaries[..., 1]) + 0.1) settings.update({ 'legend': True, 'legend_location': 'upper right', 'x_tighten': True, 'y_tighten': True, 'limits': (min(x_limit_min), max(x_limit_max), min(y_limit_min), max(y_limit_max)), 'standalone': True }) settings.update(kwargs) boundaries(**settings) decorate(**settings) return display(**settings)
def RGB_colourspaces_CIE_1976_UCS_chromaticity_diagram_plot( colourspaces=None, cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots given *RGB* colourspaces in *CIE 1976 UCS Chromaticity Diagram*. Parameters ---------- colourspaces : array_like, optional *RGB* colourspaces to plot. cmfs : unicode, optional Standard observer colour matching functions used for diagram bounds. Other Parameters ---------------- \**kwargs : dict, optional {:func:`boundaries`, :func:`canvas`, :func:`decorate`, :func:`display`}, Please refer to the documentation of the previously listed definitions. show_diagram_colours : bool, optional {:func:`CIE_1976_UCS_chromaticity_diagram_plot`}, Whether to display the chromaticity diagram background colours. Returns ------- Figure Current figure or None. Examples -------- >>> c = ['Rec. 709', 'ACEScg', 'S-Gamut'] >>> RGB_colourspaces_CIE_1976_UCS_chromaticity_diagram_plot( ... c) # doctest: +SKIP """ settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)} settings.update(kwargs) canvas(**settings) if colourspaces is None: colourspaces = ('Rec. 709', 'ACEScg', 'S-Gamut', 'Pointer Gamut') cmfs, name = get_cmfs(cmfs), cmfs illuminant = DEFAULT_PLOTTING_ILLUMINANT settings = { 'title': '{0} - {1} - CIE 1976 UCS Chromaticity Diagram'.format( ', '.join(colourspaces), name), 'standalone': False } settings.update(kwargs) CIE_1976_UCS_chromaticity_diagram_plot(**settings) x_limit_min, x_limit_max = [-0.1], [0.7] y_limit_min, y_limit_max = [-0.1], [0.7] settings = { 'colour_cycle_map': 'rainbow', 'colour_cycle_count': len(colourspaces) } settings.update(kwargs) cycle = colour_cycle(**settings) for colourspace in colourspaces: if colourspace == 'Pointer Gamut': uv = Luv_to_uv( XYZ_to_Luv(xy_to_XYZ(POINTER_GAMUT_BOUNDARIES), illuminant), illuminant) alpha_p, colour_p = 0.85, '0.95' pylab.plot(uv[..., 0], uv[..., 1], label='Pointer\'s Gamut', color=colour_p, alpha=alpha_p, linewidth=2) pylab.plot((uv[-1][0], uv[0][0]), (uv[-1][1], uv[0][1]), color=colour_p, alpha=alpha_p, linewidth=2) XYZ = Lab_to_XYZ(LCHab_to_Lab(POINTER_GAMUT_DATA), POINTER_GAMUT_ILLUMINANT) uv = Luv_to_uv(XYZ_to_Luv(XYZ, illuminant), illuminant) pylab.scatter(uv[..., 0], uv[..., 1], alpha=alpha_p / 2, color=colour_p, marker='+') else: colourspace, name = get_RGB_colourspace(colourspace), colourspace r, g, b, _a = next(cycle) # RGB colourspaces such as *ACES2065-1* have primaries with # chromaticity coordinates set to 0 thus we prevent nan from being # yield by zero division in later colour transformations. P = np.where(colourspace.primaries == 0, EPSILON, colourspace.primaries) P = Luv_to_uv(XYZ_to_Luv(xy_to_XYZ(P), illuminant), illuminant) W = Luv_to_uv( XYZ_to_Luv(xy_to_XYZ(colourspace.whitepoint), illuminant), illuminant) pylab.plot((W[0], W[0]), (W[1], W[1]), color=(r, g, b), label=colourspace.name, linewidth=2) pylab.plot((W[0], W[0]), (W[1], W[1]), 'o', color=(r, g, b), linewidth=2) pylab.plot((P[0, 0], P[1, 0]), (P[0, 1], P[1, 1]), 'o-', color=(r, g, b), linewidth=2) pylab.plot((P[1, 0], P[2, 0]), (P[1, 1], P[2, 1]), 'o-', color=(r, g, b), linewidth=2) pylab.plot((P[2, 0], P[0, 0]), (P[2, 1], P[0, 1]), 'o-', color=(r, g, b), linewidth=2) x_limit_min.append(np.amin(P[..., 0]) - 0.1) y_limit_min.append(np.amin(P[..., 1]) - 0.1) x_limit_max.append(np.amax(P[..., 0]) + 0.1) y_limit_max.append(np.amax(P[..., 1]) + 0.1) settings.update({ 'legend': True, 'legend_location': 'upper right', 'x_tighten': True, 'y_tighten': True, 'limits': (min(x_limit_min), max(x_limit_max), min(y_limit_min), max(y_limit_max)), 'standalone': True }) settings.update(kwargs) boundaries(**settings) decorate(**settings) return display(**settings)
def DIN99_to_XYZ( Lab_99: ArrayLike, illuminant: ArrayLike = CCS_ILLUMINANTS[ "CIE 1931 2 Degree Standard Observer"]["D65"], k_E: Floating = 1, k_CH: Floating = 1, method: Union[Literal["ASTMD2244-07", "DIN99", "DIN99b", "DIN99c", "DIN99d"], str] = "DIN99", ) -> NDArray: """ Convert from *DIN99* colourspace or one of the *DIN99b*, *DIN99c*, *DIN99d* refined formulas according to *Cui et al. (2002)* to *CIE XYZ* tristimulus values. Parameters ---------- Lab_99 *DIN99* colourspace array. illuminant Reference *illuminant* *CIE xy* chromaticity coordinates or *CIE xyY* colourspace array. k_E Parametric factor :math:`K_E` used to compensate for texture and other specimen presentation effects. k_CH Parametric factor :math:`K_{CH}` used to compensate for texture and other specimen presentation effects. method Computation method to choose between the :cite:`ASTMInternational2007` formula and the refined formulas according to *Cui et al. (2002)*. Returns ------- :class:`numpy.ndarray` *CIE XYZ* tristimulus values. Notes ----- +----------------+------------------------+--------------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +================+========================+====================+ | ``Lab_99`` | ``L_99`` : [0, 100] | ``L_99`` : [0, 1] | | | | | | | ``a_99`` : [-100, 100] | ``a_99`` : [-1, 1] | | | | | | | ``b_99`` : [-100, 100] | ``b_99`` : [-1, 1] | +----------------+------------------------+--------------------+ | ``illuminant`` | [0, 1] | [0, 1] | +----------------+------------------------+--------------------+ +----------------+-----------------------+---------------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +================+=======================+=====================+ | ``XYZ`` | [0, 1] | [0, 1] | +----------------+-----------------------+---------------------+ References ---------- :cite:`ASTMInternational2007` Examples -------- >>> import numpy as np >>> Lab_99 = np.array([53.22821989, 28.41634656, 3.89839552]) >>> DIN99_to_XYZ(Lab_99) # doctest: +ELLIPSIS array([ 0.2065400..., 0.1219722..., 0.0513695...]) """ Lab = DIN99_to_Lab(Lab_99, k_E, k_CH, method) return Lab_to_XYZ(Lab, illuminant)
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)
def RGB_colourspaces_CIE_1960_UCS_chromaticity_diagram_plot( colourspaces=None, cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots given *RGB* colourspaces in *CIE 1960 UCS Chromaticity Diagram*. Parameters ---------- colourspaces : array_like, optional *RGB* colourspaces to plot. cmfs : unicode, optional Standard observer colour matching functions used for diagram bounds. \**kwargs : dict, optional Keywords arguments. Returns ------- bool Definition success. Examples -------- >>> c = ['Rec. 709', 'ACEScg', 'S-Gamut'] >>> RGB_colourspaces_CIE_1960_UCS_chromaticity_diagram_plot( ... c) # doctest: +SKIP True """ settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)} settings.update(kwargs) canvas(**settings) if colourspaces is None: colourspaces = ('Rec. 709', 'ACEScg', 'S-Gamut', 'Pointer Gamut') cmfs, name = get_cmfs(cmfs), cmfs settings = { 'title': '{0} - {1} - CIE 1960 UCS Chromaticity Diagram'.format( ', '.join(colourspaces), name), 'standalone': False} settings.update(kwargs) CIE_1960_UCS_chromaticity_diagram_plot(**settings) x_limit_min, x_limit_max = [-0.1], [0.7] y_limit_min, y_limit_max = [-0.2], [0.6] settings = {'colour_cycle_map': 'rainbow', 'colour_cycle_count': len(colourspaces)} settings.update(kwargs) cycle = colour_cycle(**settings) for colourspace in colourspaces: if colourspace == 'Pointer Gamut': uv = UCS_to_uv(XYZ_to_UCS(xy_to_XYZ(POINTER_GAMUT_BOUNDARIES))) alpha_p, colour_p = 0.85, '0.95' pylab.plot(uv[..., 0], uv[..., 1], label='Pointer\'s Gamut', color=colour_p, alpha=alpha_p, linewidth=2) pylab.plot((uv[-1][0], uv[0][0]), (uv[-1][1], uv[0][1]), color=colour_p, alpha=alpha_p, linewidth=2) XYZ = Lab_to_XYZ(LCHab_to_Lab(POINTER_GAMUT_DATA), POINTER_GAMUT_ILLUMINANT) uv = UCS_to_uv(XYZ_to_UCS(XYZ)) pylab.scatter(uv[..., 0], uv[..., 1], alpha=alpha_p / 2, color=colour_p, marker='+') else: colourspace, name = get_RGB_colourspace(colourspace), colourspace r, g, b, _a = next(cycle) # RGB colourspaces such as *ACES2065-1* have primaries with # chromaticity coordinates set to 0 thus we prevent nan from being # yield by zero division in later colour transformations. primaries = np.where(colourspace.primaries == 0, EPSILON, colourspace.primaries) primaries = UCS_to_uv(XYZ_to_UCS(xy_to_XYZ(primaries))) whitepoint = UCS_to_uv(XYZ_to_UCS(xy_to_XYZ( colourspace.whitepoint))) pylab.plot((whitepoint[0], whitepoint[0]), (whitepoint[1], whitepoint[1]), color=(r, g, b), label=colourspace.name, linewidth=2) pylab.plot((whitepoint[0], whitepoint[0]), (whitepoint[1], whitepoint[1]), 'o', color=(r, g, b), linewidth=2) pylab.plot((primaries[0, 0], primaries[1, 0]), (primaries[0, 1], primaries[1, 1]), 'o-', color=(r, g, b), linewidth=2) pylab.plot((primaries[1, 0], primaries[2, 0]), (primaries[1, 1], primaries[2, 1]), 'o-', color=(r, g, b), linewidth=2) pylab.plot((primaries[2, 0], primaries[0, 0]), (primaries[2, 1], primaries[0, 1]), 'o-', color=(r, g, b), linewidth=2) x_limit_min.append(np.amin(primaries[..., 0]) - 0.1) y_limit_min.append(np.amin(primaries[..., 1]) - 0.1) x_limit_max.append(np.amax(primaries[..., 0]) + 0.1) y_limit_max.append(np.amax(primaries[..., 1]) + 0.1) settings.update({ 'legend': True, 'legend_location': 'upper right', 'x_tighten': True, 'y_tighten': True, 'limits': (min(x_limit_min), max(x_limit_max), min(y_limit_min), max(y_limit_max)), 'standalone': True}) settings.update(kwargs) boundaries(**settings) decorate(**settings) return display(**settings)
Notes ----- - *X-Rite* data is given as *CIE L\\*a\\*b\\** colourspace values under *CIE Illuminant D Series D50* for the *CIE 1931 2 Degree Standard Observer*. DATA_COLORCHECKER24_BEFORE_NOV2014 : ndarray """ DATA_COLORCHECKER24_BEFORE_NOV2014 = OrderedDict( zip( SAMPLE_LABELS_COLORCHECKER_CLASSIC, XYZ_to_xyY( Lab_to_XYZ( list(DATA_COLORCHECKER24_BEFORE_NOV2014.values()), CCS_ILLUMINANTS['CIE 1931 2 Degree Standard Observer'] ['ICC D50'])))) CCS_ILLUMINANT_COLORCHECKER24_BEFORE_NOV2014 = ( CCS_ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['ICC D50']) """ *ColorChecker24 - Before November 2014* illuminant. CCS_ILLUMINANT_COLORCHECKER24_BEFORE_NOV2014 : ndarray """ CCS_COLORCHECKER24_BEFORE_NOV2014 = ColourChecker( 'ColorChecker24 - Before November 2014', DATA_COLORCHECKER24_BEFORE_NOV2014, CCS_ILLUMINANT_COLORCHECKER24_BEFORE_NOV2014) """
def plot_pointer_gamut(method='CIE 1931', **kwargs): """ Plots *Pointer's Gamut* according to given method. Parameters ---------- method : unicode, optional **{'CIE 1931', 'CIE 1960 UCS', 'CIE 1976 UCS'}**, Plotting method. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_pointer_gamut() # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Pointer_Gamut.png :align: center :alt: plot_pointer_gamut """ settings = {'uniform': True} settings.update(kwargs) figure, axes = artist(**settings) method = method.upper() if method == 'CIE 1931': def XYZ_to_ij(XYZ, *args): """ Converts given *CIE XYZ* tristimulus values to *ij* chromaticity coordinates. """ return XYZ_to_xy(XYZ, *args) def xy_to_ij(xy): """ Converts given *xy* chromaticity coordinates to *ij* chromaticity coordinates. """ return xy elif method == 'CIE 1960 UCS': def XYZ_to_ij(XYZ, *args): """ Converts given *CIE XYZ* tristimulus values to *ij* chromaticity coordinates. """ return UCS_to_uv(XYZ_to_UCS(XYZ)) def xy_to_ij(xy): """ Converts given *xy* chromaticity coordinates to *ij* chromaticity coordinates. """ return xy_to_UCS_uv(xy) elif method == 'CIE 1976 UCS': def XYZ_to_ij(XYZ, *args): """ Converts given *CIE XYZ* tristimulus values to *ij* chromaticity coordinates. """ return Luv_to_uv(XYZ_to_Luv(XYZ, *args), *args) def xy_to_ij(xy): """ Converts given *xy* chromaticity coordinates to *ij* chromaticity coordinates. """ return xy_to_Luv_uv(xy) else: raise ValueError( 'Invalid method: "{0}", must be one of ' '{\'CIE 1931\', \'CIE 1960 UCS\', \'CIE 1976 UCS\'}'.format( method)) ij = xy_to_ij(as_float_array(POINTER_GAMUT_BOUNDARIES)) alpha_p = COLOUR_STYLE_CONSTANTS.opacity.high colour_p = COLOUR_STYLE_CONSTANTS.colour.darkest axes.plot(ij[..., 0], ij[..., 1], label='Pointer\'s Gamut', color=colour_p, alpha=alpha_p) axes.plot((ij[-1][0], ij[0][0]), (ij[-1][1], ij[0][1]), color=colour_p, alpha=alpha_p) XYZ = Lab_to_XYZ(LCHab_to_Lab(POINTER_GAMUT_DATA), POINTER_GAMUT_ILLUMINANT) ij = XYZ_to_ij(XYZ, POINTER_GAMUT_ILLUMINANT) axes.scatter(ij[..., 0], ij[..., 1], alpha=alpha_p / 2, color=colour_p, marker='+') settings.update({'axes': axes}) settings.update(kwargs) return render(**settings)
np.array([96.539, -0.425, 1.186]), np.array([81.257, -0.638, -0.335]), np.array([66.766, -0.734, -0.504]), np.array([50.867, -0.153, -0.27]), np.array([35.656, -0.421, -1.231]), np.array([20.461, -0.079, -0.973]), ], )) DATA_COLORCHECKER24_BEFORE_NOV2014: Dict = dict( zip( SAMPLE_LABELS_COLORCHECKER_CLASSIC, XYZ_to_xyY( Lab_to_XYZ( list(DATA_COLORCHECKER24_BEFORE_NOV2014_CIE_LAB.values()), CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"] ["ICC D50"], )), )) CCS_ILLUMINANT_COLORCHECKER24_BEFORE_NOV2014: NDArray = CCS_ILLUMINANTS[ "CIE 1931 2 Degree Standard Observer"]["ICC D50"] """*ColorChecker24 - Before November 2014* illuminant.""" CCS_COLORCHECKER24_BEFORE_NOV2014: ColourChecker = ColourChecker( "ColorChecker24 - Before November 2014", DATA_COLORCHECKER24_BEFORE_NOV2014, CCS_ILLUMINANT_COLORCHECKER24_BEFORE_NOV2014, ) """ Reference *ColorChecker Classic* data from *X-Rite (2015)*.