Lee1010
Lee1010

Reputation: 99

Converting sRGB D65 to CIELab D50

I want to convert from sRGB D65 to CIELab D50. I'm aware of the Bruce Lindbloom functions and calculator but I just want to be sure if I am doing the calculations right. Starting from a values of sR/100, sG/80, sB/20 and D65, would the following workflow be correct? sRGB D65 -> XYZ -> Bradford Chromatic adaptation to D50 -> CIE Lab D50 = 34.99, 0.51, 31.35.

Upvotes: 1

Views: 1946

Answers (1)

Kel Solaar
Kel Solaar

Reputation: 4090

There is something not working in the chromatic adaption part of your implementation.

Using colour and a manual conversion:

>>> import colour
>>> import numpy as np
>>> RGB = np.array([100, 80, 20]) / 255
>>> D50 = colour.CCS_ILLUMINANTS['cie_2_1931']['D50']
>>> XYZ = colour.sRGB_to_XYZ(RGB, illuminant=D50)
>>> print(colour.XYZ_to_Lab(XYZ, illuminant=D50))
[ 35.31471609   3.63177851  37.28158403]

And with the Automatic Colour Conversion graph:

>>> colour.convert(RGB, 'sRGB', 'CIE Lab', illuminant=D50) * 100
array([ 35.31471609,   3.63177851,  37.28158403]

And an alternative path that does not use the colour.sRGB_to_XYZ definition and seem to match yours:

>>> colour.convert(RGB, 'Output-Referred RGB', 'CIE Lab', illuminant=D50, verbose={'mode': 'short'}) * 100
===============================================================================
*                                                                             *
*   [ Conversion Path ]                                                       *
*                                                                             *
*   "cctf_decoding" --> "RGB_to_XYZ" --> "XYZ_to_Lab"                         *
*                                                                             *
===============================================================================
array([ 34.99753019,   0.50577795,  31.35732344])

What is happening though here is that the conversion from RGB to CIE XYZ tristimulus values does not perform any chromatic adaptation between D65 and D50 because the illuminant argument is not matched by the colour.RGB_to_XYZ definition. The proper way to do it would be to specify illuminant_RGB for the RGB side although it defaults to D65 and illuminant_XYZ for the CIE XYZ side:

>>> colour.convert(RGB, 'Output-Referred RGB', 'CIE Lab', illuminant_XYZ=D50, illuminant=D50, verbose={'mode': 'short'}) * 100
===============================================================================
*                                                                             *
*   [ Conversion Path ]                                                       *
*                                                                             *
*   "cctf_decoding" --> "RGB_to_XYZ" --> "XYZ_to_Lab"                         *
*                                                                             *
===============================================================================
array([ 35.31471609,   3.63177851,  37.28158403])

Now we match the expected conversion result. Here is the verbose conversion so that you can check the intermediate values:

>>> colour.convert(RGB, 'Output-Referred RGB', 'CIE Lab', RGB_to_XYZ={'illuminant_XYZ': D50}, XYZ_to_Lab={'illuminant': D50}, verbose={'mode': 'Extended'}) * 100
===================================================================================
*                                                                                 *
*   [ Conversion Path ]                                                           *
*                                                                                 *
*   "cctf_decoding" --> "RGB_to_XYZ" --> "XYZ_to_Lab"                             *
*                                                                                 *
===================================================================================
===================================================================================
*                                                                                 *
*   [ "cctf_decoding" ]                                                           *
*                                                                                 *
*   [ Signature ]                                                                 *
*                                                                                 *
*   <Signature (value, function='sRGB', **kwargs)>                                *
*                                                                                 *
*   [ Documentation ]                                                             *
*                                                                                 *
*   Decodes non-linear :math:`R'G'B'` values to linear :math:`RGB` values using   *
*   given decoding colour component transfer function (Decoding CCTF).            *
*                                                                                 *
*   Parameters                                                                    *
*   ----------                                                                    *
*   value : numeric or array_like                                                 *
*       Non-linear :math:`R'G'B'` values.                                         *
*   function : unicode, optional                                                  *
*       {:attr:`colour.CCTF_DECODINGS`},                                          *
*       Computation function.                                                     *
*                                                                                 *
*   Other Parameters                                                              *
*   ----------------                                                              *
*   \**kwargs : dict, optional                                                    *
*       Keywords arguments for the relevant decoding CCTF of the                  *
*       :attr:`colour.CCTF_DECODINGS` attribute collection.                       *
*                                                                                 *
*   Warnings                                                                      *
*   --------                                                                      *
*   For *ITU-R BT.2100*, only the electro-optical transfer functions              *
*   (EOTFs / EOCFs) are exposed by this definition, please refer to the           *
*   :func:`colour.oetf_inverse` definition for the inverse opto-electronic        *
*   transfer functions (OETF / OECF).                                             *
*                                                                                 *
*   Returns                                                                       *
*   -------                                                                       *
*   numeric or ndarray                                                            *
*       Linear :math:`RGB` values.                                                *
*                                                                                 *
*   Examples                                                                      *
*   --------                                                                      *
*   >>> cctf_decoding(0.391006842619746, function='PLog', log_reference=400)      *
*   ... # doctest: +ELLIPSIS                                                      *
*   0.1...                                                                        *
*   >>> cctf_decoding(0.182011532850008, function='ST 2084', L_p=1000)            *
*   ... # doctest: +ELLIPSIS                                                      *
*   0.1...                                                                        *
*   >>> cctf_decoding(  # doctest: +ELLIPSIS                                      *
*   ...     0.461356129500442, function='ITU-R BT.1886')                          *
*   0.1...                                                                        *
*                                                                                 *
*   [ Conversion Output ]                                                         *
*                                                                                 *
*   [ 0.12743768  0.08021982  0.00699541]                                         *
*                                                                                 *
===================================================================================
===================================================================================
*                                                                                 *
*   [ "RGB_to_XYZ" ]                                                              *
*                                                                                 *
*   [ Signature ]                                                                 *
*                                                                                 *
*   <Signature (RGB, illuminant_RGB, illuminant_XYZ, matrix_RGB_to_XYZ,           *
*   chromatic_adaptation_transform='CAT02', cctf_decoding=None)>                  *
*                                                                                 *
*   [ Filtered Arguments ]                                                        *
*                                                                                 *
*   {'cctf_decoding': {'return': array([ 0.12743768,  0.08021982,                 *
*   0.00699541])},                                                                *
*    'illuminant_XYZ': array([ 0.3457,  0.3585])}                                 *
*                                                                                 *
*   [ Documentation ]                                                             *
*                                                                                 *
*   Converts given *RGB* colourspace array to *CIE XYZ* tristimulus values.       *
*                                                                                 *
*   Parameters                                                                    *
*   ----------                                                                    *
*   RGB : array_like                                                              *
*       *RGB* colourspace array.                                                  *
*   illuminant_RGB : array_like                                                   *
*       *CIE xy* chromaticity coordinates or *CIE xyY* colourspace array of the   *
*       *illuminant* for the input *RGB* colourspace array.                       *
*   illuminant_XYZ : array_like                                                   *
*       *CIE xy* chromaticity coordinates or *CIE xyY* colourspace array of the   *
*       *illuminant* for the output *CIE XYZ* tristimulus values.                 *
*   matrix_RGB_to_XYZ : array_like                                                *
*       Matrix converting the *RGB* colourspace array to *CIE XYZ* tristimulus    *
*       values, i.e. the *Normalised Primary Matrix* (NPM).                       *
*   chromatic_adaptation_transform : unicode, optional                            *
*       **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',              *
*       'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02 Brill 2008',                *
*       'Bianco 2010', 'Bianco PC 2010', None}**,                                 *
*       *Chromatic adaptation* transform, if *None* no chromatic adaptation is    *
*       performed.                                                                *
*   cctf_decoding : 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'                               *
*   >>> matrix_RGB_to_XYZ = 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, matrix_RGB_to_XYZ,        *
*   ...            chromatic_adaptation_transform)  # doctest: +ELLIPSIS          *
*   array([ 0.2163881...,  0.1257    ,  0.0384749...])                            *
*                                                                                 *
*   [ Conversion Output ]                                                         *
*                                                                                 *
*   [ 0.08765592  0.08656689  0.01383652]                                         *
*                                                                                 *
===================================================================================
===================================================================================
*                                                                                 *
*   [ "XYZ_to_Lab" ]                                                              *
*                                                                                 *
*   [ Signature ]                                                                 *
*                                                                                 *
*   <Signature (XYZ, illuminant=array([ 0.3127,  0.329 ]))>                       *
*                                                                                 *
*   [ Filtered Arguments ]                                                        *
*                                                                                 *
*   {'illuminant': array([ 0.3457,  0.3585])}                                     *
*                                                                                 *
*   [ Documentation ]                                                             *
*                                                                                 *
*   Converts from *CIE XYZ* tristimulus values to *CIE L\*a\*b\**                 *
*   colourspace.                                                                  *
*                                                                                 *
*   Parameters                                                                    *
*   ----------                                                                    *
*   XYZ : array_like                                                              *
*       *CIE XYZ* tristimulus values.                                             *
*   illuminant : array_like, optional                                             *
*       Reference *illuminant* *CIE xy* chromaticity coordinates or *CIE xyY*     *
*       colourspace array.                                                        *
*                                                                                 *
*   Returns                                                                       *
*   -------                                                                       *
*   ndarray                                                                       *
*       *CIE L\*a\*b\** colourspace array.                                        *
*                                                                                 *
*   Notes                                                                         *
*   -----                                                                         *
*                                                                                 *
*   +----------------+-----------------------+-----------------+                  *
*   | **Domain**     | **Scale - Reference** | **Scale - 1**   |                  *
*   +================+=======================+=================+                  *
*   | ``XYZ``        | [0, 1]                | [0, 1]          |                  *
*   +----------------+-----------------------+-----------------+                  *
*   | ``illuminant`` | [0, 1]                | [0, 1]          |                  *
*   +----------------+-----------------------+-----------------+                  *
*                                                                                 *
*   +----------------+-----------------------+-----------------+                  *
*   | **Range**      | **Scale - Reference** | **Scale - 1**   |                  *
*   +================+=======================+=================+                  *
*   | ``Lab``        | ``L`` : [0, 100]      | ``L`` : [0, 1]  |                  *
*   |                |                       |                 |                  *
*   |                | ``a`` : [-100, 100]   | ``a`` : [-1, 1] |                  *
*   |                |                       |                 |                  *
*   |                | ``b`` : [-100, 100]   | ``b`` : [-1, 1] |                  *
*   +----------------+-----------------------+-----------------+                  *
*                                                                                 *
*   References                                                                    *
*   ----------                                                                    *
*   :cite:`CIETC1-482004m`                                                        *
*                                                                                 *
*   Examples                                                                      *
*   --------                                                                      *
*   >>> import numpy as np                                                        *
*   >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952])                      *
*   >>> XYZ_to_Lab(XYZ)  # doctest: +ELLIPSIS                                     *
*   array([ 41.5278752...,  52.6385830...,  26.9231792...])                       *
*                                                                                 *
*   [ Conversion Output ]                                                         *
*                                                                                 *
*   [ 0.35314716  0.03631779  0.37281584]                                         *
*                                                                                 *
===================================================================================
array([ 35.31471609,   3.63177851,  37.28158403])

Upvotes: 2

Related Questions