Exemplo n.º 1
0
    def test_nan_uv_to_CCT_Robertson1968(self):
        """
        Tests :func:`colour.temperature.cct.uv_to_CCT_Robertson1968` definition
        nan support.
        """

        cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]
        cases = set(permutations(cases * 3, r=2))
        for case in cases:
            uv = np.array(case)
            uv_to_CCT_Robertson1968(uv)
Exemplo n.º 2
0
    def test_nan_uv_to_CCT_Robertson1968(self):
        """
        Test :func:`colour.temperature.robertson1968.uv_to_CCT_Robertson1968`
        definition nan support.
        """

        cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]
        cases = set(permutations(cases * 3, r=2))
        for case in cases:
            uv = np.array(case)
            uv_to_CCT_Robertson1968(uv)
Exemplo n.º 3
0
    def test_n_dimensional_uv_to_CCT_Robertson1968(self):
        """
        Tests :func:`colour.temperature.cct.uv_to_CCT_Robertson1968` definition
        n-dimensional arrays support.
        """

        uv = np.array([0.1978, 0.3122])
        CCT_D_uv = uv_to_CCT_Robertson1968(uv)

        uv = np.tile(uv, (6, 1))
        CCT_D_uv = np.tile(CCT_D_uv, (6, 1))
        np.testing.assert_almost_equal(
            uv_to_CCT_Robertson1968(uv), CCT_D_uv, decimal=7)

        uv = np.reshape(uv, (2, 3, 2))
        CCT_D_uv = np.reshape(CCT_D_uv, (2, 3, 2))
        np.testing.assert_almost_equal(
            uv_to_CCT_Robertson1968(uv), CCT_D_uv, decimal=7)
Exemplo n.º 4
0
    def test_uv_to_CCT_Robertson1968(self):
        """
        Tests :func:`colour.temperature.cct.uv_to_CCT_Robertson1968`
        definition.
        """

        for key, value in TEMPERATURE_DUV_TO_UV.items():
            np.testing.assert_allclose(
                uv_to_CCT_Robertson1968(value), key, atol=0.25)
Exemplo n.º 5
0
    def test_uv_to_CCT_Robertson1968(self):
        """
        Tests :func:`colour.temperature.cct.uv_to_CCT_Robertson1968`
        definition.
        """

        for key, value in TEMPERATURE_DUV_TO_UV.items():
            np.testing.assert_allclose(uv_to_CCT_Robertson1968(value),
                                       key,
                                       atol=0.25)
Exemplo n.º 6
0
    def test_n_dimensional_uv_to_CCT_Robertson1968(self):
        """
        Test :func:`colour.temperature.robertson1968.uv_to_CCT_Robertson1968`
        definition n-dimensional arrays support.
        """

        uv = np.array([0.1978, 0.3122])
        CCT_D_uv = uv_to_CCT_Robertson1968(uv)

        uv = np.tile(uv, (6, 1))
        CCT_D_uv = np.tile(CCT_D_uv, (6, 1))
        np.testing.assert_almost_equal(uv_to_CCT_Robertson1968(uv),
                                       CCT_D_uv,
                                       decimal=7)

        uv = np.reshape(uv, (2, 3, 2))
        CCT_D_uv = np.reshape(CCT_D_uv, (2, 3, 2))
        np.testing.assert_almost_equal(uv_to_CCT_Robertson1968(uv),
                                       CCT_D_uv,
                                       decimal=7)
Exemplo n.º 7
0
Arquivo: cri.py Projeto: brehm/colour
def colour_rendering_index(spd_test, additional_data=False):
    """
    Returns the *colour rendering index* :math:`Q_a` of given spectral power
    distribution.

    Parameters
    ----------
    spd_test : SpectralPowerDistribution
        Test spectral power distribution.
    additional_data : bool, optional
        Output additional data.

    Returns
    -------
    numeric or CRI_Specification
        Colour rendering index.

    Examples
    --------
    >>> from colour import ILLUMINANTS_RELATIVE_SPDS
    >>> spd = ILLUMINANTS_RELATIVE_SPDS.get('F2')
    >>> colour_rendering_index(spd)  # doctest: +ELLIPSIS
    64.1507331...
    """

    cmfs = STANDARD_OBSERVERS_CMFS.get('CIE 1931 2 Degree Standard Observer')

    shape = cmfs.shape
    spd_test = spd_test.clone().align(shape)

    tcs_spds = {}
    for index, tcs_spd in TCS_SPDS.items():
        tcs_spds[index] = tcs_spd.clone().align(shape)

    XYZ = spectral_to_XYZ(spd_test, cmfs)
    uv = UCS_to_uv(XYZ_to_UCS(XYZ))
    CCT, _D_uv = uv_to_CCT_Robertson1968(uv)

    if CCT < 5000:
        spd_reference = blackbody_spd(CCT, shape)
    else:
        xy = CCT_to_xy_CIE_D(CCT)
        spd_reference = D_illuminant_relative_spd(xy)
        spd_reference.align(shape)

    test_tcs_colorimetry_data = tcs_colorimetry_data(
        spd_test,
        spd_reference,
        tcs_spds,
        cmfs,
        chromatic_adaptation=True)

    reference_tcs_colorimetry_data = tcs_colorimetry_data(
        spd_reference,
        spd_reference,
        tcs_spds,
        cmfs)

    Q_as = colour_rendering_indexes(
        test_tcs_colorimetry_data, reference_tcs_colorimetry_data)

    Q_a = np.average([v.Q_a for k, v in Q_as.items()
                      if k in (1, 2, 3, 4, 5, 6, 7, 8)])

    if additional_data:
        return CRI_Specification(spd_test.name,
                                 Q_a,
                                 Q_as,
                                 (test_tcs_colorimetry_data,
                                  reference_tcs_colorimetry_data))
    else:
        return Q_a
Exemplo n.º 8
0
def colour_rendering_index(sd_test, additional_data=False):
    """
    Returns the *Colour Rendering Index* (CRI) :math:`Q_a` of given spectral
    distribution.

    Parameters
    ----------
    sd_test : SpectralDistribution
        Test spectral distribution.
    additional_data : bool, optional
        Whether to output additional data.

    Returns
    -------
    numeric or CRI_Specification
        *Colour Rendering Index* (CRI).

    References
    ----------
    :cite:`Ohno2008a`

    Examples
    --------
    >>> from colour import ILLUMINANTS_SDS
    >>> sd = ILLUMINANTS_SDS['FL2']
    >>> colour_rendering_index(sd)  # doctest: +ELLIPSIS
    64.1515202...
    """

    cmfs = STANDARD_OBSERVERS_CMFS['CIE 1931 2 Degree Standard Observer'].copy(
    ).trim(DEFAULT_SPECTRAL_SHAPE)

    shape = cmfs.shape
    sd_test = sd_test.copy().align(shape)
    tcs_sds = {sd.name: sd.copy().align(shape) for sd in TCS_SDS.values()}

    with domain_range_scale('1'):
        XYZ = sd_to_XYZ(sd_test, cmfs)

    uv = UCS_to_uv(XYZ_to_UCS(XYZ))
    CCT, _D_uv = uv_to_CCT_Robertson1968(uv)

    if CCT < 5000:
        sd_reference = sd_blackbody(CCT, shape)
    else:
        xy = CCT_to_xy_CIE_D(CCT)
        sd_reference = sd_CIE_illuminant_D_series(xy)
        sd_reference.align(shape)

    test_tcs_colorimetry_data = tcs_colorimetry_data(sd_test,
                                                     sd_reference,
                                                     tcs_sds,
                                                     cmfs,
                                                     chromatic_adaptation=True)

    reference_tcs_colorimetry_data = tcs_colorimetry_data(
        sd_reference, sd_reference, tcs_sds, cmfs)

    Q_as = colour_rendering_indexes(test_tcs_colorimetry_data,
                                    reference_tcs_colorimetry_data)

    Q_a = np.average(
        [v.Q_a for k, v in Q_as.items() if k in (1, 2, 3, 4, 5, 6, 7, 8)])

    if additional_data:
        return CRI_Specification(
            sd_test.name, Q_a, Q_as,
            (test_tcs_colorimetry_data, reference_tcs_colorimetry_data))
    else:
        return Q_a
Exemplo n.º 9
0
def colour_rendering_index(spd_test, additional_data=False):
    """
    Returns the *Colour Rendering Index* (CRI) :math:`Q_a` of given spectral
    power distribution.

    Parameters
    ----------
    spd_test : SpectralPowerDistribution
        Test spectral power distribution.
    additional_data : bool, optional
        Output additional data.

    Returns
    -------
    numeric or CRI_Specification
        *Colour Rendering Index* (CRI).

    Examples
    --------
    >>> from colour import ILLUMINANTS_RELATIVE_SPDS
    >>> spd = ILLUMINANTS_RELATIVE_SPDS['F2']
    >>> colour_rendering_index(spd)  # doctest: +ELLIPSIS
    64.1515202...
    """

    cmfs = STANDARD_OBSERVERS_CMFS[
        'CIE 1931 2 Degree Standard Observer'].clone().trim_wavelengths(
            ASTME30815_PRACTISE_SHAPE)

    shape = cmfs.shape
    spd_test = spd_test.clone().align(shape)
    tcs_spds = {
        spd.name: spd.clone().align(shape)
        for spd in TCS_SPDS.values()
    }

    XYZ = spectral_to_XYZ(spd_test, cmfs)
    uv = UCS_to_uv(XYZ_to_UCS(XYZ))
    CCT, _D_uv = uv_to_CCT_Robertson1968(uv)

    if CCT < 5000:
        spd_reference = blackbody_spd(CCT, shape)
    else:
        xy = CCT_to_xy_CIE_D(CCT)
        spd_reference = D_illuminant_relative_spd(xy)
        spd_reference.align(shape)

    test_tcs_colorimetry_data = tcs_colorimetry_data(
        spd_test, spd_reference, tcs_spds, cmfs, chromatic_adaptation=True)

    reference_tcs_colorimetry_data = tcs_colorimetry_data(
        spd_reference, spd_reference, tcs_spds, cmfs)

    Q_as = colour_rendering_indexes(test_tcs_colorimetry_data,
                                    reference_tcs_colorimetry_data)

    Q_a = np.average(
        [v.Q_a for k, v in Q_as.items() if k in (1, 2, 3, 4, 5, 6, 7, 8)])

    if additional_data:
        return CRI_Specification(spd_test.name, Q_a, Q_as,
                                 (test_tcs_colorimetry_data,
                                  reference_tcs_colorimetry_data))
    else:
        return Q_a
Exemplo n.º 10
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
Exemplo n.º 11
0
def 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):
    """
    Returns the *CIE XYZ* to *Camera Space* 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.

    Returns
    -------
    ndarray
        *CIE XYZ* to *Camera Space* 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:`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)
    >>> XYZ_to_camera_space_matrix(  # doctest: +ELLIPSIS
    ...     np.array([0.34510414, 0.35162252]),
    ...     2850,
    ...     6500,
    ...     M_color_matrix_1,
    ...     M_color_matrix_2,
    ...     M_camera_calibration_1,
    ...     M_camera_calibration_2,
    ...     analog_balance)
    array([[ 0.4854908...,  0.0408106..., -0.0714282...],
           [-0.7433278...,  1.4956549...,  0.2680749...],
           [-0.1336946...,  0.1767874...,  0.6654045...]])
    """

    M_AB = np.diagflat(analog_balance)

    uv = UCS_to_uv(XYZ_to_UCS(xy_to_XYZ(xy)))
    CCT, _D_uv = uv_to_CCT_Robertson1968(uv)

    if is_identity(M_color_matrix_1) or is_identity(M_color_matrix_2):
        M_CM = (M_color_matrix_1
                if is_identity(M_color_matrix_2) else M_color_matrix_2)
    else:
        M_CM = interpolated_matrix(CCT, CCT_calibration_illuminant_1,
                                   CCT_calibration_illuminant_2,
                                   M_color_matrix_1, M_color_matrix_2)

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

    M_XYZ_to_camera_space = dot_matrix(dot_matrix(M_AB, M_CC), M_CM)

    return M_XYZ_to_camera_space
Exemplo n.º 12
0
def colour_rendering_index(sd_test, additional_data=False):
    """
    Returns the *Colour Rendering Index* (CRI) :math:`Q_a` of given spectral
    distribution.

    Parameters
    ----------
    sd_test : SpectralDistribution
        Test spectral distribution.
    additional_data : bool, optional
        Whether to output additional data.

    Returns
    -------
    numeric or CRI_Specification
        *Colour Rendering Index* (CRI).

    References
    ----------
    :cite:`Ohno2008a`

    Examples
    --------
    >>> from colour import ILLUMINANTS_SDS
    >>> sd = ILLUMINANTS_SDS['FL2']
    >>> colour_rendering_index(sd)  # doctest: +ELLIPSIS
    64.1515202...
    """

    cmfs = STANDARD_OBSERVERS_CMFS['CIE 1931 2 Degree Standard Observer'].copy(
    ).trim(ASTME30815_PRACTISE_SHAPE)

    shape = cmfs.shape
    sd_test = sd_test.copy().align(shape)
    tcs_sds = {sd.name: sd.copy().align(shape) for sd in TCS_SDS.values()}

    with domain_range_scale('1'):
        XYZ = sd_to_XYZ(sd_test, cmfs)

    uv = UCS_to_uv(XYZ_to_UCS(XYZ))
    CCT, _D_uv = uv_to_CCT_Robertson1968(uv)

    if CCT < 5000:
        sd_reference = sd_blackbody(CCT, shape)
    else:
        xy = CCT_to_xy_CIE_D(CCT)
        sd_reference = sd_CIE_illuminant_D_series(xy)
        sd_reference.align(shape)

    test_tcs_colorimetry_data = tcs_colorimetry_data(
        sd_test, sd_reference, tcs_sds, cmfs, chromatic_adaptation=True)

    reference_tcs_colorimetry_data = tcs_colorimetry_data(
        sd_reference, sd_reference, tcs_sds, cmfs)

    Q_as = colour_rendering_indexes(test_tcs_colorimetry_data,
                                    reference_tcs_colorimetry_data)

    Q_a = np.average(
        [v.Q_a for k, v in Q_as.items() if k in (1, 2, 3, 4, 5, 6, 7, 8)])

    if additional_data:
        return CRI_Specification(
            sd_test.name, Q_a, Q_as,
            (test_tcs_colorimetry_data, reference_tcs_colorimetry_data))
    else:
        return Q_a
Exemplo n.º 13
0
def colour_rendering_index(
    sd_test: SpectralDistribution, additional_data: Boolean = False
) -> Union[Floating, ColourRendering_Specification_CRI]:
    """
    Return the *Colour Rendering Index* (CRI) :math:`Q_a` of given spectral
    distribution.

    Parameters
    ----------
    sd_test
        Test spectral distribution.
    additional_data
        Whether to output additional data.

    Returns
    -------
    :class:`numpy.floating` or \
:class:`colour.quality.ColourRendering_Specification_CRI`
        *Colour Rendering Index* (CRI).

    References
    ----------
    :cite:`Ohno2008a`

    Examples
    --------
    >>> from colour import SDS_ILLUMINANTS
    >>> sd = SDS_ILLUMINANTS['FL2']
    >>> colour_rendering_index(sd)  # doctest: +ELLIPSIS
    64.2337241...
    """

    # pylint: disable=E1102
    cmfs = reshape_msds(
        MSDS_CMFS["CIE 1931 2 Degree Standard Observer"],
        SPECTRAL_SHAPE_DEFAULT,
    )

    shape = cmfs.shape
    sd_test = reshape_sd(sd_test, shape)
    tcs_sds = {sd.name: reshape_sd(sd, shape) for sd in SDS_TCS.values()}

    with domain_range_scale("1"):
        XYZ = sd_to_XYZ(sd_test, cmfs)

    uv = UCS_to_uv(XYZ_to_UCS(XYZ))
    CCT, _D_uv = uv_to_CCT_Robertson1968(uv)

    if CCT < 5000:
        sd_reference = sd_blackbody(CCT, shape)
    else:
        xy = CCT_to_xy_CIE_D(CCT)
        sd_reference = sd_CIE_illuminant_D_series(xy)
        sd_reference.align(shape)

    test_tcs_colorimetry_data = tcs_colorimetry_data(
        sd_test, sd_reference, tcs_sds, cmfs, chromatic_adaptation=True
    )

    reference_tcs_colorimetry_data = tcs_colorimetry_data(
        sd_reference, sd_reference, tcs_sds, cmfs
    )

    Q_as = colour_rendering_indexes(
        test_tcs_colorimetry_data, reference_tcs_colorimetry_data
    )

    Q_a = as_float_scalar(
        np.average(
            [v.Q_a for k, v in Q_as.items() if k in (1, 2, 3, 4, 5, 6, 7, 8)]
        )
    )

    if additional_data:
        return ColourRendering_Specification_CRI(
            sd_test.name,
            Q_a,
            Q_as,
            (test_tcs_colorimetry_data, reference_tcs_colorimetry_data),
        )
    else:
        return Q_a