Coverage for graph/conversion.py: 48%

181 statements  

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

1""" 

2Automatic Colour Conversion Graph 

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

4 

5Define the automatic colour conversion graph objects. 

6 

7- :func:`colour.conversion_path` 

8- :func:`colour.describe_conversion_path` 

9- :func:`colour.convert` 

10""" 

11 

12from __future__ import annotations 

13 

14import inspect 

15import itertools 

16import re 

17import sys 

18import textwrap 

19import typing 

20from copy import copy 

21from dataclasses import dataclass 

22from functools import partial 

23from pprint import pformat 

24 

25import numpy as np 

26 

27import colour 

28import colour.models 

29from colour.appearance import ( 

30 CAM16_to_XYZ, 

31 CAM_Specification_CAM16, 

32 CAM_Specification_CIECAM02, 

33 CAM_Specification_CIECAM16, 

34 CAM_Specification_Hellwig2022, 

35 CAM_Specification_Kim2009, 

36 CAM_Specification_sCAM, 

37 CAM_Specification_ZCAM, 

38 CIECAM02_to_XYZ, 

39 CIECAM16_to_XYZ, 

40 Hellwig2022_to_XYZ, 

41 Kim2009_to_XYZ, 

42 XYZ_to_ATD95, 

43 XYZ_to_CAM16, 

44 XYZ_to_CIECAM02, 

45 XYZ_to_CIECAM16, 

46 XYZ_to_Hellwig2022, 

47 XYZ_to_Hunt, 

48 XYZ_to_Kim2009, 

49 XYZ_to_LLAB, 

50 XYZ_to_Nayatani95, 

51 XYZ_to_RLAB, 

52 XYZ_to_sCAM, 

53 XYZ_to_ZCAM, 

54 ZCAM_to_XYZ, 

55 sCAM_to_XYZ, 

56) 

57from colour.appearance.ciecam02 import CAM_KWARGS_CIECAM02_sRGB 

58from colour.colorimetry import ( 

59 CCS_ILLUMINANTS, 

60 TVS_ILLUMINANTS_HUNTERLAB, 

61 colorimetric_purity, 

62 complementary_wavelength, 

63 dominant_wavelength, 

64 excitation_purity, 

65 lightness, 

66 luminance, 

67 luminous_efficacy, 

68 luminous_efficiency, 

69 luminous_flux, 

70 sd_to_XYZ, 

71 wavelength_to_XYZ, 

72 whiteness, 

73 yellowness, 

74) 

75 

76if typing.TYPE_CHECKING: 

77 from colour.hints import ( 

78 Any, 

79 ArrayLike, 

80 Callable, 

81 Domain1, 

82 Domain100_100_360, 

83 List, 

84 Literal, 

85 Range1, 

86 Range100_100_360, 

87 ) 

88 

89from colour.hints import Annotated, NDArrayFloat, cast 

90from colour.models import ( 

91 COLOURSPACE_MODELS_POLAR_CONVERSIONS, 

92 CAM02LCD_to_JMh_CIECAM02, 

93 CAM02SCD_to_JMh_CIECAM02, 

94 CAM02UCS_to_JMh_CIECAM02, 

95 CAM16LCD_to_JMh_CAM16, 

96 CAM16SCD_to_JMh_CAM16, 

97 CAM16UCS_to_JMh_CAM16, 

98 CIE1960UCS_to_XYZ, 

99 CIE1976UCS_to_XYZ, 

100 CMY_to_CMYK, 

101 CMY_to_RGB, 

102 CMYK_to_CMY, 

103 DIN99_to_XYZ, 

104 HCL_to_RGB, 

105 HSL_to_RGB, 

106 HSV_to_RGB, 

107 Hunter_Lab_to_XYZ, 

108 Hunter_Rdab_to_XYZ, 

109 ICaCb_to_XYZ, 

110 ICtCp_to_XYZ, 

111 IgPgTg_to_XYZ, 

112 IHLS_to_RGB, 

113 IPT_Ragoo2021_to_XYZ, 

114 IPT_to_XYZ, 

115 JMh_CAM16_to_CAM16LCD, 

116 JMh_CAM16_to_CAM16SCD, 

117 JMh_CAM16_to_CAM16UCS, 

118 JMh_CIECAM02_to_CAM02LCD, 

119 JMh_CIECAM02_to_CAM02SCD, 

120 JMh_CIECAM02_to_CAM02UCS, 

121 Jzazbz_to_XYZ, 

122 Lab_to_XYZ, 

123 Luv_to_uv, 

124 Luv_to_XYZ, 

125 Luv_uv_to_xy, 

126 Oklab_to_XYZ, 

127 OSA_UCS_to_XYZ, 

128 Prismatic_to_RGB, 

129 ProLab_to_XYZ, 

130 RGB_Colourspace, 

131 RGB_COLOURSPACE_sRGB, 

132 RGB_luminance, 

133 RGB_to_CMY, 

134 RGB_to_HCL, 

135 RGB_to_HSL, 

136 RGB_to_HSV, 

137 RGB_to_IHLS, 

138 RGB_to_Prismatic, 

139 RGB_to_RGB, 

140 RGB_to_XYZ, 

141 RGB_to_YCbCr, 

142 RGB_to_YcCbcCrc, 

143 RGB_to_YCoCg, 

144 UCS_to_uv, 

145 UCS_to_XYZ, 

146 UCS_uv_to_xy, 

147 UVW_to_XYZ, 

148 XYZ_to_CIE1960UCS, 

149 XYZ_to_CIE1976UCS, 

150 XYZ_to_DIN99, 

151 XYZ_to_hdr_CIELab, 

152 XYZ_to_hdr_IPT, 

153 XYZ_to_Hunter_Lab, 

154 XYZ_to_Hunter_Rdab, 

155 XYZ_to_ICaCb, 

156 XYZ_to_ICtCp, 

157 XYZ_to_IgPgTg, 

158 XYZ_to_IPT, 

159 XYZ_to_IPT_Ragoo2021, 

160 XYZ_to_Jzazbz, 

161 XYZ_to_Lab, 

162 XYZ_to_Luv, 

163 XYZ_to_Oklab, 

164 XYZ_to_OSA_UCS, 

165 XYZ_to_ProLab, 

166 XYZ_to_RGB, 

167 XYZ_to_sRGB, 

168 XYZ_to_sUCS, 

169 XYZ_to_UCS, 

170 XYZ_to_UVW, 

171 XYZ_to_xy, 

172 XYZ_to_xyY, 

173 XYZ_to_Yrg, 

174 YCbCr_to_RGB, 

175 YcCbcCrc_to_RGB, 

176 YCoCg_to_RGB, 

177 Yrg_to_XYZ, 

178 cctf_decoding, 

179 cctf_encoding, 

180 hdr_CIELab_to_XYZ, 

181 hdr_IPT_to_XYZ, 

182 sRGB_to_XYZ, 

183 sUCS_to_XYZ, 

184 uv_to_Luv, 

185 uv_to_UCS, 

186 xy_to_Luv_uv, 

187 xy_to_UCS_uv, 

188 xy_to_xyY, 

189 xy_to_XYZ, 

190 xyY_to_xy, 

191 xyY_to_XYZ, 

192) 

193from colour.notation import ( 

194 HEX_to_RGB, 

195 RGB_to_HEX, 

196 keyword_to_RGB_CSSColor3, 

197 munsell_colour_to_xyY, 

198 munsell_value, 

199 xyY_to_munsell_colour, 

200) 

201from colour.quality import colour_quality_scale, colour_rendering_index 

202from colour.recovery import XYZ_to_sd 

203from colour.temperature import CCT_to_mired, CCT_to_uv, mired_to_CCT, uv_to_CCT 

204from colour.utilities import ( 

205 as_float_array, 

206 domain_range_scale, 

207 filter_kwargs, 

208 get_domain_range_scale_metadata, 

209 message_box, 

210 required, 

211 tsplit, 

212 tstack, 

213 validate_method, 

214 zeros, 

215) 

216 

217__author__ = "Colour Developers" 

218__copyright__ = "Copyright 2013 Colour Developers" 

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

220__maintainer__ = "Colour Developers" 

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

222__status__ = "Production" 

223 

224__all__ = [ 

225 "Conversion_Specification", 

226 "CIECAM02_to_JMh_CIECAM02", 

227 "JMh_CIECAM02_to_CIECAM02", 

228 "CAM16_to_JMh_CAM16", 

229 "JMh_CAM16_to_CAM16", 

230 "CIECAM16_to_JMh_CIECAM16", 

231 "JMh_CIECAM16_to_CIECAM16", 

232 "Hellwig2022_to_JMh_Hellwig2022", 

233 "JMh_Hellwig2022_to_Hellwig2022", 

234 "sCAM_to_JMh_sCAM", 

235 "JMh_sCAM_to_sCAM", 

236 "ZCAM_to_JMh_ZCAM", 

237 "JMh_ZCAM_to_ZCAM", 

238 "Kim2009_to_JMh_Kim2009", 

239 "JMh_Kim2009_to_Kim2009", 

240 "XYZ_to_luminance", 

241 "RGB_luminance_to_RGB", 

242 "CCT_D_uv_to_mired", 

243 "mired_to_CCT_D_uv", 

244 "CONVERSION_SPECIFICATIONS_DATA", 

245 "CONVERSION_GRAPH_NODE_LABELS", 

246 "CONVERSION_SPECIFICATIONS", 

247 "CONVERSION_GRAPH", 

248 "conversion_path", 

249 "describe_conversion_path", 

250 "convert", 

251] 

252 

253 

254@dataclass(frozen=True) 

255class Conversion_Specification: 

256 """ 

257 Define a conversion specification for the *Colour* graph used in automatic 

258 colour space conversions. 

259 

260 The specification describes the relationship between two nodes (colour 

261 spaces or representations) and the transformation function that connects 

262 them within the conversion graph. 

263 

264 Parameters 

265 ---------- 

266 source 

267 Source node in the graph. 

268 target 

269 Target node in the graph. 

270 conversion_function 

271 Callable converting from the ``source`` node to the ``target`` node. 

272 """ 

273 

274 source: str 

275 target: str 

276 conversion_function: Callable 

277 

278 def __post_init__(self) -> None: 

279 """ 

280 Post-initialise the class. 

281 

282 Convert the source and target attribute values to lowercase for 

283 consistent case-insensitive comparisons. 

284 """ 

285 

286 object.__setattr__(self, "source", self.source.lower()) 

287 object.__setattr__(self, "target", self.target.lower()) 

288 

289 

290def CIECAM02_to_JMh_CIECAM02( 

291 specification: Annotated[ 

292 CAM_Specification_CIECAM02, (100, 100, 360, 100, 100, 100, 400) 

293 ], 

294) -> Range100_100_360: 

295 """ 

296 Convert from *CIECAM02* specification to *CIECAM02* :math:`JMh` 

297 correlates. 

298 

299 Parameters 

300 ---------- 

301 specification 

302 *CIECAM02* colour appearance model specification. 

303 

304 Returns 

305 ------- 

306 :class:`numpy.ndarray` 

307 *CIECAM02* :math:`JMh` correlates. 

308 

309 Notes 

310 ----- 

311 +---------------------+-----------------------+-----------------+ 

312 | **Domain** | **Scale - Reference** | **Scale - 1** | 

313 +=====================+=======================+=================+ 

314 | ``specification.J`` | 100 | 1 | 

315 +---------------------+-----------------------+-----------------+ 

316 | ``specification.C`` | 100 | 1 | 

317 +---------------------+-----------------------+-----------------+ 

318 | ``specification.h`` | 360 | 1 | 

319 +---------------------+-----------------------+-----------------+ 

320 | ``specification.s`` | 100 | 1 | 

321 +---------------------+-----------------------+-----------------+ 

322 | ``specification.Q`` | 100 | 1 | 

323 +---------------------+-----------------------+-----------------+ 

324 | ``specification.M`` | 100 | 1 | 

325 +---------------------+-----------------------+-----------------+ 

326 | ``specification.H`` | 400 | 1 | 

327 +---------------------+-----------------------+-----------------+ 

328 

329 +---------------------+-----------------------+-----------------+ 

330 | **Range** | **Scale - Reference** | **Scale - 1** | 

331 +=====================+=======================+=================+ 

332 | ``JMh`` | ``J`` : 100 | ``J`` : 1 | 

333 | | | | 

334 | | ``M`` : 100 | ``M`` : 1 | 

335 | | | | 

336 | | ``h`` : 360 | ``h`` : 1 | 

337 +---------------------+-----------------------+-----------------+ 

338 

339 Examples 

340 -------- 

341 >>> specification = CAM_Specification_CIECAM02( 

342 ... J=34.434525727859, M=70.024939419291385, h=22.279164147957076 

343 ... ) 

344 >>> CIECAM02_to_JMh_CIECAM02(specification) # doctest: +ELLIPSIS 

345 array([ 34.4345257..., 70.0249394..., 22.2791641...]) 

346 """ 

347 

348 return tstack( 

349 [ 

350 cast("NDArrayFloat", specification.J), 

351 cast("NDArrayFloat", specification.M), 

352 cast("NDArrayFloat", specification.h), 

353 ] 

354 ) 

355 

356 

357def JMh_CIECAM02_to_CIECAM02( 

358 JMh: Domain100_100_360, 

359) -> Annotated[CAM_Specification_CIECAM02, (100, 100, 360, 100, 100, 100, 400)]: 

360 """ 

361 Convert from *CIECAM02* :math:`JMh` correlates to *CIECAM02* 

362 specification. 

363 

364 Parameters 

365 ---------- 

366 JMh 

367 *CIECAM02* :math:`JMh` correlates. 

368 

369 Returns 

370 ------- 

371 :class:`colour.CAM_Specification_CIECAM02` 

372 *CIECAM02* colour appearance model specification. 

373 

374 Notes 

375 ----- 

376 +---------------------+-----------------------+-----------------+ 

377 | **Domain** | **Scale - Reference** | **Scale - 1** | 

378 +=====================+=======================+=================+ 

379 | ``JMh`` | ``J`` : 100 | ``J`` : 1 | 

380 | | | | 

381 | | ``M`` : 100 | ``M`` : 1 | 

382 | | | | 

383 | | ``h`` : 360 | ``h`` : 1 | 

384 +---------------------+-----------------------+-----------------+ 

385 

386 +---------------------+-----------------------+-----------------+ 

387 | **Range** | **Scale - Reference** | **Scale - 1** | 

388 +=====================+=======================+=================+ 

389 | ``specification.J`` | 100 | 1 | 

390 +---------------------+-----------------------+-----------------+ 

391 | ``specification.C`` | 100 | 1 | 

392 +---------------------+-----------------------+-----------------+ 

393 | ``specification.h`` | 360 | 1 | 

394 +---------------------+-----------------------+-----------------+ 

395 | ``specification.s`` | 100 | 1 | 

396 +---------------------+-----------------------+-----------------+ 

397 | ``specification.Q`` | 100 | 1 | 

398 +---------------------+-----------------------+-----------------+ 

399 | ``specification.M`` | 100 | 1 | 

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

401 | ``specification.H`` | 400 | 1 | 

402 +---------------------+-----------------------+-----------------+ 

403 

404 Examples 

405 -------- 

406 >>> import numpy as np 

407 >>> JMh = np.array([34.4345257, 70.0249394, 22.2791641]) 

408 >>> JMh_CIECAM02_to_CIECAM02(JMh) # doctest: +ELLIPSIS 

409 CAM_Specification_CIECAM02(J=34.4345257..., C=None, h=22.2791640..., \ 

410s=None, Q=None, M=70.0249393..., H=None, HC=None) 

411 """ 

412 

413 J, M, h = tsplit(JMh) 

414 

415 return CAM_Specification_CIECAM02(J=J, M=M, h=h) 

416 

417 

418def CAM16_to_JMh_CAM16( 

419 specification: Annotated[ 

420 CAM_Specification_CAM16, (100, 100, 360, 100, 100, 100, 400) 

421 ], 

422) -> Range100_100_360: 

423 """ 

424 Convert from *CAM16* specification to *CAM16* :math:`JMh` correlates. 

425 

426 Parameters 

427 ---------- 

428 specification 

429 *CAM16* colour appearance model specification. 

430 

431 Returns 

432 ------- 

433 :class:`numpy.ndarray` 

434 *CAM16* :math:`JMh` correlates. 

435 

436 Notes 

437 ----- 

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

439 | **Domain** | **Scale - Reference** | **Scale - 1** | 

440 +=====================+=======================+=================+ 

441 | ``specification.J`` | 100 | 1 | 

442 +---------------------+-----------------------+-----------------+ 

443 | ``specification.C`` | 100 | 1 | 

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

445 | ``specification.h`` | 360 | 1 | 

446 +---------------------+-----------------------+-----------------+ 

447 | ``specification.s`` | 100 | 1 | 

448 +---------------------+-----------------------+-----------------+ 

449 | ``specification.Q`` | 100 | 1 | 

450 +---------------------+-----------------------+-----------------+ 

451 | ``specification.M`` | 100 | 1 | 

452 +---------------------+-----------------------+-----------------+ 

453 | ``specification.H`` | 400 | 1 | 

454 +---------------------+-----------------------+-----------------+ 

455 

456 +---------------------+-----------------------+-----------------+ 

457 | **Range** | **Scale - Reference** | **Scale - 1** | 

458 +=====================+=======================+=================+ 

459 | ``JMh`` | ``J`` : 100 | ``J`` : 1 | 

460 | | | | 

461 | | ``M`` : 100 | ``M`` : 1 | 

462 | | | | 

463 | | ``h`` : 360 | ``h`` : 1 | 

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

465 

466 Examples 

467 -------- 

468 >>> specification = CAM_Specification_CAM16( 

469 ... J=33.880368498111686, M=72.18638534116765, h=19.510887327451748 

470 ... ) 

471 >>> CAM16_to_JMh_CAM16(specification) # doctest: +ELLIPSIS 

472 array([ 33.8803685 , 72.18638534, 19.51088733]) 

473 """ 

474 

475 return tstack([specification.J, specification.M, specification.h]) # pyright: ignore 

476 

477 

478def JMh_CAM16_to_CAM16( 

479 JMh: Domain100_100_360, 

480) -> Annotated[CAM_Specification_CAM16, (100, 100, 360, 100, 100, 100, 400)]: 

481 """ 

482 Convert from *CAM16* :math:`JMh` correlates to *CAM16* specification. 

483 

484 Parameters 

485 ---------- 

486 JMh 

487 *CAM16* :math:`JMh` correlates. 

488 

489 Returns 

490 ------- 

491 :class:`colour.CAM_Specification_CAM16` 

492 *CAM16* colour appearance model specification. 

493 

494 Notes 

495 ----- 

496 +---------------------+-----------------------+-----------------+ 

497 | **Domain** | **Scale - Reference** | **Scale - 1** | 

498 +=====================+=======================+=================+ 

499 | ``JMh`` | ``J`` : 100 | ``J`` : 1 | 

500 | | | | 

501 | | ``M`` : 100 | ``M`` : 1 | 

502 | | | | 

503 | | ``h`` : 360 | ``h`` : 1 | 

504 +---------------------+-----------------------+-----------------+ 

505 

506 +---------------------+-----------------------+-----------------+ 

507 | **Range** | **Scale - Reference** | **Scale - 1** | 

508 +=====================+=======================+=================+ 

509 | ``specification.J`` | 100 | 1 | 

510 +---------------------+-----------------------+-----------------+ 

511 | ``specification.C`` | 100 | 1 | 

512 +---------------------+-----------------------+-----------------+ 

513 | ``specification.h`` | 360 | 1 | 

514 +---------------------+-----------------------+-----------------+ 

515 | ``specification.s`` | 100 | 1 | 

516 +---------------------+-----------------------+-----------------+ 

517 | ``specification.Q`` | 100 | 1 | 

518 +---------------------+-----------------------+-----------------+ 

519 | ``specification.M`` | 100 | 1 | 

520 +---------------------+-----------------------+-----------------+ 

521 | ``specification.H`` | 400 | 1 | 

522 +---------------------+-----------------------+-----------------+ 

523 

524 Examples 

525 -------- 

526 >>> import numpy as np 

527 >>> JMh = np.array([33.8803685, 72.1863853, 19.5108873]) 

528 >>> JMh_CAM16_to_CAM16(JMh) # doctest: +ELLIPSIS 

529 CAM_Specification_CAM16(J=33.8803685..., C=None, h=19.5108873, s=None, \ 

530Q=None, M=72.1863852..., H=None, HC=None) 

531 """ 

532 

533 J, M, h = tsplit(JMh) 

534 

535 return CAM_Specification_CAM16(J=J, M=M, h=h) 

536 

537 

538def CIECAM16_to_JMh_CIECAM16( 

539 specification: Annotated[ 

540 CAM_Specification_CIECAM16, (100, 100, 360, 100, 100, 100, 400) 

541 ], 

542) -> Range100_100_360: 

543 """ 

544 Convert from *CIECAM16* specification to *CIECAM16* :math:`JMh` 

545 correlates. 

546 

547 Parameters 

548 ---------- 

549 specification 

550 *CIECAM16* colour appearance model specification. 

551 

552 Returns 

553 ------- 

554 :class:`numpy.ndarray` 

555 *CIECAM16* :math:`JMh` correlates. 

556 

557 Notes 

558 ----- 

559 +---------------------+-----------------------+-----------------+ 

560 | **Domain** | **Scale - Reference** | **Scale - 1** | 

561 +=====================+=======================+=================+ 

562 | ``specification.J`` | 100 | 1 | 

563 +---------------------+-----------------------+-----------------+ 

564 | ``specification.C`` | 100 | 1 | 

565 +---------------------+-----------------------+-----------------+ 

566 | ``specification.h`` | 360 | 1 | 

567 +---------------------+-----------------------+-----------------+ 

568 | ``specification.s`` | 100 | 1 | 

569 +---------------------+-----------------------+-----------------+ 

570 | ``specification.Q`` | 100 | 1 | 

571 +---------------------+-----------------------+-----------------+ 

572 | ``specification.M`` | 100 | 1 | 

573 +---------------------+-----------------------+-----------------+ 

574 | ``specification.H`` | 400 | 1 | 

575 +---------------------+-----------------------+-----------------+ 

576 

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

578 | **Range** | **Scale - Reference** | **Scale - 1** | 

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

580 | ``JMh`` | ``J`` : 100 | ``J`` : 1 | 

581 | | | | 

582 | | ``M`` : 100 | ``M`` : 1 | 

583 | | | | 

584 | | ``h`` : 360 | ``h`` : 1 | 

585 +---------------------+-----------------------+-----------------+ 

586 

587 Examples 

588 -------- 

589 >>> specification = CAM_Specification_CIECAM16( 

590 ... J=33.880368498111686, M=72.18638534116765, h=19.510887327451748 

591 ... ) 

592 >>> CIECAM16_to_JMh_CIECAM16(specification) # doctest: +ELLIPSIS 

593 array([ 33.8803685 , 72.18638534, 19.51088733]) 

594 """ 

595 

596 return tstack([specification.J, specification.M, specification.h]) # pyright: ignore 

597 

598 

599def JMh_CIECAM16_to_CIECAM16( 

600 JMh: Domain100_100_360, 

601) -> Annotated[CAM_Specification_CIECAM16, (100, 100, 360, 100, 100, 100, 400)]: 

602 """ 

603 Convert from *CIECAM16* :math:`JMh` correlates to *CIECAM16* 

604 specification. 

605 

606 Parameters 

607 ---------- 

608 JMh 

609 *CIECAM16* :math:`JMh` correlates. 

610 

611 Returns 

612 ------- 

613 :class:`colour.CAM_Specification_CIECAM16` 

614 *CIECAM16* colour appearance model specification. 

615 

616 Notes 

617 ----- 

618 +---------------------+-----------------------+-----------------+ 

619 | **Domain** | **Scale - Reference** | **Scale - 1** | 

620 +=====================+=======================+=================+ 

621 | ``JMh`` | ``J`` : 100 | ``J`` : 1 | 

622 | | | | 

623 | | ``M`` : 100 | ``M`` : 1 | 

624 | | | | 

625 | | ``h`` : 360 | ``h`` : 1 | 

626 +---------------------+-----------------------+-----------------+ 

627 

628 +---------------------+-----------------------+-----------------+ 

629 | **Range** | **Scale - Reference** | **Scale - 1** | 

630 +=====================+=======================+=================+ 

631 | ``specification.J`` | 100 | 1 | 

632 +---------------------+-----------------------+-----------------+ 

633 | ``specification.C`` | 100 | 1 | 

634 +---------------------+-----------------------+-----------------+ 

635 | ``specification.h`` | 360 | 1 | 

636 +---------------------+-----------------------+-----------------+ 

637 | ``specification.s`` | 100 | 1 | 

638 +---------------------+-----------------------+-----------------+ 

639 | ``specification.Q`` | 100 | 1 | 

640 +---------------------+-----------------------+-----------------+ 

641 | ``specification.M`` | 100 | 1 | 

642 +---------------------+-----------------------+-----------------+ 

643 | ``specification.H`` | 400 | 1 | 

644 +---------------------+-----------------------+-----------------+ 

645 

646 Examples 

647 -------- 

648 >>> import numpy as np 

649 >>> JMh = np.array([33.8803685, 72.1863853, 19.5108873]) 

650 >>> JMh_CIECAM16_to_CIECAM16(JMh) # doctest: +ELLIPSIS 

651 CAM_Specification_CIECAM16(J=33.8803685..., C=None, h=19.5108873, \ 

652s=None, Q=None, M=72.1863852..., H=None, HC=None) 

653 """ 

654 

655 J, M, h = tsplit(JMh) 

656 

657 return CAM_Specification_CIECAM16(J=J, M=M, h=h) 

658 

659 

660def Hellwig2022_to_JMh_Hellwig2022( 

661 specification: Annotated[ 

662 CAM_Specification_Hellwig2022, (100, 100, 360, 100, 100, 100, 400, 100, 100) 

663 ], 

664) -> Range100_100_360: 

665 """ 

666 Convert from *Hellwig and Fairchild (2022)* specification to 

667 *Hellwig and Fairchild (2022)* :math:`JMh` correlates. 

668 

669 Parameters 

670 ---------- 

671 specification 

672 *Hellwig and Fairchild (2022)* colour appearance model 

673 specification. 

674 

675 Returns 

676 ------- 

677 :class:`numpy.ndarray` 

678 *Hellwig and Fairchild (2022)* :math:`JMh` correlates. 

679 

680 Notes 

681 ----- 

682 +-------------------------+-----------------------+-----------------+ 

683 | **Domain** | **Scale - Reference** | **Scale - 1** | 

684 +=========================+=======================+=================+ 

685 | ``specification.J`` | 100 | 1 | 

686 +-------------------------+-----------------------+-----------------+ 

687 | ``specification.C`` | 100 | 1 | 

688 +-------------------------+-----------------------+-----------------+ 

689 | ``specification.h`` | 360 | 1 | 

690 +-------------------------+-----------------------+-----------------+ 

691 | ``specification.s`` | 100 | 1 | 

692 +-------------------------+-----------------------+-----------------+ 

693 | ``specification.Q`` | 100 | 1 | 

694 +-------------------------+-----------------------+-----------------+ 

695 | ``specification.M`` | 100 | 1 | 

696 +-------------------------+-----------------------+-----------------+ 

697 | ``specification.H`` | 400 | 1 | 

698 +-------------------------+-----------------------+-----------------+ 

699 | ``specification.HC`` | 100 | 1 | 

700 +-------------------------+-----------------------+-----------------+ 

701 | ``specification.J_HK`` | 100 | 1 | 

702 +-------------------------+-----------------------+-----------------+ 

703 | ``specification.Q_HK`` | 100 | 1 | 

704 +-------------------------+-----------------------+-----------------+ 

705 

706 +-------------------------+-----------------------+-----------------+ 

707 | **Range** | **Scale - Reference** | **Scale - 1** | 

708 +=========================+=======================+=================+ 

709 | ``JMh`` | ``J`` : 100 | ``J`` : 1 | 

710 | | | | 

711 | | ``M`` : 100 | ``M`` : 1 | 

712 | | | | 

713 | | ``h`` : 360 | ``h`` : 1 | 

714 +-------------------------+-----------------------+-----------------+ 

715 

716 Examples 

717 -------- 

718 >>> specification = CAM_Specification_Hellwig2022( 

719 ... J=33.880368498111686, M=49.57713161802121, h=19.510887327451748 

720 ... ) 

721 >>> Hellwig2022_to_JMh_Hellwig2022(specification) # doctest: +ELLIPSIS 

722 array([ 33.8803685 , 49.57713162, 19.51088733]) 

723 """ 

724 

725 return tstack([specification.J, specification.M, specification.h]) # pyright: ignore 

726 

727 

728def JMh_Hellwig2022_to_Hellwig2022( 

729 JMh: Domain100_100_360, 

730) -> Annotated[ 

731 CAM_Specification_Hellwig2022, (100, 100, 360, 100, 100, 100, 400, 100, 100) 

732]: 

733 """ 

734 Convert from *Hellwig and Fairchild (2022)* :math:`JMh` correlates to 

735 *Hellwig and Fairchild (2022)* specification. 

736 

737 Parameters 

738 ---------- 

739 JMh 

740 *Hellwig and Fairchild (2022)* :math:`JMh` correlates. 

741 

742 Returns 

743 ------- 

744 :class:`colour.CAM_Specification_Hellwig2022` 

745 *Hellwig and Fairchild (2022)* colour appearance model specification. 

746 

747 Notes 

748 ----- 

749 +-------------------------+-----------------------+-----------------+ 

750 | **Domain** | **Scale - Reference** | **Scale - 1** | 

751 +=========================+=======================+=================+ 

752 | ``JMh`` | ``J`` : 100 | ``J`` : 1 | 

753 | | | | 

754 | | ``M`` : 100 | ``M`` : 1 | 

755 | | | | 

756 | | ``h`` : 360 | ``h`` : 1 | 

757 +-------------------------+-----------------------+-----------------+ 

758 

759 +-------------------------+-----------------------+-----------------+ 

760 | **Range** | **Scale - Reference** | **Scale - 1** | 

761 +=========================+=======================+=================+ 

762 | ``specification.J`` | 100 | 1 | 

763 +-------------------------+-----------------------+-----------------+ 

764 | ``specification.C`` | 100 | 1 | 

765 +-------------------------+-----------------------+-----------------+ 

766 | ``specification.h`` | 360 | 1 | 

767 +-------------------------+-----------------------+-----------------+ 

768 | ``specification.s`` | 100 | 1 | 

769 +-------------------------+-----------------------+-----------------+ 

770 | ``specification.Q`` | 100 | 1 | 

771 +-------------------------+-----------------------+-----------------+ 

772 | ``specification.M`` | 100 | 1 | 

773 +-------------------------+-----------------------+-----------------+ 

774 | ``specification.H`` | 400 | 1 | 

775 +-------------------------+-----------------------+-----------------+ 

776 | ``specification.HC`` | 100 | 1 | 

777 +-------------------------+-----------------------+-----------------+ 

778 | ``specification.J_HK`` | 100 | 1 | 

779 +-------------------------+-----------------------+-----------------+ 

780 | ``specification.Q_HK`` | 100 | 1 | 

781 +-------------------------+-----------------------+-----------------+ 

782 

783 Examples 

784 -------- 

785 >>> import numpy as np 

786 >>> JMh = np.array([33.8803685, 49.5771316, 19.5108873]) 

787 >>> JMh_Hellwig2022_to_Hellwig2022(JMh) # doctest: +ELLIPSIS 

788 CAM_Specification_Hellwig2022(J=33.8803685..., C=None, h=19.5108873..., \ 

789s=None, Q=None, M=49.5771316..., H=None, HC=None, J_HK=None, Q_HK=None) 

790 """ 

791 

792 J, M, h = tsplit(JMh) 

793 

794 return CAM_Specification_Hellwig2022(J=J, M=M, h=h) 

795 

796 

797def sCAM_to_JMh_sCAM( 

798 specification: Annotated[ 

799 CAM_Specification_sCAM, (100, 100, 360, 100, 100, 400, 100, 100, 100, 100) 

800 ], 

801) -> Range100_100_360: 

802 """ 

803 Convert from *sCAM* specification to *sCAM* :math:`JMh` correlates. 

804 

805 Parameters 

806 ---------- 

807 specification 

808 *sCAM* colour appearance model specification. 

809 

810 Returns 

811 ------- 

812 :class:`numpy.ndarray` 

813 *sCAM* :math:`JMh` correlates. 

814 

815 Notes 

816 ----- 

817 +---------------------+-----------------------+-----------------+ 

818 | **Domain** | **Scale - Reference** | **Scale - 1** | 

819 +=====================+=======================+=================+ 

820 | ``specification.J`` | 100 | 1 | 

821 +---------------------+-----------------------+-----------------+ 

822 | ``specification.C`` | 100 | 1 | 

823 +---------------------+-----------------------+-----------------+ 

824 | ``specification.h`` | 360 | 1 | 

825 +---------------------+-----------------------+-----------------+ 

826 | ``specification.Q`` | 100 | 1 | 

827 +---------------------+-----------------------+-----------------+ 

828 | ``specification.M`` | 100 | 1 | 

829 +---------------------+-----------------------+-----------------+ 

830 | ``specification.H`` | 400 | 1 | 

831 +---------------------+-----------------------+-----------------+ 

832 | ``specification.HC`` | 100 | 1 | 

833 +---------------------+-----------------------+-----------------+ 

834 | ``specification.V`` | 100 | 1 | 

835 +---------------------+-----------------------+-----------------+ 

836 | ``specification.K`` | 100 | 1 | 

837 +---------------------+-----------------------+-----------------+ 

838 | ``specification.W`` | 100 | 1 | 

839 +---------------------+-----------------------+-----------------+ 

840 | ``specification.D`` | 100 | 1 | 

841 +---------------------+-----------------------+-----------------+ 

842 

843 +---------------------+-----------------------+-----------------+ 

844 | **Range** | **Scale - Reference** | **Scale - 1** | 

845 +=====================+=======================+=================+ 

846 | ``JMh`` | ``J`` : 100 | ``J`` : 1 | 

847 | | | | 

848 | | ``M`` : 100 | ``M`` : 1 | 

849 | | | | 

850 | | ``h`` : 360 | ``h`` : 1 | 

851 +---------------------+-----------------------+-----------------+ 

852 

853 Examples 

854 -------- 

855 >>> specification = CAM_Specification_sCAM( 

856 ... J=42.55099214246278, M=14.325369984981474, h=20.90445543302642 

857 ... ) 

858 >>> sCAM_to_JMh_sCAM(specification) # doctest: +ELLIPSIS 

859 array([ 42.5509921..., 14.3253699..., 20.9044554...]) 

860 """ 

861 

862 return tstack([specification.J, specification.M, specification.h]) # pyright: ignore 

863 

864 

865def JMh_sCAM_to_sCAM( 

866 JMh: Domain100_100_360, 

867) -> Annotated[ 

868 CAM_Specification_sCAM, (100, 100, 360, 100, 100, 400, 100, 100, 100, 100) 

869]: 

870 """ 

871 Convert from *sCAM* :math:`JMh` correlates to *sCAM* specification. 

872 

873 Parameters 

874 ---------- 

875 JMh 

876 *sCAM* :math:`JMh` correlates. 

877 

878 Returns 

879 ------- 

880 :class:`colour.CAM_Specification_sCAM` 

881 *sCAM* colour appearance model specification. 

882 

883 Notes 

884 ----- 

885 +---------------------+-----------------------+-----------------+ 

886 | **Domain** | **Scale - Reference** | **Scale - 1** | 

887 +=====================+=======================+=================+ 

888 | ``JMh`` | ``J`` : 100 | ``J`` : 1 | 

889 | | | | 

890 | | ``M`` : 100 | ``M`` : 1 | 

891 | | | | 

892 | | ``h`` : 360 | ``h`` : 1 | 

893 +---------------------+-----------------------+-----------------+ 

894 

895 +---------------------+-----------------------+-----------------+ 

896 | **Range** | **Scale - Reference** | **Scale - 1** | 

897 +=====================+=======================+=================+ 

898 | ``specification.J`` | 100 | 1 | 

899 +---------------------+-----------------------+-----------------+ 

900 | ``specification.C`` | 100 | 1 | 

901 +---------------------+-----------------------+-----------------+ 

902 | ``specification.h`` | 360 | 1 | 

903 +---------------------+-----------------------+-----------------+ 

904 | ``specification.Q`` | 100 | 1 | 

905 +---------------------+-----------------------+-----------------+ 

906 | ``specification.M`` | 100 | 1 | 

907 +---------------------+-----------------------+-----------------+ 

908 | ``specification.H`` | 400 | 1 | 

909 +---------------------+-----------------------+-----------------+ 

910 | ``specification.HC`` | 100 | 1 | 

911 +---------------------+-----------------------+-----------------+ 

912 | ``specification.V`` | 100 | 1 | 

913 +---------------------+-----------------------+-----------------+ 

914 | ``specification.K`` | 100 | 1 | 

915 +---------------------+-----------------------+-----------------+ 

916 | ``specification.W`` | 100 | 1 | 

917 +---------------------+-----------------------+-----------------+ 

918 | ``specification.D`` | 100 | 1 | 

919 +---------------------+-----------------------+-----------------+ 

920 

921 Examples 

922 -------- 

923 >>> import numpy as np 

924 >>> JMh = np.array([42.5509921, 14.3253700, 20.9044554]) 

925 >>> JMh_sCAM_to_sCAM(JMh) # doctest: +ELLIPSIS 

926 CAM_Specification_sCAM(J=42.5509921..., C=None, h=20.9044554, Q=None, \ 

927M=14.3253699..., H=None, HC=None, V=None, K=None, W=None, D=None) 

928 """ 

929 

930 J, M, h = tsplit(JMh) 

931 

932 return CAM_Specification_sCAM(J=J, M=M, h=h) 

933 

934 

935def ZCAM_to_JMh_ZCAM( 

936 specification: Annotated[ 

937 CAM_Specification_ZCAM, (1, 1, 360, 1, 1, 1, 400, 1, 1, 1) 

938 ], 

939) -> Annotated[NDArrayFloat, (1, 1, 360)]: 

940 """ 

941 Convert from *ZCAM* specification to *ZCAM* :math:`JMh` correlates. 

942 

943 Parameters 

944 ---------- 

945 specification 

946 *ZCAM* colour appearance model specification. 

947 

948 Returns 

949 ------- 

950 :class:`numpy.ndarray` 

951 *ZCAM* :math:`JMh` correlates. 

952 

953 Notes 

954 ----- 

955 +---------------------+-----------------------+-----------------+ 

956 | **Domain** | **Scale - Reference** | **Scale - 1** | 

957 +=====================+=======================+=================+ 

958 | ``specification.J`` | 1 | 1 | 

959 +---------------------+-----------------------+-----------------+ 

960 | ``specification.C`` | 1 | 1 | 

961 +---------------------+-----------------------+-----------------+ 

962 | ``specification.h`` | 360 | 1 | 

963 +---------------------+-----------------------+-----------------+ 

964 | ``specification.s`` | 1 | 1 | 

965 +---------------------+-----------------------+-----------------+ 

966 | ``specification.Q`` | 1 | 1 | 

967 +---------------------+-----------------------+-----------------+ 

968 | ``specification.M`` | 1 | 1 | 

969 +---------------------+-----------------------+-----------------+ 

970 | ``specification.H`` | 400 | 1 | 

971 +---------------------+-----------------------+-----------------+ 

972 | ``specification.HC`` | 1 | 1 | 

973 +---------------------+-----------------------+-----------------+ 

974 | ``specification.V`` | 1 | 1 | 

975 +---------------------+-----------------------+-----------------+ 

976 | ``specification.K`` | 1 | 1 | 

977 +---------------------+-----------------------+-----------------+ 

978 | ``specification.W`` | 1 | 1 | 

979 +---------------------+-----------------------+-----------------+ 

980 

981 +---------------------+-----------------------+-----------------+ 

982 | **Range** | **Scale - Reference** | **Scale - 1** | 

983 +=====================+=======================+=================+ 

984 | ``JMh`` | ``J`` : 100 | ``J`` : 1 | 

985 | | | | 

986 | | ``M`` : 100 | ``M`` : 1 | 

987 | | | | 

988 | | ``h`` : 360 | ``h`` : 1 | 

989 +---------------------+-----------------------+-----------------+ 

990 

991 Examples 

992 -------- 

993 >>> specification = CAM_Specification_ZCAM( 

994 ... J=38.34718627895636, M=42.40380583390051, h=33.71157893109518 

995 ... ) 

996 >>> ZCAM_to_JMh_ZCAM(specification) # doctest: +ELLIPSIS 

997 array([ 38.3471862..., 42.4038058..., 33.7115789...]) 

998 """ 

999 

1000 return tstack( 

1001 [ 

1002 cast("NDArrayFloat", specification.J), 

1003 cast("NDArrayFloat", specification.M), 

1004 cast("NDArrayFloat", specification.h), 

1005 ] 

1006 ) 

1007 

1008 

1009def JMh_ZCAM_to_ZCAM( 

1010 JMh: Annotated[ArrayLike, (1, 1, 360)], 

1011) -> Annotated[CAM_Specification_ZCAM, (1, 1, 360, 1, 1, 1, 400, 1, 1, 1)]: 

1012 """ 

1013 Convert from *ZCAM* :math:`JMh` correlates to *ZCAM* specification. 

1014 

1015 Parameters 

1016 ---------- 

1017 JMh 

1018 *ZCAM* :math:`JMh` correlates. 

1019 

1020 Returns 

1021 ------- 

1022 :class:`colour.CAM_Specification_ZCAM` 

1023 *ZCAM* colour appearance model specification. 

1024 

1025 Notes 

1026 ----- 

1027 +---------------------+-----------------------+-----------------+ 

1028 | **Domain** | **Scale - Reference** | **Scale - 1** | 

1029 +=====================+=======================+=================+ 

1030 | ``JMh`` | ``J`` : 100 | ``J`` : 1 | 

1031 | | | | 

1032 | | ``M`` : 100 | ``M`` : 1 | 

1033 | | | | 

1034 | | ``h`` : 360 | ``h`` : 1 | 

1035 +---------------------+-----------------------+-----------------+ 

1036 

1037 +---------------------+-----------------------+-----------------+ 

1038 | **Range** | **Scale - Reference** | **Scale - 1** | 

1039 +=====================+=======================+=================+ 

1040 | ``specification.J`` | 1 | 1 | 

1041 +---------------------+-----------------------+-----------------+ 

1042 | ``specification.C`` | 1 | 1 | 

1043 +---------------------+-----------------------+-----------------+ 

1044 | ``specification.h`` | 360 | 1 | 

1045 +---------------------+-----------------------+-----------------+ 

1046 | ``specification.s`` | 1 | 1 | 

1047 +---------------------+-----------------------+-----------------+ 

1048 | ``specification.Q`` | 1 | 1 | 

1049 +---------------------+-----------------------+-----------------+ 

1050 | ``specification.M`` | 1 | 1 | 

1051 +---------------------+-----------------------+-----------------+ 

1052 | ``specification.H`` | 400 | 1 | 

1053 +---------------------+-----------------------+-----------------+ 

1054 | ``specification.HC`` | 1 | 1 | 

1055 +---------------------+-----------------------+-----------------+ 

1056 | ``specification.V`` | 1 | 1 | 

1057 +---------------------+-----------------------+-----------------+ 

1058 | ``specification.K`` | 1 | 1 | 

1059 +---------------------+-----------------------+-----------------+ 

1060 | ``specification.W`` | 1 | 1 | 

1061 +---------------------+-----------------------+-----------------+ 

1062 

1063 Examples 

1064 -------- 

1065 >>> import numpy as np 

1066 >>> JMh = np.array([38.3471863, 42.4038058, 33.7115789]) 

1067 >>> JMh_ZCAM_to_ZCAM(JMh) # doctest: +ELLIPSIS 

1068 CAM_Specification_ZCAM(J=38.3471862..., C=None, h=33.7115788..., s=None, \ 

1069Q=None, M=42.4038058..., H=None, HC=None, V=None, K=None, W=None) 

1070 """ 

1071 

1072 J, M, h = tsplit(JMh) 

1073 

1074 return CAM_Specification_ZCAM(J=J, M=M, h=h) 

1075 

1076 

1077def Kim2009_to_JMh_Kim2009( 

1078 specification: Annotated[ 

1079 CAM_Specification_Kim2009, (100, 100, 360, 100, 100, 100, 400) 

1080 ], 

1081) -> Range100_100_360: 

1082 """ 

1083 Convert from *Kim, Weyrich and Kautz (2009)* specification to 

1084 *Kim, Weyrich and Kautz (2009)* :math:`JMh` correlates. 

1085 

1086 Parameters 

1087 ---------- 

1088 specification 

1089 *Kim, Weyrich and Kautz (2009)* colour appearance model specification. 

1090 

1091 Returns 

1092 ------- 

1093 :class:`numpy.ndarray` 

1094 *Kim, Weyrich and Kautz (2009)* :math:`JMh` correlates. 

1095 

1096 Notes 

1097 ----- 

1098 +---------------------+-----------------------+-----------------+ 

1099 | **Domain** | **Scale - Reference** | **Scale - 1** | 

1100 +=====================+=======================+=================+ 

1101 | ``specification.J`` | 100 | 1 | 

1102 +---------------------+-----------------------+-----------------+ 

1103 | ``specification.C`` | 100 | 1 | 

1104 +---------------------+-----------------------+-----------------+ 

1105 | ``specification.h`` | 360 | 1 | 

1106 +---------------------+-----------------------+-----------------+ 

1107 | ``specification.s`` | 100 | 1 | 

1108 +---------------------+-----------------------+-----------------+ 

1109 | ``specification.Q`` | 100 | 1 | 

1110 +---------------------+-----------------------+-----------------+ 

1111 | ``specification.M`` | 100 | 1 | 

1112 +---------------------+-----------------------+-----------------+ 

1113 | ``specification.H`` | 400 | 1 | 

1114 +---------------------+-----------------------+-----------------+ 

1115 

1116 +---------------------+-----------------------+-----------------+ 

1117 | **Range** | **Scale - Reference** | **Scale - 1** | 

1118 +=====================+=======================+=================+ 

1119 | ``JMh`` | ``J`` : 100 | ``J`` : 1 | 

1120 | | | | 

1121 | | ``M`` : 100 | ``M`` : 1 | 

1122 | | | | 

1123 | | ``h`` : 360 | ``h`` : 1 | 

1124 +---------------------+-----------------------+-----------------+ 

1125 

1126 Examples 

1127 -------- 

1128 >>> specification = CAM_Specification_Kim2009( 

1129 ... J=19.879918542450937, M=46.34641585822787, h=22.01338816509003 

1130 ... ) 

1131 >>> Kim2009_to_JMh_Kim2009(specification) # doctest: +ELLIPSIS 

1132 array([ 19.8799185..., 46.3464158..., 22.0133881...]) 

1133 """ 

1134 

1135 return tstack( 

1136 [ 

1137 cast("NDArrayFloat", specification.J), 

1138 cast("NDArrayFloat", specification.M), 

1139 cast("NDArrayFloat", specification.h), 

1140 ] 

1141 ) 

1142 

1143 

1144def JMh_Kim2009_to_Kim2009( 

1145 JMh: Domain100_100_360, 

1146) -> Annotated[CAM_Specification_Kim2009, (100, 100, 360, 100, 100, 100, 400)]: 

1147 """ 

1148 Convert from *Kim, Weyrich and Kautz (2009)* :math:`JMh` correlates to 

1149 *Kim, Weyrich and Kautz (2009)* specification. 

1150 

1151 Parameters 

1152 ---------- 

1153 JMh 

1154 *Kim, Weyrich and Kautz (2009)* :math:`JMh` correlates. 

1155 

1156 Returns 

1157 ------- 

1158 :class:`colour.CAM_Specification_Kim2009` 

1159 *Kim, Weyrich and Kautz (2009)* colour appearance model specification. 

1160 

1161 Notes 

1162 ----- 

1163 +---------------------+-----------------------+-----------------+ 

1164 | **Domain** | **Scale - Reference** | **Scale - 1** | 

1165 +=====================+=======================+=================+ 

1166 | ``JMh`` | ``J`` : 100 | ``J`` : 1 | 

1167 | | | | 

1168 | | ``M`` : 100 | ``M`` : 1 | 

1169 | | | | 

1170 | | ``h`` : 360 | ``h`` : 1 | 

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

1172 

1173 +---------------------+-----------------------+-----------------+ 

1174 | **Range** | **Scale - Reference** | **Scale - 1** | 

1175 +=====================+=======================+=================+ 

1176 | ``specification.J`` | 100 | 1 | 

1177 +---------------------+-----------------------+-----------------+ 

1178 | ``specification.C`` | 100 | 1 | 

1179 +---------------------+-----------------------+-----------------+ 

1180 | ``specification.h`` | 360 | 1 | 

1181 +---------------------+-----------------------+-----------------+ 

1182 | ``specification.s`` | 100 | 1 | 

1183 +---------------------+-----------------------+-----------------+ 

1184 | ``specification.Q`` | 100 | 1 | 

1185 +---------------------+-----------------------+-----------------+ 

1186 | ``specification.M`` | 100 | 1 | 

1187 +---------------------+-----------------------+-----------------+ 

1188 | ``specification.H`` | 400 | 1 | 

1189 +---------------------+-----------------------+-----------------+ 

1190 

1191 Examples 

1192 -------- 

1193 >>> import numpy as np 

1194 >>> JMh = np.array([19.8799185, 46.3464159, 22.0133882]) 

1195 >>> JMh_Kim2009_to_Kim2009(JMh) # doctest: +ELLIPSIS 

1196 CAM_Specification_Kim2009(J=19.8799184..., C=None, h=22.0133882..., s=None, \ 

1197Q=None, M=46.3464158..., H=None, HC=None) 

1198 """ 

1199 

1200 J, M, h = tsplit(JMh) 

1201 

1202 return CAM_Specification_Kim2009(J=J, M=M, h=h) 

1203 

1204 

1205def XYZ_to_luminance(XYZ: Domain1) -> Range1: 

1206 """ 

1207 Convert specified *CIE XYZ* tristimulus values to *luminance* :math:`Y`. 

1208 

1209 Extract the Y component from *CIE XYZ* tristimulus values, which 

1210 represents the *luminance* of the colour stimulus. 

1211 

1212 Parameters 

1213 ---------- 

1214 XYZ 

1215 *CIE XYZ* tristimulus values. 

1216 

1217 Returns 

1218 ------- 

1219 :class:`numpy.ndarray` 

1220 *Luminance* :math:`Y`. 

1221 

1222 Notes 

1223 ----- 

1224 +------------+-----------------------+---------------+ 

1225 | **Domain** | **Scale - Reference** | **Scale - 1** | 

1226 +============+=======================+===============+ 

1227 | ``XYZ`` | 1 | 1 | 

1228 +------------+-----------------------+---------------+ 

1229 

1230 +-----------+-----------------------+---------------+ 

1231 | **Range** | **Scale - Reference** | **Scale - 1** | 

1232 +===========+=======================+===============+ 

1233 | ``Y`` | 1 | 1 | 

1234 +-----------+-----------------------+---------------+ 

1235 

1236 Examples 

1237 -------- 

1238 >>> import numpy as np 

1239 >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952]) 

1240 >>> XYZ_to_luminance(XYZ) # doctest: +ELLIPSIS 

1241 0.1219722... 

1242 """ 

1243 

1244 _X, Y, _Z = tsplit(XYZ) 

1245 

1246 return Y 

1247 

1248 

1249def RGB_luminance_to_RGB(Y: Domain1) -> Range1: 

1250 """ 

1251 Convert from *luminance* :math:`Y` to *RGB*. 

1252 

1253 Parameters 

1254 ---------- 

1255 Y 

1256 *Luminance* :math:`Y`. 

1257 

1258 Returns 

1259 ------- 

1260 :class:`numpy.ndarray` 

1261 *RGB*. 

1262 

1263 Notes 

1264 ----- 

1265 +------------+-----------------------+---------------+ 

1266 | **Domain** | **Scale - Reference** | **Scale - 1** | 

1267 +============+=======================+===============+ 

1268 | ``Y`` | 1 | 1 | 

1269 +------------+-----------------------+---------------+ 

1270 

1271 +-----------+-----------------------+---------------+ 

1272 | **Range** | **Scale - Reference** | **Scale - 1** | 

1273 +===========+=======================+===============+ 

1274 | ``RGB`` | 1 | 1 | 

1275 +-----------+-----------------------+---------------+ 

1276 

1277 Examples 

1278 -------- 

1279 >>> RGB_luminance_to_RGB(0.123014562384318) # doctest: +ELLIPSIS 

1280 array([ 0.1230145..., 0.1230145..., 0.1230145...]) 

1281 """ 

1282 

1283 Y = as_float_array(Y) 

1284 

1285 return tstack([Y, Y, Y]) 

1286 

1287 

1288def CCT_D_uv_to_mired(CCT_D_uv: ArrayLike) -> NDArrayFloat: 

1289 """ 

1290 Convert correlated colour temperature :math:`T_{cp}` and 

1291 :math:`\\Delta_{uv}` to micro reciprocal degree (mired). 

1292 

1293 Parameters 

1294 ---------- 

1295 CCT_D_uv 

1296 Correlated colour temperature :math:`T_{cp}`, :math:`\\Delta_{uv}`. 

1297 

1298 Returns 

1299 ------- 

1300 :class:`numpy.ndarray` 

1301 Micro reciprocal degree (mired). 

1302 

1303 Examples 

1304 -------- 

1305 >>> CCT_D_uv = np.array([6500.0081378199056, 0.008333331244225]) 

1306 >>> CCT_D_uv_to_mired(CCT_D_uv) # doctest: +ELLIPSIS 

1307 153.8459612... 

1308 """ 

1309 

1310 CCT, _D_uv = tsplit(CCT_D_uv) 

1311 

1312 return CCT_to_mired(CCT) 

1313 

1314 

1315def mired_to_CCT_D_uv(mired: ArrayLike) -> NDArrayFloat: 

1316 """ 

1317 Convert specified micro reciprocal degree (mired) to correlated colour 

1318 temperature :math:`T_{cp}` and :math:`\\Delta_{uv}`. 

1319 

1320 Parameters 

1321 ---------- 

1322 mired 

1323 Micro reciprocal degree (mired). 

1324 

1325 Returns 

1326 ------- 

1327 :class:`numpy.ndarray` 

1328 Correlated colour temperature :math:`T_{cp}`, :math:`\\Delta_{uv}`. 

1329 

1330 Examples 

1331 -------- 

1332 >>> mired = 153.84596123527297 

1333 >>> mired_to_CCT_D_uv(mired) # doctest: +ELLIPSIS 

1334 array([ 6500.0081378..., 0. ]) 

1335 """ 

1336 

1337 mired = as_float_array(mired) 

1338 

1339 return tstack([mired_to_CCT(mired), zeros(mired.shape)]) 

1340 

1341 

1342_ILLUMINANT_DEFAULT: str = "D65" 

1343"""Default automatic colour conversion graph illuminant name.""" 

1344 

1345_CCS_ILLUMINANT_DEFAULT: NDArrayFloat = CCS_ILLUMINANTS[ 

1346 "CIE 1931 2 Degree Standard Observer" 

1347][_ILLUMINANT_DEFAULT] 

1348""" 

1349Default automatic colour conversion graph illuminant *CIE xy* chromaticity 

1350coordinates. 

1351""" 

1352 

1353_TVS_ILLUMINANT_DEFAULT: NDArrayFloat = xy_to_XYZ(_CCS_ILLUMINANT_DEFAULT) 

1354""" 

1355Default automatic colour conversion graph illuminant *CIE XYZ* tristimulus 

1356values. 

1357""" 

1358 

1359_RGB_COLOURSPACE_DEFAULT: RGB_Colourspace = RGB_COLOURSPACE_sRGB 

1360"""Default automatic colour conversion graph *RGB* colourspace.""" 

1361 

1362_CAM_KWARGS_CIECAM02_sRGB: dict = CAM_KWARGS_CIECAM02_sRGB.copy() 

1363""" 

1364Default parameter values for the *CIECAM02* colour appearance model usage in 

1365the context of *sRGB*. 

1366 

1367Warnings 

1368-------- 

1369The *CIE XYZ* tristimulus values of reference white :math:`XYZ_w` is adjusted 

1370for the domain-range scale **'1'**. 

1371""" 

1372 

1373_CAM_KWARGS_CIECAM02_sRGB["XYZ_w"] = _CAM_KWARGS_CIECAM02_sRGB["XYZ_w"] / 100 

1374 

1375CONVERSION_SPECIFICATIONS_DATA: List[tuple] = [ 

1376 # Colorimetry 

1377 ("Spectral Distribution", "CIE XYZ", sd_to_XYZ), 

1378 ("CIE XYZ", "Spectral Distribution", XYZ_to_sd), 

1379 ("Spectral Distribution", "Luminous Flux", luminous_flux), 

1380 ("Spectral Distribution", "Luminous Efficiency", luminous_efficiency), 

1381 ("Spectral Distribution", "Luminous Efficacy", luminous_efficacy), 

1382 ("CIE XYZ", "Luminance", XYZ_to_luminance), 

1383 ("Luminance", "Lightness", lightness), 

1384 ("Lightness", "Luminance", luminance), 

1385 ("CIE XYZ", "Whiteness", partial(whiteness, XYZ_0=_TVS_ILLUMINANT_DEFAULT)), 

1386 ("CIE XYZ", "Yellowness", yellowness), 

1387 ( 

1388 "CIE xy", 

1389 "Colorimetric Purity", 

1390 partial(colorimetric_purity, xy_n=_CCS_ILLUMINANT_DEFAULT), 

1391 ), 

1392 ( 

1393 "CIE xy", 

1394 "Complementary Wavelength", 

1395 partial(complementary_wavelength, xy_n=_CCS_ILLUMINANT_DEFAULT), 

1396 ), 

1397 ( 

1398 "CIE xy", 

1399 "Dominant Wavelength", 

1400 partial(dominant_wavelength, xy_n=_CCS_ILLUMINANT_DEFAULT), 

1401 ), 

1402 ( 

1403 "CIE xy", 

1404 "Excitation Purity", 

1405 partial(excitation_purity, xy_n=_CCS_ILLUMINANT_DEFAULT), 

1406 ), 

1407 ("Wavelength", "CIE XYZ", wavelength_to_XYZ), 

1408 # Colour Models 

1409 ("CIE XYZ", "CIE xyY", XYZ_to_xyY), 

1410 ("CIE xyY", "CIE XYZ", xyY_to_XYZ), 

1411 ("CIE xyY", "CIE xy", xyY_to_xy), 

1412 ("CIE xy", "CIE xyY", xy_to_xyY), 

1413 ("CIE XYZ", "CIE xy", XYZ_to_xy), 

1414 ("CIE xy", "CIE XYZ", xy_to_XYZ), 

1415 ("CIE XYZ", "CIE Lab", XYZ_to_Lab), 

1416 ("CIE Lab", "CIE XYZ", Lab_to_XYZ), 

1417 ("CIE XYZ", "CIE Luv", XYZ_to_Luv), 

1418 ("CIE Luv", "CIE XYZ", Luv_to_XYZ), 

1419 ("CIE Luv", "CIE Luv uv", Luv_to_uv), 

1420 ("CIE Luv uv", "CIE Luv", uv_to_Luv), 

1421 ("CIE Luv uv", "CIE xy", Luv_uv_to_xy), 

1422 ("CIE xy", "CIE Luv uv", xy_to_Luv_uv), 

1423 ("CIE XYZ", "CIE UCS", XYZ_to_UCS), 

1424 ("CIE UCS", "CIE XYZ", UCS_to_XYZ), 

1425 ("CIE UCS", "CIE UCS uv", UCS_to_uv), 

1426 ("CIE UCS uv", "CIE UCS", uv_to_UCS), 

1427 ("CIE UCS uv", "CIE xy", UCS_uv_to_xy), 

1428 ("CIE xy", "CIE UCS uv", xy_to_UCS_uv), 

1429 ("CIE XYZ", "CIE UVW", XYZ_to_UVW), 

1430 ("CIE UVW", "CIE XYZ", UVW_to_XYZ), 

1431 ("CIE XYZ", "DIN99", XYZ_to_DIN99), 

1432 ("DIN99", "CIE XYZ", DIN99_to_XYZ), 

1433 ("CIE XYZ", "hdr-CIELAB", XYZ_to_hdr_CIELab), 

1434 ("hdr-CIELAB", "CIE XYZ", hdr_CIELab_to_XYZ), 

1435 ( 

1436 "CIE XYZ", 

1437 "Hunter Lab", 

1438 partial( 

1439 XYZ_to_Hunter_Lab, 

1440 XYZ_n=TVS_ILLUMINANTS_HUNTERLAB["CIE 1931 2 Degree Standard Observer"][ 

1441 "D65" 

1442 ].XYZ_n 

1443 / 100, 

1444 ), 

1445 ), 

1446 ( 

1447 "Hunter Lab", 

1448 "CIE XYZ", 

1449 partial( 

1450 Hunter_Lab_to_XYZ, 

1451 XYZ_n=TVS_ILLUMINANTS_HUNTERLAB["CIE 1931 2 Degree Standard Observer"][ 

1452 "D65" 

1453 ].XYZ_n 

1454 / 100, 

1455 ), 

1456 ), 

1457 ( 

1458 "CIE XYZ", 

1459 "Hunter Rdab", 

1460 partial( 

1461 XYZ_to_Hunter_Rdab, 

1462 XYZ_n=TVS_ILLUMINANTS_HUNTERLAB["CIE 1931 2 Degree Standard Observer"][ 

1463 "D65" 

1464 ].XYZ_n 

1465 / 100, 

1466 ), 

1467 ), 

1468 ( 

1469 "Hunter Rdab", 

1470 "CIE XYZ", 

1471 partial( 

1472 Hunter_Rdab_to_XYZ, 

1473 XYZ_n=TVS_ILLUMINANTS_HUNTERLAB["CIE 1931 2 Degree Standard Observer"][ 

1474 "D65" 

1475 ].XYZ_n 

1476 / 100, 

1477 ), 

1478 ), 

1479 ("CIE XYZ", "ICaCb", XYZ_to_ICaCb), 

1480 ("ICaCb", "CIE XYZ", ICaCb_to_XYZ), 

1481 ("CIE XYZ", "ICtCp", XYZ_to_ICtCp), 

1482 ("ICtCp", "CIE XYZ", ICtCp_to_XYZ), 

1483 ("CIE XYZ", "IgPgTg", XYZ_to_IgPgTg), 

1484 ("IgPgTg", "CIE XYZ", IgPgTg_to_XYZ), 

1485 ("CIE XYZ", "IPT", XYZ_to_IPT), 

1486 ("IPT", "CIE XYZ", IPT_to_XYZ), 

1487 ("CIE XYZ", "IPT Ragoo 2021", XYZ_to_IPT_Ragoo2021), 

1488 ("IPT Ragoo 2021", "CIE XYZ", IPT_Ragoo2021_to_XYZ), 

1489 ("CIE XYZ", "Jzazbz", XYZ_to_Jzazbz), 

1490 ("Jzazbz", "CIE XYZ", Jzazbz_to_XYZ), 

1491 ("CIE XYZ", "hdr-IPT", XYZ_to_hdr_IPT), 

1492 ("hdr-IPT", "CIE XYZ", hdr_IPT_to_XYZ), 

1493 ("CIE XYZ", "OSA UCS", XYZ_to_OSA_UCS), 

1494 ("OSA UCS", "CIE XYZ", OSA_UCS_to_XYZ), 

1495 ("CIE XYZ", "Oklab", XYZ_to_Oklab), 

1496 ("Oklab", "CIE XYZ", Oklab_to_XYZ), 

1497 ("CIE XYZ", "ProLab", XYZ_to_ProLab), 

1498 ("ProLab", "CIE XYZ", ProLab_to_XYZ), 

1499 ("CIE XYZ", "sUCS", XYZ_to_sUCS), 

1500 ("sUCS", "CIE XYZ", sUCS_to_XYZ), 

1501 ("CIE XYZ", "Yrg", XYZ_to_Yrg), 

1502 ("Yrg", "CIE XYZ", Yrg_to_XYZ), 

1503 ("CIE 1931", "CIE XYZ", xyY_to_XYZ), 

1504 ("CIE XYZ", "CIE 1931", XYZ_to_xyY), 

1505 ("CIE 1960 UCS", "CIE XYZ", CIE1960UCS_to_XYZ), 

1506 ("CIE XYZ", "CIE 1960 UCS", XYZ_to_CIE1960UCS), 

1507 ("CIE 1976 UCS", "CIE XYZ", CIE1976UCS_to_XYZ), 

1508 ("CIE XYZ", "CIE 1976 UCS", XYZ_to_CIE1976UCS), 

1509 # RGB Colour Models 

1510 ("CIE XYZ", "RGB", partial(XYZ_to_RGB, colourspace=_RGB_COLOURSPACE_DEFAULT)), 

1511 ("RGB", "CIE XYZ", partial(RGB_to_XYZ, colourspace=_RGB_COLOURSPACE_DEFAULT)), 

1512 ( 

1513 "RGB", 

1514 "Scene-Referred RGB", 

1515 partial( 

1516 RGB_to_RGB, 

1517 input_colourspace=_RGB_COLOURSPACE_DEFAULT, 

1518 output_colourspace=_RGB_COLOURSPACE_DEFAULT, 

1519 ), 

1520 ), 

1521 ( 

1522 "Scene-Referred RGB", 

1523 "RGB", 

1524 partial( 

1525 RGB_to_RGB, 

1526 input_colourspace=_RGB_COLOURSPACE_DEFAULT, 

1527 output_colourspace=_RGB_COLOURSPACE_DEFAULT, 

1528 ), 

1529 ), 

1530 ("RGB", "HSV", RGB_to_HSV), 

1531 ("HSV", "RGB", HSV_to_RGB), 

1532 ("RGB", "HSL", RGB_to_HSL), 

1533 ("HSL", "RGB", HSL_to_RGB), 

1534 ("RGB", "HCL", RGB_to_HCL), 

1535 ("HCL", "RGB", HCL_to_RGB), 

1536 ("RGB", "IHLS", RGB_to_IHLS), 

1537 ("IHLS", "RGB", IHLS_to_RGB), 

1538 ("CMY", "RGB", CMY_to_RGB), 

1539 ("RGB", "CMY", RGB_to_CMY), 

1540 ("CMY", "CMYK", CMY_to_CMYK), 

1541 ("CMYK", "CMY", CMYK_to_CMY), 

1542 ( 

1543 "RGB", 

1544 "RGB Luminance", 

1545 partial( 

1546 RGB_luminance, 

1547 primaries=_RGB_COLOURSPACE_DEFAULT.primaries, 

1548 whitepoint=_RGB_COLOURSPACE_DEFAULT.whitepoint, 

1549 ), 

1550 ), 

1551 ("RGB Luminance", "RGB", RGB_luminance_to_RGB), 

1552 ("RGB", "Prismatic", RGB_to_Prismatic), 

1553 ("Prismatic", "RGB", Prismatic_to_RGB), 

1554 ("Output-Referred RGB", "YCbCr", RGB_to_YCbCr), 

1555 ("YCbCr", "Output-Referred RGB", YCbCr_to_RGB), 

1556 ("RGB", "YcCbcCrc", RGB_to_YcCbcCrc), 

1557 ("YcCbcCrc", "RGB", YcCbcCrc_to_RGB), 

1558 ("Output-Referred RGB", "YCoCg", RGB_to_YCoCg), 

1559 ("YCoCg", "Output-Referred RGB", YCoCg_to_RGB), 

1560 ("RGB", "Output-Referred RGB", cctf_encoding), 

1561 ("Output-Referred RGB", "RGB", cctf_decoding), 

1562 ("Scene-Referred RGB", "Output-Referred RGB", cctf_encoding), 

1563 ("Output-Referred RGB", "Scene-Referred RGB", cctf_decoding), 

1564 ("CIE XYZ", "sRGB", XYZ_to_sRGB), 

1565 ("sRGB", "CIE XYZ", sRGB_to_XYZ), 

1566 # Colour Notation Systems 

1567 ("Output-Referred RGB", "Hexadecimal", RGB_to_HEX), 

1568 ("Hexadecimal", "Output-Referred RGB", HEX_to_RGB), 

1569 ("CSS Color 3", "Output-Referred RGB", keyword_to_RGB_CSSColor3), 

1570 ("CIE xyY", "Munsell Colour", xyY_to_munsell_colour), 

1571 ("Munsell Colour", "CIE xyY", munsell_colour_to_xyY), 

1572 ("Luminance", "Munsell Value", munsell_value), 

1573 ("Munsell Value", "Luminance", partial(luminance, method="ASTM D1535")), 

1574 # Colour Quality 

1575 ("Spectral Distribution", "CRI", colour_rendering_index), 

1576 ("Spectral Distribution", "CQS", colour_quality_scale), 

1577 # Colour Temperature 

1578 ("CCT", "CIE UCS uv", CCT_to_uv), 

1579 ("CIE UCS uv", "CCT", uv_to_CCT), 

1580 ("CCT", "Mired", CCT_D_uv_to_mired), 

1581 ("Mired", "CCT", mired_to_CCT_D_uv), 

1582 # Advanced Colorimetry 

1583 ( 

1584 "CIE XYZ", 

1585 "ATD95", 

1586 partial( 

1587 XYZ_to_ATD95, 

1588 XYZ_0=_TVS_ILLUMINANT_DEFAULT, 

1589 Y_0=80 * 0.2, 

1590 k_1=0, 

1591 k_2=(15 + 50) / 2, 

1592 ), 

1593 ), 

1594 ("CIE XYZ", "CIECAM02", partial(XYZ_to_CIECAM02, **_CAM_KWARGS_CIECAM02_sRGB)), 

1595 ("CIECAM02", "CIE XYZ", partial(CIECAM02_to_XYZ, **_CAM_KWARGS_CIECAM02_sRGB)), 

1596 ("CIECAM02", "CIECAM02 JMh", CIECAM02_to_JMh_CIECAM02), 

1597 ("CIECAM02 JMh", "CIECAM02", JMh_CIECAM02_to_CIECAM02), 

1598 ("CIE XYZ", "CAM16", partial(XYZ_to_CAM16, **_CAM_KWARGS_CIECAM02_sRGB)), 

1599 ("CAM16", "CIE XYZ", partial(CAM16_to_XYZ, **_CAM_KWARGS_CIECAM02_sRGB)), 

1600 ("CAM16", "CAM16 JMh", CAM16_to_JMh_CAM16), 

1601 ("CAM16 JMh", "CAM16", JMh_CAM16_to_CAM16), 

1602 ("CIE XYZ", "CIECAM16", partial(XYZ_to_CIECAM16, **_CAM_KWARGS_CIECAM02_sRGB)), 

1603 ("CIECAM16", "CIE XYZ", partial(CIECAM16_to_XYZ, **_CAM_KWARGS_CIECAM02_sRGB)), 

1604 ("CIECAM16", "CIECAM16 JMh", CIECAM16_to_JMh_CIECAM16), 

1605 ("CIECAM16 JMh", "CIECAM16", JMh_CIECAM16_to_CIECAM16), 

1606 ( 

1607 "CIE XYZ", 

1608 "Hellwig 2022", 

1609 partial(XYZ_to_Hellwig2022, **_CAM_KWARGS_CIECAM02_sRGB), 

1610 ), 

1611 ( 

1612 "Hellwig 2022", 

1613 "CIE XYZ", 

1614 partial(Hellwig2022_to_XYZ, **_CAM_KWARGS_CIECAM02_sRGB), 

1615 ), 

1616 ("Hellwig 2022", "Hellwig 2022 JMh", Hellwig2022_to_JMh_Hellwig2022), 

1617 ("Hellwig 2022 JMh", "Hellwig 2022", JMh_Hellwig2022_to_Hellwig2022), 

1618 ( 

1619 "CIE XYZ", 

1620 "Kim 2009", 

1621 partial(XYZ_to_Kim2009, XYZ_w=_TVS_ILLUMINANT_DEFAULT, L_A=80 * 0.2), 

1622 ), 

1623 ( 

1624 "Kim 2009", 

1625 "CIE XYZ", 

1626 partial(Kim2009_to_XYZ, XYZ_w=_TVS_ILLUMINANT_DEFAULT, L_A=80 * 0.2), 

1627 ), 

1628 ("Kim 2009", "Kim 2009 JMh", Kim2009_to_JMh_Kim2009), 

1629 ("Kim 2009 JMh", "Kim 2009", JMh_Kim2009_to_Kim2009), 

1630 ( 

1631 "CIE XYZ", 

1632 "Hunt", 

1633 partial( 

1634 XYZ_to_Hunt, 

1635 XYZ_w=_TVS_ILLUMINANT_DEFAULT, 

1636 XYZ_b=_TVS_ILLUMINANT_DEFAULT, 

1637 L_A=80 * 0.2, 

1638 CCT_w=6504, 

1639 ), 

1640 ), 

1641 ( 

1642 "CIE XYZ", 

1643 "LLAB", 

1644 partial(XYZ_to_LLAB, XYZ_0=_TVS_ILLUMINANT_DEFAULT, Y_b=80 * 0.2, L=80), 

1645 ), 

1646 ( 

1647 "CIE XYZ", 

1648 "Nayatani95", 

1649 partial( 

1650 XYZ_to_Nayatani95, 

1651 XYZ_n=_TVS_ILLUMINANT_DEFAULT, 

1652 Y_o=0.2, 

1653 E_o=1000, 

1654 E_or=1000, 

1655 ), 

1656 ), 

1657 ("CIE XYZ", "RLAB", partial(XYZ_to_RLAB, XYZ_n=_TVS_ILLUMINANT_DEFAULT, Y_n=20)), 

1658 ("CIE XYZ", "sCAM", partial(XYZ_to_sCAM, **_CAM_KWARGS_CIECAM02_sRGB)), 

1659 ("sCAM", "CIE XYZ", partial(sCAM_to_XYZ, **_CAM_KWARGS_CIECAM02_sRGB)), 

1660 ("sCAM", "sCAM JMh", sCAM_to_JMh_sCAM), 

1661 ("sCAM JMh", "sCAM", JMh_sCAM_to_sCAM), 

1662 ( 

1663 "CIE XYZ", 

1664 "ZCAM", 

1665 partial( 

1666 XYZ_to_ZCAM, XYZ_w=_TVS_ILLUMINANT_DEFAULT, L_A=64 / np.pi * 0.2, Y_b=20 

1667 ), 

1668 ), 

1669 ( 

1670 "ZCAM", 

1671 "CIE XYZ", 

1672 partial( 

1673 ZCAM_to_XYZ, XYZ_w=_TVS_ILLUMINANT_DEFAULT, L_A=64 / np.pi * 0.2, Y_b=20 

1674 ), 

1675 ), 

1676 ("ZCAM", "ZCAM JMh", ZCAM_to_JMh_ZCAM), 

1677 ("ZCAM JMh", "ZCAM", JMh_ZCAM_to_ZCAM), 

1678 ("CIECAM02 JMh", "CAM02LCD", JMh_CIECAM02_to_CAM02LCD), 

1679 ("CAM02LCD", "CIECAM02 JMh", CAM02LCD_to_JMh_CIECAM02), 

1680 ("CIECAM02 JMh", "CAM02SCD", JMh_CIECAM02_to_CAM02SCD), 

1681 ("CAM02SCD", "CIECAM02 JMh", CAM02SCD_to_JMh_CIECAM02), 

1682 ("CIECAM02 JMh", "CAM02UCS", JMh_CIECAM02_to_CAM02UCS), 

1683 ("CAM02UCS", "CIECAM02 JMh", CAM02UCS_to_JMh_CIECAM02), 

1684 ("CAM16 JMh", "CAM16LCD", JMh_CAM16_to_CAM16LCD), 

1685 ("CAM16LCD", "CAM16 JMh", CAM16LCD_to_JMh_CAM16), 

1686 ("CAM16 JMh", "CAM16SCD", JMh_CAM16_to_CAM16SCD), 

1687 ("CAM16SCD", "CAM16 JMh", CAM16SCD_to_JMh_CAM16), 

1688 ("CAM16 JMh", "CAM16UCS", JMh_CAM16_to_CAM16UCS), 

1689 ("CAM16UCS", "CAM16 JMh", CAM16UCS_to_JMh_CAM16), 

1690] 

1691""" 

1692Automatic colour conversion graph specifications data describing two nodes and 

1693the edge in the graph. 

1694""" 

1695 

1696 

1697# Programmatically defining the colourspace models polar conversions. 

1698def _format_node_name(name: str) -> str: 

1699 """ 

1700 Format the specified name by applying a series of substitutions. 

1701 

1702 This function transforms node names according to predefined patterns, 

1703 typically converting underscores to hyphens and applying other naming 

1704 conventions used in the colourspace models polar conversions system. 

1705 

1706 Parameters 

1707 ---------- 

1708 name 

1709 The node name to format. 

1710 

1711 Returns 

1712 ------- 

1713 :class:`str` 

1714 The formatted node name with substitutions applied. 

1715 """ 

1716 

1717 for pattern, substitution in [ 

1718 ("hdr_", "hdr-"), 

1719 ("-CIELab", "-CIELAB"), 

1720 ("_", " "), 

1721 ("^Lab", "CIE Lab"), 

1722 ("^LCHab", "CIE LCHab"), 

1723 ("^Luv", "CIE Luv"), 

1724 ("^LCHuv", "CIE LCHuv"), 

1725 ("Ragoo2021", "Ragoo 2021"), 

1726 ]: 

1727 name = re.sub(pattern, substitution, name) 

1728 

1729 return name 

1730 

1731 

1732for _Jab, _JCh in COLOURSPACE_MODELS_POLAR_CONVERSIONS: 

1733 _module = sys.modules["colour.models"] 

1734 _Jab_name = _format_node_name(_Jab) 

1735 _JCh_name = _format_node_name(_JCh) 

1736 CONVERSION_SPECIFICATIONS_DATA.append( 

1737 (_Jab_name, _JCh_name, getattr(_module, f"{_Jab}_to_{_JCh}")) 

1738 ) 

1739 CONVERSION_SPECIFICATIONS_DATA.append( 

1740 (_JCh_name, _Jab_name, getattr(_module, f"{_JCh}_to_{_Jab}")) 

1741 ) 

1742 

1743del _format_node_name, _JCh, _Jab, _module, _Jab_name, _JCh_name 

1744 

1745CONVERSION_SPECIFICATIONS: list = [ 

1746 Conversion_Specification(*specification) 

1747 for specification in CONVERSION_SPECIFICATIONS_DATA 

1748] 

1749""" 

1750Automatic colour conversion graph specifications describing two nodes and 

1751the edge in the graph. 

1752""" 

1753 

1754CONVERSION_GRAPH_NODE_LABELS: dict = { 

1755 specification[0].lower(): specification[0] 

1756 for specification in CONVERSION_SPECIFICATIONS_DATA 

1757} 

1758"""Automatic colour conversion graph node labels.""" 

1759 

1760CONVERSION_GRAPH_NODE_LABELS.update( 

1761 { 

1762 specification[1].lower(): specification[1] 

1763 for specification in CONVERSION_SPECIFICATIONS_DATA 

1764 } 

1765) 

1766 

1767 

1768@required("NetworkX") 

1769def _build_graph() -> networkx.DiGraph: # pyright: ignore # noqa: F821 

1770 """ 

1771 Build the automatic colour conversion graph. 

1772 

1773 Returns 

1774 ------- 

1775 :class:`networkx.DiGraph` 

1776 Automatic colour conversion graph. 

1777 """ 

1778 

1779 import networkx as nx # noqa: PLC0415 

1780 

1781 graph = nx.DiGraph() 

1782 

1783 for specification in CONVERSION_SPECIFICATIONS: 

1784 graph.add_edge( 

1785 specification.source, 

1786 specification.target, 

1787 conversion_function=specification.conversion_function, 

1788 ) 

1789 

1790 return graph 

1791 

1792 

1793CONVERSION_GRAPH: nx.DiGraph | None = None # pyright: ignore # noqa: F821 

1794"""Automatic colour conversion graph.""" 

1795 

1796 

1797@required("NetworkX") 

1798def conversion_path(source: str, target: str) -> List[Callable]: 

1799 """ 

1800 Generate the conversion path from the source node to the target node in 

1801 the automatic colour conversion graph. 

1802 

1803 Parameters 

1804 ---------- 

1805 source 

1806 Source node. 

1807 target 

1808 Target node. 

1809 

1810 Returns 

1811 ------- 

1812 :class:`list` 

1813 Conversion path from the source node to the target node, i.e., a 

1814 list of conversion function callables. 

1815 

1816 Examples 

1817 -------- 

1818 >>> conversion_path("cie lab", "cct") 

1819 ... # doctest: +ELLIPSIS 

1820 [<function Lab_to_XYZ at 0x...>, <function XYZ_to_UCS at 0x...>, \ 

1821<function UCS_to_uv at 0x...>, <function uv_to_CCT at 0x...>] 

1822 """ 

1823 

1824 import networkx as nx # noqa: PLC0415 

1825 

1826 global CONVERSION_GRAPH # noqa: PLW0603 

1827 

1828 if CONVERSION_GRAPH is None: 

1829 # Updating the :attr:`CONVERSION_GRAPH` attributes. 

1830 colour.graph.CONVERSION_GRAPH = CONVERSION_GRAPH = _build_graph() 

1831 

1832 path = nx.shortest_path(cast("nx.DiGraph", CONVERSION_GRAPH), source, target) 

1833 

1834 return [ 

1835 CONVERSION_GRAPH.get_edge_data(a, b)["conversion_function"] # pyright: ignore 

1836 for a, b in itertools.pairwise(path) 

1837 ] 

1838 

1839 

1840def _lower_order_function(callable_: Callable) -> Callable: 

1841 """ 

1842 Extract the lower-order function from the specified callable, such as the 

1843 underlying function wrapped by a partial object. 

1844 

1845 Parameters 

1846 ---------- 

1847 callable_ 

1848 Callable from which to extract the lower-order function. 

1849 

1850 Returns 

1851 ------- 

1852 Callable 

1853 Lower-order function if the callable is a partial object, otherwise 

1854 the original callable. 

1855 """ 

1856 

1857 return callable_.func if isinstance(callable_, partial) else callable_ 

1858 

1859 

1860def describe_conversion_path( 

1861 source: str, 

1862 target: str, 

1863 mode: Literal["Short", "Long", "Extended"] | str = "Short", 

1864 width: int = 79, 

1865 padding: int = 3, 

1866 print_callable: Callable = print, 

1867 **kwargs: Any, 

1868) -> None: 

1869 """ 

1870 Describe the conversion path from the specified source colour 

1871 representation to the specified target colour representation using the 

1872 automatic colour conversion graph. 

1873 

1874 Parameters 

1875 ---------- 

1876 source 

1877 Source colour representation, i.e., the source node in the automatic 

1878 colour conversion graph. 

1879 target 

1880 Target colour representation, i.e., the target node in the automatic 

1881 colour conversion graph. 

1882 mode 

1883 Verbose mode: *Short* describes the conversion path, *Long* provides 

1884 details about the arguments, definitions signatures and output 

1885 values, *Extended* appends the definitions' documentation. 

1886 width 

1887 Message box width. 

1888 padding 

1889 Padding on each side of the message. 

1890 print_callable 

1891 Callable used to print the message box. 

1892 

1893 Other Parameters 

1894 ---------------- 

1895 kwargs 

1896 {:func:`colour.convert`}, 

1897 See the documentation of the previously listed definition. 

1898 

1899 Raises 

1900 ------ 

1901 ValueError 

1902 If the mode is not one of the supported values. 

1903 NetworkXNoPath 

1904 If no conversion path exists between the source and target colour 

1905 representations. 

1906 

1907 Examples 

1908 -------- 

1909 >>> describe_conversion_path("Spectral Distribution", "sRGB", width=75) 

1910 =========================================================================== 

1911 * * 

1912 * [ Conversion Path ] * 

1913 * * 

1914 * "sd_to_XYZ" --> "XYZ_to_sRGB" * 

1915 * * 

1916 =========================================================================== 

1917 """ 

1918 

1919 try: # pragma: no cover 

1920 signature_inspection = inspect.signature 

1921 except AttributeError: # pragma: no cover 

1922 signature_inspection = inspect.getfullargspec 

1923 

1924 source, target = source.lower(), target.lower() 

1925 mode = validate_method( 

1926 mode, 

1927 ("Short", "Long", "Extended"), 

1928 '"{0}" mode is invalid, it must be one of {1}!', 

1929 ) 

1930 

1931 width = (79 + 2 + 2 * 3 - 4) if mode == "extended" else width 

1932 

1933 conversion_functions = conversion_path(source, target) 

1934 

1935 joined_conversion_path = " --> ".join( 

1936 [ 

1937 f'"{_lower_order_function(conversion_function).__name__}"' 

1938 for conversion_function in conversion_functions 

1939 ] 

1940 ) 

1941 

1942 message_box( 

1943 f"[ Conversion Path ]\n\n{joined_conversion_path}", 

1944 width, 

1945 padding, 

1946 print_callable, 

1947 ) 

1948 

1949 for conversion_function in conversion_functions: 

1950 conversion_function_name = _lower_order_function(conversion_function).__name__ 

1951 

1952 # Filtering compatible keyword arguments passed directly and 

1953 # irrespective of any conversion function name. 

1954 filtered_kwargs = filter_kwargs(conversion_function, **kwargs) 

1955 

1956 # Filtering keyword arguments passed as dictionary with the 

1957 # conversion function name. 

1958 filtered_kwargs.update(kwargs.get(conversion_function_name, {})) 

1959 

1960 return_value = filtered_kwargs.pop("return", None) 

1961 

1962 if mode in ("long", "extended"): 

1963 signature = pformat( 

1964 signature_inspection(_lower_order_function(conversion_function)) 

1965 ) 

1966 message = ( 

1967 f'[ "{_lower_order_function(conversion_function).__name__}" ]\n\n' 

1968 f"[ Signature ]\n\n" 

1969 f"{signature}" 

1970 ) 

1971 

1972 if filtered_kwargs: 

1973 message += f"\n\n[ Filtered Arguments ]\n\n{pformat(filtered_kwargs)}" 

1974 

1975 if mode in ("extended",): 

1976 docstring = textwrap.dedent( 

1977 str(_lower_order_function(conversion_function).__doc__) 

1978 ).strip() 

1979 message += f"\n\n[ Documentation ]\n\n {docstring}" 

1980 

1981 if return_value is not None: 

1982 message += f"\n\n[ Conversion Output ]\n\n{return_value}" 

1983 

1984 message_box(message, width, padding, print_callable) 

1985 

1986 

1987def convert( 

1988 a: Any, 

1989 source: str, 

1990 target: str, 

1991 *, 

1992 from_reference_scale: bool = False, 

1993 to_reference_scale: bool = False, 

1994 **kwargs: Any, 

1995) -> Any: 

1996 """ 

1997 Convert specified object :math:`a` from source colour representation to 

1998 target colour representation using the automatic colour conversion 

1999 graph. 

2000 

2001 The conversion is performed by finding the shortest path in a 

2002 `NetworkX <https://networkx.github.io>`__ :class:`DiGraph` class 

2003 instance. 

2004 

2005 The conversion path adopts the **'1'** domain-range scale and the 

2006 object :math:`a` is expected to be *soft* normalised accordingly. For 

2007 example, *CIE XYZ* tristimulus values arguments for use with the 

2008 *CAM16* colour appearance model should be in domain `[0, 1]` instead 

2009 of the domain `[0, 100]` used with the **'Reference'** domain-range 

2010 scale. The arguments are typically converted as follows: 

2011 

2012 - *Scalars* in domain-range `[0, 10]`, e.g *Munsell Value* are 

2013 scaled by *10*. 

2014 - *Percentages* in domain-range `[0, 100]` are scaled by *100*. 

2015 - *Degrees* in domain-range `[0, 360]` are scaled by *360*. 

2016 - *Integers* in domain-range `[0, 2**n -1]` where `n` is the bit 

2017 depth are scaled by *2**n -1*. 

2018 

2019 The ``from_reference_scale`` and ``to_reference_scale`` parameters enable 

2020 automatic scaling of input and output values based on the scale metadata in 

2021 the function type annotations (PEP 593 ``Annotated`` hints). 

2022 

2023 See the `Domain-Range Scales <../basics.html#domain-range-scales>`__ 

2024 page for more information. 

2025 

2026 Parameters 

2027 ---------- 

2028 a 

2029 Object :math:`a` to convert. If :math:`a` represents a 

2030 reflectance, transmittance or absorptance value, the expectation 

2031 is that it is viewed under *CIE Standard Illuminant D Series* 

2032 *D65*. The illuminant can be changed on a per-definition basis 

2033 along the conversion path. 

2034 source 

2035 Source colour representation, i.e., the source node in the 

2036 automatic colour conversion graph. 

2037 target 

2038 Target colour representation, i.e., the target node in the 

2039 automatic colour conversion graph. 

2040 from_reference_scale 

2041 If *True*, the input value :math:`a` is assumed to be in reference 

2042 scale (e.g., [0, 100] for CIE XYZ) and will be automatically scaled 

2043 to scale-1 before conversion using the scale metadata from the first 

2044 conversion function's type annotations. 

2045 to_reference_scale 

2046 If *True*, the output value will be automatically scaled from scale-1 

2047 to reference scale (e.g., [0, 100] for CIE XYZ) after conversion using 

2048 the scale metadata from the last conversion function's type annotations. 

2049 

2050 Other Parameters 

2051 ---------------- 

2052 kwargs 

2053 See the documentation of the supported conversion definitions. 

2054 

2055 Arguments for the conversion definitions are passed as keyword 

2056 arguments whose names are those of the conversion definitions and 

2057 values set as dictionaries. For example, in the conversion from 

2058 spectral distribution to *sRGB* colourspace, passing arguments to 

2059 the :func:`colour.sd_to_XYZ` definition is done as follows:: 

2060 

2061 convert( 

2062 sd, 

2063 "Spectral Distribution", 

2064 "sRGB", 

2065 sd_to_XYZ={"illuminant": SDS_ILLUMINANTS["FL2"]}, 

2066 ) 

2067 

2068 It is also possible to pass keyword arguments directly to the 

2069 various conversion definitions irrespective of their name. This is 

2070 ``dangerous`` and could cause unexpected behaviour, consider the 

2071 following conversion:: 

2072 

2073 convert(sd, "Spectral Distribution", "sRGB", "illuminant": \ 

2074SDS_ILLUMINANTS["FL2"]) 

2075 

2076 Because both the :func:`colour.sd_to_XYZ` and 

2077 :func:`colour.XYZ_to_sRGB` definitions have an *illuminant* 

2078 argument, `SDS_ILLUMINANTS["FL2"]` will be passed to both of them 

2079 and will raise an exception in the :func:`colour.XYZ_to_sRGB` 

2080 definition. This will be addressed in the future by either 

2081 catching the exception and trying a new time without the keyword 

2082 argument or more elegantly via type checking. 

2083 

2084 With that in mind, this mechanism offers some good benefits: For 

2085 example, it allows defining a conversion from *CIE XYZ* 

2086 colourspace to *n* different colour models while passing an 

2087 illuminant argument but without having to explicitly define all 

2088 the explicit conversion definition arguments:: 

2089 

2090 a = np.array([0.20654008, 0.12197225, 0.05136952]) 

2091 illuminant = CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"]["D65"] 

2092 for model in ("CIE xyY", "CIE Lab"): 

2093 convert(a, "CIE XYZ", model, illuminant=illuminant) 

2094 

2095 Instead of:: 

2096 

2097 for model in ("CIE xyY", "CIE Lab"): 

2098 convert( 

2099 a, 

2100 "CIE XYZ", 

2101 model, 

2102 XYZ_to_xyY={"illuminant": illuminant}, 

2103 XYZ_to_Lab={"illuminant": illuminant}, 

2104 ) 

2105 

2106 Mixing both approaches is possible for the brevity benefits. It is 

2107 made possible because the keyword arguments directly passed are 

2108 filtered first and then the resulting dict is updated with the 

2109 explicit conversion definition arguments:: 

2110 

2111 illuminant = CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"]["D65"] 

2112 convert(sd, "Spectral Distribution", "sRGB", "illuminant": \ 

2113SDS_ILLUMINANTS["FL2"], XYZ_to_sRGB={"illuminant": illuminant}) 

2114 

2115 For inspection purposes, verbose is enabled by passing arguments 

2116 to the :func:`colour.describe_conversion_path` definition via the 

2117 ``verbose`` keyword argument as follows:: 

2118 

2119 convert(sd, "Spectral Distribution", "sRGB", verbose={"mode": "Long"}) 

2120 

2121 Returns 

2122 ------- 

2123 Any 

2124 Converted object :math:`a`. 

2125 

2126 Raises 

2127 ------ 

2128 NetworkXNoPath 

2129 If no conversion path exists between the source and target colour 

2130 representations. 

2131 

2132 Warnings 

2133 -------- 

2134 The domain-range scale is **'1'** and cannot be changed. 

2135 

2136 Notes 

2137 ----- 

2138 - The **RGB** colour representation is assumed to be linear and 

2139 representing *scene-referred* imagery, i.e., **Scene-Referred 

2140 RGB** representation. To encode such *RGB* values as 

2141 *output-referred* (*display-referred*) imagery, i.e., encode the 

2142 *RGB* values using an encoding colour component transfer function 

2143 (Encoding CCTF) / opto-electronic transfer function (OETF), the 

2144 **Output-Referred RGB** representation must be used:: 

2145 

2146 convert(RGB, "Scene-Referred RGB", "Output-Referred RGB") 

2147 

2148 Likewise, encoded *output-referred* *RGB* values can be decoded 

2149 with the **Scene-Referred RGB** representation:: 

2150 

2151 convert(RGB, "Output-Referred RGB", "Scene-Referred RGB") 

2152 

2153 - The following defaults have been adopted: 

2154 

2155 - The default illuminant for the computation is *CIE Standard 

2156 Illuminant D Series* *D65*. It can be changed on a 

2157 per-definition basis along the conversion path. Note that the 

2158 conversion from spectral to *CIE XYZ* tristimulus values 

2159 remains unchanged. 

2160 - The default *RGB* colourspace primaries and whitepoint are 

2161 that of the *BT.709*/*sRGB* colourspace. They can be changed 

2162 on a per-definition basis along the conversion path. 

2163 - When using **sRGB** as a source or target colour 

2164 representation, the convenient :func:`colour.sRGB_to_XYZ` and 

2165 :func:`colour.XYZ_to_sRGB` definitions are used, 

2166 respectively. Thus, decoding and encoding using the sRGB 

2167 electro-optical transfer function (EOTF) and its inverse will 

2168 be applied by default. 

2169 - Most of the colour appearance models have defaults set 

2170 according to *IEC 61966-2-1:1999* viewing conditions, i.e., 

2171 *sRGB* 64 Lux ambient illumination, 80 :math:`cd/m^2`, 

2172 adapting field luminance about 20% of a white object in the 

2173 scene. 

2174 

2175 Examples 

2176 -------- 

2177 >>> import numpy as np 

2178 >>> from colour import SDS_COLOURCHECKERS, SDS_ILLUMINANTS 

2179 >>> sd = SDS_COLOURCHECKERS["ColorChecker N Ohta"]["dark skin"] 

2180 >>> convert( 

2181 ... sd, 

2182 ... "Spectral Distribution", 

2183 ... "sRGB", 

2184 ... verbose={"mode": "Short", "width": 75}, 

2185 ... ) 

2186 ... # doctest: +ELLIPSIS 

2187 =========================================================================== 

2188 * * 

2189 * [ Conversion Path ] * 

2190 * * 

2191 * "sd_to_XYZ" --> "XYZ_to_sRGB" * 

2192 * * 

2193 =========================================================================== 

2194 array([ 0.4903477..., 0.3018587..., 0.2358768...]) 

2195 >>> illuminant = SDS_ILLUMINANTS["FL2"] 

2196 >>> convert( 

2197 ... sd, 

2198 ... "Spectral Distribution", 

2199 ... "sRGB", 

2200 ... sd_to_XYZ={"illuminant": illuminant}, 

2201 ... ) 

2202 ... # doctest: +ELLIPSIS 

2203 array([ 0.4792457..., 0.3167696..., 0.1736272...]) 

2204 >>> a = np.array([0.45675795, 0.30986982, 0.24861924]) 

2205 >>> convert(a, "Output-Referred RGB", "CAM16UCS") 

2206 ... # doctest: +ELLIPSIS 

2207 array([ 0.3999481..., 0.0920655..., 0.0812752...]) 

2208 >>> a = np.array([0.39994811, 0.09206558, 0.08127526]) 

2209 >>> convert(a, "CAM16UCS", "sRGB", verbose={"mode": "Short", "width": 75}) 

2210 ... # doctest: +ELLIPSIS 

2211 =========================================================================== 

2212 * * 

2213 * [ Conversion Path ] * 

2214 * * 

2215 * "UCS_Li2017_to_JMh_CAM16" --> "JMh_CAM16_to_CAM16" --> * 

2216 * "CAM16_to_XYZ" --> "XYZ_to_sRGB" * 

2217 * * 

2218 =========================================================================== 

2219 array([ 0.4567576..., 0.3098826..., 0.2486222...]) 

2220 """ 

2221 

2222 source, target = source.lower(), target.lower() 

2223 

2224 conversion_path_list = conversion_path(source, target) 

2225 

2226 verbose_kwargs = copy(kwargs) 

2227 for i, conversion_function in enumerate(conversion_path_list): 

2228 conversion_function_name = _lower_order_function(conversion_function).__name__ 

2229 

2230 # Scale input from reference to scale-1 on first iteration 

2231 if i == 0 and from_reference_scale: 

2232 metadata = get_domain_range_scale_metadata( 

2233 _lower_order_function(conversion_function) 

2234 ) 

2235 if ( 

2236 metadata["domain"] 

2237 and (scale := next(iter(metadata["domain"].values()))) is not None 

2238 ): 

2239 a = a / as_float_array(scale) 

2240 

2241 # Filtering compatible keyword arguments passed directly and 

2242 # irrespective of any conversion function name. 

2243 filtered_kwargs = filter_kwargs(conversion_function, **kwargs) 

2244 

2245 # Filtering keyword arguments passed as dictionary with the 

2246 # conversion function name. 

2247 filtered_kwargs.update(kwargs.get(conversion_function_name, {})) 

2248 

2249 with domain_range_scale("1"): 

2250 a = conversion_function(a, **filtered_kwargs) 

2251 

2252 # Scale output from scale-1 to reference on last iteration 

2253 if i == len(conversion_path_list) - 1 and to_reference_scale: 

2254 metadata = get_domain_range_scale_metadata( 

2255 _lower_order_function(conversion_function) 

2256 ) 

2257 if (scale := metadata["range"]) is not None: 

2258 a = a * as_float_array(scale) 

2259 

2260 if conversion_function_name in verbose_kwargs: 

2261 verbose_kwargs[conversion_function_name]["return"] = a 

2262 else: 

2263 verbose_kwargs[conversion_function_name] = {"return": a} 

2264 

2265 if "verbose" in verbose_kwargs: 

2266 verbose_kwargs.update(verbose_kwargs.pop("verbose")) 

2267 describe_conversion_path(source, target, **verbose_kwargs) 

2268 

2269 return a