mirror of
https://github.com/oddluck/limnoria-plugins.git
synced 2025-05-02 00:11:08 -05:00
much faster cie2000 function, no dither by default
This commit is contained in:
parent
42afb01ec5
commit
acf51a5b2f
134
ASCII/plugin.py
134
ASCII/plugin.py
@ -368,56 +368,79 @@ class ASCII(callbacks.Plugin):
|
||||
Lab [ 2 ] = round( b, 4 )
|
||||
return Lab
|
||||
|
||||
def cie_de_2000(self, lab1,lab2,k_L=1,k_C=1,k_H=1):
|
||||
L_1_star,a_1_star,b_1_star=lab1
|
||||
L_2_star,a_2_star,b_2_star=lab2
|
||||
C_1_star=np.sqrt(np.power(a_1_star,2)+np.power(b_1_star,2))
|
||||
C_2_star=np.sqrt(np.power(a_2_star,2)+np.power(b_2_star,2))
|
||||
C_bar_star=np.average([C_1_star,C_2_star])
|
||||
G=0.5*(1-np.sqrt(np.power(C_bar_star,7)/(np.power(C_bar_star,7)+np.power(25,7))))
|
||||
a_1_dash=(1+G)*a_1_star
|
||||
a_2_dash=(1+G)*a_2_star
|
||||
C_1_dash=np.sqrt(np.power(a_1_dash,2)+np.power(b_1_star,2))
|
||||
C_2_dash=np.sqrt(np.power(a_2_dash,2)+np.power(b_2_star,2))
|
||||
h_1_dash=np.degrees(np.arctan2(b_1_star,a_1_dash))
|
||||
h_1_dash += (h_1_dash < 0) * 360
|
||||
h_2_dash=np.degrees(np.arctan2(b_2_star,a_2_dash))
|
||||
h_2_dash += (h_2_dash < 0) * 360
|
||||
delta_L_dash=L_2_star-L_1_star
|
||||
delta_C_dash=C_2_dash-C_1_dash
|
||||
delta_h_dash=0.0
|
||||
if(C_1_dash*C_2_dash):
|
||||
if(np.fabs(h_2_dash-h_1_dash)<=180):
|
||||
delta_h_dash=h_2_dash-h_1_dash
|
||||
elif(h_2_dash-h_1_dash>180):
|
||||
delta_h_dash=(h_2_dash-h_1_dash)-360
|
||||
elif(h_2_dash-h_1_dash)<-180:
|
||||
delta_h_dash=(h_2_dash-h_1_dash)+360
|
||||
delta_H_dash=2*np.sqrt(C_1_dash*C_2_dash)*np.sin(np.radians(delta_h_dash)/2.0)
|
||||
L_bar_dash=np.average([L_1_star,L_2_star])
|
||||
C_bar_dash=np.average([C_1_dash,C_2_dash])
|
||||
h_bar_dash=h_1_dash+h_2_dash
|
||||
if(C_1_dash*C_2_dash):
|
||||
if(np.fabs(h_1_dash-h_2_dash)<=180):
|
||||
h_bar_dash=np.average([h_1_dash,h_2_dash])
|
||||
def ciede2000(self, color1, color2):
|
||||
"""
|
||||
Calculates color difference according to the `CIEDE 2000`_ formula. This is
|
||||
the most accurate algorithm currently implemented but also the most complex
|
||||
and slowest. Like CIE1994 it is largely based in CIE L*C*h* space, but with
|
||||
several modifications to account for perceptual uniformity flaws.
|
||||
.. _CIEDE 2000: https://en.wikipedia.org/wiki/Color_difference#CIEDE2000
|
||||
"""
|
||||
# See WP article and Sharma 2005 for important implementation notes:
|
||||
# http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf
|
||||
#
|
||||
# Yes, there's lots of locals; but this is easiest to understand as it's a
|
||||
# near straight translation of the math
|
||||
# pylint: disable=too-many-locals
|
||||
C_ = (
|
||||
math.sqrt(color1[1] ** 2 + color1[2] ** 2) +
|
||||
math.sqrt(color2[1] ** 2 + color2[2] ** 2)
|
||||
) / 2
|
||||
|
||||
G = (1 - math.sqrt(C_ ** 7 / (C_ ** 7 + 25 ** 7))) / 2
|
||||
a1_prime = (1 + G) * color1[1]
|
||||
a2_prime = (1 + G) * color2[1]
|
||||
C1_prime = math.sqrt(a1_prime ** 2 + color1[2] ** 2)
|
||||
C2_prime = math.sqrt(a2_prime ** 2 + color2[2] ** 2)
|
||||
L_ = (color1[0] + color2[0]) / 2
|
||||
C_ = (C1_prime + C2_prime) / 2
|
||||
h1 = (
|
||||
0.0 if color1[2] == a1_prime == 0 else
|
||||
math.degrees(math.atan2(color1[2], a1_prime)) % 360
|
||||
)
|
||||
h2 = (
|
||||
0.0 if color2[2] == a2_prime == 0 else
|
||||
math.degrees(math.atan2(color2[2], a2_prime)) % 360
|
||||
)
|
||||
if C1_prime * C2_prime == 0.0:
|
||||
dh = 0.0
|
||||
h_ = h1 + h2
|
||||
elif abs(h1 - h2) <= 180:
|
||||
dh = h2 - h1
|
||||
h_ = (h1 + h2) / 2
|
||||
else:
|
||||
if h2 > h1:
|
||||
dh = h2 - h1 - 360
|
||||
else:
|
||||
if(h_1_dash+h_2_dash)<360:
|
||||
h_bar_dash=(h_1_dash+h_2_dash+360)/2
|
||||
else:
|
||||
h_bar_dash=(h_1_dash+h_2_dash-360)/2
|
||||
T=1-0.17*np.cos(np.radians(h_bar_dash-30))+0.24*np.cos(np.radians(2*h_bar_dash))\
|
||||
+0.32*np.cos(np.radians(3*h_bar_dash+6))-0.20*np.cos(np.radians(4*h_bar_dash-63))
|
||||
delta_theta=30 * np.exp(- np.power( (h_bar_dash-275) / 25, 2))
|
||||
R_c=2*np.sqrt( np.power(C_bar_dash,7) / (np.power(C_bar_dash,7)+np.power(25,7)) )
|
||||
S_L=1+((0.015*np.power(L_bar_dash-50,2))/np.sqrt(20+np.power(L_bar_dash-50,2)))
|
||||
S_C=1+0.045*C_bar_dash
|
||||
S_H=1+0.015*C_bar_dash*T
|
||||
R_T=-R_c * np.sin(2*np.radians(delta_theta))
|
||||
delta_e=np.sqrt(np.power(delta_L_dash/(k_L*S_L),2)+\
|
||||
np.power(delta_C_dash/(k_C*S_C),2)+\
|
||||
np.power(delta_H_dash/(k_H*S_H),2)+\
|
||||
R_T*(delta_C_dash/(k_C*S_C))*(delta_H_dash/(k_H*S_H))\
|
||||
)
|
||||
dh = h2 - h1 + 360
|
||||
if h1 + h2 >= 360:
|
||||
h_ = (h1 + h2 - 360) / 2
|
||||
else:
|
||||
h_ = (h1 + h2 + 360) / 2
|
||||
|
||||
dL = color2[0] - color1[0]
|
||||
dC = C2_prime - C1_prime
|
||||
dH = 2 * math.sqrt(C1_prime * C2_prime) * math.sin(math.radians(dh / 2))
|
||||
T = (
|
||||
1 -
|
||||
0.17 * math.cos(math.radians(h_ - 30)) +
|
||||
0.24 * math.cos(math.radians(2 * h_)) +
|
||||
0.32 * math.cos(math.radians(3 * h_ + 6)) -
|
||||
0.20 * math.cos(math.radians(4 * h_ - 63))
|
||||
)
|
||||
SL = 1 + (0.015 * (L_ - 50) ** 2) / math.sqrt(20 + (L_ - 50) ** 2)
|
||||
SC = 1 + 0.045 * C_
|
||||
SH = 1 + 0.015 * C_ * T
|
||||
RT = (
|
||||
-2 * math.sqrt(C_ ** 7 / (C_ ** 7 + 25 ** 7)) *
|
||||
math.sin(math.radians(60 * math.exp(-(((h_ - 275) / 25) ** 2))))
|
||||
)
|
||||
delta_e = math.sqrt(
|
||||
(dL / SL) ** 2 +
|
||||
(dC / SC) ** 2 +
|
||||
(dH / SH) ** 2 +
|
||||
RT * (dC / SC) * (dH / SH)
|
||||
)
|
||||
return delta_e
|
||||
|
||||
def distance(self, c1, c2, speed):
|
||||
@ -426,7 +449,7 @@ class ASCII(callbacks.Plugin):
|
||||
(r2,g2,b2) = (c2[0], c2[1], c2[2])
|
||||
delta_e = math.sqrt((r1 - r2)**2 + (g1 - g2) ** 2 + (b1 - b2) **2)
|
||||
elif speed == 'slow':
|
||||
delta_e = self.cie_de_2000(c1, c2)
|
||||
delta_e = self.ciede2000(c1, c2)
|
||||
return delta_e
|
||||
|
||||
def png(self, irc, msg, args, optlist, url):
|
||||
@ -556,8 +579,6 @@ class ASCII(callbacks.Plugin):
|
||||
speed = 'fast'
|
||||
elif 'slow' in optlist:
|
||||
speed = 'slow'
|
||||
elif 'insane' in optlist:
|
||||
speed = 'slow'
|
||||
else:
|
||||
speed = 'slow'
|
||||
if 'chars' in optlist:
|
||||
@ -644,11 +665,8 @@ class ASCII(callbacks.Plugin):
|
||||
image2 = image.resize((cols, rows), Image.LANCZOS)
|
||||
if 's' in optlist:
|
||||
image2 = ImageEnhance.Color(image2).enhance(s)
|
||||
if 'dither' in optlist and 'insane' not in optlist:
|
||||
image2 = image2.convert('P', dither=Image.FLOYDSTEINBERG, palette=Image.ADAPTIVE)
|
||||
image2 = image2.convert('RGB')
|
||||
elif 'insane' not in optlist:
|
||||
image2 = image2.convert('P', dither=None, palette=Image.ADAPTIVE)
|
||||
if 'dither' in optlist:
|
||||
image2 = image2.convert('P', palette=Image.ADAPTIVE)
|
||||
image2 = image2.convert('RGB')
|
||||
colormap = np.array(image2)
|
||||
self.matches = {}
|
||||
@ -904,7 +922,7 @@ class ASCII(callbacks.Plugin):
|
||||
irc.reply(line, prefixNick=False, noLengthCheck=True, private=False, notice=False, to=channel)
|
||||
if self.registryValue('pasteEnable', msg.args[0]):
|
||||
irc.reply(self.doPaste(url, paste), private=False, notice=False, to=channel)
|
||||
img = wrap(img,[optional('channel'), getopts({'w':'int', 'invert':'', 'fast':'', 'slow':'', 'insane':'', '16':'', 'delay':'float', 'dither':'', 'chars':'text', 'bg':'int', 'fg':'int', 'ramp':'text', 'nocolor':'', 'block':'', 'ascii':'', '1/4':'', 's':'float', 'tops':''}), ('text')])
|
||||
img = wrap(img,[optional('channel'), getopts({'w':'int', 'invert':'', 'fast':'', 'slow':'', '16':'', 'delay':'float', 'dither':'', 'chars':'text', 'bg':'int', 'fg':'int', 'ramp':'text', 'nocolor':'', 'block':'', 'ascii':'', '1/4':'', 's':'float', 'tops':''}), ('text')])
|
||||
|
||||
def scroll(self, irc, msg, args, channel, optlist, url):
|
||||
"""[<channel>] <url>
|
||||
|
Loading…
x
Reference in New Issue
Block a user