Coverage for models/rgb/transfer_functions/gamma.py: 43%

1"""

2 Gamma Colour Component Transfer Function

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

4

5 Define the gamma encoding / decoding colour component transfer function

6 related objects.

7

8- :func:`colour.gamma_function`

9"""

10

11 from __future__ import annotations

12

13 import typing

14

15 import numpy as np

16

17 from colour.algebra import spow

18

19 if typing.TYPE_CHECKING:

20 from colour.hints import ArrayLike, Literal, NDArrayFloat

21

22 from colour.utilities import as_float, as_float_array, validate_method

23

24 __author__ = "Colour Developers"

25 __copyright__ = "Copyright 2013 Colour Developers"

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

27 __maintainer__ = "Colour Developers"

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

29 __status__ = "Production"

30

31 __all__ = [

32 "gamma_function",

33]

34

35

36 def gamma_function(

37 a: ArrayLike,

38 exponent: ArrayLike = 1,

39 negative_number_handling: (

40 Literal["Clamp", "Indeterminate", "Mirror", "Preserve"] | str

41 ) = "Indeterminate",

42) -> NDArrayFloat:

43 """

44 Apply a gamma encoding or decoding transformation to the specified array.

45

46 Parameters

47 ----------

48 a

49 Array to encode or decode.

50 exponent

51 Encoding or decoding exponent.

52 negative_number_handling

53 Behaviour for ``a`` negative numbers and the definition return

54 value:

55

56 - *Indeterminate*: The behaviour will be indeterminate and the

57 definition return value might contain *nans*.

58 - *Mirror*: The definition return value will be mirrored around

59 the abscissa and ordinate axes, i.e., Blackmagic Design:

60 Davinci Resolve behaviour.

61 - *Preserve*: The definition will preserve any negative number

62 in ``a``, i.e., The Foundry Nuke behaviour.

63 - *Clamp*: The definition will clamp any negative number in

64 ``a`` to 0.

65

66 Returns

67 -------

68 :class:`numpy.ndarray`

69 Encoded or decoded array.

70

71 Examples

72 --------

73 >>> gamma_function(0.18, 2.2) # doctest: +ELLIPSIS

74 0.0229932...

75 >>> gamma_function(-0.18, 2.0) # doctest: +ELLIPSIS

76 0.0323999...

77 >>> gamma_function(-0.18, 2.2)

78 nan

79 >>> gamma_function(-0.18, 2.2, "Mirror") # doctest: +ELLIPSIS

80 -0.0229932...

81 >>> gamma_function(-0.18, 2.2, "Preserve") # doctest: +ELLIPSIS

82 -0.1...

83 >>> gamma_function(-0.18, 2.2, "Clamp") # doctest: +ELLIPSIS

84 0.0

85 """

86

87 a = as_float_array(a)

88 exponent = as_float_array(exponent)

89 negative_number_handling = validate_method(

90 negative_number_handling,

91 ("Indeterminate", "Mirror", "Preserve", "Clamp"),

92 '"{0}" negative number handling is invalid, it must be one of {1}!',

93 )

94

95 if negative_number_handling == "indeterminate":

96 return as_float(a**exponent)

97

98 if negative_number_handling == "mirror":

99 return spow(a, exponent)

100

101 if negative_number_handling == "preserve":

102 return as_float(np.where(a <= 0, a, a**exponent))

103

104 # negative_number_handling == 'clamp':

105 return as_float(np.where(a <= 0, 0, a**exponent))