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

43 statements  

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

1""" 

2Recommendation ITU-T H.273 Transfer Characteristics 

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

4 

5Define the *Recommendation ITU-T H.273* transfer functions that do not belong 

6in another specification or standard, or have been modified for inclusion. 

7 

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

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

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

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

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

13- :func:`colour.models.oetf_inverse_H273_IEC61966_2` 

14- :func:`colour.models.eotf_H273_ST428_1` 

15- :func:`colour.models.eotf_inverse_H273_ST428_1` 

16 

17References 

18---------- 

19- :cite:`InternationalTelecommunicationUnion2021` : International 

20 Telecommunication Union. (2021). Recommendation ITU-T H.273 - 

21 Coding-independent code points for video signal type identification. 

22 https://www.itu.int/rec/T-REC-H.273-202107-I/en 

23- :cite:`SocietyofMotionPictureandTelevisionEngineers2019` : Society of 

24 Motion Picture and Television Engineers. (2019). ST 428-1:2019 - D-Cinema 

25 Distribution Master — Image Characteristic. doi:10.5594/SMPTE.ST428-1.2019 

26""" 

27 

28from __future__ import annotations 

29 

30import numpy as np 

31 

32from colour.algebra import spow 

33from colour.hints import ( # noqa: TC001 

34 Domain1, 

35 Range1, 

36) 

37from colour.models.rgb.transfer_functions import ( 

38 eotf_DCDM, 

39 eotf_inverse_DCDM, 

40 eotf_inverse_sRGB, 

41 eotf_sRGB, 

42) 

43from colour.utilities import as_float, as_float_array, from_range_1, to_domain_1 

44 

45__author__ = "Colour Developers" 

46__copyright__ = "Copyright 2013 Colour Developers" 

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

48__maintainer__ = "Colour Developers" 

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

50__status__ = "Production" 

51 

52__all__ = [ 

53 "oetf_H273_Log", 

54 "oetf_inverse_H273_Log", 

55 "oetf_H273_LogSqrt", 

56 "oetf_inverse_H273_LogSqrt", 

57 "oetf_H273_IEC61966_2", 

58 "oetf_inverse_H273_IEC61966_2", 

59 "eotf_H273_ST428_1", 

60 "eotf_inverse_H273_ST428_1", 

61] 

62 

63 

64def oetf_H273_Log(L_c: Domain1) -> Range1: 

65 """ 

66 Apply the *Recommendation ITU-T H.273* opto-electronic transfer function 

67 (OETF) for logarithmic encoding with 100:1 dynamic range. 

68 

69 Parameters 

70 ---------- 

71 L_c 

72 Scene *luminance* :math:`L_c`. 

73 

74 Returns 

75 ------- 

76 :class:`numpy.ndarray` 

77 Electrical signal :math:`V`. 

78 

79 Notes 

80 ----- 

81 +------------+-----------------------+---------------+ 

82 | **Domain** | **Scale - Reference** | **Scale - 1** | 

83 +============+=======================+===============+ 

84 | ``L_c`` | 1 | 1 | 

85 +------------+-----------------------+---------------+ 

86 

87 +------------+-----------------------+---------------+ 

88 | **Range** | **Scale - Reference** | **Scale - 1** | 

89 +============+=======================+===============+ 

90 | ``V`` | 1 | 1 | 

91 +------------+-----------------------+---------------+ 

92 

93 References 

94 ---------- 

95 :cite:`InternationalTelecommunicationUnion2021` 

96 

97 Warnings 

98 -------- 

99 - The function is clamped to domain [0.01, np.inf]. 

100 

101 Examples 

102 -------- 

103 >>> oetf_H273_Log(0.18) # doctest: +ELLIPSIS 

104 0.6276362525516... 

105 >>> oetf_H273_Log(0.01) # doctest: +ELLIPSIS 

106 0.0 

107 >>> oetf_H273_Log(0.001) # doctest: +ELLIPSIS 

108 0.0 

109 >>> oetf_H273_Log(1.0) # doctest: +ELLIPSIS 

110 1.0 

111 """ 

112 

113 L_c = to_domain_1(L_c) 

114 

115 V = np.where( 

116 L_c >= 0.01, 

117 # L_c in [0.01, 1] range 

118 1 + np.log10(L_c) / 2, 

119 # L_c in [0, 0.01] range 

120 0, 

121 ) 

122 

123 return as_float(from_range_1(V)) 

124 

125 

126def oetf_inverse_H273_Log(V: Domain1) -> Range1: 

127 """ 

128 Apply the *Recommendation ITU-T H.273* inverse opto-electronic transfer 

129 function (OETF) for logarithmic encoding with 100:1 dynamic range. 

130 

131 Parameters 

132 ---------- 

133 V 

134 Electrical signal :math:`V`. 

135 

136 Returns 

137 ------- 

138 :class:`numpy.ndarray` 

139 Scene *luminance* :math:`L_c`. 

140 

141 Notes 

142 ----- 

143 +------------+-----------------------+---------------+ 

144 | **Domain** | **Scale - Reference** | **Scale - 1** | 

145 +============+=======================+===============+ 

146 | ``V`` | 1 | 1 | 

147 +------------+-----------------------+---------------+ 

148 

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

150 | **Range** | **Scale - Reference** | **Scale - 1** | 

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

152 | ``L_c`` | 1 | 1 | 

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

154 

155 References 

156 ---------- 

157 :cite:`InternationalTelecommunicationUnion2021` 

158 

159 Warnings 

160 -------- 

161 - The function is clamped to domain 

162 [:func:`colour.models.oetf_H273_Log` (0.01), np.inf]. 

163 

164 Examples 

165 -------- 

166 >>> oetf_inverse_H273_Log(0.6276362525516) # doctest: +ELLIPSIS 

167 0.17999999... 

168 >>> oetf_inverse_H273_Log(0.0) # doctest: +ELLIPSIS 

169 0.01 

170 >>> oetf_inverse_H273_Log(1.0) # doctest: +ELLIPSIS 

171 1.0 

172 """ 

173 

174 V = to_domain_1(V) 

175 

176 L_c = np.where( 

177 oetf_H273_Log(0.01) <= V, 

178 # L_c in [0.01, 1] range 

179 spow(10, (V - 1) * 2), 

180 # L_c in [0, 0.01] range 

181 0, 

182 ) 

183 

184 return as_float(from_range_1(L_c)) 

185 

186 

187def oetf_H273_LogSqrt(L_c: Domain1) -> Range1: 

188 """ 

189 Apply the *Recommendation ITU-T H.273* opto-electronic transfer function 

190 (OETF) for logarithmic encoding (100\\*Sqrt(10):1 range). 

191 

192 Parameters 

193 ---------- 

194 L_c 

195 Scene *luminance* :math:`L_c`. 

196 

197 Returns 

198 ------- 

199 :class:`numpy.ndarray` 

200 Electrical signal :math:`V`. 

201 

202 Notes 

203 ----- 

204 +------------+-----------------------+---------------+ 

205 | **Domain** | **Scale - Reference** | **Scale - 1** | 

206 +============+=======================+===============+ 

207 | ``L_c`` | 1 | 1 | 

208 +------------+-----------------------+---------------+ 

209 

210 +------------+-----------------------+---------------+ 

211 | **Range** | **Scale - Reference** | **Scale - 1** | 

212 +============+=======================+===============+ 

213 | ``V`` | 1 | 1 | 

214 +------------+-----------------------+---------------+ 

215 

216 References 

217 ---------- 

218 :cite:`InternationalTelecommunicationUnion2021` 

219 

220 Warnings 

221 -------- 

222 - The function is clamped to domain 

223 [:func:`colour.models.oetf_H273_LogSqrt` (sqrt(10) / 1000), 

224 np.inf]. 

225 

226 Examples 

227 -------- 

228 >>> oetf_H273_LogSqrt(0.18) # doctest: +ELLIPSIS 

229 0.702109002041... 

230 >>> oetf_H273_LogSqrt(0.003162277660168) # doctest: +ELLIPSIS 

231 0.0 

232 >>> oetf_H273_LogSqrt(0.0001) # doctest: +ELLIPSIS 

233 0.0 

234 >>> oetf_H273_LogSqrt(1.0) # doctest: +ELLIPSIS 

235 1.0 

236 """ 

237 

238 L_c = to_domain_1(L_c) 

239 

240 V = np.where( 

241 L_c >= np.sqrt(10) / 1000, 

242 # L_c in [sqrt(10)/1000, 1] range 

243 1 + np.log10(L_c) / 2.5, 

244 # L_c in [0, sqrt(10)/1000] range 

245 0, 

246 ) 

247 

248 return as_float(from_range_1(V)) 

249 

250 

251def oetf_inverse_H273_LogSqrt(V: Domain1) -> Range1: 

252 """ 

253 Apply the *Recommendation ITU-T H.273* inverse opto-electronic transfer 

254 function (OETF) for logarithmic encoding (100\\*Sqrt(10):1 range). 

255 

256 Parameters 

257 ---------- 

258 V 

259 Electrical signal :math:`V`. 

260 

261 Returns 

262 ------- 

263 :class:`numpy.ndarray` 

264 Scene *luminance* :math:`L_c`. 

265 

266 Notes 

267 ----- 

268 +------------+-----------------------+---------------+ 

269 | **Domain** | **Scale - Reference** | **Scale - 1** | 

270 +============+=======================+===============+ 

271 | ``V`` | 1 | 1 | 

272 +------------+-----------------------+---------------+ 

273 

274 +------------+-----------------------+---------------+ 

275 | **Range** | **Scale - Reference** | **Scale - 1** | 

276 +============+=======================+===============+ 

277 | ``L_c`` | 1 | 1 | 

278 +------------+-----------------------+---------------+ 

279 

280 References 

281 ---------- 

282 :cite:`InternationalTelecommunicationUnion2021` 

283 

284 Warnings 

285 -------- 

286 - The function is clamped to domain [sqrt(10) / 1000, np.inf]. 

287 

288 Examples 

289 -------- 

290 >>> oetf_inverse_H273_LogSqrt(0.702109002041) # doctest: +ELLIPSIS 

291 0.1799999999... 

292 >>> oetf_inverse_H273_LogSqrt(0.0) # doctest: +ELLIPSIS 

293 0.00316227766... 

294 >>> oetf_inverse_H273_LogSqrt(1.0) # doctest: +ELLIPSIS 

295 1.0 

296 """ 

297 

298 V = to_domain_1(V) 

299 

300 L_c = np.where( 

301 oetf_H273_LogSqrt(np.sqrt(10) / 1000) <= V, 

302 # L_c in [sqrt(10)/1000, 1] range 

303 spow(10, (V - 1) * 2.5), 

304 # L_c in [0, sqrt(10)/1000] range 

305 0, 

306 ) 

307 

308 return as_float(from_range_1(L_c)) 

309 

310 

311def oetf_H273_IEC61966_2(L_c: Domain1) -> Range1: 

312 """ 

313 Apply the *Recommendation ITU-T H.273* opto-electronic transfer function 

314 (OETF) for *IEC 61966-2* family of transfer functions (*2-1 sRGB*, *2-1 

315 sYCC*, *2-4 xvYCC*). 

316 

317 Parameters 

318 ---------- 

319 L_c 

320 Scene *luminance* :math:`L_c`. 

321 

322 Returns 

323 ------- 

324 :class:`numpy.ndarray` 

325 Electrical signal :math:`V`. 

326 

327 Notes 

328 ----- 

329 Usage in :cite:`InternationalTelecommunicationUnion2021` is as follows: 

330 

331 - For *IEC 61966-2-1 sRGB (MatrixCoefficients=0)*, the function is 

332 only defined for :math:`L_c` in [0-1] range. 

333 - For *IEC 61966-2-1 sYCC (MatrixCoefficients=5)* and *IEC 61966-2-4 

334 xvYCC*, the function is defined for any real-valued :math:`L_c`. 

335 

336 +------------+-----------------------+---------------+ 

337 | **Domain** | **Scale - Reference** | **Scale - 1** | 

338 +============+=======================+===============+ 

339 | ``L_c`` | 1 | 1 | 

340 +------------+-----------------------+---------------+ 

341 

342 +------------+-----------------------+---------------+ 

343 | **Range** | **Scale - Reference** | **Scale - 1** | 

344 +============+=======================+===============+ 

345 | ``V`` | 1 | 1 | 

346 +------------+-----------------------+---------------+ 

347 

348 References 

349 ---------- 

350 - :cite:`InternationalTelecommunicationUnion2021` 

351 

352 Examples 

353 -------- 

354 >>> oetf_H273_IEC61966_2(0.18) # doctest: +ELLIPSIS 

355 0.4613561295004... 

356 >>> oetf_H273_IEC61966_2(-0.18) # doctest: +ELLIPSIS 

357 -0.4613561295004... 

358 """ 

359 

360 L_c = as_float_array(L_c) 

361 

362 V = np.where( 

363 L_c >= 0, 

364 eotf_inverse_sRGB(L_c), 

365 -eotf_inverse_sRGB(-L_c), 

366 ) 

367 

368 return as_float(V) 

369 

370 

371def oetf_inverse_H273_IEC61966_2( 

372 V: Domain1, 

373) -> Range1: 

374 """ 

375 Apply the *Recommendation ITU-T H.273* inverse opto-electronic 

376 transfer function (OETF) for the *IEC 61966-2* family of transfer 

377 functions (*2-1 sRGB*, *2-1 sYCC*, *2-4 xvYCC*). 

378 

379 Parameters 

380 ---------- 

381 V 

382 Electrical signal :math:`V`. 

383 

384 Returns 

385 ------- 

386 :class:`numpy.ndarray` 

387 Scene *luminance* :math:`L_c`. 

388 

389 Notes 

390 ----- 

391 Usage in :cite:`InternationalTelecommunicationUnion2021` is 

392 specified as follows: 

393 

394 - For *IEC 61966-2-1 sRGB (MatrixCoefficients=0)*, the function is 

395 only defined for :math:`L_c` in [0-1] range. 

396 - For *IEC 61966-2-1 sYCC (MatrixCoefficients=5)* and *IEC 

397 61966-2-4 xvYCC*, the function is defined for any real-valued 

398 :math:`L_c`. 

399 

400 +------------+-----------------------+---------------+ 

401 | **Domain** | **Scale - Reference** | **Scale - 1** | 

402 +============+=======================+===============+ 

403 | ``V`` | 1 | 1 | 

404 +------------+-----------------------+---------------+ 

405 

406 +------------+-----------------------+---------------+ 

407 | **Range** | **Scale - Reference** | **Scale - 1** | 

408 +============+=======================+===============+ 

409 | ``L_c`` | 1 | 1 | 

410 +------------+-----------------------+---------------+ 

411 

412 References 

413 ---------- 

414 - :cite:`InternationalTelecommunicationUnion2021` 

415 

416 Examples 

417 -------- 

418 >>> oetf_inverse_H273_IEC61966_2(0.461356129500) # doctest: +ELLIPSIS 

419 0.1799999999... 

420 >>> oetf_inverse_H273_IEC61966_2(-0.461356129500) # doctest: +ELLIPSIS 

421 -0.1799999999... 

422 """ 

423 

424 V = as_float_array(V) 

425 

426 L_c = np.where( 

427 V >= 0, 

428 eotf_sRGB(V), 

429 -eotf_sRGB(-V), 

430 ) 

431 

432 return as_float(L_c) 

433 

434 

435def eotf_H273_ST428_1(V: Domain1) -> Range1: 

436 """ 

437 Apply the *SMPTE ST 428-1 (2019)* electro-optical transfer function 

438 (EOTF) as specified in *ITU-T H.273*. 

439 

440 Parameters 

441 ---------- 

442 V 

443 Electrical signal :math:`V`. 

444 

445 Returns 

446 ------- 

447 :class:`numpy.ndarray` 

448 Output display *Luminance* :math:`L_o` of the image. 

449 

450 Notes 

451 ----- 

452 - The function specified in 

453 :cite:`InternationalTelecommunicationUnion2021` divides 

454 :math:`L_o` by 48, contrary to what is specified in 

455 :cite:`SocietyofMotionPictureandTelevisionEngineers2019` and 

456 :func:`colour.models.eotf_DCDM`. 

457 

458 +------------+-----------------------+---------------+ 

459 | **Domain** | **Scale - Reference** | **Scale - 1** | 

460 +============+=======================+===============+ 

461 | ``V`` | 1 | 1 | 

462 +------------+-----------------------+---------------+ 

463 

464 +------------+-----------------------+---------------+ 

465 | **Range** | **Scale - Reference** | **Scale - 1** | 

466 +============+=======================+===============+ 

467 | ``L_o`` | 1 | 1 | 

468 +------------+-----------------------+---------------+ 

469 

470 References 

471 ---------- 

472 - :cite:`InternationalTelecommunicationUnion2021`, 

473 :cite:`SocietyofMotionPictureandTelevisionEngineers2019` 

474 

475 Examples 

476 -------- 

477 >>> eotf_H273_ST428_1(0.5000483377172) # doctest: +ELLIPSIS 

478 0.1799999... 

479 """ 

480 

481 V = to_domain_1(V) 

482 

483 return as_float(from_range_1(eotf_DCDM(V) / 48)) 

484 

485 

486def eotf_inverse_H273_ST428_1( 

487 L_o: Domain1, 

488) -> Range1: 

489 """ 

490 Apply the *SMPTE ST 428-1 (2019)* inverse electro-optical transfer function 

491 (EOTF) as specified in *ITU-T H.273*. 

492 

493 Parameters 

494 ---------- 

495 L_o 

496 Output display *Luminance* :math:`L_o` of the image. 

497 

498 Returns 

499 ------- 

500 :class:`numpy.ndarray` 

501 Electrical signal :math:`V`. 

502 

503 Notes 

504 ----- 

505 - The function specified in 

506 :cite:`InternationalTelecommunicationUnion2021` multiplies :math:`L_o` 

507 by 48, contrary to what is specified in 

508 :cite:`SocietyofMotionPictureandTelevisionEngineers2019` and 

509 :func:`colour.models.eotf_inverse_DCDM`. 

510 

511 +------------+-----------------------+---------------+ 

512 | **Domain** | **Scale - Reference** | **Scale - 1** | 

513 +============+=======================+===============+ 

514 | ``L_o`` | 1 | 1 | 

515 +------------+-----------------------+---------------+ 

516 

517 +------------+-----------------------+---------------+ 

518 | **Range** | **Scale - Reference** | **Scale - 1** | 

519 +============+=======================+===============+ 

520 | ``V`` | 1 | 1 | 

521 +------------+-----------------------+---------------+ 

522 

523 References 

524 ---------- 

525 - :cite:`InternationalTelecommunicationUnion2021`, 

526 :cite:`SocietyofMotionPictureandTelevisionEngineers2019` 

527 

528 Examples 

529 -------- 

530 >>> eotf_inverse_H273_ST428_1(0.18) # doctest: +ELLIPSIS 

531 0.5000483... 

532 """ 

533 

534 L_o = to_domain_1(L_o) 

535 

536 return as_float(from_range_1(eotf_inverse_DCDM(L_o * 48)))