Coverage for models/rgb/transfer_functions/canon.py: 68%

133 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-16 22:49 +1300

1""" 

2Canon Log Encodings 

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

4 

5Define the *Canon Log* encodings. 

6 

7- :attr:`colour.models.CANON_LOG_ENCODING_METHODS` 

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

9- :attr:`colour.models.CANON_LOG_DECODING_METHODS` 

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

11- :attr:`colour.models.CANON_LOG_2_ENCODING_METHODS` 

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

13- :attr:`colour.models.CANON_LOG_2_DECODING_METHODS` 

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

15- :attr:`colour.models.CANON_LOG_3_ENCODING_METHODS` 

16- :func:`colour.models.log_encoding_CanonLog3` 

17- :attr:`colour.models.CANON_LOG_3_DECODING_METHODS` 

18- :func:`colour.models.log_decoding_CanonLog3` 

19 

20Notes 

21----- 

22- :cite:`Canon2016` is available as a *Drivers & Downloads* *Software* for 

23 Windows 7 *Operating System*, a copy of the archive is hosted at 

24 this url: https://drive.google.com/open?id=0B_IQZQdc4Vy8ZGYyY29pMEVwZU0 

25- :cite:`Canon2020` is available as a *Drivers & Downloads* *Software* for 

26 Windows 10 *Operating System*, a copy of the archive is hosted at 

27 this url: https://drive.google.com/open?id=1Vcz8RVIXgXL54lhZsOwGUjjVZRObZSc5 

28 

29References 

30---------- 

31- :cite:`Canon2016` : Canon. (2016). Input Transform Version 201612 for EOS 

32 C300 Mark II. Retrieved August 23, 2016, from https://www.usa.canon.com/\ 

33internet/portal/us/home/support/details/cameras/cinema-eos/eos-c300-mark-ii 

34- :cite:`Canon2020` : Canon. (2020). Input Transform Version 202007 for EOS 

35 C300 Mark II. Retrieved July 16, 2023, from https://www.usa.canon.com/\ 

36internet/portal/us/home/support/details/cameras/cinema-eos/eos-c300-mark-ii 

37- :cite:`Thorpe2012a` : Thorpe, L. (2012). CANON-LOG TRANSFER CHARACTERISTIC. 

38 Retrieved September 25, 2014, from 

39 http://downloads.canon.com/CDLC/Canon-Log_Transfer_Characteristic_6-20-2012.pdf 

40""" 

41 

42from __future__ import annotations 

43 

44import typing 

45 

46import numpy as np 

47 

48if typing.TYPE_CHECKING: 

49 from colour.hints import Literal 

50 

51from colour.hints import ( # noqa: TC001 

52 Domain1, 

53 Range1, 

54) 

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

56from colour.utilities import ( 

57 CanonicalMapping, 

58 as_float, 

59 domain_range_scale, 

60 from_range_1, 

61 to_domain_1, 

62 validate_method, 

63) 

64 

65__author__ = "Colour Developers" 

66__copyright__ = "Copyright 2013 Colour Developers" 

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

68__maintainer__ = "Colour Developers" 

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

70__status__ = "Production" 

71 

72__all__ = [ 

73 "log_encoding_CanonLog_v1", 

74 "log_decoding_CanonLog_v1", 

75 "log_encoding_CanonLog_v1_2", 

76 "log_decoding_CanonLog_v1_2", 

77 "CANON_LOG_ENCODING_METHODS", 

78 "log_encoding_CanonLog", 

79 "CANON_LOG_DECODING_METHODS", 

80 "log_decoding_CanonLog", 

81 "log_encoding_CanonLog2_v1", 

82 "log_decoding_CanonLog2_v1", 

83 "log_encoding_CanonLog2_v1_2", 

84 "log_decoding_CanonLog2_v1_2", 

85 "CANON_LOG_2_ENCODING_METHODS", 

86 "log_encoding_CanonLog2", 

87 "CANON_LOG_2_DECODING_METHODS", 

88 "log_decoding_CanonLog2", 

89 "log_encoding_CanonLog3_v1", 

90 "log_decoding_CanonLog3_v1", 

91 "log_encoding_CanonLog3_v1_2", 

92 "log_decoding_CanonLog3_v1_2", 

93 "CANON_LOG_3_ENCODING_METHODS", 

94 "log_encoding_CanonLog3", 

95 "CANON_LOG_3_DECODING_METHODS", 

96 "log_decoding_CanonLog3", 

97] 

98 

99 

100def log_encoding_CanonLog_v1( 

101 x: Domain1, 

102 bit_depth: int = 10, 

103 out_normalised_code_value: bool = True, 

104 in_reflection: bool = True, 

105) -> Range1: 

106 """ 

107 Apply the *Canon Log* v1 log encoding opto-electronic transfer function (OETF). 

108 

109 Parameters 

110 ---------- 

111 x 

112 Linear data :math:`x`. 

113 bit_depth 

114 Bit-depth used for conversion. 

115 out_normalised_code_value 

116 Whether the *Canon Log* v1 non-linear data is encoded as normalised 

117 code values. 

118 in_reflection 

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

120 

121 Returns 

122 ------- 

123 :class:`numpy.ndarray` 

124 *Canon Log* v1 non-linear encoded data. 

125 

126 References 

127 ---------- 

128 :cite:`Canon2016`, :cite:`Thorpe2012a` 

129 

130 Notes 

131 ----- 

132 +------------+-----------------------+---------------+ 

133 | **Domain** | **Scale - Reference** | **Scale - 1** | 

134 +============+=======================+===============+ 

135 | ``x`` | 1 | 1 | 

136 +------------+-----------------------+---------------+ 

137 

138 +------------+-----------------------+---------------+ 

139 | **Range** | **Scale - Reference** | **Scale - 1** | 

140 +============+=======================+===============+ 

141 | ``clog`` | 1 | 1 | 

142 +------------+-----------------------+---------------+ 

143 

144 Examples 

145 -------- 

146 >>> log_encoding_CanonLog_v1(0.18) * 100 # doctest: +ELLIPSIS 

147 34.3389651... 

148 

149 The values of *Table 2 Canon-Log Code Values* table in 

150 :cite:`Thorpe2012a` are obtained as follows: 

151 

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

153 >>> np.around(log_encoding_CanonLog_v1(x) * (2**10 - 1)).astype(np.int_) 

154 array([ 128, 169, 351, 614, 1016]) 

155 >>> np.around(log_encoding_CanonLog_v1(x, 10, False) * 100, 1) 

156 array([ 7.3, 12. , 32.8, 62.7, 108.7]) 

157 """ 

158 

159 x = to_domain_1(x) 

160 

161 if in_reflection: 

162 x = x / 0.9 

163 

164 with domain_range_scale("ignore"): 

165 clog = np.where( 

166 x < log_decoding_CanonLog_v1(0.0730597, bit_depth, False), 

167 -(0.529136 * (np.log10(-x * 10.1596 + 1)) - 0.0730597), 

168 0.529136 * np.log10(10.1596 * x + 1) + 0.0730597, 

169 ) 

170 

171 clog_cv = full_to_legal(clog, bit_depth) if out_normalised_code_value else clog 

172 

173 return as_float(from_range_1(clog_cv)) 

174 

175 

176def log_decoding_CanonLog_v1( 

177 clog: Domain1, 

178 bit_depth: int = 10, 

179 in_normalised_code_value: bool = True, 

180 out_reflection: bool = True, 

181) -> Range1: 

182 """ 

183 Apply the *Canon Log* v1 log decoding inverse opto-electronic transfer 

184 function (OETF). 

185 

186 Parameters 

187 ---------- 

188 clog 

189 *Canon Log* v1 non-linear encoded data. 

190 bit_depth 

191 Bit-depth used for conversion. 

192 in_normalised_code_value 

193 Whether the *Canon Log* v1 non-linear data is encoded with normalised 

194 code values. 

195 out_reflection 

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

197 

198 Returns 

199 ------- 

200 :class:`numpy.ndarray` 

201 Linear data :math:`x`. 

202 

203 Notes 

204 ----- 

205 +------------+-----------------------+---------------+ 

206 | **Domain** | **Scale - Reference** | **Scale - 1** | 

207 +============+=======================+===============+ 

208 | ``clog`` | 1 | 1 | 

209 +------------+-----------------------+---------------+ 

210 

211 +------------+-----------------------+---------------+ 

212 | **Range** | **Scale - Reference** | **Scale - 1** | 

213 +============+=======================+===============+ 

214 | ``x`` | 1 | 1 | 

215 +------------+-----------------------+---------------+ 

216 

217 References 

218 ---------- 

219 :cite:`Canon2016`, :cite:`Thorpe2012a` 

220 

221 Examples 

222 -------- 

223 >>> log_decoding_CanonLog_v1(34.338965172606912 / 100) # doctest: +ELLIPSIS 

224 0.17999999... 

225 """ 

226 

227 clog = to_domain_1(clog) 

228 

229 clog = legal_to_full(clog, bit_depth) if in_normalised_code_value else clog 

230 

231 x = np.where( 

232 clog < 0.0730597, 

233 -(10 ** ((0.0730597 - clog) / 0.529136) - 1) / 10.1596, 

234 (10 ** ((clog - 0.0730597) / 0.529136) - 1) / 10.1596, 

235 ) 

236 

237 if out_reflection: 

238 x = x * 0.9 

239 

240 return as_float(from_range_1(x)) 

241 

242 

243def log_encoding_CanonLog_v1_2( 

244 x: Domain1, 

245 bit_depth: int = 10, 

246 out_normalised_code_value: bool = True, 

247 in_reflection: bool = True, 

248) -> Range1: 

249 """ 

250 Apply the *Canon Log* v1.2 log encoding opto-electronic transfer function (OETF). 

251 

252 Parameters 

253 ---------- 

254 x 

255 Linear data :math:`x`. 

256 bit_depth 

257 Bit-depth used for conversion. 

258 out_normalised_code_value 

259 Whether the *Canon Log* v1.2 non-linear data is encoded as 

260 normalised code values. 

261 in_reflection 

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

263 

264 Returns 

265 ------- 

266 :class:`numpy.ndarray` 

267 *Canon Log* v1.2 non-linear encoded data. 

268 

269 References 

270 ---------- 

271 :cite:`Canon2020` 

272 

273 Notes 

274 ----- 

275 +------------+-----------------------+---------------+ 

276 | **Domain** | **Scale - Reference** | **Scale - 1** | 

277 +============+=======================+===============+ 

278 | ``x`` | 1 | 1 | 

279 +------------+-----------------------+---------------+ 

280 

281 +------------+-----------------------+---------------+ 

282 | **Range** | **Scale - Reference** | **Scale - 1** | 

283 +============+=======================+===============+ 

284 | ``clog`` | 1 | 1 | 

285 +------------+-----------------------+---------------+ 

286 

287 Examples 

288 -------- 

289 >>> log_encoding_CanonLog_v1_2(0.18) * 100 # doctest: +ELLIPSIS 

290 34.3389649... 

291 """ 

292 

293 x = to_domain_1(x) 

294 

295 if in_reflection: 

296 x = x / 0.9 

297 

298 with domain_range_scale("ignore"): 

299 clog = np.where( 

300 x < (log_decoding_CanonLog_v1_2(0.12512248, bit_depth, True)), 

301 -(0.45310179 * (np.log10(-x * 10.1596 + 1)) - 0.12512248), 

302 0.45310179 * np.log10(10.1596 * x + 1) + 0.12512248, 

303 ) 

304 

305 # NOTE: *Canon Log* v1.2 constants are expressed in legal range 

306 # (studio swing). 

307 clog_cv = clog if out_normalised_code_value else legal_to_full(clog, bit_depth) 

308 

309 return as_float(from_range_1(clog_cv)) 

310 

311 

312def log_decoding_CanonLog_v1_2( 

313 clog: Domain1, 

314 bit_depth: int = 10, 

315 in_normalised_code_value: bool = True, 

316 out_reflection: bool = True, 

317) -> Range1: 

318 """ 

319 Apply the *Canon Log* v1.2 log decoding inverse opto-electronic transfer 

320 

321 function (OETF). 

322 

323 Parameters 

324 ---------- 

325 clog 

326 *Canon Log* v1.2 non-linear encoded data. 

327 bit_depth 

328 Bit-depth used for conversion. 

329 in_normalised_code_value 

330 Whether the *Canon Log* v1.2 non-linear data is encoded with normalised 

331 code values. 

332 out_reflection 

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

334 

335 Returns 

336 ------- 

337 :class:`numpy.ndarray` 

338 Linear data :math:`x`. 

339 

340 Notes 

341 ----- 

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

343 | **Domain** | **Scale - Reference** | **Scale - 1** | 

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

345 | ``clog`` | 1 | 1 | 

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

347 

348 +------------+-----------------------+---------------+ 

349 | **Range** | **Scale - Reference** | **Scale - 1** | 

350 +============+=======================+===============+ 

351 | ``x`` | 1 | 1 | 

352 +------------+-----------------------+---------------+ 

353 

354 References 

355 ---------- 

356 :cite:`Canon2020` 

357 

358 Examples 

359 -------- 

360 >>> log_decoding_CanonLog_v1_2(34.338964929528061 / 100) 

361 ... # doctest: +ELLIPSIS 

362 0.17999999... 

363 """ 

364 

365 clog = to_domain_1(clog) 

366 

367 # NOTE: *Canon Log* v1.2 constants are expressed in legal range 

368 # (studio swing). 

369 clog = clog if in_normalised_code_value else full_to_legal(clog, bit_depth) 

370 

371 x = np.where( 

372 clog < 0.12512248, 

373 -(10 ** ((0.12512248 - clog) / 0.45310179) - 1) / 10.1596, 

374 (10 ** ((clog - 0.12512248) / 0.45310179) - 1) / 10.1596, 

375 ) 

376 

377 if out_reflection: 

378 x = x * 0.9 

379 

380 return as_float(from_range_1(x)) 

381 

382 

383CANON_LOG_ENCODING_METHODS: CanonicalMapping = CanonicalMapping( 

384 { 

385 "v1": log_encoding_CanonLog_v1, 

386 "v1.2": log_encoding_CanonLog_v1_2, 

387 } 

388) 

389CANON_LOG_ENCODING_METHODS.__doc__ = """ 

390Supported *Canon Log* log encoding curve / opto-electronic transfer function 

391(OETF) methods. 

392 

393References 

394---------- 

395:cite:`Canon2016`, :cite:`Canon2020` 

396""" 

397 

398 

399def log_encoding_CanonLog( 

400 x: Domain1, 

401 bit_depth: int = 10, 

402 out_normalised_code_value: bool = True, 

403 in_reflection: bool = True, 

404 method: Literal["v1", "v1.2"] | str = "v1.2", 

405) -> Range1: 

406 """ 

407 Apply the *Canon Log* log encoding opto-electronic transfer function (OETF). 

408 

409 Parameters 

410 ---------- 

411 x 

412 Linear data :math:`x`. 

413 bit_depth 

414 Bit-depth used for conversion. 

415 out_normalised_code_value 

416 Whether the *Canon Log* non-linear data is encoded as normalised 

417 code values. 

418 in_reflection 

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

420 method 

421 Computation method. 

422 

423 Returns 

424 ------- 

425 :class:`numpy.ndarray` 

426 *Canon Log* non-linear encoded data. 

427 

428 References 

429 ---------- 

430 :cite:`Canon2016`, :cite:`Canon2020`, :cite:`Thorpe2012a` 

431 

432 Notes 

433 ----- 

434 +------------+-----------------------+---------------+ 

435 | **Domain** | **Scale - Reference** | **Scale - 1** | 

436 +============+=======================+===============+ 

437 | ``x`` | 1 | 1 | 

438 +------------+-----------------------+---------------+ 

439 

440 +------------+-----------------------+---------------+ 

441 | **Range** | **Scale - Reference** | **Scale - 1** | 

442 +============+=======================+===============+ 

443 | ``clog`` | 1 | 1 | 

444 +------------+-----------------------+---------------+ 

445 

446 Examples 

447 -------- 

448 >>> log_encoding_CanonLog(0.18) * 100 # doctest: +ELLIPSIS 

449 34.3389649... 

450 >>> log_encoding_CanonLog(0.18, method="v1") * 100 # doctest: +ELLIPSIS 

451 34.3389651... 

452 

453 The values of *Table 2 Canon-Log Code Values* table in 

454 :cite:`Thorpe2012a` are obtained as follows: 

455 

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

457 >>> np.around(log_encoding_CanonLog(x, method="v1") * (2**10 - 1)).astype(np.int_) 

458 array([ 128, 169, 351, 614, 1016]) 

459 >>> np.around(log_encoding_CanonLog(x, 10, False, method="v1") * 100, 1) 

460 array([ 7.3, 12. , 32.8, 62.7, 108.7]) 

461 """ 

462 

463 method = validate_method(method, tuple(CANON_LOG_ENCODING_METHODS)) 

464 

465 return CANON_LOG_ENCODING_METHODS[method]( 

466 x, bit_depth, out_normalised_code_value, in_reflection 

467 ) 

468 

469 

470CANON_LOG_DECODING_METHODS: CanonicalMapping = CanonicalMapping( 

471 { 

472 "v1": log_decoding_CanonLog_v1, 

473 "v1.2": log_decoding_CanonLog_v1_2, 

474 } 

475) 

476CANON_LOG_DECODING_METHODS.__doc__ = """ 

477Supported *Canon Log* log decoding curve / electro-optical transfer function 

478(EOTF) methods. 

479 

480References 

481---------- 

482:cite:`Canon2016`, :cite:`Canon2020` 

483""" 

484 

485 

486def log_decoding_CanonLog( 

487 clog: Domain1, 

488 bit_depth: int = 10, 

489 in_normalised_code_value: bool = True, 

490 out_reflection: bool = True, 

491 method: Literal["v1", "v1.2"] | str = "v1.2", 

492) -> Range1: 

493 """ 

494 Apply the *Canon Log* log decoding inverse opto-electronic transfer function (OETF). 

495 

496 Parameters 

497 ---------- 

498 clog 

499 *Canon Log* non-linear encoded data. 

500 bit_depth 

501 Bit-depth used for conversion. 

502 in_normalised_code_value 

503 Whether the *Canon Log* non-linear data is encoded with normalised 

504 code values. 

505 out_reflection 

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

507 method 

508 Computation method. 

509 

510 Returns 

511 ------- 

512 :class:`numpy.ndarray` 

513 Linear data :math:`x`. 

514 

515 Notes 

516 ----- 

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

518 | **Domain** | **Scale - Reference** | **Scale - 1** | 

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

520 | ``clog`` | 1 | 1 | 

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

522 

523 +------------+-----------------------+---------------+ 

524 | **Range** | **Scale - Reference** | **Scale - 1** | 

525 +============+=======================+===============+ 

526 | ``x`` | 1 | 1 | 

527 +------------+-----------------------+---------------+ 

528 

529 References 

530 ---------- 

531 :cite:`Canon2016`, :cite:`Canon2020`, :cite:`Thorpe2012a` 

532 

533 Examples 

534 -------- 

535 >>> log_decoding_CanonLog(34.338964929528061 / 100) # doctest: +ELLIPSIS 

536 0.17999999... 

537 >>> log_decoding_CanonLog(34.338965172606912 / 100, method="v1") 

538 ... # doctest: +ELLIPSIS 

539 0.17999999... 

540 """ 

541 

542 method = validate_method(method, tuple(CANON_LOG_DECODING_METHODS)) 

543 

544 return CANON_LOG_DECODING_METHODS[method]( 

545 clog, bit_depth, in_normalised_code_value, out_reflection 

546 ) 

547 

548 

549def log_encoding_CanonLog2_v1( 

550 x: Domain1, 

551 bit_depth: int = 10, 

552 out_normalised_code_value: bool = True, 

553 in_reflection: bool = True, 

554) -> Range1: 

555 """ 

556 Apply the *Canon Log 2* v1 log encoding opto-electronic transfer function (OETF). 

557 

558 Parameters 

559 ---------- 

560 x 

561 Linear data :math:`x`. 

562 bit_depth 

563 Bit-depth used for conversion. 

564 out_normalised_code_value 

565 Whether the *Canon Log 2* v1 non-linear data is encoded as normalised 

566 code values. 

567 in_reflection 

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

569 

570 Returns 

571 ------- 

572 :class:`numpy.ndarray` 

573 *Canon Log 2* v1 non-linear encoded data. 

574 

575 Notes 

576 ----- 

577 +------------+-----------------------+---------------+ 

578 | **Domain** | **Scale - Reference** | **Scale - 1** | 

579 +============+=======================+===============+ 

580 | ``x`` | 1 | 1 | 

581 +------------+-----------------------+---------------+ 

582 

583 +------------+-----------------------+---------------+ 

584 | **Range** | **Scale - Reference** | **Scale - 1** | 

585 +============+=======================+===============+ 

586 | ``clog2`` | 1 | 1 | 

587 +------------+-----------------------+---------------+ 

588 

589 References 

590 ---------- 

591 :cite:`Canon2016` 

592 

593 Examples 

594 -------- 

595 >>> log_encoding_CanonLog2_v1(0.18) * 100 # doctest: +ELLIPSIS 

596 39.8254694... 

597 """ 

598 

599 x = to_domain_1(x) 

600 

601 if in_reflection: 

602 x = x / 0.9 

603 

604 with domain_range_scale("ignore"): 

605 clog2 = np.where( 

606 x < log_decoding_CanonLog2_v1(0.035388128, bit_depth, False), 

607 -(0.281863093 * (np.log10(-x * 87.09937546 + 1)) - 0.035388128), 

608 0.281863093 * np.log10(x * 87.09937546 + 1) + 0.035388128, 

609 ) 

610 

611 clog2_cv = full_to_legal(clog2, bit_depth) if out_normalised_code_value else clog2 

612 

613 return as_float(from_range_1(clog2_cv)) 

614 

615 

616def log_decoding_CanonLog2_v1( 

617 clog2: Domain1, 

618 bit_depth: int = 10, 

619 in_normalised_code_value: bool = True, 

620 out_reflection: bool = True, 

621) -> Range1: 

622 """ 

623 Apply the *Canon Log 2* v1 log decoding inverse opto-electronic transfer 

624 function (OETF). 

625 

626 Parameters 

627 ---------- 

628 clog2 

629 *Canon Log 2* v1 non-linear encoded data. 

630 bit_depth 

631 Bit-depth used for conversion. 

632 in_normalised_code_value 

633 Whether the *Canon Log 2* v1 non-linear data is encoded with 

634 normalised code values. 

635 out_reflection 

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

637 

638 Returns 

639 ------- 

640 :class:`numpy.ndarray` 

641 Linear data :math:`x`. 

642 

643 Notes 

644 ----- 

645 +------------+-----------------------+---------------+ 

646 | **Domain** | **Scale - Reference** | **Scale - 1** | 

647 +============+=======================+===============+ 

648 | ``clog2`` | 1 | 1 | 

649 +------------+-----------------------+---------------+ 

650 

651 +------------+-----------------------+---------------+ 

652 | **Range** | **Scale - Reference** | **Scale - 1** | 

653 +============+=======================+===============+ 

654 | ``x`` | 1 | 1 | 

655 +------------+-----------------------+---------------+ 

656 

657 References 

658 ---------- 

659 :cite:`Canon2016` 

660 

661 Examples 

662 -------- 

663 >>> log_decoding_CanonLog2_v1(39.825469498316735 / 100) # doctest: +ELLIPSIS 

664 0.1799999... 

665 """ 

666 

667 clog2 = to_domain_1(clog2) 

668 

669 clog2 = legal_to_full(clog2, bit_depth) if in_normalised_code_value else clog2 

670 

671 x = np.where( 

672 clog2 < 0.035388128, 

673 -(10 ** ((0.035388128 - clog2) / 0.281863093) - 1) / 87.09937546, 

674 (10 ** ((clog2 - 0.035388128) / 0.281863093) - 1) / 87.09937546, 

675 ) 

676 

677 if out_reflection: 

678 x = x * 0.9 

679 

680 return as_float(from_range_1(x)) 

681 

682 

683def log_encoding_CanonLog2_v1_2( 

684 x: Domain1, 

685 bit_depth: int = 10, 

686 out_normalised_code_value: bool = True, 

687 in_reflection: bool = True, 

688) -> Range1: 

689 """ 

690 Apply the *Canon Log 2* v1.2 log encoding opto-electronic transfer function 

691 (OETF). 

692 

693 Parameters 

694 ---------- 

695 x 

696 Linear data :math:`x`. 

697 bit_depth 

698 Bit-depth used for conversion. 

699 out_normalised_code_value 

700 Whether the *Canon Log 2* v1.2 non-linear data is encoded as 

701 normalised code values. 

702 in_reflection 

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

704 

705 Returns 

706 ------- 

707 :class:`numpy.ndarray` 

708 *Canon Log 2* v1.2 non-linear encoded data. 

709 

710 Notes 

711 ----- 

712 +------------+-----------------------+---------------+ 

713 | **Domain** | **Scale - Reference** | **Scale - 1** | 

714 +============+=======================+===============+ 

715 | ``x`` | 1 | 1 | 

716 +------------+-----------------------+---------------+ 

717 

718 +------------+-----------------------+---------------+ 

719 | **Range** | **Scale - Reference** | **Scale - 1** | 

720 +============+=======================+===============+ 

721 | ``clog2`` | 1 | 1 | 

722 +------------+-----------------------+---------------+ 

723 

724 References 

725 ---------- 

726 :cite:`Canon2020` 

727 

728 Examples 

729 -------- 

730 >>> log_encoding_CanonLog2_v1_2(0.18) * 100 # doctest: +ELLIPSIS 

731 39.8254692... 

732 """ 

733 

734 x = to_domain_1(x) 

735 

736 if in_reflection: 

737 x = x / 0.9 

738 

739 with domain_range_scale("ignore"): 

740 clog2 = np.where( 

741 x < (log_decoding_CanonLog2_v1_2(0.092864125, bit_depth, True)), 

742 -(0.24136077 * (np.log10(-x * 87.09937546 + 1)) - 0.092864125), 

743 0.24136077 * np.log10(x * 87.09937546 + 1) + 0.092864125, 

744 ) 

745 

746 # NOTE: *Canon Log 2* v1.2 constants are expressed in legal range 

747 # (studio swing). 

748 clog2_cv = clog2 if out_normalised_code_value else legal_to_full(clog2, bit_depth) 

749 

750 return as_float(from_range_1(clog2_cv)) 

751 

752 

753def log_decoding_CanonLog2_v1_2( 

754 clog2: Domain1, 

755 bit_depth: int = 10, 

756 in_normalised_code_value: bool = True, 

757 out_reflection: bool = True, 

758) -> Range1: 

759 """ 

760 Apply the *Canon Log 2* v1.2 log decoding inverse opto-electronic transfer 

761 function (OETF). 

762 

763 Parameters 

764 ---------- 

765 clog2 

766 *Canon Log 2* v1.2 non-linear encoded data. 

767 bit_depth 

768 Bit-depth used for conversion. 

769 in_normalised_code_value 

770 Whether the *Canon Log 2* v1.2 non-linear data is encoded with normalised 

771 code values. 

772 out_reflection 

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

774 

775 Returns 

776 ------- 

777 :class:`numpy.ndarray` 

778 Linear data :math:`x`. 

779 

780 Notes 

781 ----- 

782 +------------+-----------------------+---------------+ 

783 | **Domain** | **Scale - Reference** | **Scale - 1** | 

784 +============+=======================+===============+ 

785 | ``clog2`` | 1 | 1 | 

786 +------------+-----------------------+---------------+ 

787 

788 +------------+-----------------------+---------------+ 

789 | **Range** | **Scale - Reference** | **Scale - 1** | 

790 +============+=======================+===============+ 

791 | ``x`` | 1 | 1 | 

792 +------------+-----------------------+---------------+ 

793 

794 References 

795 ---------- 

796 :cite:`Canon2020` 

797 

798 Examples 

799 -------- 

800 >>> log_decoding_CanonLog2_v1_2(39.825469256149191 / 100) 

801 ... # doctest: +ELLIPSIS 

802 0.1799999... 

803 """ 

804 

805 clog2 = to_domain_1(clog2) 

806 

807 # NOTE: *Canon Log 2* v1.2 constants are expressed in legal range 

808 # (studio swing). 

809 clog2 = clog2 if in_normalised_code_value else full_to_legal(clog2, bit_depth) 

810 

811 x = np.where( 

812 clog2 < 0.092864125, 

813 -(10 ** ((0.092864125 - clog2) / 0.24136077) - 1) / 87.09937546, 

814 (10 ** ((clog2 - 0.092864125) / 0.24136077) - 1) / 87.09937546, 

815 ) 

816 

817 if out_reflection: 

818 x = x * 0.9 

819 

820 return as_float(from_range_1(x)) 

821 

822 

823CANON_LOG_2_ENCODING_METHODS: CanonicalMapping = CanonicalMapping( 

824 { 

825 "v1": log_encoding_CanonLog2_v1, 

826 "v1.2": log_encoding_CanonLog2_v1_2, 

827 } 

828) 

829CANON_LOG_2_ENCODING_METHODS.__doc__ = """ 

830Supported *Canon Log 2* log encoding curve / opto-electronic transfer function 

831(OETF) methods. 

832 

833References 

834---------- 

835:cite:`Canon2016`, :cite:`Canon2020` 

836""" 

837 

838 

839def log_encoding_CanonLog2( 

840 x: Domain1, 

841 bit_depth: int = 10, 

842 out_normalised_code_value: bool = True, 

843 in_reflection: bool = True, 

844 method: Literal["v1", "v1.2"] | str = "v1.2", 

845) -> Range1: 

846 """ 

847 Apply the *Canon Log 2* log encoding opto-electronic transfer function (OETF). 

848 

849 Parameters 

850 ---------- 

851 x 

852 Linear data :math:`x`. 

853 bit_depth 

854 Bit-depth used for conversion. 

855 out_normalised_code_value 

856 Whether the *Canon Log 2* non-linear data is encoded as normalised 

857 code values. 

858 in_reflection 

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

860 method 

861 Computation method. 

862 

863 Returns 

864 ------- 

865 :class:`numpy.ndarray` 

866 *Canon Log 2* non-linear encoded data. 

867 

868 Notes 

869 ----- 

870 +------------+-----------------------+---------------+ 

871 | **Domain** | **Scale - Reference** | **Scale - 1** | 

872 +============+=======================+===============+ 

873 | ``x`` | 1 | 1 | 

874 +------------+-----------------------+---------------+ 

875 

876 +------------+-----------------------+---------------+ 

877 | **Range** | **Scale - Reference** | **Scale - 1** | 

878 +============+=======================+===============+ 

879 | ``clog2`` | 1 | 1 | 

880 +------------+-----------------------+---------------+ 

881 

882 References 

883 ---------- 

884 :cite:`Canon2016`, :cite:`Canon2020` 

885 

886 Examples 

887 -------- 

888 >>> log_encoding_CanonLog2(0.18) * 100 # doctest: +ELLIPSIS 

889 39.8254692... 

890 """ 

891 

892 method = validate_method(method, tuple(CANON_LOG_2_ENCODING_METHODS)) 

893 

894 return CANON_LOG_2_ENCODING_METHODS[method]( 

895 x, bit_depth, out_normalised_code_value, in_reflection 

896 ) 

897 

898 

899CANON_LOG_2_DECODING_METHODS: CanonicalMapping = CanonicalMapping( 

900 { 

901 "v1": log_decoding_CanonLog2_v1, 

902 "v1.2": log_decoding_CanonLog2_v1_2, 

903 } 

904) 

905CANON_LOG_2_DECODING_METHODS.__doc__ = """ 

906Supported *Canon Log 2* log decoding curve / electro-optical transfer function 

907(EOTF) methods. 

908 

909References 

910---------- 

911:cite:`Canon2016`, :cite:`Canon2020` 

912""" 

913 

914 

915def log_decoding_CanonLog2( 

916 clog2: Domain1, 

917 bit_depth: int = 10, 

918 in_normalised_code_value: bool = True, 

919 out_reflection: bool = True, 

920 method: Literal["v1", "v1.2"] | str = "v1.2", 

921) -> Range1: 

922 """ 

923 Apply the *Canon Log 2* log decoding inverse opto-electronic transfer 

924 function (OETF). 

925 

926 Parameters 

927 ---------- 

928 clog2 

929 *Canon Log 2* non-linear encoded data. 

930 bit_depth 

931 Bit-depth used for conversion. 

932 in_normalised_code_value 

933 Whether the *Canon Log 2* non-linear data is encoded with normalised 

934 code values. 

935 out_reflection 

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

937 method 

938 Computation method. 

939 

940 Returns 

941 ------- 

942 :class:`numpy.ndarray` 

943 Linear data :math:`x`. 

944 

945 Notes 

946 ----- 

947 +------------+-----------------------+---------------+ 

948 | **Domain** | **Scale - Reference** | **Scale - 1** | 

949 +============+=======================+===============+ 

950 | ``clog2`` | 1 | 1 | 

951 +------------+-----------------------+---------------+ 

952 

953 +------------+-----------------------+---------------+ 

954 | **Range** | **Scale - Reference** | **Scale - 1** | 

955 +============+=======================+===============+ 

956 | ``x`` | 1 | 1 | 

957 +------------+-----------------------+---------------+ 

958 

959 References 

960 ---------- 

961 :cite:`Canon2016`, :cite:`Canon2020` 

962 

963 Examples 

964 -------- 

965 >>> log_decoding_CanonLog2(39.825469256149191 / 100) # doctest: +ELLIPSIS 

966 0.1799999... 

967 """ 

968 

969 method = validate_method(method, tuple(CANON_LOG_2_DECODING_METHODS)) 

970 

971 return CANON_LOG_2_DECODING_METHODS[method]( 

972 clog2, bit_depth, in_normalised_code_value, out_reflection 

973 ) 

974 

975 

976def log_encoding_CanonLog3_v1( 

977 x: Domain1, 

978 bit_depth: int = 10, 

979 out_normalised_code_value: bool = True, 

980 in_reflection: bool = True, 

981) -> Range1: 

982 """ 

983 Apply the *Canon Log 3* v1 log encoding opto-electronic transfer function 

984 (OETF). 

985 

986 Parameters 

987 ---------- 

988 x 

989 Linear data :math:`x`. 

990 bit_depth 

991 Bit-depth used for conversion. 

992 out_normalised_code_value 

993 Whether the *Canon Log 3* v1 non-linear data is encoded as 

994 normalised code values. 

995 in_reflection 

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

997 

998 Returns 

999 ------- 

1000 :class:`numpy.ndarray` 

1001 *Canon Log 3* v1 non-linear encoded data. 

1002 

1003 Notes 

1004 ----- 

1005 - Introspection of the grafting points by Shaw, N. (2018) shows 

1006 that the *Canon Log 3* v1 IDT was likely derived from its 

1007 encoding curve as the latter is grafted at *+/-0.014*:: 

1008 

1009 >>> clog3 = 0.04076162 

1010 >>> (clog3 - 0.073059361) / 2.3069815 

1011 -0.014000000000000002 

1012 >>> clog3 = 0.105357102 

1013 >>> (clog3 - 0.073059361) / 2.3069815 

1014 0.013999999999999997 

1015 

1016 +------------+-----------------------+---------------+ 

1017 | **Domain** | **Scale - Reference** | **Scale - 1** | 

1018 +============+=======================+===============+ 

1019 | ``x`` | 1 | 1 | 

1020 +------------+-----------------------+---------------+ 

1021 

1022 +------------+-----------------------+---------------+ 

1023 | **Range** | **Scale - Reference** | **Scale - 1** | 

1024 +============+=======================+===============+ 

1025 | ``clog3`` | 1 | 1 | 

1026 +------------+-----------------------+---------------+ 

1027 

1028 References 

1029 ---------- 

1030 :cite:`Canon2016` 

1031 

1032 Examples 

1033 -------- 

1034 >>> log_encoding_CanonLog3_v1(0.18) * 100 # doctest: +ELLIPSIS 

1035 34.3389369... 

1036 """ 

1037 

1038 x = to_domain_1(x) 

1039 

1040 if in_reflection: 

1041 x = x / 0.9 

1042 

1043 with domain_range_scale("ignore"): 

1044 clog3 = np.select( 

1045 ( 

1046 x < log_decoding_CanonLog3_v1(0.04076162, bit_depth, False, False), 

1047 x <= log_decoding_CanonLog3_v1(0.105357102, bit_depth, False, False), 

1048 x > log_decoding_CanonLog3_v1(0.105357102, bit_depth, False, False), 

1049 ), 

1050 ( 

1051 -0.42889912 * np.log10(-x * 14.98325 + 1) + 0.07623209, 

1052 2.3069815 * x + 0.073059361, 

1053 0.42889912 * np.log10(x * 14.98325 + 1) + 0.069886632, 

1054 ), 

1055 ) 

1056 

1057 clog3_cv = full_to_legal(clog3, bit_depth) if out_normalised_code_value else clog3 

1058 

1059 return as_float(from_range_1(clog3_cv)) 

1060 

1061 

1062def log_decoding_CanonLog3_v1( 

1063 clog3: Domain1, 

1064 bit_depth: int = 10, 

1065 in_normalised_code_value: bool = True, 

1066 out_reflection: bool = True, 

1067) -> Range1: 

1068 """ 

1069 Apply the *Canon Log 3* v1 log decoding inverse opto-electronic transfer 

1070 function (OETF). 

1071 

1072 Parameters 

1073 ---------- 

1074 clog3 

1075 *Canon Log 3* v1 non-linear encoded data. 

1076 bit_depth 

1077 Bit-depth used for conversion. 

1078 in_normalised_code_value 

1079 Whether the *Canon Log 3* v1 non-linear data is encoded with 

1080 normalised code values. 

1081 out_reflection 

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

1083 

1084 Returns 

1085 ------- 

1086 :class:`numpy.ndarray` 

1087 Linear data :math:`x`. 

1088 

1089 Notes 

1090 ----- 

1091 +------------+-----------------------+---------------+ 

1092 | **Domain** | **Scale - Reference** | **Scale - 1** | 

1093 +============+=======================+===============+ 

1094 | ``clog3`` | 1 | 1 | 

1095 +------------+-----------------------+---------------+ 

1096 

1097 +------------+-----------------------+---------------+ 

1098 | **Range** | **Scale - Reference** | **Scale - 1** | 

1099 +============+=======================+===============+ 

1100 | ``x`` | 1 | 1 | 

1101 +------------+-----------------------+---------------+ 

1102 

1103 References 

1104 ---------- 

1105 :cite:`Canon2016` 

1106 

1107 Examples 

1108 -------- 

1109 >>> log_decoding_CanonLog3_v1(34.338936938868677 / 100) # doctest: +ELLIPSIS 

1110 0.1800000... 

1111 """ 

1112 

1113 clog3 = to_domain_1(clog3) 

1114 

1115 clog3 = legal_to_full(clog3, bit_depth) if in_normalised_code_value else clog3 

1116 

1117 x = np.select( 

1118 (clog3 < 0.04076162, clog3 <= 0.105357102, clog3 > 0.105357102), 

1119 ( 

1120 -(10 ** ((0.07623209 - clog3) / 0.42889912) - 1) / 14.98325, 

1121 (clog3 - 0.073059361) / 2.3069815, 

1122 (10 ** ((clog3 - 0.069886632) / 0.42889912) - 1) / 14.98325, 

1123 ), 

1124 ) 

1125 

1126 if out_reflection: 

1127 x = x * 0.9 

1128 

1129 return as_float(from_range_1(x)) 

1130 

1131 

1132def log_encoding_CanonLog3_v1_2( 

1133 x: Domain1, 

1134 bit_depth: int = 10, 

1135 out_normalised_code_value: bool = True, 

1136 in_reflection: bool = True, 

1137) -> Range1: 

1138 """ 

1139 Apply the *Canon Log 3* v1.2 log encoding opto-electronic transfer function 

1140 (OETF). 

1141 

1142 Parameters 

1143 ---------- 

1144 x 

1145 Linear data :math:`x`. 

1146 bit_depth 

1147 Bit-depth used for conversion. 

1148 out_normalised_code_value 

1149 Whether the *Canon Log 3* v1.2 non-linear data is encoded as normalised 

1150 code values. 

1151 in_reflection 

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

1153 

1154 Returns 

1155 ------- 

1156 :class:`numpy.ndarray` 

1157 *Canon Log 3* v1.2 non-linear encoded data. 

1158 

1159 Notes 

1160 ----- 

1161 +------------+-----------------------+---------------+ 

1162 | **Domain** | **Scale - Reference** | **Scale - 1** | 

1163 +============+=======================+===============+ 

1164 | ``x`` | 1 | 1 | 

1165 +------------+-----------------------+---------------+ 

1166 

1167 +------------+-----------------------+---------------+ 

1168 | **Range** | **Scale - Reference** | **Scale - 1** | 

1169 +============+=======================+===============+ 

1170 | ``clog3`` | 1 | 1 | 

1171 +------------+-----------------------+---------------+ 

1172 

1173 References 

1174 ---------- 

1175 :cite:`Canon2020` 

1176 

1177 Examples 

1178 -------- 

1179 >>> log_encoding_CanonLog3_v1_2(0.18) * 100 # doctest: +ELLIPSIS 

1180 34.3389370... 

1181 """ 

1182 

1183 x = to_domain_1(x) 

1184 

1185 if in_reflection: 

1186 x = x / 0.9 

1187 

1188 with domain_range_scale("ignore"): 

1189 clog3 = np.select( 

1190 ( 

1191 x < log_decoding_CanonLog3_v1_2(0.097465473, bit_depth, True, False), 

1192 x <= log_decoding_CanonLog3_v1_2(0.15277891, bit_depth, True, False), 

1193 x > log_decoding_CanonLog3_v1_2(0.15277891, bit_depth, True, False), 

1194 ), 

1195 ( 

1196 -0.36726845 * np.log10(-x * 14.98325 + 1) + 0.12783901, 

1197 1.9754798 * x + 0.12512219, 

1198 0.36726845 * np.log10(x * 14.98325 + 1) + 0.12240537, 

1199 ), 

1200 ) 

1201 

1202 # NOTE: *Canon Log 3* v1.2 constants are expressed in legal range 

1203 # (studio swing). 

1204 clog3_cv = clog3 if out_normalised_code_value else legal_to_full(clog3, bit_depth) 

1205 

1206 return as_float(from_range_1(clog3_cv)) 

1207 

1208 

1209def log_decoding_CanonLog3_v1_2( 

1210 clog3: Domain1, 

1211 bit_depth: int = 10, 

1212 in_normalised_code_value: bool = True, 

1213 out_reflection: bool = True, 

1214) -> Range1: 

1215 """ 

1216 Apply the *Canon Log 3* v1.2 log decoding inverse opto-electronic transfer 

1217 function (OETF). 

1218 

1219 Parameters 

1220 ---------- 

1221 clog3 

1222 *Canon Log 3* v1.2 non-linear encoded data. 

1223 bit_depth 

1224 Bit-depth used for conversion. 

1225 in_normalised_code_value 

1226 Whether the *Canon Log 3* v1.2 non-linear data is encoded with 

1227 normalised code values. 

1228 out_reflection 

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

1230 

1231 Returns 

1232 ------- 

1233 :class:`numpy.ndarray` 

1234 Linear data :math:`x`. 

1235 

1236 Notes 

1237 ----- 

1238 +------------+-----------------------+---------------+ 

1239 | **Domain** | **Scale - Reference** | **Scale - 1** | 

1240 +============+=======================+===============+ 

1241 | ``clog3`` | 1 | 1 | 

1242 +------------+-----------------------+---------------+ 

1243 

1244 +------------+-----------------------+---------------+ 

1245 | **Range** | **Scale - Reference** | **Scale - 1** | 

1246 +============+=======================+===============+ 

1247 | ``x`` | 1 | 1 | 

1248 +------------+-----------------------+---------------+ 

1249 

1250 References 

1251 ---------- 

1252 :cite:`Canon2020` 

1253 

1254 Examples 

1255 -------- 

1256 >>> log_decoding_CanonLog3_v1_2(34.338937037393549 / 100) 

1257 ... # doctest: +ELLIPSIS 

1258 0.1799999... 

1259 """ 

1260 

1261 clog3 = to_domain_1(clog3) 

1262 

1263 # NOTE: *Canon Log 3* v1.2 constants are expressed in legal range 

1264 # (studio swing). 

1265 clog3 = clog3 if in_normalised_code_value else full_to_legal(clog3, bit_depth) 

1266 

1267 x = np.select( 

1268 (clog3 < 0.097465473, clog3 <= 0.15277891, clog3 > 0.15277891), 

1269 ( 

1270 -(10 ** ((0.12783901 - clog3) / 0.36726845) - 1) / 14.98325, 

1271 (clog3 - 0.12512219) / 1.9754798, 

1272 (10 ** ((clog3 - 0.12240537) / 0.36726845) - 1) / 14.98325, 

1273 ), 

1274 ) 

1275 

1276 if out_reflection: 

1277 x = x * 0.9 

1278 

1279 return as_float(from_range_1(x)) 

1280 

1281 

1282CANON_LOG_3_ENCODING_METHODS: CanonicalMapping = CanonicalMapping( 

1283 { 

1284 "v1": log_encoding_CanonLog3_v1, 

1285 "v1.2": log_encoding_CanonLog3_v1_2, 

1286 } 

1287) 

1288CANON_LOG_3_ENCODING_METHODS.__doc__ = """ 

1289Supported *Canon Log 3* log encoding curve / opto-electronic transfer function 

1290(OETF) methods. 

1291 

1292References 

1293---------- 

1294:cite:`Canon2016`, :cite:`Canon2020` 

1295""" 

1296 

1297 

1298def log_encoding_CanonLog3( 

1299 x: Domain1, 

1300 bit_depth: int = 10, 

1301 out_normalised_code_value: bool = True, 

1302 in_reflection: bool = True, 

1303 method: Literal["v1", "v1.2"] | str = "v1.2", 

1304) -> Range1: 

1305 """ 

1306 Apply the *Canon Log 3* log encoding opto-electronic transfer function (OETF). 

1307 

1308 Parameters 

1309 ---------- 

1310 x 

1311 Linear data :math:`x`. 

1312 bit_depth 

1313 Bit-depth used for conversion. 

1314 out_normalised_code_value 

1315 Whether the *Canon Log 3* non-linear data is encoded as normalised 

1316 code values. 

1317 in_reflection 

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

1319 method 

1320 Computation method. 

1321 

1322 Returns 

1323 ------- 

1324 :class:`numpy.ndarray` 

1325 *Canon Log 3* non-linear encoded data. 

1326 

1327 Notes 

1328 ----- 

1329 - Introspection of the grafting points by Shaw, N. (2018) shows that 

1330 the *Canon Log 3* v1 IDT was likely derived from its encoding curve 

1331 as the latter is grafted at *+/-0.014*:: 

1332 

1333 >>> clog3 = 0.04076162 

1334 >>> (clog3 - 0.073059361) / 2.3069815 

1335 -0.014000000000000002 

1336 >>> clog3 = 0.105357102 

1337 >>> (clog3 - 0.073059361) / 2.3069815 

1338 0.013999999999999997 

1339 

1340 +------------+-----------------------+---------------+ 

1341 | **Domain** | **Scale - Reference** | **Scale - 1** | 

1342 +============+=======================+===============+ 

1343 | ``x`` | 1 | 1 | 

1344 +------------+-----------------------+---------------+ 

1345 

1346 +------------+-----------------------+---------------+ 

1347 | **Range** | **Scale - Reference** | **Scale - 1** | 

1348 +============+=======================+===============+ 

1349 | ``clog3`` | 1 | 1 | 

1350 +------------+-----------------------+---------------+ 

1351 

1352 References 

1353 ---------- 

1354 :cite:`Canon2016`, :cite:`Canon2020` 

1355 

1356 Examples 

1357 -------- 

1358 >>> log_encoding_CanonLog3(0.18) * 100 # doctest: +ELLIPSIS 

1359 34.3389370... 

1360 """ 

1361 

1362 method = validate_method(method, tuple(CANON_LOG_3_ENCODING_METHODS)) 

1363 

1364 return CANON_LOG_3_ENCODING_METHODS[method]( 

1365 x, bit_depth, out_normalised_code_value, in_reflection 

1366 ) 

1367 

1368 

1369CANON_LOG_3_DECODING_METHODS: CanonicalMapping = CanonicalMapping( 

1370 { 

1371 "v1": log_decoding_CanonLog3_v1, 

1372 "v1.2": log_decoding_CanonLog3_v1_2, 

1373 } 

1374) 

1375CANON_LOG_3_DECODING_METHODS.__doc__ = """ 

1376Supported *Canon Log 3* log decoding curve / electro-optical transfer function 

1377(EOTF) methods. 

1378 

1379References 

1380---------- 

1381:cite:`Canon2016`, :cite:`Canon2020` 

1382""" 

1383 

1384 

1385def log_decoding_CanonLog3( 

1386 clog3: Domain1, 

1387 bit_depth: int = 10, 

1388 in_normalised_code_value: bool = True, 

1389 out_reflection: bool = True, 

1390 method: Literal["v1", "v1.2"] | str = "v1.2", 

1391) -> Range1: 

1392 """ 

1393 Apply the *Canon Log 3* log decoding inverse opto-electronic transfer 

1394 function (OETF). 

1395 

1396 Parameters 

1397 ---------- 

1398 clog3 

1399 *Canon Log 3* non-linear encoded data. 

1400 bit_depth 

1401 Bit-depth used for conversion. 

1402 in_normalised_code_value 

1403 Whether the *Canon Log 3* non-linear data is encoded with normalised 

1404 code values. 

1405 out_reflection 

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

1407 method 

1408 Computation method. 

1409 

1410 Returns 

1411 ------- 

1412 :class:`numpy.ndarray` 

1413 Linear data :math:`x`. 

1414 

1415 Notes 

1416 ----- 

1417 +------------+-----------------------+---------------+ 

1418 | **Domain** | **Scale - Reference** | **Scale - 1** | 

1419 +============+=======================+===============+ 

1420 | ``clog3`` | 1 | 1 | 

1421 +------------+-----------------------+---------------+ 

1422 

1423 +------------+-----------------------+---------------+ 

1424 | **Range** | **Scale - Reference** | **Scale - 1** | 

1425 +============+=======================+===============+ 

1426 | ``x`` | 1 | 1 | 

1427 +------------+-----------------------+---------------+ 

1428 

1429 References 

1430 ---------- 

1431 :cite:`Canon2016`, :cite:`Canon2020` 

1432 

1433 Examples 

1434 -------- 

1435 >>> log_decoding_CanonLog3(34.338937037393549 / 100) # doctest: +ELLIPSIS 

1436 0.1799999... 

1437 """ 

1438 

1439 method = validate_method(method, tuple(CANON_LOG_3_DECODING_METHODS)) 

1440 

1441 return CANON_LOG_3_DECODING_METHODS[method]( 

1442 clog3, bit_depth, in_normalised_code_value, out_reflection 

1443 )