Coverage for models/igpgtg.py: 21%

1"""

2:math:`I_GP_GT_G` Colourspace

3=============================

4

5 Define the :math:`I_GP_GT_G` colourspace transformations.

6

7- :func:`colour.XYZ_to_IgPgTg`

8- :func:`colour.IgPgTg_to_XYZ`

9

10 References

11----------

12- :cite:`Hellwig2020` : Hellwig, L., & Fairchild, M. D. (2020). Using

13 Gaussian Spectra to Derive a Hue-linear Color Space. Journal of Perceptual

14 Imaging. doi:10.2352/J.Percept.Imaging.2020.3.2.020401

15"""

16

17 from __future__ import annotations

18

19 import numpy as np

20

21 from colour.algebra import spow

22 from colour.hints import ( # noqa: TC001

23 ArrayLike,

24 Domain1,

25 NDArrayFloat,

26 Range1,

27)

28 from colour.models import Iab_to_XYZ, XYZ_to_Iab

29

30 __author__ = "Colour Developers"

31 __copyright__ = "Copyright 2013 Colour Developers"

32 __license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"

33 __maintainer__ = "Colour Developers"

34 __email__ = "colour-developers@colour-science.org"

35 __status__ = "Production"

36

37 __all__ = [

38 "MATRIX_IGPGTG_XYZ_TO_LMS",

39 "MATRIX_IGPGTG_LMS_TO_XYZ",

40 "MATRIX_IGPGTG_LMS_P_TO_IGPGTG",

41 "MATRIX_IGPGTG_IGPGTG_TO_LMS_P",

42 "XYZ_to_IgPgTg",

43 "IgPgTg_to_XYZ",

44]

45

46 MATRIX_IGPGTG_XYZ_TO_LMS: NDArrayFloat = np.array(

47 [

48 [2.968, 2.741, -0.649],

49 [1.237, 5.969, -0.173],

50 [-0.318, 0.387, 2.311],

51 ]

52)

53"""*CIE XYZ* tristimulus values to normalised cone responses matrix."""

54

55 MATRIX_IGPGTG_LMS_TO_XYZ: NDArrayFloat = np.linalg.inv(MATRIX_IGPGTG_XYZ_TO_LMS)

56"""Normalised cone responses to *CIE XYZ* tristimulus values matrix."""

57

58 MATRIX_IGPGTG_LMS_P_TO_IGPGTG: NDArrayFloat = np.array(

59 [

60 [0.117, 1.464, 0.130],

61 [8.285, -8.361, 21.400],

62 [-1.208, 2.412, -36.530],

63 ]

64)

65"""Normalised non-linear cone responses to :math:`I_GP_GT_G` colourspace matrix."""

66

67 MATRIX_IGPGTG_IGPGTG_TO_LMS_P: NDArrayFloat = np.linalg.inv(

68 MATRIX_IGPGTG_LMS_P_TO_IGPGTG

69)

70""":math:`I_GP_GT_G` colourspace to normalised non-linear cone responses matrix."""

71

72

73 def XYZ_to_IgPgTg(XYZ: Domain1) -> Range1:

74 """

75 Convert from *CIE XYZ* tristimulus values to :math:`I_GP_GT_G`

76 colourspace.

77

78 Parameters

79 ----------

80 XYZ

81 *CIE XYZ* tristimulus values.

82

83 Returns

84 -------

85 :class:`numpy.ndarray`

86 :math:`I_GP_GT_G` colourspace array.

87

88 Notes

89 -----

90 +------------+-----------------------+-----------------+

91 | **Domain** | **Scale - Reference** | **Scale - 1** |

92 +============+=======================+=================+

93 | ``XYZ`` | 1 | 1 |

94 +------------+-----------------------+-----------------+

95

96 +------------+-----------------------+-----------------+

97 | **Range** | **Scale - Reference** | **Scale - 1** |

98 +============+=======================+=================+

99 | ``IgPgTg`` | 1 | 1 |

100 +------------+-----------------------+-----------------+

101

102 - Input *CIE XYZ* tristimulus values must be adapted to

103 *CIE Standard Illuminant D Series* *D65*.

104

105 References

106 ----------

107 :cite:`Hellwig2020`

108

109 Examples

110 --------

111 >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952])

112 >>> XYZ_to_IgPgTg(XYZ) # doctest: +ELLIPSIS

113 array([ 0.4242125..., 0.1863249..., 0.1068922...])

114 """

115

116 def LMS_to_LMS_p_callable(LMS: ArrayLike) -> NDArrayFloat:

117 """

118 Callable applying the forward non-linearity to the :math:`LMS`

119 colourspace array.

120 """

121

122 return spow(LMS / np.array([18.36, 21.46, 19435]), 0.427)

123

124 return XYZ_to_Iab(

125 XYZ,

126 LMS_to_LMS_p_callable,

127 MATRIX_IGPGTG_XYZ_TO_LMS,

128 MATRIX_IGPGTG_LMS_P_TO_IGPGTG,

129 )

130

131

132 def IgPgTg_to_XYZ(IgPgTg: Domain1) -> Range1:

133 """

134 Convert from :math:`I_GP_GT_G` colourspace to *CIE XYZ* tristimulus

135 values.

136

137 Parameters

138 ----------

139 IgPgTg

140 :math:`I_GP_GT_G` colourspace array.

141

142 Returns

143 -------

144 :class:`numpy.ndarray`

145 *CIE XYZ* tristimulus values.

146

147 Notes

148 -----

149 +------------+-----------------------+-----------------+

150 | **Domain** | **Scale - Reference** | **Scale - 1** |

151 +============+=======================+=================+

152 | ``IgPgTg`` | 1 | 1 |

153 +------------+-----------------------+-----------------+

154

155 +------------+-----------------------+-----------------+

156 | **Range** | **Scale - Reference** | **Scale - 1** |

157 +============+=======================+=================+

158 | ``XYZ`` | 1 | 1 |

159 +------------+-----------------------+-----------------+

160

161 - Output *CIE XYZ* tristimulus values are adapted to

162 *CIE Standard Illuminant D Series* *D65*.

163

164 References

165 ----------

166 :cite:`Hellwig2020`

167

168 Examples

169 --------

170 >>> IgPgTg = np.array([0.42421258, 0.18632491, 0.10689223])

171 >>> IgPgTg_to_XYZ(IgPgTg) # doctest: +ELLIPSIS

172 array([ 0.2065400..., 0.1219722..., 0.0513695...])

173 """

174

175 def LMS_p_to_LMS_callable(LMS_p: ArrayLike) -> NDArrayFloat:

176 """

177 Callable applying the reverse non-linearity to the :math:`LMS_p`

178 colourspace array.

179 """

180

181 return spow(LMS_p, 1 / 0.427) * np.array([18.36, 21.46, 19435])

182

183 return Iab_to_XYZ(

184 IgPgTg,

185 LMS_p_to_LMS_callable,

186 MATRIX_IGPGTG_IGPGTG_TO_LMS_P,

187 MATRIX_IGPGTG_LMS_TO_XYZ,

188 )