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

46 statements  

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

1""" 

2Sony Encodings 

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

4 

5Define the *Sony* log encodings. 

6 

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

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

9- :func:`colour.models.log_encoding_SLog2` 

10- :func:`colour.models.log_decoding_SLog2` 

11- :func:`colour.models.log_encoding_SLog3` 

12- :func:`colour.models.log_decoding_SLog3` 

13 

14References 

15---------- 

16- :cite:`SonyCorporation2012a` : Sony Corporation. (2012). S-Log2 Technical 

17 Paper (pp. 1-9). https://drive.google.com/file/d/\ 

181Q1RYri6BaxtYYxX0D4zVD6lAmbwmgikc/view?usp=sharing 

19- :cite:`SonyCorporationd` : Sony Corporation. (n.d.). Technical Summary 

20 for S-Gamut3.Cine/S-Log3 and S-Gamut3/S-Log3 (pp. 1-7). 

21 http://community.sony.com/sony/attachments/sony/\ 

22large-sensor-camera-F5-F55/12359/2/TechnicalSummary_for_S-Gamut3Cine_S-Gamut3_S-Log3_V1_00.pdf 

23""" 

24 

25from __future__ import annotations 

26 

27import numpy as np 

28 

29from colour.hints import ( # noqa: TC001 

30 Domain1, 

31 Range1, 

32) 

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

34from colour.utilities import ( 

35 as_float, 

36 as_float_array, 

37 domain_range_scale, 

38 from_range_1, 

39 to_domain_1, 

40) 

41 

42__author__ = "Colour Developers" 

43__copyright__ = "Copyright 2013 Colour Developers" 

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

45__maintainer__ = "Colour Developers" 

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

47__status__ = "Production" 

48 

49__all__ = [ 

50 "log_encoding_SLog", 

51 "log_decoding_SLog", 

52 "log_encoding_SLog2", 

53 "log_decoding_SLog2", 

54 "log_encoding_SLog3", 

55 "log_decoding_SLog3", 

56] 

57 

58 

59def log_encoding_SLog( 

60 x: Domain1, 

61 bit_depth: int = 10, 

62 out_normalised_code_value: bool = True, 

63 in_reflection: bool = True, 

64) -> Range1: 

65 """ 

66 Apply the *Sony S-Log* log encoding opto-electronic transfer function 

67 (OETF). 

68 

69 Parameters 

70 ---------- 

71 x 

72 Reflection or :math:`IRE / 100` input light level :math:`x` to a 

73 camera. 

74 bit_depth 

75 Bit-depth used for conversion. 

76 out_normalised_code_value 

77 Whether the *Sony S-Log* non-linear data :math:`y` is encoded as 

78 normalised code values. 

79 in_reflection 

80 Whether the light level :math:`x` to a camera is reflection. 

81 

82 Returns 

83 ------- 

84 :class:`numpy.ndarray` 

85 *Sony S-Log* non-linear encoded data :math:`y`. 

86 

87 Notes 

88 ----- 

89 +------------+-----------------------+---------------+ 

90 | **Domain** | **Scale - Reference** | **Scale - 1** | 

91 +============+=======================+===============+ 

92 | ``x`` | 1 | 1 | 

93 +------------+-----------------------+---------------+ 

94 

95 +------------+-----------------------+---------------+ 

96 | **Range** | **Scale - Reference** | **Scale - 1** | 

97 +============+=======================+===============+ 

98 | ``y`` | 1 | 1 | 

99 +------------+-----------------------+---------------+ 

100 

101 References 

102 ---------- 

103 :cite:`SonyCorporation2012a` 

104 

105 Examples 

106 -------- 

107 >>> log_encoding_SLog(0.18) # doctest: +ELLIPSIS 

108 0.3849708... 

109 

110 The values of *IRE and CV of S-Log2 @ISO800* table in 

111 :cite:`SonyCorporation2012a` are obtained as follows: 

112 

113 >>> x = np.array([0, 18, 90]) / 100 

114 >>> np.around(log_encoding_SLog(x, 10, False) * 100).astype(np.int_) 

115 array([ 3, 38, 65]) 

116 >>> np.around(log_encoding_SLog(x) * (2**10 - 1)).astype(np.int_) 

117 array([ 90, 394, 636]) 

118 """ 

119 

120 x = to_domain_1(x) 

121 

122 if in_reflection: 

123 x = x / 0.9 

124 

125 y = np.where( 

126 x >= 0, 

127 ((0.432699 * np.log10(x + 0.037584) + 0.616596) + 0.03), 

128 x * 5 + 0.030001222851889303, 

129 ) 

130 

131 y_cv = full_to_legal(y, bit_depth) if out_normalised_code_value else y 

132 

133 return as_float(from_range_1(y_cv)) 

134 

135 

136def log_decoding_SLog( 

137 y: Domain1, 

138 bit_depth: int = 10, 

139 in_normalised_code_value: bool = True, 

140 out_reflection: bool = True, 

141) -> Range1: 

142 """ 

143 Apply the *Sony S-Log* log decoding inverse opto-electronic transfer 

144 function (OETF). 

145 

146 Parameters 

147 ---------- 

148 y 

149 *Sony S-Log* non-linear encoded data :math:`y`. 

150 bit_depth 

151 Bit-depth used for conversion. 

152 in_normalised_code_value 

153 Whether the *Sony S-Log* non-linear data :math:`y` is encoded as 

154 normalised code values. 

155 out_reflection 

156 Whether the output light level :math:`x` represents reflection. 

157 

158 Returns 

159 ------- 

160 :class:`numpy.ndarray` 

161 Reflection or :math:`IRE / 100` input light level :math:`x` to a 

162 camera. 

163 

164 Notes 

165 ----- 

166 +------------+-----------------------+---------------+ 

167 | **Domain** | **Scale - Reference** | **Scale - 1** | 

168 +============+=======================+===============+ 

169 | ``y`` | 1 | 1 | 

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

171 

172 +------------+-----------------------+---------------+ 

173 | **Range** | **Scale - Reference** | **Scale - 1** | 

174 +============+=======================+===============+ 

175 | ``x`` | 1 | 1 | 

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

177 

178 References 

179 ---------- 

180 :cite:`SonyCorporation2012a` 

181 

182 Examples 

183 -------- 

184 >>> log_decoding_SLog(0.384970815928670) # doctest: +ELLIPSIS 

185 0.1... 

186 """ 

187 

188 y = to_domain_1(y) 

189 

190 x = legal_to_full(y, bit_depth) if in_normalised_code_value else y 

191 

192 with domain_range_scale("ignore"): 

193 x = np.where( 

194 y >= log_encoding_SLog(0.0, bit_depth, in_normalised_code_value), 

195 10 ** ((x - 0.616596 - 0.03) / 0.432699) - 0.037584, 

196 (x - 0.030001222851889303) / 5.0, 

197 ) 

198 

199 if out_reflection: 

200 x = x * 0.9 

201 

202 return as_float(from_range_1(x)) 

203 

204 

205def log_encoding_SLog2( 

206 x: Domain1, 

207 bit_depth: int = 10, 

208 out_normalised_code_value: bool = True, 

209 in_reflection: bool = True, 

210) -> Range1: 

211 """ 

212 Apply the *Sony S-Log2* log encoding opto-electronic transfer function 

213 (OETF). 

214 

215 Parameters 

216 ---------- 

217 x 

218 Reflection or :math:`IRE / 100` input light level :math:`x` to a 

219 camera. 

220 bit_depth 

221 Bit-depth used for conversion. 

222 out_normalised_code_value 

223 Whether the *Sony S-Log2* non-linear data :math:`y` is encoded as 

224 normalised code values. 

225 in_reflection 

226 Whether the light level :math:`x` to a camera is reflection. 

227 

228 Returns 

229 ------- 

230 :class:`numpy.ndarray` 

231 *Sony S-Log2* non-linear encoded data :math:`y`. 

232 

233 Notes 

234 ----- 

235 +------------+-----------------------+---------------+ 

236 | **Domain** | **Scale - Reference** | **Scale - 1** | 

237 +============+=======================+===============+ 

238 | ``x`` | 1 | 1 | 

239 +------------+-----------------------+---------------+ 

240 

241 +------------+-----------------------+---------------+ 

242 | **Range** | **Scale - Reference** | **Scale - 1** | 

243 +============+=======================+===============+ 

244 | ``y`` | 1 | 1 | 

245 +------------+-----------------------+---------------+ 

246 

247 References 

248 ---------- 

249 :cite:`SonyCorporation2012a` 

250 

251 Examples 

252 -------- 

253 >>> log_encoding_SLog2(0.18) # doctest: +ELLIPSIS 

254 0.3395325... 

255 

256 The values of *IRE and CV of S-Log2 @ISO800* table in 

257 :cite:`SonyCorporation2012a` are obtained as follows: 

258 

259 >>> x = np.array([0, 18, 90]) / 100 

260 >>> np.around(log_encoding_SLog2(x, 10, False) * 100).astype(np.int_) 

261 array([ 3, 32, 59]) 

262 >>> np.around(log_encoding_SLog2(x) * (2**10 - 1)).astype(np.int_) 

263 array([ 90, 347, 582]) 

264 """ 

265 

266 x = as_float_array(x) 

267 

268 return log_encoding_SLog( 

269 x * 155 / 219, bit_depth, out_normalised_code_value, in_reflection 

270 ) 

271 

272 

273def log_decoding_SLog2( 

274 y: Domain1, 

275 bit_depth: int = 10, 

276 in_normalised_code_value: bool = True, 

277 out_reflection: bool = True, 

278) -> Range1: 

279 """ 

280 Apply the *Sony S-Log2* log decoding inverse opto-electronic transfer 

281 function (OETF). 

282 

283 Parameters 

284 ---------- 

285 y 

286 *Sony S-Log2* non-linear encoded data :math:`y`. 

287 bit_depth 

288 Bit-depth used for conversion. 

289 in_normalised_code_value 

290 Whether the *Sony S-Log2* non-linear data :math:`y` is encoded as 

291 normalised code values. 

292 out_reflection 

293 Whether the output light level :math:`x` represents reflection. 

294 

295 Returns 

296 ------- 

297 :class:`numpy.ndarray` 

298 Reflection or :math:`IRE / 100` input light level :math:`x` to a 

299 camera. 

300 

301 Notes 

302 ----- 

303 +------------+-----------------------+---------------+ 

304 | **Domain** | **Scale - Reference** | **Scale - 1** | 

305 +============+=======================+===============+ 

306 | ``y`` | 1 | 1 | 

307 +------------+-----------------------+---------------+ 

308 

309 +------------+-----------------------+---------------+ 

310 | **Range** | **Scale - Reference** | **Scale - 1** | 

311 +============+=======================+===============+ 

312 | ``x`` | 1 | 1 | 

313 +------------+-----------------------+---------------+ 

314 

315 References 

316 ---------- 

317 :cite:`SonyCorporation2012a` 

318 

319 Examples 

320 -------- 

321 >>> log_decoding_SLog2(0.339532524633774) # doctest: +ELLIPSIS 

322 0.1... 

323 """ 

324 

325 return ( 

326 219 

327 * log_decoding_SLog(y, bit_depth, in_normalised_code_value, out_reflection) 

328 / 155 

329 ) 

330 

331 

332def log_encoding_SLog3( 

333 x: Domain1, 

334 bit_depth: int = 10, 

335 out_normalised_code_value: bool = True, 

336 in_reflection: bool = True, 

337) -> Range1: 

338 """ 

339 Apply the *Sony S-Log3* log encoding opto-electronic transfer function 

340 (OETF). 

341 

342 Parameters 

343 ---------- 

344 x 

345 Reflection or :math:`IRE / 100` input light level :math:`x` to a 

346 camera. 

347 bit_depth 

348 Bit-depth used for conversion. 

349 out_normalised_code_value 

350 Whether the *Sony S-Log3* non-linear data data :math:`y` is encoded as 

351 normalised code values. 

352 in_reflection 

353 Whether the light level :math:`x` to a camera is reflection. 

354 

355 Returns 

356 ------- 

357 :class:`numpy.ndarray` 

358 *Sony S-Log3* non-linear encoded data :math:`y`. 

359 

360 Notes 

361 ----- 

362 +------------+-----------------------+---------------+ 

363 | **Domain** | **Scale - Reference** | **Scale - 1** | 

364 +============+=======================+===============+ 

365 | ``x`` | 1 | 1 | 

366 +------------+-----------------------+---------------+ 

367 

368 +------------+-----------------------+---------------+ 

369 | **Range** | **Scale - Reference** | **Scale - 1** | 

370 +============+=======================+===============+ 

371 | ``y`` | 1 | 1 | 

372 +------------+-----------------------+---------------+ 

373 

374 References 

375 ---------- 

376 :cite:`SonyCorporationd` 

377 

378 Examples 

379 -------- 

380 >>> log_encoding_SLog3(0.18) # doctest: +ELLIPSIS 

381 0.4105571... 

382 

383 The values of *S-Log3 10bit code values (18%, 90%)* table in 

384 :cite:`SonyCorporationd` are obtained as follows: 

385 

386 >>> x = np.array([0, 18, 90]) / 100 

387 >>> np.around(log_encoding_SLog3(x, 10, False) * 100).astype(np.int_) 

388 array([ 4, 41, 61]) 

389 >>> np.around(log_encoding_SLog3(x) * (2**10 - 1)).astype(np.int_) 

390 array([ 95, 420, 598]) 

391 """ 

392 

393 x = to_domain_1(x) 

394 

395 if not in_reflection: 

396 x = x * 0.9 

397 

398 y = np.where( 

399 x >= 0.01125000, 

400 (420 + np.log10((x + 0.01) / (0.18 + 0.01)) * 261.5) / 1023, 

401 (x * (171.2102946929 - 95) / 0.01125000 + 95) / 1023, 

402 ) 

403 

404 y_cv = y if out_normalised_code_value else legal_to_full(y, bit_depth) 

405 

406 return as_float(from_range_1(y_cv)) 

407 

408 

409def log_decoding_SLog3( 

410 y: Domain1, 

411 bit_depth: int = 10, 

412 in_normalised_code_value: bool = True, 

413 out_reflection: bool = True, 

414) -> Range1: 

415 """ 

416 Apply the *Sony S-Log3* log decoding inverse opto-electronic transfer 

417 function (OETF). 

418 

419 Parameters 

420 ---------- 

421 y 

422 *Sony S-Log3* non-linear encoded data :math:`y`. 

423 bit_depth 

424 Bit-depth used for conversion. 

425 in_normalised_code_value 

426 Whether the *Sony S-Log3* non-linear data :math:`y` is encoded as 

427 normalised code values. 

428 out_reflection 

429 Whether the output light level :math:`x` represents reflection. 

430 

431 Returns 

432 ------- 

433 :class:`numpy.ndarray` 

434 Reflection or :math:`IRE / 100` input light level :math:`x` to a 

435 camera. 

436 

437 Notes 

438 ----- 

439 +------------+-----------------------+---------------+ 

440 | **Domain** | **Scale - Reference** | **Scale - 1** | 

441 +============+=======================+===============+ 

442 | ``y`` | 1 | 1 | 

443 +------------+-----------------------+---------------+ 

444 

445 +------------+-----------------------+---------------+ 

446 | **Range** | **Scale - Reference** | **Scale - 1** | 

447 +============+=======================+===============+ 

448 | ``x`` | 1 | 1 | 

449 +------------+-----------------------+---------------+ 

450 

451 References 

452 ---------- 

453 :cite:`SonyCorporationd` 

454 

455 Examples 

456 -------- 

457 >>> log_decoding_SLog3(0.410557184750733) # doctest: +ELLIPSIS 

458 0.1... 

459 """ 

460 

461 y = to_domain_1(y) 

462 

463 y = y if in_normalised_code_value else full_to_legal(y, bit_depth) 

464 

465 x = np.where( 

466 y >= 171.2102946929 / 1023, 

467 ((10 ** ((y * 1023 - 420) / 261.5)) * (0.18 + 0.01) - 0.01), 

468 (y * 1023 - 95) * 0.01125000 / (171.2102946929 - 95), 

469 ) 

470 

471 if not out_reflection: 

472 x = x / 0.9 

473 

474 return as_float(from_range_1(x))