-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhelpers.py
152 lines (114 loc) · 4.36 KB
/
helpers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim: fenc=utf-8 ts=4 sw=4 et
import math
# Taken from https://stackoverflow.com/a/16020102
def rgb2lab ( inputColor ) :
num = 0
RGB = [0, 0, 0]
for value in inputColor :
value = float(value) / 255
if value > 0.04045 :
value = ( ( value + 0.055 ) / 1.055 ) ** 2.4
else :
value = value / 12.92
RGB[num] = value * 100
num = num + 1
XYZ = [0, 0, 0,]
X = RGB [0] * 0.4124 + RGB [1] * 0.3576 + RGB [2] * 0.1805
Y = RGB [0] * 0.2126 + RGB [1] * 0.7152 + RGB [2] * 0.0722
Z = RGB [0] * 0.0193 + RGB [1] * 0.1192 + RGB [2] * 0.9505
XYZ[ 0 ] = round( X, 4 )
XYZ[ 1 ] = round( Y, 4 )
XYZ[ 2 ] = round( Z, 4 )
XYZ[ 0 ] = float( XYZ[ 0 ] ) / 95.047 # ref_X = 95.047 Observer= 2°, Illuminant= D65
XYZ[ 1 ] = float( XYZ[ 1 ] ) / 100.0 # ref_Y = 100.000
XYZ[ 2 ] = float( XYZ[ 2 ] ) / 108.883 # ref_Z = 108.883
num = 0
for value in XYZ :
if value > 0.008856 :
value = value ** ( 1/3 )
else :
value = ( 7.787 * value ) + ( 16 / 116 )
XYZ[num] = value
num = num + 1
Lab = [0, 0, 0]
L = ( 116 * XYZ[ 1 ] ) - 16
a = 500 * ( XYZ[ 0 ] - XYZ[ 1 ] )
b = 200 * ( XYZ[ 1 ] - XYZ[ 2 ] )
Lab [ 0 ] = round( L, 4 )
Lab [ 1 ] = round( a, 4 )
Lab [ 2 ] = round( b, 4 )
return Lab
# Copyright to https://github.com/lovro-i/CIEDE2000.
def ciede2000(Lab_1, Lab_2):
"""Calculates CIEDE2000 color distance between two CIE L*a*b* colors."""
C_25_7 = 6103515625 # 25**7
L1, a1, b1 = Lab_1[0], Lab_1[1], Lab_1[2]
L2, a2, b2 = Lab_2[0], Lab_2[1], Lab_2[2]
C1 = math.sqrt(a1**2 + b1**2)
C2 = math.sqrt(a2**2 + b2**2)
C_ave = (C1 + C2) / 2
G = 0.5 * (1 - math.sqrt(C_ave**7 / (C_ave**7 + C_25_7)))
L1_, L2_ = L1, L2
a1_, a2_ = (1 + G) * a1, (1 + G) * a2
b1_, b2_ = b1, b2
C1_ = math.sqrt(a1_**2 + b1_**2)
C2_ = math.sqrt(a2_**2 + b2_**2)
if b1_ == 0 and a1_ == 0: h1_ = 0
elif a1_ >= 0: h1_ = math.atan2(b1_, a1_)
else: h1_ = math.atan2(b1_, a1_) + 2 * math.pi
if b2_ == 0 and a2_ == 0: h2_ = 0
elif a2_ >= 0: h2_ = math.atan2(b2_, a2_)
else: h2_ = math.atan2(b2_, a2_) + 2 * math.pi
dL_ = L2_ - L1_
dC_ = C2_ - C1_
dh_ = h2_ - h1_
if C1_ * C2_ == 0: dh_ = 0
elif dh_ > math.pi: dh_ -= 2 * math.pi
elif dh_ < -math.pi: dh_ += 2 * math.pi
dH_ = 2 * math.sqrt(C1_ * C2_) * math.sin(dh_ / 2)
L_ave = (L1_ + L2_) / 2
C_ave = (C1_ + C2_) / 2
_dh = abs(h1_ - h2_)
_sh = h1_ + h2_
C1C2 = C1_ * C2_
if _dh <= math.pi and C1C2 != 0: h_ave = (h1_ + h2_) / 2
elif _dh > math.pi and _sh < 2 * math.pi and C1C2 != 0: h_ave = (h1_ + h2_) / 2 + math.pi
elif _dh > math.pi and _sh >= 2 * math.pi and C1C2 != 0: h_ave = (h1_ + h2_) / 2 - math.pi
else: h_ave = h1_ + h2_
T = 1 - 0.17 * math.cos(h_ave - math.pi / 6) + 0.24 * math.cos(2 * h_ave) + 0.32 * math.cos(3 * h_ave + math.pi / 30) - 0.2 * math.cos(4 * h_ave - 63 * math.pi / 180)
h_ave_deg = h_ave * 180 / math.pi
if h_ave_deg < 0: h_ave_deg += 360
elif h_ave_deg > 360: h_ave_deg -= 360
dTheta = 30 * math.exp(-(((h_ave_deg - 275) / 25)**2))
R_C = 2 * math.sqrt(C_ave**7 / (C_ave**7 + C_25_7))
S_C = 1 + 0.045 * C_ave
S_H = 1 + 0.015 * C_ave * T
Lm50s = (L_ave - 50)**2
S_L = 1 + 0.015 * Lm50s / math.sqrt(20 + Lm50s)
R_T = -math.sin(dTheta * math.pi / 90) * R_C
k_L, k_C, k_H = 1, 1, 1
f_L = dL_ / k_L / S_L
f_C = dC_ / k_C / S_C
f_H = dH_ / k_H / S_H
dE_00 = math.sqrt(f_L**2 + f_C**2 + f_H**2 + R_T * f_C * f_H)
return dE_00
def get_closest_color(rgb,cp):
"""
Get the closest color of a BGR color using CIEDE2000 distance.
:param bgr tuple: The BGR color to use.
:returns: dict
"""
lab = rgb2lab(rgb)
distances = []
for color_name, color_rgb in cp.items():
distances.append({
'color_name': color_name,
'color_rgb': color_rgb,
'distance': ciede2000(lab, rgb2lab(color_rgb))
})
#print(distances)
closest = min(distances, key=lambda item: item['distance'])
#print(closest)
return closest