Coverage for models/rgb/transfer_functions/common.py: 62%

1"""

2 Common Transfer Functions Utilities

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

4

5 Define various transfer functions common utilities.

6"""

7

8 from __future__ import annotations

9

10 import typing

11

12 import numpy as np

13

14 if typing.TYPE_CHECKING:

15 from colour.hints import ArrayLike, NDArrayReal

16

17 from colour.utilities import as_float, as_float_array, as_int, as_int_array

18

19 __author__ = "Colour Developers"

20 __copyright__ = "Copyright 2013 Colour Developers"

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

22 __maintainer__ = "Colour Developers"

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

24 __status__ = "Production"

25

26 __all__ = [

27 "CV_range",

28 "legal_to_full",

29 "full_to_legal",

30]

31

32

33 def CV_range(

34 bit_depth: int = 10, is_legal: bool = False, is_int: bool = False

35) -> NDArrayReal:

36 """

37 Return the code value :math:`CV` range for the specified bit-depth,

38 range legality and representation.

39

40 Parameters

41 ----------

42 bit_depth

43 Bit-depth of the code value :math:`CV` range.

44 is_legal

45 Whether the code value :math:`CV` range represents legal code values.

46 is_int

47 Whether the code value :math:`CV` range represents int code

48 values.

49

50 Returns

51 -------

52 :class:`numpy.ndarray`

53 Code value :math:`CV` range.

54

55 Examples

56 --------

57 >>> CV_range(8, True, True)

58 array([ 16, 235])

59 >>> CV_range(8, True, False) # doctest: +ELLIPSIS

60 array([ 0.0627451..., 0.9215686...])

61 >>> CV_range(10, False, False)

62 array([ 0., 1.])

63 """

64

65 if is_legal:

66 ranges = np.array([16, 235])

67 ranges *= 2 ** (bit_depth - 8)

68 else:

69 ranges = np.array([0, 2**bit_depth - 1])

70

71 if not is_int:

72 ranges = as_float_array(ranges) / (2**bit_depth - 1)

73

74 return ranges

75

76

77 def legal_to_full(

78 CV: ArrayLike,

79 bit_depth: int = 10,

80 in_int: bool = False,

81 out_int: bool = False,

82) -> NDArrayReal:

83 """

84 Convert the specified code value :math:`CV` or float equivalent of a code

85 value at a specified bit-depth from *legal range* (studio swing) to

86 *full range* (full swing).

87

88 Parameters

89 ----------

90 CV

91 Legal range code value :math:`CV` or float equivalent of a code value

92 at a specified bit-depth.

93 bit_depth

94 Bit-depth used for conversion.

95 in_int

96 Whether to treat the input value as integer code value or floating

97 point equivalent of a code value at a specified bit-depth.

98 out_int

99 Whether to return value as integer code value or floating point

100 equivalent of a code value at a specified bit-depth.

101

102 Returns

103 -------

104 :class:`numpy.ndarray`

105 Full range code value :math:`CV` or float equivalent of a code value

106 at a specified bit-depth.

107

108 Examples

109 --------

110 >>> legal_to_full(64 / 1023)

111 0.0

112 >>> legal_to_full(940 / 1023)

113 1.0

114 >>> legal_to_full(64 / 1023, out_int=True)

115 0

116 >>> legal_to_full(940 / 1023, out_int=True)

117 1023

118 >>> legal_to_full(64, in_int=True)

119 0.0

120 >>> legal_to_full(940, in_int=True)

121 1.0

122 >>> legal_to_full(64, in_int=True, out_int=True)

123 0

124 >>> legal_to_full(940, in_int=True, out_int=True)

125 1023

126 """

127

128 CV = as_float_array(CV)

129

130 MV = 2**bit_depth - 1

131

132 CV_full = as_int_array(np.round(CV)) if in_int else CV * MV

133

134 B, W = CV_range(bit_depth, True, True)

135

136 CV_full = (CV_full - B) / (W - B)

137

138 if out_int:

139 return as_int(np.round(CV_full * MV))

140

141 return as_float(CV_full)

142

143

144 def full_to_legal(

145 CV: ArrayLike,

146 bit_depth: int = 10,

147 in_int: bool = False,

148 out_int: bool = False,

149) -> NDArrayReal:

150 """

151 Convert the specified code value :math:`CV` or float equivalent of a

152 code value at a specified bit-depth from full range (full swing) to

153 legal range (studio swing).

154

155 Parameters

156 ----------

157 CV

158 Full range code value :math:`CV` or float equivalent of a code value

159 at a specified bit-depth.

160 bit_depth

161 Bit-depth used for conversion.

162 in_int

163 Whether to treat the input value as integer code value or floating

164 point equivalent of a code value at a specified bit-depth.

165 out_int

166 Whether to return value as integer code value or floating point

167 equivalent of a code value at a specified bit-depth.

168

169 Returns

170 -------

171 :class:`numpy.ndarray`

172 Legal range code value :math:`CV` or float equivalent of a code value

173 at a specified bit-depth.

174

175 Examples

176 --------

177 >>> full_to_legal(0.0) # doctest: +ELLIPSIS

178 0.0625610...

179 >>> full_to_legal(1.0) # doctest: +ELLIPSIS

180 0.9188660...

181 >>> full_to_legal(0.0, out_int=True)

182 64

183 >>> full_to_legal(1.0, out_int=True)

184 940

185 >>> full_to_legal(0, in_int=True) # doctest: +ELLIPSIS

186 0.0625610...

187 >>> full_to_legal(1023, in_int=True) # doctest: +ELLIPSIS

188 0.9188660...

189 >>> full_to_legal(0, in_int=True, out_int=True)

190 64

191 >>> full_to_legal(1023, in_int=True, out_int=True)

192 940

193 """

194

195 CV = as_float_array(CV)

196

197 MV = 2**bit_depth - 1

198

199 CV_legal = as_int_array(np.round(CV / MV)) if in_int else CV

200

201 B, W = CV_range(bit_depth, True, True)

202

203 CV_legal = (W - B) * CV_legal + B

204

205 if out_int:

206 return as_int(np.round(CV_legal))

207

208 return as_float(CV_legal / MV)