Coverage for colour/models/rgb/transfer_functions/panasonic_v_log.py: 100%

38 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-15 19:01 +1300

1""" 

2Panasonic V-Log Log Encoding 

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

4 

5Define the *Panasonic V-Log* log encoding. 

6 

7- :func:`colour.models.log_encoding_VLog` 

8- :func:`colour.models.log_decoding_VLog` 

9 

10References 

11---------- 

12- :cite:`Panasonic2014a` : Panasonic. (2014). VARICAM V-Log/V-Gamut (pp. 

13 1-7). 

14 http://pro-av.panasonic.net/en/varicam/common/pdf/VARICAM_V-Log_V-Gamut.pdf 

15""" 

16 

17from __future__ import annotations 

18 

19import numpy as np 

20 

21from colour.hints import ( # noqa: TC001 

22 Domain1, 

23 Range1, 

24) 

25from colour.models.rgb.transfer_functions import full_to_legal, legal_to_full 

26from colour.utilities import Structure, as_float, from_range_1, optional, to_domain_1 

27 

28__author__ = "Colour Developers" 

29__copyright__ = "Copyright 2013 Colour Developers" 

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

31__maintainer__ = "Colour Developers" 

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

33__status__ = "Production" 

34 

35__all__ = [ 

36 "CONSTANTS_VLOG", 

37 "log_encoding_VLog", 

38 "log_decoding_VLog", 

39] 

40 

41CONSTANTS_VLOG: Structure = Structure( 

42 cut1=0.01, cut2=0.181, b=0.00873, c=0.241514, d=0.598206 

43) 

44"""*Panasonic V-Log* constants.""" 

45 

46 

47def log_encoding_VLog( 

48 L_in: Domain1, 

49 bit_depth: int = 10, 

50 out_normalised_code_value: bool = True, 

51 in_reflection: bool = True, 

52 constants: Structure | None = None, 

53) -> Range1: 

54 """ 

55 Apply the *Panasonic V-Log* log encoding opto-electronic transfer function (OETF). 

56 

57 Parameters 

58 ---------- 

59 L_in 

60 Linear reflection data :math:`L_{in}`. 

61 bit_depth 

62 Bit-depth used for conversion. 

63 out_normalised_code_value 

64 Whether the *Panasonic V-Log* non-linear data :math:`V_{out}` is 

65 encoded as normalised code values. 

66 in_reflection 

67 Whether the light level :math:`L_{in}` to a camera is reflection. 

68 constants 

69 *Panasonic V-Log* constants. 

70 

71 Returns 

72 ------- 

73 :class:`numpy.ndarray` 

74 *Panasonic V-Log* mon-linear encoded data :math:`V_{out}`. 

75 

76 Notes 

77 ----- 

78 +------------+-----------------------+---------------+ 

79 | **Domain** | **Scale - Reference** | **Scale - 1** | 

80 +============+=======================+===============+ 

81 | ``L_in`` | 1 | 1 | 

82 +------------+-----------------------+---------------+ 

83 

84 +------------+-----------------------+---------------+ 

85 | **Range** | **Scale - Reference** | **Scale - 1** | 

86 +============+=======================+===============+ 

87 | ``V_out`` | 1 | 1 | 

88 +------------+-----------------------+---------------+ 

89 

90 References 

91 ---------- 

92 :cite:`Panasonic2014a` 

93 

94 Examples 

95 -------- 

96 >>> log_encoding_VLog(0.18) # doctest: +ELLIPSIS 

97 0.4233114... 

98 

99 The values of *Fig.2.2 V-Log Code Value* table in :cite:`Panasonic2014a` 

100 are obtained as follows: 

101 

102 >>> L_in = np.array([0, 18, 90]) / 100 

103 >>> np.around(log_encoding_VLog(L_in, 10, False) * 100).astype(np.int_) 

104 array([ 7, 42, 61]) 

105 >>> np.around(log_encoding_VLog(L_in) * (2**10 - 1)).astype(np.int_) 

106 array([128, 433, 602]) 

107 >>> np.around(log_encoding_VLog(L_in) * (2**12 - 1)).astype(np.int_) 

108 array([ 512, 1733, 2409]) 

109 

110 Note that some values in the last column values of 

111 *Fig.2.2 V-Log Code Value* table in :cite:`Panasonic2014a` are different 

112 by a code: [512, 1732, 2408]. 

113 """ 

114 

115 L_in = to_domain_1(L_in) 

116 constants = optional(constants, CONSTANTS_VLOG) 

117 

118 if not in_reflection: 

119 L_in = L_in * 0.9 

120 

121 cut1 = constants.cut1 

122 b = constants.b 

123 c = constants.c 

124 d = constants.d 

125 

126 V_out = np.where( 

127 L_in < cut1, 

128 5.6 * L_in + 0.125, 

129 c * np.log10(L_in + b) + d, 

130 ) 

131 

132 V_out_cv = V_out if out_normalised_code_value else legal_to_full(V_out, bit_depth) 

133 

134 return as_float(from_range_1(V_out_cv)) 

135 

136 

137def log_decoding_VLog( 

138 V_out: Domain1, 

139 bit_depth: int = 10, 

140 in_normalised_code_value: bool = True, 

141 out_reflection: bool = True, 

142 constants: Structure | None = None, 

143) -> Range1: 

144 """ 

145 Apply the *Panasonic V-Log* log decoding inverse opto-electronic transfer 

146 

147 function (OETF). 

148 

149 Parameters 

150 ---------- 

151 V_out 

152 *Panasonic V-Log* mon-linear encoded data :math:`V_{out}`. 

153 bit_depth 

154 Bit-depth used for conversion. 

155 in_normalised_code_value 

156 Whether the *Panasonic V-Log* non-linear data :math:`V_{out}` is 

157 encoded as normalised code values. 

158 out_reflection 

159 Whether the light level :math:`L_{in}` to a camera is reflection. 

160 constants 

161 *Panasonic V-Log* constants. 

162 

163 Returns 

164 ------- 

165 :class:`numpy.ndarray` 

166 Linear reflection data :math:`L_{in}`. 

167 

168 Notes 

169 ----- 

170 +------------+-----------------------+---------------+ 

171 | **Domain** | **Scale - Reference** | **Scale - 1** | 

172 +============+=======================+===============+ 

173 | ``V_out`` | 1 | 1 | 

174 +------------+-----------------------+---------------+ 

175 

176 +------------+-----------------------+---------------+ 

177 | **Range** | **Scale - Reference** | **Scale - 1** | 

178 +============+=======================+===============+ 

179 | ``L_in`` | 1 | 1 | 

180 +------------+-----------------------+---------------+ 

181 

182 References 

183 ---------- 

184 :cite:`Panasonic2014a` 

185 

186 Examples 

187 -------- 

188 >>> log_decoding_VLog(0.423311448760136) # doctest: +ELLIPSIS 

189 0.1799999... 

190 """ 

191 

192 V_out = to_domain_1(V_out) 

193 constants = optional(constants, CONSTANTS_VLOG) 

194 

195 V_out = V_out if in_normalised_code_value else full_to_legal(V_out, bit_depth) 

196 

197 cut2 = constants.cut2 

198 b = constants.b 

199 c = constants.c 

200 d = constants.d 

201 

202 L_in = np.where( 

203 V_out < cut2, 

204 (V_out - 0.125) / 5.6, 

205 10 ** ((V_out - d) / c) - b, 

206 ) 

207 

208 if not out_reflection: 

209 L_in = L_in / 0.9 

210 

211 return as_float(from_range_1(L_in))