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

41 statements  

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

1""" 

2Nikon N-Log Log Encoding 

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

4 

5Define the *Nikon N-Log* log encoding. 

6 

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

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

9 

10References 

11---------- 

12- :cite:`Nikon2018` : Nikon. (2018). N-Log Specification Document - Version 

13 1.0.0 (pp. 1-5). Retrieved September 9, 2019, from 

14 http://download.nikonimglib.com/archive3/hDCmK00m9JDI03RPruD74xpoU905/\ 

15N-Log_Specification_(En)01.pdf 

16""" 

17 

18from __future__ import annotations 

19 

20import numpy as np 

21 

22from colour.algebra import spow 

23from colour.hints import ( # noqa: TC001 

24 Domain1, 

25 Range1, 

26) 

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

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

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 "CONSTANTS_NLOG", 

39 "log_encoding_NLog", 

40 "log_decoding_NLog", 

41] 

42 

43CONSTANTS_NLOG: Structure = Structure( 

44 cut1=0.328, 

45 cut2=(452 / 1023), 

46 a=(650 / 1023), 

47 b=0.0075, 

48 c=(150 / 1023), 

49 d=(619 / 1023), 

50) 

51"""*Nikon N-Log* constants.""" 

52 

53 

54def log_encoding_NLog( 

55 y: Domain1, 

56 bit_depth: int = 10, 

57 out_normalised_code_value: bool = True, 

58 in_reflection: bool = True, 

59 constants: Structure | None = None, 

60) -> Range1: 

61 """ 

62 Apply the *Nikon N-Log* log encoding opto-electronic transfer function (OETF). 

63 

64 Parameters 

65 ---------- 

66 y 

67 Linear light reflectance :math:`y`, where :math:`y = 0.18` represents 

68 middle grey at Stop 0. 

69 bit_depth 

70 Bit-depth used for conversion. 

71 out_normalised_code_value 

72 Whether to return the *Nikon N-Log* encoded data :math:`x` as 

73 normalised code values. 

74 in_reflection 

75 Whether the input light level represents reflected light. 

76 constants 

77 *Nikon N-Log* constants. 

78 

79 Returns 

80 ------- 

81 :class:`numpy.ndarray` 

82 *N-Log* 10-bit equivalent code value :math:`x`. 

83 

84 Notes 

85 ----- 

86 +------------+-----------------------+---------------+ 

87 | **Domain** | **Scale - Reference** | **Scale - 1** | 

88 +============+=======================+===============+ 

89 | ``y`` | 1 | 1 | 

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

91 

92 +------------+-----------------------+---------------+ 

93 | **Range** | **Scale - Reference** | **Scale - 1** | 

94 +============+=======================+===============+ 

95 | ``x`` | 1 | 1 | 

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

97 

98 References 

99 ---------- 

100 :cite:`Nikon2018` 

101 

102 Examples 

103 -------- 

104 >>> log_encoding_NLog(0.18) # doctest: +ELLIPSIS 

105 0.3636677... 

106 """ 

107 

108 y = to_domain_1(y) 

109 constants = optional(constants, CONSTANTS_NLOG) 

110 

111 if not in_reflection: 

112 y = y * 0.9 

113 

114 cut1 = constants.cut1 

115 a = constants.a 

116 b = constants.b 

117 c = constants.c 

118 d = constants.d 

119 

120 x = np.where( 

121 y < cut1, 

122 a * spow(y + b, 1 / 3), 

123 c * np.log(y) + d, 

124 ) 

125 

126 x_cv = x if out_normalised_code_value else legal_to_full(x, bit_depth) 

127 

128 return as_float(from_range_1(x_cv)) 

129 

130 

131def log_decoding_NLog( 

132 x: Domain1, 

133 bit_depth: int = 10, 

134 in_normalised_code_value: bool = True, 

135 out_reflection: bool = True, 

136 constants: Structure | None = None, 

137) -> Range1: 

138 """ 

139 Apply the *Nikon N-Log* log decoding inverse opto-electronic transfer 

140 function (OETF). 

141 

142 Parameters 

143 ---------- 

144 x 

145 *N-Log* 10-bit equivalent code value :math:`x`. 

146 bit_depth 

147 Bit-depth used for conversion. 

148 in_normalised_code_value 

149 Whether the non-linear *Nikon N-Log* data :math:`x` is encoded as 

150 normalised code values. 

151 out_reflection 

152 Whether the light level :math:`y` to a camera is reflection. 

153 constants 

154 *Nikon N-Log* constants. 

155 

156 Returns 

157 ------- 

158 :class:`numpy.ndarray` 

159 Linear light reflectance :math:`y`, where :math:`y = 0.18` represents 

160 middle grey at Stop 0. 

161 

162 Notes 

163 ----- 

164 +------------+-----------------------+---------------+ 

165 | **Domain** | **Scale - Reference** | **Scale - 1** | 

166 +============+=======================+===============+ 

167 | ``x`` | 1 | 1 | 

168 +------------+-----------------------+---------------+ 

169 

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

171 | **Range** | **Scale - Reference** | **Scale - 1** | 

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

173 | ``y`` | 1 | 1 | 

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

175 

176 References 

177 ---------- 

178 :cite:`Nikon2018` 

179 

180 Examples 

181 -------- 

182 >>> log_decoding_NLog(0.36366777011713869) # doctest: +ELLIPSIS 

183 0.1799999... 

184 """ 

185 

186 x = to_domain_1(x) 

187 constants = optional(constants, CONSTANTS_NLOG) 

188 

189 x = x if in_normalised_code_value else full_to_legal(x, bit_depth) 

190 

191 cut2 = constants.cut2 

192 a = constants.a 

193 b = constants.b 

194 c = constants.c 

195 d = constants.d 

196 

197 y = np.where( 

198 x < cut2, 

199 spow(x / a, 3) - b, 

200 np.exp((x - d) / c), 

201 ) 

202 

203 if not out_reflection: 

204 y = y / 0.9 

205 

206 return as_float(from_range_1(y))