Exemple #1
0
    def test_n_dimensional_chromatic_adaptation_matrix_VonKries(self):
        """
        Tests :func:`colour.adaptation.vonkries.\
chromatic_adaptation_matrix_VonKries` definition n-dimensional arrays support.
        """

        XYZ_w = np.array([0.95045593, 1.00000000, 1.08905775])
        XYZ_wr = np.array([0.96429568, 1.00000000, 0.82510460])
        M = np.array([
            [1.04257389, 0.03089108, -0.05281257],
            [0.02219345, 1.00185663, -0.02107375],
            [-0.00116488, -0.00342053, 0.76178907],
        ])
        np.testing.assert_almost_equal(chromatic_adaptation_matrix_VonKries(
            XYZ_w, XYZ_wr),
                                       M,
                                       decimal=7)

        XYZ_w = np.tile(XYZ_w, (6, 1))
        XYZ_wr = np.tile(XYZ_wr, (6, 1))
        M = np.reshape(np.tile(M, (6, 1)), (6, 3, 3))
        np.testing.assert_almost_equal(chromatic_adaptation_matrix_VonKries(
            XYZ_w, XYZ_wr),
                                       M,
                                       decimal=7)

        XYZ_w = np.reshape(XYZ_w, (2, 3, 3))
        XYZ_wr = np.reshape(XYZ_wr, (2, 3, 3))
        M = np.reshape(M, (2, 3, 3, 3))
        np.testing.assert_almost_equal(chromatic_adaptation_matrix_VonKries(
            XYZ_w, XYZ_wr),
                                       M,
                                       decimal=7)
Exemple #2
0
    def test_n_dimensional_chromatic_adaptation_matrix_VonKries(self):
        """
        Tests :func:`colour.adaptation.vonkries.\
chromatic_adaptation_matrix_VonKries` definition n-dimensional arrays support.
        """

        XYZ_w = np.array([1.09846607, 1.00000000, 0.35582280])
        XYZ_wr = np.array([0.95042855, 1.00000000, 1.08890037])
        M = np.array([[0.86876537, -0.14165393, 0.38719611],
                      [-0.10300724, 1.05840142, 0.15386462],
                      [0.00781674, 0.02678750, 2.96081771]])
        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(XYZ_w, XYZ_wr),
            M,
            decimal=7)

        XYZ_w = np.tile(XYZ_w, (6, 1))
        XYZ_wr = np.tile(XYZ_wr, (6, 1))
        M = np.reshape(np.tile(M, (6, 1)), (6, 3, 3))
        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(XYZ_w, XYZ_wr),
            M,
            decimal=7)

        XYZ_w = np.reshape(XYZ_w, (2, 3, 3))
        XYZ_wr = np.reshape(XYZ_wr, (2, 3, 3))
        M = np.reshape(M, (2, 3, 3, 3))
        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(XYZ_w, XYZ_wr),
            M,
            decimal=7)
Exemple #3
0
    def test_n_dimensional_chromatic_adaptation_matrix_VonKries(self):
        """
        Tests :func:`colour.adaptation.vonkries.\
chromatic_adaptation_matrix_VonKries` definition n-dimensional arrays support.
        """

        XYZ_w = np.array([1.09846607, 1.00000000, 0.35582280])
        XYZ_wr = np.array([0.95042855, 1.00000000, 1.08890037])
        M = np.array([[0.86876537, -0.14165393, 0.38719611],
                      [-0.10300724, 1.05840142, 0.15386462],
                      [0.00781674, 0.02678750, 2.96081771]])  # yapf: disable
        np.testing.assert_almost_equal(chromatic_adaptation_matrix_VonKries(
            XYZ_w, XYZ_wr),
                                       M,
                                       decimal=7)

        XYZ_w = np.tile(XYZ_w, (6, 1))
        XYZ_wr = np.tile(XYZ_wr, (6, 1))
        M = np.reshape(np.tile(M, (6, 1)), (6, 3, 3))
        np.testing.assert_almost_equal(chromatic_adaptation_matrix_VonKries(
            XYZ_w, XYZ_wr),
                                       M,
                                       decimal=7)

        XYZ_w = np.reshape(XYZ_w, (2, 3, 3))
        XYZ_wr = np.reshape(XYZ_wr, (2, 3, 3))
        M = np.reshape(M, (2, 3, 3, 3))
        np.testing.assert_almost_equal(chromatic_adaptation_matrix_VonKries(
            XYZ_w, XYZ_wr),
                                       M,
                                       decimal=7)
Exemple #4
0
    def test_n_dimensional_chromatic_adaptation_matrix_VonKries(self):
        """
        Tests :func:`colour.adaptation.vonkries.\
chromatic_adaptation_matrix_VonKries` definition n-dimensional arrays support.
        """

        XYZ_w = np.array([0.95045593, 1.00000000, 1.08905775])
        XYZ_wr = np.array([0.96429568, 1.00000000, 0.82510460])
        M = chromatic_adaptation_matrix_VonKries(XYZ_w, XYZ_wr)

        XYZ_w = np.tile(XYZ_w, (6, 1))
        XYZ_wr = np.tile(XYZ_wr, (6, 1))
        M = np.reshape(np.tile(M, (6, 1)), (6, 3, 3))
        np.testing.assert_almost_equal(chromatic_adaptation_matrix_VonKries(
            XYZ_w, XYZ_wr),
                                       M,
                                       decimal=7)

        XYZ_w = np.reshape(XYZ_w, (2, 3, 3))
        XYZ_wr = np.reshape(XYZ_wr, (2, 3, 3))
        M = np.reshape(M, (2, 3, 3, 3))
        np.testing.assert_almost_equal(chromatic_adaptation_matrix_VonKries(
            XYZ_w, XYZ_wr),
                                       M,
                                       decimal=7)
    def test_nan_chromatic_adaptation_matrix_VonKries(self):
        """
        Tests :func:`colour.adaptation.vonkries.\
chromatic_adaptation_matrix_VonKries` 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_w = np.array(case)
            XYZ_wr = np.array(case)
            chromatic_adaptation_matrix_VonKries(XYZ_w, XYZ_wr)
Exemple #6
0
    def test_nan_chromatic_adaptation_matrix_VonKries(self):
        """
        Tests :func:`colour.adaptation.vonkries.\
chromatic_adaptation_matrix_VonKries` 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_w = np.array(case)
            XYZ_wr = np.array(case)
            chromatic_adaptation_matrix_VonKries(XYZ_w, XYZ_wr)
    def test_domain_range_scale_chromatic_adaptation_VonKries(self):
        """
        Tests :func:`colour.adaptation.vonkries.\
chromatic_adaptation_matrix_VonKries` definition domain and range scale
        support.
        """

        XYZ_w = np.array([0.95045593, 1.00000000, 1.08905775])
        XYZ_wr = np.array([0.96429568, 1.00000000, 0.82510460])
        M = chromatic_adaptation_matrix_VonKries(XYZ_w, XYZ_wr)

        d_r = (('reference', 1), (1, 1), (100, 0.01))
        for scale, factor in d_r:
            with domain_range_scale(scale):
                np.testing.assert_almost_equal(
                    chromatic_adaptation_matrix_VonKries(
                        XYZ_w * factor, XYZ_wr * factor),
                    M,
                    decimal=7)
Exemple #8
0
    def test_domain_range_scale_chromatic_adaptation_VonKries(self):
        """
        Tests :func:`colour.adaptation.vonkries.\
chromatic_adaptation_matrix_VonKries` definition domain and range scale
        support.
        """

        XYZ_w = np.array([0.95045593, 1.00000000, 1.08905775])
        XYZ_wr = np.array([0.96429568, 1.00000000, 0.82510460])
        M = chromatic_adaptation_matrix_VonKries(XYZ_w, XYZ_wr)

        d_r = (('reference', 1), (1, 1), (100, 0.01))
        for scale, factor in d_r:
            with domain_range_scale(scale):
                np.testing.assert_almost_equal(
                    chromatic_adaptation_matrix_VonKries(
                        XYZ_w * factor, XYZ_wr * factor),
                    M,
                    decimal=7)
Exemple #9
0
def RGB_to_RGB(RGB,
               input_colourspace,
               output_colourspace,
               chromatic_adaptation_transform='CAT02'):
    """
    Converts from given input *RGB* colourspace to output *RGB* colourspace
    using given *chromatic adaptation* method.

    Parameters
    ----------
    RGB : array_like
        *RGB* colourspace array.
    input_colourspace : RGB_Colourspace
        *RGB* input colourspace.
    output_colourspace : RGB_Colourspace
        *RGB* output colourspace.
    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
        *RGB* colourspace array.

    Notes
    -----
    -   Input / output *RGB* colourspace arrays are in domain / range [0, 1].
    -   Input / output *RGB* colourspace arrays are assumed to be representing
        linear light values.

    Examples
    --------
    >>> from colour import sRGB_COLOURSPACE, PROPHOTO_RGB_COLOURSPACE
    >>> RGB = np.array([0.01103742, 0.12734226, 0.11632971])
    >>> RGB_to_RGB(
    ...     RGB,
    ...     sRGB_COLOURSPACE,
    ...     PROPHOTO_RGB_COLOURSPACE)  # doctest: +ELLIPSIS
    array([ 0.0643538...,  0.1157289...,  0.1158038...])
    """

    cat = chromatic_adaptation_matrix_VonKries(
        xy_to_XYZ(input_colourspace.whitepoint),
        xy_to_XYZ(output_colourspace.whitepoint),
        chromatic_adaptation_transform)

    M = dot_matrix(cat, input_colourspace.RGB_to_XYZ_matrix)
    M = dot_matrix(output_colourspace.XYZ_to_RGB_matrix, M)

    RGB = dot_vector(M, RGB)

    return RGB
    def test_n_dimensional_chromatic_adaptation_matrix_VonKries(self):
        """
        Tests :func:`colour.adaptation.vonkries.\
chromatic_adaptation_matrix_VonKries` definition n-dimensional arrays support.
        """

        XYZ_w = np.array([0.95045593, 1.00000000, 1.08905775])
        XYZ_wr = np.array([0.96429568, 1.00000000, 0.82510460])
        M = chromatic_adaptation_matrix_VonKries(XYZ_w, XYZ_wr)

        XYZ_w = np.tile(XYZ_w, (6, 1))
        XYZ_wr = np.tile(XYZ_wr, (6, 1))
        M = np.reshape(np.tile(M, (6, 1)), (6, 3, 3))
        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(XYZ_w, XYZ_wr), M, decimal=7)

        XYZ_w = np.reshape(XYZ_w, (2, 3, 3))
        XYZ_wr = np.reshape(XYZ_wr, (2, 3, 3))
        M = np.reshape(M, (2, 3, 3, 3))
        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(XYZ_w, XYZ_wr), M, decimal=7)
Exemple #11
0
def RGB_to_RGB(RGB,
               input_colourspace,
               output_colourspace,
               chromatic_adaptation_transform='CAT02'):
    """
    Converts from given input *RGB* colourspace to output *RGB* colourspace
    using given *chromatic adaptation* method.

    Parameters
    ----------
    RGB : array_like
        *RGB* colourspace array.
    input_colourspace : RGB_Colourspace
        *RGB* input colourspace.
    output_colourspace : RGB_Colourspace
        *RGB* output colourspace.
    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
        *RGB* colourspace array.

    Notes
    -----
    -   *RGB* colourspace arrays are in domain [0, 1].

    Examples
    --------
    >>> from colour import sRGB_COLOURSPACE, PROPHOTO_RGB_COLOURSPACE
    >>> RGB = np.array([0.01103604, 0.12734466, 0.11631037])
    >>> RGB_to_RGB(
    ...     RGB,
    ...     sRGB_COLOURSPACE,
    ...     PROPHOTO_RGB_COLOURSPACE)  # doctest: +ELLIPSIS
    array([ 0.0643338...,  0.1157362...,  0.1157614...])
    """

    cat = chromatic_adaptation_matrix_VonKries(
        xy_to_XYZ(input_colourspace.whitepoint),
        xy_to_XYZ(output_colourspace.whitepoint),
        chromatic_adaptation_transform)

    M = dot_matrix(cat, input_colourspace.RGB_to_XYZ_matrix)
    M = dot_matrix(output_colourspace.XYZ_to_RGB_matrix, M)

    RGB = dot_vector(M, RGB)

    return RGB
def RGB_to_RGB_matrix(input_colourspace,
                      output_colourspace,
                      chromatic_adaptation_transform='CAT02'):
    """
    Computes the matrix :math:`M` converting from given input *RGB*
    colourspace to output *RGB* colourspace using given *chromatic
    adaptation* method.

    Parameters
    ----------
    input_colourspace : RGB_Colourspace
        *RGB* input colourspace.
    output_colourspace : RGB_Colourspace
        *RGB* output colourspace.
    chromatic_adaptation_transform : unicode, optional
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco',
        'Bianco PC', None}**,
        *Chromatic adaptation* transform, if *None* no chromatic adaptation is
        performed.

    Returns
    -------
    ndarray
        Conversion matrix :math:`M`.

    Examples
    --------
    >>> from colour.models import sRGB_COLOURSPACE, PROPHOTO_RGB_COLOURSPACE
    >>> RGB_to_RGB_matrix(sRGB_COLOURSPACE, PROPHOTO_RGB_COLOURSPACE)
    ... # doctest: +ELLIPSIS
    array([[ 0.5288241...,  0.3340609...,  0.1373616...],
           [ 0.0975294...,  0.8790074...,  0.0233981...],
           [ 0.0163599...,  0.1066124...,  0.8772485...]])
    """

    M = input_colourspace.RGB_to_XYZ_matrix

    if chromatic_adaptation_transform is not None:
        M_CAT = chromatic_adaptation_matrix_VonKries(
            xy_to_XYZ(input_colourspace.whitepoint),
            xy_to_XYZ(output_colourspace.whitepoint),
            chromatic_adaptation_transform)

        M = dot_matrix(M_CAT, input_colourspace.RGB_to_XYZ_matrix)

    M = dot_matrix(output_colourspace.XYZ_to_RGB_matrix, M)

    return M
Exemple #13
0
def RGB_to_RGB_matrix(input_colourspace,
                      output_colourspace,
                      chromatic_adaptation_transform='CAT02'):
    """
    Computes the matrix :math:`M` converting from given input *RGB*
    colourspace to output *RGB* colourspace using given *chromatic
    adaptation* method.

    Parameters
    ----------
    input_colourspace : RGB_Colourspace
        *RGB* input colourspace.
    output_colourspace : RGB_Colourspace
        *RGB* output colourspace.
    chromatic_adaptation_transform : unicode, optional
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco',
        'Bianco PC', None}**,
        *Chromatic adaptation* transform, if *None* no chromatic adaptation is
        performed.

    Returns
    -------
    ndarray
        Conversion matrix :math:`M`.

    Examples
    --------
    >>> from colour.models import sRGB_COLOURSPACE, PROPHOTO_RGB_COLOURSPACE
    >>> RGB_to_RGB_matrix(sRGB_COLOURSPACE, PROPHOTO_RGB_COLOURSPACE)
    ... # doctest: +ELLIPSIS
    array([[ 0.5288241...,  0.3340609...,  0.1373616...],
           [ 0.0975294...,  0.8790074...,  0.0233981...],
           [ 0.0163599...,  0.1066124...,  0.8772485...]])
    """

    M = input_colourspace.RGB_to_XYZ_matrix

    if chromatic_adaptation_transform is not None:
        M_CAT = chromatic_adaptation_matrix_VonKries(
            xy_to_XYZ(input_colourspace.whitepoint),
            xy_to_XYZ(output_colourspace.whitepoint),
            chromatic_adaptation_transform)

        M = dot_matrix(M_CAT, input_colourspace.RGB_to_XYZ_matrix)

    M = dot_matrix(output_colourspace.XYZ_to_RGB_matrix, M)

    return M
def XYZ_to_RGB(XYZ,
               illuminant_XYZ,
               illuminant_RGB,
               XYZ_to_RGB_matrix,
               chromatic_adaptation_transform='CAT02',
               encoding_cctf=None):
    """
    Converts from *CIE XYZ* tristimulus values to *RGB* colourspace array.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values.
    illuminant_XYZ : array_like
        *CIE XYZ* tristimulus values *illuminant* *xy* chromaticity coordinates
        or *CIE xyY* colourspace array.
    illuminant_RGB : array_like
        *RGB* colourspace *illuminant* *xy* chromaticity coordinates or
        *CIE xyY* colourspace array.
    XYZ_to_RGB_matrix : array_like
        *Normalised primary matrix*.
    chromatic_adaptation_transform : unicode, optional
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco',
        'Bianco PC', None}**,
        *Chromatic adaptation* transform, if *None* no chromatic adaptation is
        performed.
    encoding_cctf : object, optional
        Encoding colour component transfer function (Encoding CCTF) or
        opto-electronic transfer function (OETF / OECF).

    Returns
    -------
    ndarray
        *RGB* colourspace array.

    Notes
    -----

    +--------------------+-----------------------+---------------+
    | **Domain**         | **Scale - Reference** | **Scale - 1** |
    +====================+=======================+===============+
    | ``XYZ``            | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+
    | ``illuminant_XYZ`` | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+
    | ``illuminant_RGB`` | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+

    +--------------------+-----------------------+---------------+
    | **Range**          | **Scale - Reference** | **Scale - 1** |
    +====================+=======================+===============+
    | ``RGB``            | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+

    Examples
    --------
    >>> XYZ = np.array([0.21638819, 0.12570000, 0.03847493])
    >>> illuminant_XYZ = np.array([0.34570, 0.35850])
    >>> illuminant_RGB = np.array([0.31270, 0.32900])
    >>> chromatic_adaptation_transform = 'Bradford'
    >>> XYZ_to_RGB_matrix = np.array(
    ...     [[3.24062548, -1.53720797, -0.49862860],
    ...      [-0.96893071, 1.87575606, 0.04151752],
    ...      [0.05571012, -0.20402105, 1.05699594]]
    ... )
    >>> XYZ_to_RGB(XYZ, illuminant_XYZ, illuminant_RGB, XYZ_to_RGB_matrix,
    ...            chromatic_adaptation_transform)  # doctest: +ELLIPSIS
    array([ 0.4559557...,  0.0303970...,  0.0408724...])
    """

    XYZ = to_domain_1(XYZ)

    if chromatic_adaptation_transform is not None:
        M_CAT = chromatic_adaptation_matrix_VonKries(
            xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)),
            xyY_to_XYZ(xy_to_xyY(illuminant_RGB)),
            transform=chromatic_adaptation_transform)

        XYZ = dot_vector(M_CAT, XYZ)

    RGB = dot_vector(XYZ_to_RGB_matrix, XYZ)

    if encoding_cctf is not None:
        with domain_range_scale('ignore'):
            RGB = encoding_cctf(RGB)

    return from_range_1(RGB)
Exemple #15
0
    def test_chromatic_adaptation_matrix_VonKries(self):
        """
        Tests :func:`colour.adaptation.vonkries.\
chromatic_adaptation_matrix_VonKries` definition.
        """

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([1.09846607, 1.00000000, 0.35582280]),
                np.array([0.95042855, 1.00000000, 1.08890037])),
            np.array([[0.86876537, -0.14165393, 0.38719611],
                      [-0.10300724, 1.05840142, 0.15386462],
                      [0.00781674, 0.02678750, 2.96081771]]),
            decimal=7)  # yapf: disable

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.99092745, 1.00000000, 0.85313273]),
                np.array([1.01679082, 1.00000000, 0.67610122])),
            np.array([[1.03379528, 0.03065322, -0.04486819],
                      [0.02195826, 0.99354348, -0.01793687],
                      [-0.00102726, -0.00281712, 0.79698769]]),
            decimal=7)  # yapf: disable

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.98070597, 1.00000000, 1.18224949]),
                np.array([0.92833635, 1.00000000, 1.03664720])),
            np.linalg.inv(
                chromatic_adaptation_matrix_VonKries(
                    np.array([0.92833635, 1.00000000, 1.03664720]),
                    np.array([0.98070597, 1.00000000, 1.18224949]))))

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([1.09846607, 1.00000000, 0.35582280]),
                np.array([0.95042855, 1.00000000, 1.08890037]),
                transform='XYZ Scaling'),
            np.array([[0.86523251, 0.00000000, 0.00000000],
                      [0.00000000, 1.00000000, 0.00000000],
                      [0.00000000, 0.00000000, 3.06023214]]),
            decimal=7)  # yapf: disable

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([1.09846607, 1.00000000, 0.35582280]),
                np.array([0.95042855, 1.00000000, 1.08890037]),
                transform='Bradford'),
            np.array([[0.84467949, -0.11793553, 0.39489408],
                      [-0.13664085, 1.10412369, 0.12919812],
                      [0.07986716, -0.13493155, 3.19288296]]),
            decimal=7)  # yapf: disable

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([1.09846607, 1.00000000, 0.35582280]),
                np.array([0.95042855, 1.00000000, 1.08890037]),
                transform='Von Kries'),
            np.array([[0.93949221, -0.23393727, 0.42820614],
                      [-0.02569635, 1.02638463, 0.00517656],
                      [0.00000000, 0.00000000, 3.06023214]]),
            decimal=7)  # yapf: disable
Exemple #16
0
def RGB_to_XYZ(RGB,
               illuminant_RGB,
               illuminant_XYZ,
               RGB_to_XYZ_matrix,
               chromatic_adaptation_transform='CAT02',
               decoding_cctf=None):
    """
    Converts given *RGB* colourspace array to *CIE XYZ* tristimulus values.

    Parameters
    ----------
    RGB : array_like
        *RGB* colourspace array.
    illuminant_RGB : array_like
        *RGB* colourspace *illuminant* chromaticity coordinates or *CIE xyY*
        colourspace array.
    illuminant_XYZ : array_like
        *CIE XYZ* tristimulus values *illuminant* chromaticity coordinates or
        *CIE xyY* colourspace array.
    RGB_to_XYZ_matrix : array_like
        *Normalised primary matrix*.
    chromatic_adaptation_transform : unicode, optional
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco',
        'Bianco PC', None}**,
        *Chromatic adaptation* transform, if *None* no chromatic adaptation is
        performed.
    decoding_cctf : object, optional
        Decoding colour component transfer function (Decoding CCTF) or
        electro-optical transfer function (EOTF / EOCF).

    Returns
    -------
    ndarray
        *CIE XYZ* tristimulus values.

    Notes
    -----

    +--------------------+-----------------------+---------------+
    | **Domain**         | **Scale - Reference** | **Scale - 1** |
    +====================+=======================+===============+
    | ``RGB``            | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+
    | ``illuminant_XYZ`` | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+
    | ``illuminant_RGB`` | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+

    +--------------------+-----------------------+---------------+
    | **Range**          | **Scale - Reference** | **Scale - 1** |
    +====================+=======================+===============+
    | ``XYZ``            | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+

    Examples
    --------
    >>> RGB = np.array([0.45595571, 0.03039702, 0.04087245])
    >>> illuminant_RGB = np.array([0.31270, 0.32900])
    >>> illuminant_XYZ = np.array([0.34570, 0.35850])
    >>> chromatic_adaptation_transform = 'Bradford'
    >>> RGB_to_XYZ_matrix = np.array(
    ...     [[0.41240000, 0.35760000, 0.18050000],
    ...      [0.21260000, 0.71520000, 0.07220000],
    ...      [0.01930000, 0.11920000, 0.95050000]]
    ... )
    >>> RGB_to_XYZ(RGB, illuminant_RGB, illuminant_XYZ, RGB_to_XYZ_matrix,
    ...            chromatic_adaptation_transform)  # doctest: +ELLIPSIS
    array([ 0.2163881...,  0.1257    ,  0.0384749...])
    """

    RGB = to_domain_1(RGB)

    if decoding_cctf is not None:
        with domain_range_scale('ignore'):
            RGB = decoding_cctf(RGB)

    XYZ = dot_vector(RGB_to_XYZ_matrix, RGB)

    if chromatic_adaptation_transform is not None:
        M_CAT = chromatic_adaptation_matrix_VonKries(
            xyY_to_XYZ(xy_to_xyY(illuminant_RGB)),
            xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)),
            transform=chromatic_adaptation_transform)

        XYZ = dot_vector(M_CAT, XYZ)

    return from_range_1(XYZ)
Exemple #17
0
def XYZ_to_RGB(XYZ,
               illuminant_XYZ,
               illuminant_RGB,
               XYZ_to_RGB_matrix,
               chromatic_adaptation_transform='CAT02',
               encoding_cctf=None):
    """
    Converts from *CIE XYZ* tristimulus values to *RGB* colourspace array.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values.
    illuminant_XYZ : array_like
        *CIE XYZ* tristimulus values *illuminant* *xy* chromaticity coordinates
        or *CIE xyY* colourspace array.
    illuminant_RGB : array_like
        *RGB* colourspace *illuminant* *xy* chromaticity coordinates or
        *CIE xyY* colourspace array.
    XYZ_to_RGB_matrix : array_like
        *Normalised primary matrix*.
    chromatic_adaptation_transform : unicode, optional
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco',
        'Bianco PC', None}**,
        *Chromatic adaptation* transform, if *None* no chromatic adaptation is
        performed.
    encoding_cctf : object, optional
        Encoding colour component transfer function (Encoding CCTF) or
        opto-electronic transfer function (OETF / OECF).

    Returns
    -------
    ndarray
        *RGB* colourspace array.

    Notes
    -----

    +--------------------+-----------------------+---------------+
    | **Domain**         | **Scale - Reference** | **Scale - 1** |
    +====================+=======================+===============+
    | ``XYZ``            | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+
    | ``illuminant_XYZ`` | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+
    | ``illuminant_RGB`` | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+

    +--------------------+-----------------------+---------------+
    | **Range**          | **Scale - Reference** | **Scale - 1** |
    +====================+=======================+===============+
    | ``RGB``            | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+

    Examples
    --------
    >>> XYZ = np.array([0.21638819, 0.12570000, 0.03847493])
    >>> illuminant_XYZ = np.array([0.34570, 0.35850])
    >>> illuminant_RGB = np.array([0.31270, 0.32900])
    >>> chromatic_adaptation_transform = 'Bradford'
    >>> XYZ_to_RGB_matrix = np.array(
    ...     [[3.24062548, -1.53720797, -0.49862860],
    ...      [-0.96893071, 1.87575606, 0.04151752],
    ...      [0.05571012, -0.20402105, 1.05699594]]
    ... )
    >>> XYZ_to_RGB(XYZ, illuminant_XYZ, illuminant_RGB, XYZ_to_RGB_matrix,
    ...            chromatic_adaptation_transform)  # doctest: +ELLIPSIS
    array([ 0.4559557...,  0.0303970...,  0.0408724...])
    """

    XYZ = to_domain_1(XYZ)

    if chromatic_adaptation_transform is not None:
        M_CAT = chromatic_adaptation_matrix_VonKries(
            xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)),
            xyY_to_XYZ(xy_to_xyY(illuminant_RGB)),
            transform=chromatic_adaptation_transform)

        XYZ = dot_vector(M_CAT, XYZ)

    RGB = dot_vector(XYZ_to_RGB_matrix, XYZ)

    if encoding_cctf is not None:
        with domain_range_scale('ignore'):
            RGB = encoding_cctf(RGB)

    return from_range_1(RGB)
def RGB_to_XYZ(RGB,
               illuminant_RGB,
               illuminant_XYZ,
               RGB_to_XYZ_matrix,
               chromatic_adaptation_transform='CAT02',
               decoding_cctf=None):
    """
    Converts given *RGB* colourspace array to *CIE XYZ* tristimulus values.

    Parameters
    ----------
    RGB : array_like
        *RGB* colourspace array.
    illuminant_RGB : array_like
        *RGB* colourspace *illuminant* chromaticity coordinates or *CIE xyY*
        colourspace array.
    illuminant_XYZ : array_like
        *CIE XYZ* tristimulus values *illuminant* chromaticity coordinates or
        *CIE xyY* colourspace array.
    RGB_to_XYZ_matrix : array_like
        *Normalised primary matrix*.
    chromatic_adaptation_transform : unicode, optional
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco',
        'Bianco PC', None}**,
        *Chromatic adaptation* transform, if *None* no chromatic adaptation is
        performed.
    decoding_cctf : object, optional
        Decoding colour component transfer function (Decoding CCTF) or
        electro-optical transfer function (EOTF / EOCF).

    Returns
    -------
    ndarray
        *CIE XYZ* tristimulus values.

    Notes
    -----

    +--------------------+-----------------------+---------------+
    | **Domain**         | **Scale - Reference** | **Scale - 1** |
    +====================+=======================+===============+
    | ``RGB``            | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+
    | ``illuminant_XYZ`` | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+
    | ``illuminant_RGB`` | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+

    +--------------------+-----------------------+---------------+
    | **Range**          | **Scale - Reference** | **Scale - 1** |
    +====================+=======================+===============+
    | ``XYZ``            | [0, 1]                | [0, 1]        |
    +--------------------+-----------------------+---------------+

    Examples
    --------
    >>> RGB = np.array([0.45595571, 0.03039702, 0.04087245])
    >>> illuminant_RGB = np.array([0.31270, 0.32900])
    >>> illuminant_XYZ = np.array([0.34570, 0.35850])
    >>> chromatic_adaptation_transform = 'Bradford'
    >>> RGB_to_XYZ_matrix = np.array(
    ...     [[0.41240000, 0.35760000, 0.18050000],
    ...      [0.21260000, 0.71520000, 0.07220000],
    ...      [0.01930000, 0.11920000, 0.95050000]]
    ... )
    >>> RGB_to_XYZ(RGB, illuminant_RGB, illuminant_XYZ, RGB_to_XYZ_matrix,
    ...            chromatic_adaptation_transform)  # doctest: +ELLIPSIS
    array([ 0.2163881...,  0.1257    ,  0.0384749...])
    """

    RGB = to_domain_1(RGB)

    if decoding_cctf is not None:
        with domain_range_scale('ignore'):
            RGB = decoding_cctf(RGB)

    XYZ = dot_vector(RGB_to_XYZ_matrix, RGB)

    if chromatic_adaptation_transform is not None:
        M_CAT = chromatic_adaptation_matrix_VonKries(
            xyY_to_XYZ(xy_to_xyY(illuminant_RGB)),
            xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)),
            transform=chromatic_adaptation_transform)

        XYZ = dot_vector(M_CAT, XYZ)

    return from_range_1(XYZ)
Exemple #19
0
def XYZ_to_RGB(XYZ,
               illuminant_XYZ,
               illuminant_RGB,
               XYZ_to_RGB_matrix,
               chromatic_adaptation_transform='CAT02',
               OECF=None):
    """
    Converts from *CIE XYZ* tristimulus values to given *RGB* colourspace.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values.
    illuminant_XYZ : array_like
        *CIE XYZ* tristimulus values *illuminant* *xy* chromaticity coordinates
        or *CIE xyY* colourspace array.
    illuminant_RGB : array_like
        *RGB* colourspace *illuminant* *xy* chromaticity coordinates or
        *CIE xyY* colourspace array.
    XYZ_to_RGB_matrix : array_like
        *Normalised primary matrix*.
    chromatic_adaptation_transform : unicode, optional
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild, 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco',
        'Bianco PC'}**,
        *Chromatic adaptation* transform.
    OECF : object, optional
        *Opto-electronic conversion function*.

    Returns
    -------
    ndarray
        *RGB* colourspace array.

    Notes
    -----
    -   Input *CIE XYZ* tristimulus values are in domain [0, 1].
    -   Input *illuminant_XYZ* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array are in domain [0, :math:`\infty`].
    -   Input *illuminant_RGB* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array are in domain [0, :math:`\infty`].
    -   Output *RGB* colourspace array is in domain [0, 1].

    Examples
    --------
    >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313])
    >>> illuminant_XYZ = np.array([0.34567, 0.35850])
    >>> illuminant_RGB = np.array([0.31271, 0.32902])
    >>> chromatic_adaptation_transform = 'Bradford'
    >>> XYZ_to_RGB_matrix = np.array([
    ...     [3.24100326, -1.53739899, -0.49861587],
    ...     [-0.96922426, 1.87592999, 0.04155422],
    ...     [0.05563942, -0.20401120, 1.05714897]])
    >>> XYZ_to_RGB(
    ...     XYZ,
    ...     illuminant_XYZ,
    ...     illuminant_RGB,
    ...     XYZ_to_RGB_matrix,
    ...     chromatic_adaptation_transform)  # doctest: +ELLIPSIS
    array([ 0.0110360...,  0.1273446...,  0.1163103...])
    """

    M = chromatic_adaptation_matrix_VonKries(
        xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)),
        xyY_to_XYZ(xy_to_xyY(illuminant_RGB)),
        transform=chromatic_adaptation_transform)

    XYZ_a = dot_vector(M, XYZ)

    RGB = dot_vector(XYZ_to_RGB_matrix, XYZ_a)

    if OECF is not None:
        RGB = OECF(RGB)

    return RGB
Exemple #20
0
def XYZ_to_RGB(XYZ,
               illuminant_XYZ,
               illuminant_RGB,
               XYZ_to_RGB_matrix,
               chromatic_adaptation_transform='CAT02',
               encoding_cctf=None):
    """
    Converts from *CIE XYZ* tristimulus values to given *RGB* colourspace.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values.
    illuminant_XYZ : array_like
        *CIE XYZ* tristimulus values *illuminant* *xy* chromaticity coordinates
        or *CIE xyY* colourspace array.
    illuminant_RGB : array_like
        *RGB* colourspace *illuminant* *xy* chromaticity coordinates or
        *CIE xyY* colourspace array.
    XYZ_to_RGB_matrix : array_like
        *Normalised primary matrix*.
    chromatic_adaptation_transform : unicode, optional
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco',
        'Bianco PC'}**,
        *Chromatic adaptation* transform.
    encoding_cctf : object, optional
        Encoding colour component transfer function (Encoding CCTF) or
        opto-electronic transfer function (OETF / OECF).

    Returns
    -------
    ndarray
        *RGB* colourspace array.

    Notes
    -----
    -   Input *CIE XYZ* tristimulus values are in domain [0, 1].
    -   Input *illuminant_XYZ* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array are in domain [0, :math:`\infty`].
    -   Input *illuminant_RGB* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array are in domain [0, :math:`\infty`].
    -   Output *RGB* colourspace array is in range [0, 1].

    Examples
    --------
    >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313])
    >>> illuminant_XYZ = np.array([0.34570, 0.35850])
    >>> illuminant_RGB = np.array([0.31270, 0.32900])
    >>> chromatic_adaptation_transform = 'Bradford'
    >>> XYZ_to_RGB_matrix = np.array([
    ...     [3.24062548, -1.53720797, -0.49862860],
    ...     [-0.96893071, 1.87575606, 0.04151752],
    ...     [0.05571012, -0.20402105, 1.05699594]])
    >>> XYZ_to_RGB(
    ...     XYZ,
    ...     illuminant_XYZ,
    ...     illuminant_RGB,
    ...     XYZ_to_RGB_matrix,
    ...     chromatic_adaptation_transform)  # doctest: +ELLIPSIS
    array([ 0.0110015...,  0.1273504...,  0.1163271...])
    """

    M = chromatic_adaptation_matrix_VonKries(
        xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)),
        xyY_to_XYZ(xy_to_xyY(illuminant_RGB)),
        transform=chromatic_adaptation_transform)

    XYZ_a = dot_vector(M, XYZ)

    RGB = dot_vector(XYZ_to_RGB_matrix, XYZ_a)

    if encoding_cctf is not None:
        RGB = encoding_cctf(RGB)

    return RGB
    def test_chromatic_adaptation_matrix_VonKries(self):
        """
        Tests :func:`colour.adaptation.vonkries.\
chromatic_adaptation_matrix_VonKries` definition.
        """

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.95045593, 1.00000000, 1.08905775]),
                np.array([0.96429568, 1.00000000, 0.82510460])),
            np.array([
                [1.04257389, 0.03089108, -0.05281257],
                [0.02219345, 1.00185663, -0.02107375],
                [-0.00116488, -0.00342053, 0.76178907],
            ]),
            decimal=7)

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.95045593, 1.00000000, 1.08905775]),
                np.array([1.09846607, 1.00000000, 0.35582280])),
            np.array([
                [1.17159793, 0.16088780, -0.16158366],
                [0.11462057, 0.96182051, -0.06497572],
                [-0.00413024, -0.00912739, 0.33871096],
            ]),
            decimal=7)

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.95045593, 1.00000000, 1.08905775]),
                np.array([0.99144661, 1.00000000, 0.67315942])),
            np.linalg.inv(
                chromatic_adaptation_matrix_VonKries(
                    np.array([0.99144661, 1.00000000, 0.67315942]),
                    np.array([0.95045593, 1.00000000, 1.08905775]))),
            decimal=7)

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.95045593, 1.00000000, 1.08905775]),
                np.array([0.96429568, 1.00000000, 0.82510460]),
                transform='XYZ Scaling'),
            np.array([
                [1.01456117, 0.00000000, 0.00000000],
                [0.00000000, 1.00000000, 0.00000000],
                [0.00000000, 0.00000000, 0.75763163],
            ]),
            decimal=7)

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.95045593, 1.00000000, 1.08905775]),
                np.array([0.96429568, 1.00000000, 0.82510460]),
                transform='Bradford'),
            np.array([
                [1.04792979, 0.02294687, -0.05019227],
                [0.02962781, 0.99043443, -0.01707380],
                [-0.00924304, 0.01505519, 0.75187428],
            ]),
            decimal=7)

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.95045593, 1.00000000, 1.08905775]),
                np.array([0.96429568, 1.00000000, 0.82510460]),
                transform='Von Kries'),
            np.array([
                [1.01611856, 0.05535971, -0.05219186],
                [0.00608087, 0.99555604, -0.00122642],
                [0.00000000, 0.00000000, 0.75763163],
            ]),
            decimal=7)
Exemple #22
0
    def test_chromatic_adaptation_matrix_VonKries(self):
        """
        Tests
        :func:`colour.adaptation.vonkries.chromatic_adaptation_matrix_VonKries`
        definition.
        """

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([1.09846607, 1., 0.3558228]),
                np.array([0.95042855, 1., 1.08890037])),
            np.array([[0.86876537, -0.14165393, 0.38719611],
                      [-0.10300724, 1.05840142, 0.15386462],
                      [0.00781674, 0.0267875, 2.96081771]]),
            decimal=7)

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.99092745, 1., 0.85313273]),
                np.array([1.01679082, 1., 0.67610122])),
            np.array([[1.03379528e+00, 3.06532172e-02, -4.48681876e-02],
                      [2.19582633e-02, 9.93543483e-01, -1.79368671e-02],
                      [-1.02726253e-03, -2.81711777e-03, 7.96987686e-01]]),
            decimal=7)

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.98070597, 1., 1.18224949]),
                np.array([0.92833635, 1., 1.0366472])),
            np.linalg.inv(chromatic_adaptation_matrix_VonKries(
                np.array([0.92833635, 1., 1.0366472]),
                np.array([0.98070597, 1., 1.18224949]))))

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([1.09846607, 1., 0.3558228]),
                np.array([0.95042855, 1., 1.08890037]),
                transform='XYZ Scaling'),
            np.array([[0.86523251, 0., 0.],
                      [0., 1., 0.],
                      [0., 0., 3.06023214]]),
            decimal=7)

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([1.09846607, 1., 0.3558228]),
                np.array([0.95042855, 1., 1.08890037]),
                transform='Bradford'),
            np.array([[0.84467949, -0.11793553, 0.39489408],
                      [-0.13664085, 1.10412369, 0.12919812],
                      [0.07986716, -0.13493155, 3.19288296]]),
            decimal=7)

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([1.09846607, 1., 0.3558228]),
                np.array([0.95042855, 1., 1.08890037]),
                transform='Von Kries'),
            np.array([[0.93949221, -0.23393727, 0.42820614],
                      [-0.02569635, 1.02638463, 0.00517656],
                      [0., 0., 3.06023214]]),
            decimal=7)
Exemple #23
0
def RGB_to_XYZ(RGB,
               illuminant_RGB,
               illuminant_XYZ,
               RGB_to_XYZ_matrix,
               chromatic_adaptation_transform='CAT02',
               inverse_transfer_function=None):
    """
    Converts from *RGB* colourspace to *CIE XYZ* colourspace using given
    *RGB* colourspace matrix, *illuminants*, *chromatic adaptation* method,
    *normalised primary matrix* and *transfer function*.

    Parameters
    ----------
    RGB : array_like, (3,)
        *RGB* colourspace matrix.
    illuminant_RGB : array_like
        *RGB* colourspace *illuminant* chromaticity coordinates.
    illuminant_XYZ : array_like
        *CIE XYZ* colourspace *illuminant* chromaticity coordinates.
    RGB_to_XYZ_matrix : array_like, (3, 3)
        *Normalised primary matrix*.
    chromatic_adaptation_transform : unicode, optional
        {'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild,
        'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC'},
        *Chromatic adaptation* transform.
    inverse_transfer_function : object, optional
        *Inverse transfer function*.

    Returns
    -------
    ndarray, (3,)
        *CIE XYZ* colourspace matrix.

    Notes
    -----
    -   Input *RGB* colourspace matrix is in domain [0, 1].
    -   Input *illuminant_RGB* *xy* chromaticity coordinates are in domain
        [0, 1].
    -   Input *illuminant_XYZ* *xy* chromaticity coordinates are in domain
        [0, 1].
    -   Output *CIE XYZ* colourspace matrix is in domain [0, 1].

    Examples
    --------
    >>> RGB = np.array([0.01103604, 0.12734466, 0.11631037])
    >>> illuminant_RGB = (0.31271, 0.32902)
    >>> illuminant_XYZ = (0.34567, 0.35850)
    >>> chromatic_adaptation_transform = 'Bradford'
    >>> RGB_to_XYZ_matrix = np.array([
    ...     [0.41238656, 0.35759149, 0.18045049],
    ...     [0.21263682, 0.71518298, 0.0721802],
    ...     [0.01933062, 0.11919716, 0.95037259]])
    >>> RGB_to_XYZ(
    ...     RGB,
    ...     illuminant_RGB,
    ...     illuminant_XYZ,
    ...     RGB_to_XYZ_matrix,
    ...     chromatic_adaptation_transform)  # doctest: +ELLIPSIS
    array([ 0.0704953...,  0.1008    ,  0.0955831...])
    """

    RGB = np.ravel(RGB)

    if inverse_transfer_function is not None:
        RGB = np.array([inverse_transfer_function(x) for x in RGB])

    XYZ = np.dot(RGB_to_XYZ_matrix.reshape((3, 3)), RGB.reshape((3, 1)))

    cat = chromatic_adaptation_matrix_VonKries(
        xy_to_XYZ(illuminant_RGB),
        xy_to_XYZ(illuminant_XYZ),
        transform=chromatic_adaptation_transform)

    XYZ_a = np.dot(cat, XYZ.reshape((3, 1)))

    return np.ravel(XYZ_a)
Exemple #24
0
def XYZ_to_RGB(XYZ,
               illuminant_XYZ,
               illuminant_RGB,
               XYZ_to_RGB_matrix,
               chromatic_adaptation_transform='CAT02',
               OECF=None):
    """
    Converts from *CIE XYZ* tristimulus values to given *RGB* colourspace.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values.
    illuminant_XYZ : array_like
        *CIE XYZ* tristimulus values *illuminant* *xy* chromaticity coordinates
        or *CIE xyY* colourspace array.
    illuminant_RGB : array_like
        *RGB* colourspace *illuminant* *xy* chromaticity coordinates or
        *CIE xyY* colourspace array.
    XYZ_to_RGB_matrix : array_like
        *Normalised primary matrix*.
    chromatic_adaptation_transform : unicode, optional
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild, 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco',
        'Bianco PC'}**,
        *Chromatic adaptation* transform.
    OECF : object, optional
        *Opto-electronic conversion function*.

    Returns
    -------
    ndarray
        *RGB* colourspace array.

    Notes
    -----
    -   Input *CIE XYZ* tristimulus values are in domain [0, 1].
    -   Input *illuminant_XYZ* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array are in domain [0, :math:`\infty`].
    -   Input *illuminant_RGB* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array are in domain [0, :math:`\infty`].
    -   Output *RGB* colourspace array is in domain [0, 1].

    Examples
    --------
    >>> XYZ = np.array([0.07049534, 0.10080000, 0.09558313])
    >>> illuminant_XYZ = np.array([0.34567, 0.35850])
    >>> illuminant_RGB = np.array([0.31271, 0.32902])
    >>> chromatic_adaptation_transform = 'Bradford'
    >>> XYZ_to_RGB_matrix = np.array([
    ...     [3.24100326, -1.53739899, -0.49861587],
    ...     [-0.96922426, 1.87592999, 0.04155422],
    ...     [0.05563942, -0.20401120, 1.05714897]])
    >>> XYZ_to_RGB(
    ...     XYZ,
    ...     illuminant_XYZ,
    ...     illuminant_RGB,
    ...     XYZ_to_RGB_matrix,
    ...     chromatic_adaptation_transform)  # doctest: +ELLIPSIS
    array([ 0.0110360...,  0.1273446...,  0.1163103...])
    """

    M = chromatic_adaptation_matrix_VonKries(
        xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)),
        xyY_to_XYZ(xy_to_xyY(illuminant_RGB)),
        transform=chromatic_adaptation_transform)

    XYZ_a = dot_vector(M, XYZ)

    RGB = dot_vector(XYZ_to_RGB_matrix, XYZ_a)

    if OECF is not None:
        RGB = OECF(RGB)

    return RGB
Exemple #25
0
def RGB_to_XYZ(RGB,
               illuminant_RGB,
               illuminant_XYZ,
               RGB_to_XYZ_matrix,
               chromatic_adaptation_transform='CAT02',
               EOCF=None):
    """
    Converts from given *RGB* colourspace to *CIE XYZ* tristimulus values.

    Parameters
    ----------
    RGB : array_like
        *RGB* colourspace array.
    illuminant_RGB : array_like
        *RGB* colourspace *illuminant* chromaticity coordinates or *CIE xyY*
        colourspace array.
    illuminant_XYZ : array_like
        *CIE XYZ* tristimulus values *illuminant* chromaticity coordinates or
        *CIE xyY* colourspace array.
    RGB_to_XYZ_matrix : array_like
        *Normalised primary matrix*.
    chromatic_adaptation_transform : unicode, optional
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild, 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco',
        'Bianco PC'}**,
        *Chromatic adaptation* transform.
    EOCF : object, optional
        *Electro-optical conversion function*.

    Returns
    -------
    ndarray
        *CIE XYZ* tristimulus values.

    Notes
    -----
    -   Input *RGB* colourspace array is in domain [0, 1].
    -   Input *illuminant_RGB* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array are in domain [0, :math:`\infty`].
    -   Input *illuminant_XYZ* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array are in domain [0, :math:`\infty`].
    -   Output *CIE XYZ* tristimulus values are in domain [0, 1].

    Examples
    --------
    >>> RGB = np.array([0.01103604, 0.12734466, 0.11631037])
    >>> illuminant_RGB = np.array([0.31271, 0.32902])
    >>> illuminant_XYZ = np.array([0.34567, 0.35850])
    >>> chromatic_adaptation_transform = 'Bradford'
    >>> RGB_to_XYZ_matrix = np.array([
    ...     [0.41238656, 0.35759149, 0.18045049],
    ...     [0.21263682, 0.71518298, 0.07218020],
    ...     [0.01933062, 0.11919716, 0.95037259]])
    >>> RGB_to_XYZ(
    ...     RGB,
    ...     illuminant_RGB,
    ...     illuminant_XYZ,
    ...     RGB_to_XYZ_matrix,
    ...     chromatic_adaptation_transform)  # doctest: +ELLIPSIS
    array([ 0.0704953...,  0.1008    ,  0.0955831...])
    """

    if EOCF is not None:
        RGB = EOCF(RGB)

    M = chromatic_adaptation_matrix_VonKries(
        xyY_to_XYZ(xy_to_xyY(illuminant_RGB)),
        xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)),
        transform=chromatic_adaptation_transform)

    XYZ = dot_vector(RGB_to_XYZ_matrix, RGB)

    XYZ_a = dot_vector(M, XYZ)

    return XYZ_a
Exemple #26
0
def RGB_to_XYZ(RGB,
               illuminant_RGB,
               illuminant_XYZ,
               RGB_to_XYZ_matrix,
               chromatic_adaptation_transform='CAT02',
               decoding_cctf=None):
    """
    Converts from given *RGB* colourspace to *CIE XYZ* tristimulus values.

    Parameters
    ----------
    RGB : array_like
        *RGB* colourspace array.
    illuminant_RGB : array_like
        *RGB* colourspace *illuminant* chromaticity coordinates or *CIE xyY*
        colourspace array.
    illuminant_XYZ : array_like
        *CIE XYZ* tristimulus values *illuminant* chromaticity coordinates or
        *CIE xyY* colourspace array.
    RGB_to_XYZ_matrix : array_like
        *Normalised primary matrix*.
    chromatic_adaptation_transform : unicode, optional
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco',
        'Bianco PC'}**,
        *Chromatic adaptation* transform.
    decoding_cctf : object, optional
        Decoding colour component transfer function (Decoding CCTF) or
        electro-optical transfer function (EOTF / EOCF).

    Returns
    -------
    ndarray
        *CIE XYZ* tristimulus values.

    Notes
    -----
    -   Input *RGB* colourspace array is in domain [0, 1].
    -   Input *illuminant_RGB* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array are in domain [0, :math:`\infty`].
    -   Input *illuminant_XYZ* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array are in domain [0, :math:`\infty`].
    -   Output *CIE XYZ* tristimulus values are in range [0, 1].

    Examples
    --------
    >>> RGB = np.array([0.01100154,  0.12735048,  0.11632713])
    >>> illuminant_RGB = np.array([0.31270, 0.32900])
    >>> illuminant_XYZ = np.array([0.34570, 0.35850])
    >>> chromatic_adaptation_transform = 'Bradford'
    >>> RGB_to_XYZ_matrix = np.array([
    ...     [0.41240000, 0.35760000, 0.18050000],
    ...     [0.21260000, 0.71520000, 0.07220000],
    ...     [0.01930000, 0.11920000, 0.95050000]])
    >>> RGB_to_XYZ(
    ...     RGB,
    ...     illuminant_RGB,
    ...     illuminant_XYZ,
    ...     RGB_to_XYZ_matrix,
    ...     chromatic_adaptation_transform)  # doctest: +ELLIPSIS
    array([ 0.0704953...,  0.1008    ,  0.0955831...])
    """

    if decoding_cctf is not None:
        RGB = decoding_cctf(RGB)

    M = chromatic_adaptation_matrix_VonKries(
        xyY_to_XYZ(xy_to_xyY(illuminant_RGB)),
        xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)),
        transform=chromatic_adaptation_transform)

    XYZ = dot_vector(RGB_to_XYZ_matrix, RGB)

    XYZ_a = dot_vector(M, XYZ)

    return XYZ_a
Exemple #27
0
def camera_space_to_XYZ_matrix(xy,
                               CCT_calibration_illuminant_1,
                               CCT_calibration_illuminant_2,
                               M_color_matrix_1,
                               M_color_matrix_2,
                               M_camera_calibration_1,
                               M_camera_calibration_2,
                               analog_balance,
                               M_forward_matrix_1,
                               M_forward_matrix_2,
                               chromatic_adaptation_transform='Bradford'):
    """
    Returns the *Camera Space* to *CIE XYZ* matrix for given *xy* white
    balance chromaticity coordinates.

    Parameters
    ----------
    xy : array_like
        *xy* white balance chromaticity coordinates.
    CCT_calibration_illuminant_1 : numeric
        Correlated colour temperature of *CalibrationIlluminant1*.
    CCT_calibration_illuminant_2 : numeric
        Correlated colour temperature of *CalibrationIlluminant2*.
    M_color_matrix_1 : array_like
        *ColorMatrix1* tag matrix.
    M_color_matrix_2 : array_like
        *ColorMatrix2* tag matrix.
    M_camera_calibration_1 : array_like
        *CameraCalibration1* tag matrix.
    M_camera_calibration_2 : array_like
        *CameraCalibration2* tag matrix.
    analog_balance : array_like
        *AnalogBalance* tag vector.
    M_forward_matrix_1 : array_like
        *ForwardMatrix1* tag matrix.
    M_forward_matrix_2 : array_like
        *ForwardMatrix2* tag matrix.
    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
        *Camera Space* to *CIE XYZ* matrix.

    Notes
    -----
    -   The reference illuminant is D50 as defined per
        :attr:`colour_hdri.models.dataset.dng.ADOBE_DNG_XYZ_ILLUMINANT`
        attribute.

    References
    ----------
    -   :cite:`AdobeSystems2012f`
    -   :cite:`AdobeSystems2012g`
    -   :cite:`AdobeSystems2015d`
    -   :cite:`McGuffog2012a`

    Examples
    --------
    >>> M_color_matrix_1 = np.array(
    ...     [[0.5309, -0.0229, -0.0336],
    ...      [-0.6241, 1.3265, 0.3337],
    ...      [-0.0817, 0.1215, 0.6664]])
    >>> M_color_matrix_2 = np.array(
    ...     [[0.4716, 0.0603, -0.0830],
    ...      [-0.7798, 1.5474, 0.2480],
    ...      [-0.1496, 0.1937, 0.6651]])
    >>> M_camera_calibration_1 = np.identity(3)
    >>> M_camera_calibration_2 = np.identity(3)
    >>> analog_balance = np.ones(3)
    >>> M_forward_matrix_1 = np.array(
    ...     [[0.8924, -0.1041, 0.1760],
    ...      [0.4351, 0.6621, -0.0972],
    ...      [0.0505, -0.1562, 0.9308]])
    >>> M_forward_matrix_2 = np.array(
    ...     [[0.8924, -0.1041, 0.1760],
    ...      [0.4351, 0.6621, -0.0972],
    ...      [0.0505, -0.1562, 0.9308]])
    >>> camera_space_to_XYZ_matrix(  # doctest: +ELLIPSIS
    ...     np.array([0.32816244, 0.34698169]),
    ...     2850,
    ...     6500,
    ...     M_color_matrix_1,
    ...     M_color_matrix_2,
    ...     M_camera_calibration_1,
    ...     M_camera_calibration_2,
    ...     analog_balance,
    ...     M_forward_matrix_1,
    ...     M_forward_matrix_2)
    array([[ 2.1604087..., -0.1041...    ,  0.2722498...],
           [ 1.0533324...,  0.6621...    , -0.1503561...],
           [ 0.1222553..., -0.1562...    ,  1.4398304...]])
    """

    # *ForwardMatrix1* and *ForwardMatrix2* are not included in the camera
    # profile.
    if is_identity(M_forward_matrix_1) and is_identity(M_forward_matrix_2):
        M_camera_to_XYZ = np.linalg.inv(
            XYZ_to_camera_space_matrix(xy, CCT_calibration_illuminant_1,
                                       CCT_calibration_illuminant_2,
                                       M_color_matrix_1, M_color_matrix_2,
                                       M_camera_calibration_1,
                                       M_camera_calibration_2, analog_balance))
        M_CAT = chromatic_adaptation_matrix_VonKries(
            xy_to_XYZ(xy), xy_to_XYZ(ADOBE_DNG_XYZ_ILLUMINANT),
            chromatic_adaptation_transform)
        M_camera_space_to_XYZ = dot_matrix(M_CAT, M_camera_to_XYZ)
    else:
        uv = UCS_to_uv(XYZ_to_UCS(xy_to_XYZ(xy)))
        CCT, _D_uv = uv_to_CCT_Robertson1968(uv)

        M_CC = interpolated_matrix(CCT, CCT_calibration_illuminant_1,
                                   CCT_calibration_illuminant_2,
                                   M_camera_calibration_1,
                                   M_camera_calibration_2)

        # The reference implementation :cite:`AdobeSystems2015d` diverges from
        # the white-paper :cite:`AdobeSystems2012f`:
        # The reference implementation directly computes the camera neutral by
        # multiplying directly the interpolated colour matrix :math:`CM` with
        # the tristimulus values of the *xy* white balance chromaticity
        # coordinates.
        # The current implementation is based on the white-paper so that the
        # interpolated camera calibration matrix :math:`CC` and the
        # analog balance matrix :math:`AB` are accounted for.
        camera_neutral = xy_to_camera_neutral(
            xy, CCT_calibration_illuminant_1, CCT_calibration_illuminant_2,
            M_color_matrix_1, M_color_matrix_2, M_camera_calibration_1,
            M_camera_calibration_2, analog_balance)

        M_AB = np.diagflat(analog_balance)

        M_reference_neutral = dot_vector(np.linalg.inv(dot_matrix(M_AB, M_CC)),
                                         camera_neutral)
        M_D = np.linalg.inv(np.diagflat(M_reference_neutral))
        M_FM = interpolated_matrix(CCT, CCT_calibration_illuminant_1,
                                   CCT_calibration_illuminant_2,
                                   M_forward_matrix_1, M_forward_matrix_2)
        M_camera_space_to_XYZ = dot_matrix(
            dot_matrix(M_FM, M_D), np.linalg.inv(dot_matrix(M_AB, M_CC)))

    return M_camera_space_to_XYZ
Exemple #28
0
def RGB_to_XYZ(RGB,
               illuminant_RGB,
               illuminant_XYZ,
               RGB_to_XYZ_matrix,
               chromatic_adaptation_transform='CAT02',
               EOCF=None):
    """
    Converts from given *RGB* colourspace to *CIE XYZ* tristimulus values.

    Parameters
    ----------
    RGB : array_like
        *RGB* colourspace array.
    illuminant_RGB : array_like
        *RGB* colourspace *illuminant* chromaticity coordinates or *CIE xyY*
        colourspace array.
    illuminant_XYZ : array_like
        *CIE XYZ* tristimulus values *illuminant* chromaticity coordinates or
        *CIE xyY* colourspace array.
    RGB_to_XYZ_matrix : array_like
        *Normalised primary matrix*.
    chromatic_adaptation_transform : unicode, optional
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild, 'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco',
        'Bianco PC'}**,
        *Chromatic adaptation* transform.
    EOCF : object, optional
        *Electro-optical conversion function*.

    Returns
    -------
    ndarray
        *CIE XYZ* tristimulus values.

    Notes
    -----
    -   Input *RGB* colourspace array is in domain [0, 1].
    -   Input *illuminant_RGB* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array are in domain [0, :math:`\infty`].
    -   Input *illuminant_XYZ* *xy* chromaticity coordinates or *CIE xyY*
        colourspace array are in domain [0, :math:`\infty`].
    -   Output *CIE XYZ* tristimulus values are in domain [0, 1].

    Examples
    --------
    >>> RGB = np.array([0.01103604, 0.12734466, 0.11631037])
    >>> illuminant_RGB = np.array([0.31271, 0.32902])
    >>> illuminant_XYZ = np.array([0.34567, 0.35850])
    >>> chromatic_adaptation_transform = 'Bradford'
    >>> RGB_to_XYZ_matrix = np.array([
    ...     [0.41238656, 0.35759149, 0.18045049],
    ...     [0.21263682, 0.71518298, 0.07218020],
    ...     [0.01933062, 0.11919716, 0.95037259]])
    >>> RGB_to_XYZ(
    ...     RGB,
    ...     illuminant_RGB,
    ...     illuminant_XYZ,
    ...     RGB_to_XYZ_matrix,
    ...     chromatic_adaptation_transform)  # doctest: +ELLIPSIS
    array([ 0.0704953...,  0.1008    ,  0.0955831...])
    """

    if EOCF is not None:
        RGB = EOCF(RGB)

    M = chromatic_adaptation_matrix_VonKries(
        xyY_to_XYZ(xy_to_xyY(illuminant_RGB)),
        xyY_to_XYZ(xy_to_xyY(illuminant_XYZ)),
        transform=chromatic_adaptation_transform)

    XYZ = dot_vector(RGB_to_XYZ_matrix, RGB)

    XYZ_a = dot_vector(M, XYZ)

    return XYZ_a
Exemple #29
0
    def test_chromatic_adaptation_matrix_VonKries(self):
        """
        Tests :func:`colour.adaptation.vonkries.\
chromatic_adaptation_matrix_VonKries` definition.
        """

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.95045593, 1.00000000, 1.08905775]),
                np.array([0.96429568, 1.00000000, 0.82510460])),
            np.array([
                [1.04257389, 0.03089108, -0.05281257],
                [0.02219345, 1.00185663, -0.02107375],
                [-0.00116488, -0.00342053, 0.76178907],
            ]),
            decimal=7)

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.95045593, 1.00000000, 1.08905775]),
                np.array([1.09846607, 1.00000000, 0.35582280])),
            np.array([
                [1.17159793, 0.16088780, -0.16158366],
                [0.11462057, 0.96182051, -0.06497572],
                [-0.00413024, -0.00912739, 0.33871096],
            ]),
            decimal=7)

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.95045593, 1.00000000, 1.08905775]),
                np.array([0.99144661, 1.00000000, 0.67315942])),
            np.linalg.inv(
                chromatic_adaptation_matrix_VonKries(
                    np.array([0.99144661, 1.00000000, 0.67315942]),
                    np.array([0.95045593, 1.00000000, 1.08905775]))),
            decimal=7)

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.95045593, 1.00000000, 1.08905775]),
                np.array([0.96429568, 1.00000000, 0.82510460]),
                transform='XYZ Scaling'),
            np.array([
                [1.01456117, 0.00000000, 0.00000000],
                [0.00000000, 1.00000000, 0.00000000],
                [0.00000000, 0.00000000, 0.75763163],
            ]),
            decimal=7)

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.95045593, 1.00000000, 1.08905775]),
                np.array([0.96429568, 1.00000000, 0.82510460]),
                transform='Bradford'),
            np.array([
                [1.04792979, 0.02294687, -0.05019227],
                [0.02962781, 0.99043443, -0.01707380],
                [-0.00924304, 0.01505519, 0.75187428],
            ]),
            decimal=7)

        np.testing.assert_almost_equal(
            chromatic_adaptation_matrix_VonKries(
                np.array([0.95045593, 1.00000000, 1.08905775]),
                np.array([0.96429568, 1.00000000, 0.82510460]),
                transform='Von Kries'),
            np.array([
                [1.01611856, 0.05535971, -0.05219186],
                [0.00608087, 0.99555604, -0.00122642],
                [0.00000000, 0.00000000, 0.75763163],
            ]),
            decimal=7)
Exemple #30
0
def XYZ_to_RGB(XYZ,
               illuminant_XYZ,
               illuminant_RGB,
               XYZ_to_RGB_matrix,
               chromatic_adaptation_transform='CAT02',
               transfer_function=None):
    """
    Converts from *CIE XYZ* colourspace to *RGB* colourspace using given
    *CIE XYZ* colourspace matrix, *illuminants*, *chromatic adaptation* method,
    *normalised primary matrix* and *transfer function*.

    Parameters
    ----------
    XYZ : array_like, (3,)
        *CIE XYZ* colourspace matrix.
    illuminant_XYZ : array_like
        *CIE XYZ* colourspace *illuminant* *xy* chromaticity coordinates.
    illuminant_RGB : array_like
        *RGB* colourspace *illuminant* *xy* chromaticity coordinates.
    XYZ_to_RGB_matrix : array_like, (3, 3)
        *Normalised primary matrix*.
    chromatic_adaptation_transform : unicode, optional
        {'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp', 'Fairchild,
        'CMCCAT97', 'CMCCAT2000', 'CAT02_BRILL_CAT', 'Bianco', 'Bianco PC'},
        *Chromatic adaptation* transform.
    transfer_function : object, optional
        *Transfer function*.

    Returns
    -------
    ndarray, (3,)
        *RGB* colourspace matrix.

    Notes
    -----
    -   Input *CIE XYZ* colourspace matrix is in domain [0, 1].
    -   Input *illuminant_XYZ* *xy* chromaticity coordinates are in domain
        [0, 1].
    -   Input *illuminant_RGB* *xy* chromaticity coordinates are in domain
        [0, 1].
    -   Output *RGB* colourspace matrix is in domain [0, 1].

    Examples
    --------
    >>> XYZ = np.array([0.07049534, 0.1008, 0.09558313])
    >>> illuminant_XYZ = (0.34567, 0.35850)
    >>> illuminant_RGB = (0.31271, 0.32902)
    >>> chromatic_adaptation_transform = 'Bradford'
    >>> XYZ_to_RGB_matrix = np.array([
    ...     [3.24100326, -1.53739899, -0.49861587],
    ...     [-0.96922426, 1.87592999, 0.04155422],
    ...     [0.05563942, -0.2040112, 1.05714897]])
    >>> XYZ_to_RGB(
    ...     XYZ,
    ...     illuminant_XYZ,
    ...     illuminant_RGB,
    ...     XYZ_to_RGB_matrix,
    ...     chromatic_adaptation_transform)  # doctest: +ELLIPSIS
    array([ 0.0110360...,  0.1273446...,  0.1163103...])
    """

    XYZ = np.ravel(XYZ)

    cat = chromatic_adaptation_matrix_VonKries(
        xy_to_XYZ(illuminant_XYZ),
        xy_to_XYZ(illuminant_RGB),
        transform=chromatic_adaptation_transform)

    XYZ_a = np.dot(cat, XYZ)

    RGB = np.dot(XYZ_to_RGB_matrix.reshape((3, 3)),
                 XYZ_a.reshape((3, 1)))

    RGB = np.ravel(RGB)

    if transfer_function is not None:
        RGB = np.array([transfer_function(x) for x in RGB])

    return RGB