Coverage for /usr/lib/python3/dist-packages/colorzero/deltae.py: 14%

53 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2024-02-10 12:38 +0000

1# vim: set et sw=4 sts=4 fileencoding=utf-8: 

2# 

3# The colorzero color library 

4# Copyright (c) 2016-2018 Dave Jones <dave@waveform.org.uk> 

5# 

6# Redistribution and use in source and binary forms, with or without 

7# modification, are permitted provided that the following conditions are met: 

8# 

9# * Redistributions of source code must retain the above copyright 

10# notice, this list of conditions and the following disclaimer. 

11# * Redistributions in binary form must reproduce the above copyright 

12# notice, this list of conditions and the following disclaimer in the 

13# documentation and/or other materials provided with the distribution. 

14# * Neither the name of the copyright holder nor the 

15# names of its contributors may be used to endorse or promote products 

16# derived from this software without specific prior written permission. 

17# 

18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 

19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 

20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 

21# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 

22# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 

23# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 

24# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

25# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 

26# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 

27# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 

28# POSSIBILITY OF SUCH DAMAGE. 

29 

30"Defines the various algorithms for :meth:`Color.difference`." 

31 

32from __future__ import ( 

33 unicode_literals, 

34 print_function, 

35 division, 

36 absolute_import, 

37) 

38 

39from math import sqrt, atan2, degrees, radians, sin, cos, exp 

40 

41# Lots of the delta-e functions use single character parameter names and 

42# variables internally; this is is normal and in keeping with most of the 

43# referenced sources 

44# pylint: disable=invalid-name 

45 

46 

47def euclid(color1, color2): 

48 """ 

49 Calculates color difference as a simple `Euclidean distance`_ by treating 

50 the three components as spatial dimensions. 

51 

52 .. note:: 

53 

54 This function will return considerably different values to the other 

55 difference functions. In particular, the maximum "difference" will 

56 be √3 which is much smaller than the output of the CIE functions. 

57 

58 .. _Euclidean distance: https://en.wikipedia.org/wiki/Euclidean_distance 

59 """ 

60 return sqrt(sum((e1 - e2) ** 2 for e1, e2 in zip(color1, color2))) 

61 

62 

63def cie1976(color1, color2): 

64 """ 

65 Calculates color difference according to the `CIE 1976`_ formula. 

66 Effectively this is the Euclidean formula, but with CIE L*a*b* components 

67 instead of RGB. 

68 

69 .. _CIE 1976: https://en.wikipedia.org/wiki/Color_difference#CIE76 

70 """ 

71 return sqrt(sum((e1 - e2) ** 2 for e1, e2 in zip(color1, color2))) 

72 

73 

74def cie1994(color1, color2, method): 

75 """ 

76 Calculates color difference according to the `CIE 1994`_ formula. The 

77 *method* can be either "cie1994g" for the "graphical" biases, or "cie1994t" 

78 for the "textile" biases. The CIE1994 is also basically the Euclidean 

79 formula (with biases) but in CIE L*C*H* space. 

80 

81 .. _CIE 1994: https://en.wikipedia.org/wiki/Color_difference#CIE94 

82 """ 

83 C1 = sqrt(color1.a ** 2 + color1.b ** 2) 

84 C2 = sqrt(color2.a ** 2 + color2.b ** 2) 

85 

86 dL = color1.l - color2.l 

87 dC = C1 - C2 

88 # Don't bother with the sqrt here as due to limited float precision 

89 # we can wind up with a domain error (because the value is ever so 

90 # slightly negative - try it with black'n'white for an example), and we're 

91 # just going to square the result in the final equation anyway 

92 dH2 = (color1.a - color2.a) ** 2 + (color1.b - color2.b) ** 2 - dC ** 2 

93 

94 kL, K1, K2 = { 

95 'cie1994g': (1, 0.045, 0.015), 

96 'cie1994t': (2, 0.048, 0.014), 

97 }[method] 

98 SC = 1 + K1 * C1 

99 SH = 1 + K2 * C1 

100 return sqrt( 

101 (dL / kL) ** 2 + 

102 (dC / SC) ** 2 + 

103 (dH2 / SH ** 2) 

104 ) 

105 

106 

107def cie1994g(color1, color2): 

108 """ 

109 Calculates color difference according to the `CIE 1994`_ formula with the 

110 "textile" bias. See :func:`cie1994` for further information. 

111 

112 .. _CIE 1994: https://en.wikipedia.org/wiki/Color_difference#CIE94 

113 """ 

114 return cie1994(color1, color2, 'cie1994g') 

115 

116 

117def cie1994t(color1, color2): 

118 """ 

119 Calculates color difference according to the `CIE 1994`_ formula with the 

120 "graphics" bias. See :func:`cie1994` for further information. 

121 

122 .. _CIE 1994: https://en.wikipedia.org/wiki/Color_difference#CIE94 

123 """ 

124 return cie1994(color1, color2, 'cie1994t') 

125 

126 

127def ciede2000(color1, color2): 

128 """ 

129 Calculates color difference according to the `CIEDE 2000`_ formula. This is 

130 the most accurate algorithm currently implemented but also the most complex 

131 and slowest. Like CIE1994 it is largely based in CIE L*C*h* space, but with 

132 several modifications to account for perceptual uniformity flaws. 

133 

134 .. _CIEDE 2000: https://en.wikipedia.org/wiki/Color_difference#CIEDE2000 

135 """ 

136 # See WP article and Sharma 2005 for important implementation notes: 

137 # http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf 

138 # 

139 # Yes, there's lots of locals; but this is easiest to understand as it's a 

140 # near straight translation of the math 

141 # pylint: disable=too-many-locals 

142 

143 C_ = ( 

144 sqrt(color1.a ** 2 + color1.b ** 2) + 

145 sqrt(color2.a ** 2 + color2.b ** 2) 

146 ) / 2 

147 

148 G = (1 - sqrt(C_ ** 7 / (C_ ** 7 + 25 ** 7))) / 2 

149 a1_prime = (1 + G) * color1.a 

150 a2_prime = (1 + G) * color2.a 

151 

152 C1_prime = sqrt(a1_prime ** 2 + color1.b ** 2) 

153 C2_prime = sqrt(a2_prime ** 2 + color2.b ** 2) 

154 L_ = (color1.l + color2.l) / 2 

155 C_ = (C1_prime + C2_prime) / 2 

156 

157 h1 = ( 

158 0.0 if color1.b == a1_prime == 0 else 

159 degrees(atan2(color1.b, a1_prime)) % 360 

160 ) 

161 h2 = ( 

162 0.0 if color2.b == a2_prime == 0 else 

163 degrees(atan2(color2.b, a2_prime)) % 360 

164 ) 

165 if C1_prime * C2_prime == 0.0: 

166 dh = 0.0 

167 h_ = h1 + h2 

168 elif abs(h1 - h2) <= 180: 

169 dh = h2 - h1 

170 h_ = (h1 + h2) / 2 

171 else: 

172 if h2 > h1: 

173 dh = h2 - h1 - 360 

174 else: 

175 dh = h2 - h1 + 360 

176 if h1 + h2 >= 360: 

177 h_ = (h1 + h2 - 360) / 2 

178 else: 

179 h_ = (h1 + h2 + 360) / 2 

180 

181 dL = color2.l - color1.l 

182 dC = C2_prime - C1_prime 

183 dH = 2 * sqrt(C1_prime * C2_prime) * sin(radians(dh / 2)) 

184 

185 T = ( 

186 1 - 

187 0.17 * cos(radians(h_ - 30)) + 

188 0.24 * cos(radians(2 * h_)) + 

189 0.32 * cos(radians(3 * h_ + 6)) - 

190 0.20 * cos(radians(4 * h_ - 63)) 

191 ) 

192 SL = 1 + (0.015 * (L_ - 50) ** 2) / sqrt(20 + (L_ - 50) ** 2) 

193 SC = 1 + 0.045 * C_ 

194 SH = 1 + 0.015 * C_ * T 

195 RT = ( 

196 -2 * sqrt(C_ ** 7 / (C_ ** 7 + 25 ** 7)) * 

197 sin(radians(60 * exp(-(((h_ - 275) / 25) ** 2)))) 

198 ) 

199 

200 return sqrt( 

201 (dL / SL) ** 2 + 

202 (dC / SC) ** 2 + 

203 (dH / SH) ** 2 + 

204 RT * (dC / SC) * (dH / SH) 

205 )