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

36 statements  

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

1""" 

2Apple Log Profile Log Encoding 

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

4 

5Define the *Apple Log Profile* log encoding. 

6 

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

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

9 

10References 

11---------- 

12- :cite:`AppleInc.2023` : Apple Inc. (2023). Apple Log Profile White Paper. 

13 https://developer.apple.com/download/all/?q=Apple%20log%20profile 

14- :cite:`TheAcademyofMotionPictureArtsandSciences2023` : The Academy of 

15 Motion Picture Arts and Sciences. (2023). IDT.Apple.AppleLog_BT2020.ctl. 

16 Retrieved December 17, 2023, from 

17 https://github.com/ampas/aces-dev/blob/\ 

18528c78fe2c0f4e7eb322581e98aba05de79466cb/transforms/ctl/idt/vendorSupplied/\ 

19apple/IDT.Apple.AppleLog_BT2020.ctl 

20 

21""" 

22 

23from __future__ import annotations 

24 

25import numpy as np 

26 

27from colour.hints import ( # noqa: TC001 

28 Domain1, 

29 Range1, 

30) 

31from colour.utilities import Structure, as_float, from_range_1, optional, to_domain_1 

32 

33__author__ = "Colour Developers" 

34__copyright__ = "Copyright 2013 Colour Developers" 

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

36__maintainer__ = "Colour Developers" 

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

38__status__ = "Production" 

39 

40__all__ = [ 

41 "CONSTANTS_APPLE_LOG_PROFILE", 

42 "log_encoding_AppleLogProfile", 

43 "log_decoding_AppleLogProfile", 

44] 

45 

46CONSTANTS_APPLE_LOG_PROFILE: Structure = Structure( 

47 R_0=-0.05641088, 

48 R_t=0.01, 

49 sigma=47.28711236, 

50 beta=0.00964052, 

51 gamma=0.08550479, 

52 delta=0.69336945, 

53) 

54"""*Apple Log Profile* constants.""" 

55 

56 

57def log_encoding_AppleLogProfile( 

58 R: Domain1, 

59 constants: Structure | None = None, 

60) -> Range1: 

61 """ 

62 Apply the *Apple Log Profile* log encoding opto-electronic transfer function (OETF). 

63 

64 Parameters 

65 ---------- 

66 R 

67 Linear reflection data :math:`R`. 

68 constants 

69 *Apple Log Profile* constants. 

70 

71 Returns 

72 ------- 

73 :class:`numpy.ndarray` 

74 Logarithmically encoded value :math:`P`. 

75 

76 References 

77 ---------- 

78 :cite:`AppleInc.2023`, 

79 :cite:`TheAcademyofMotionPictureArtsandSciences2023` 

80 

81 Notes 

82 ----- 

83 - The scene reflection signal :math:`R` captured by the camera is 

84 represented using a floating point encoding. The :math:`R` value 

85 of 0.18 corresponds to the signal produced by an 18% reflectance 

86 reference gray chart. 

87 

88 +------------+-----------------------+---------------+ 

89 | **Domain** | **Scale - Reference** | **Scale - 1** | 

90 +============+=======================+===============+ 

91 | ``R`` | 1 | 1 | 

92 +------------+-----------------------+---------------+ 

93 

94 +------------+-----------------------+---------------+ 

95 | **Range** | **Scale - Reference** | **Scale - 1** | 

96 +============+=======================+===============+ 

97 | ``P`` | 1 | 1 | 

98 +------------+-----------------------+---------------+ 

99 

100 Examples 

101 -------- 

102 >>> log_encoding_AppleLogProfile(0.18) # doctest: +ELLIPSIS 

103 0.4882724... 

104 """ 

105 

106 R = to_domain_1(R) 

107 constants = optional(constants, CONSTANTS_APPLE_LOG_PROFILE) 

108 

109 R_0 = constants.R_0 

110 R_t = constants.R_t 

111 sigma = constants.sigma 

112 beta = constants.beta 

113 gamma = constants.gamma 

114 delta = constants.delta 

115 

116 P = np.select( 

117 [ 

118 R >= R_t, # noqa: SIM300 

119 np.logical_and(R_0 <= R, R < R_t), # noqa: SIM300 

120 R < R_0, 

121 ], 

122 [ 

123 gamma * np.log2(R + beta) + delta, 

124 sigma * (R - R_0) ** 2, 

125 0, 

126 ], 

127 ) 

128 

129 return as_float(from_range_1(P)) 

130 

131 

132def log_decoding_AppleLogProfile( 

133 P: Domain1, 

134 constants: Structure | None = None, 

135) -> Range1: 

136 """ 

137 Apply the *Apple Log Profile* log decoding inverse opto-electronic transfer 

138 function (OETF). 

139 

140 Parameters 

141 ---------- 

142 P 

143 Logarithmically encoded value :math:`P`. 

144 constants 

145 *Apple Log Profile* constants. 

146 

147 Returns 

148 ------- 

149 :class:`numpy.ndarray` 

150 Linear reflection data :math:`R`. 

151 

152 References 

153 ---------- 

154 :cite:`AppleInc.2023`, 

155 :cite:`TheAcademyofMotionPictureArtsandSciences2023` 

156 

157 Notes 

158 ----- 

159 - The captured pixel :math:`P` value uses floating point encoding 

160 normalized to the [0, 1] range. 

161 

162 +------------+-----------------------+---------------+ 

163 | **Domain** | **Scale - Reference** | **Scale - 1** | 

164 +============+=======================+===============+ 

165 | ``P`` | 1 | 1 | 

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

167 

168 +------------+-----------------------+---------------+ 

169 | **Range** | **Scale - Reference** | **Scale - 1** | 

170 +============+=======================+===============+ 

171 | ``R`` | 1 | 1 | 

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

173 

174 Examples 

175 -------- 

176 >>> log_decoding_AppleLogProfile(0.48827245852686763) # doctest: +ELLIPSIS 

177 0.1800000... 

178 """ 

179 

180 P = to_domain_1(P) 

181 constants = optional(constants, CONSTANTS_APPLE_LOG_PROFILE) 

182 

183 R_0 = constants.R_0 

184 R_t = constants.R_t 

185 sigma = constants.sigma 

186 beta = constants.beta 

187 gamma = constants.gamma 

188 delta = constants.delta 

189 

190 P_t = sigma * (R_t - R_0) ** 2 

191 

192 R = np.select( 

193 [ 

194 P >= P_t, # noqa: SIM300 

195 np.logical_and(0 <= P, P < P_t), # noqa: SIM300 

196 P < 0, 

197 ], 

198 [ 

199 2 ** ((P - delta) / gamma) - beta, 

200 np.sqrt(P / sigma) + R_0, 

201 R_0, 

202 ], 

203 ) 

204 

205 return as_float(from_range_1(R))