mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-02-10 05:22:34 +08:00
136 lines
5.2 KiB
Python
136 lines
5.2 KiB
Python
from PIL import Image
|
|
from sklearn.cluster import KMeans
|
|
import numpy as np
|
|
from scipy.spatial import KDTree
|
|
import colorsys
|
|
import webcolors
|
|
|
|
|
|
|
|
class extract_rainbow():
|
|
|
|
def __init__(self):
|
|
pass
|
|
|
|
# Utility Functions
|
|
def rgb_to_hsv(self,rgb):
|
|
return colorsys.rgb_to_hsv(rgb[0]/255, rgb[1]/255, rgb[2]/255)
|
|
|
|
def hsv_to_rgb(self,hsv):
|
|
return tuple(round(i * 255) for i in colorsys.hsv_to_rgb(hsv[0], hsv[1], hsv[2]))
|
|
|
|
def rgb_to_hex(self,rgb):
|
|
return '#{:02x}{:02x}{:02x}'.format(int(rgb[0]), int(rgb[1]), int(rgb[2]))
|
|
|
|
def hex_to_rgb(self,hex_color):
|
|
return webcolors.hex_to_rgb(hex_color)
|
|
|
|
def get_most_common_colors(self,image, n_colors=4):
|
|
image = image.resize((50, 50)) # Reduce the size
|
|
ar = np.asarray(image)
|
|
ar = ar.reshape(-1, 3)
|
|
|
|
kmeans = KMeans(n_clusters=n_colors)
|
|
kmeans.fit(ar)
|
|
|
|
return [self.rgb_to_hex(tuple(map(int, center))) for center in kmeans.cluster_centers_]
|
|
|
|
def closest_color_name(self,requested_color):
|
|
min_colors = {}
|
|
for key, name in webcolors.CSS3_HEX_TO_NAMES.items():
|
|
r_c, g_c, b_c = webcolors.hex_to_rgb(key)
|
|
rd = (r_c - requested_color[0]) ** 2
|
|
gd = (g_c - requested_color[1]) ** 2
|
|
bd = (b_c - requested_color[2]) ** 2
|
|
min_colors[(rd + gd + bd)] = name
|
|
return min_colors[min(min_colors.keys())]
|
|
|
|
def get_color_name(self,hex_color):
|
|
try:
|
|
closest_name = actual_name = webcolors.hex_to_name(hex_color)
|
|
except ValueError:
|
|
closest_name = self.closest_color_name(self.hex_to_rgb(hex_color))
|
|
actual_name = None
|
|
return closest_name
|
|
|
|
def get_analogous_colors(self,hsv, angle=30):
|
|
analogous1_hue = (hsv[0] + angle/360) % 1
|
|
analogous2_hue = (hsv[0] - angle/360) % 1
|
|
analogous1 = self.rgb_to_hex(self.hsv_to_rgb((analogous1_hue, hsv[1], hsv[2])))
|
|
analogous2 = self.rgb_to_hex(self.hsv_to_rgb((analogous2_hue, hsv[1], hsv[2])))
|
|
return analogous1, analogous2
|
|
|
|
def get_triadic_colors(self,hsv):
|
|
triadic1_hue = (hsv[0] + 1/3) % 1
|
|
triadic2_hue = (hsv[0] + 2/3) % 1
|
|
triadic1 = self.rgb_to_hex(self.hsv_to_rgb((triadic1_hue, hsv[1], hsv[2])))
|
|
triadic2 = self.rgb_to_hex(self.hsv_to_rgb((triadic2_hue, hsv[1], hsv[2])))
|
|
return triadic1, triadic2
|
|
|
|
def get_complementary_color(self,hsv):
|
|
complementary_hue = (hsv[0] + 0.5) % 1
|
|
complementary = self.rgb_to_hex(self.hsv_to_rgb((complementary_hue, hsv[1], hsv[2])))
|
|
return complementary
|
|
|
|
def get_monochromatic_color(self,hsv):
|
|
# Here we are taking 3 saturation levels for a given color
|
|
monochromatic1 = self.rgb_to_hex(self.hsv_to_rgb((hsv[0], hsv[1]*0.3, hsv[2])))
|
|
monochromatic2 = self.rgb_to_hex(self.hsv_to_rgb((hsv[0], hsv[1]*0.5, hsv[2])))
|
|
monochromatic3 = self.rgb_to_hex(self.hsv_to_rgb((hsv[0], hsv[1]*0.7, hsv[2])))
|
|
return monochromatic1, monochromatic2, monochromatic3
|
|
|
|
def main(self,image):
|
|
# Load image and get most common colors
|
|
hex_colors = self.get_most_common_colors(image)
|
|
|
|
# Get color names and HSV
|
|
MC_hex = []
|
|
MC_names = []
|
|
MC_hsv = []
|
|
|
|
for hex_color in hex_colors:
|
|
MC_hex.append(hex_color)
|
|
MC_names.append(self.get_color_name(hex_color))
|
|
MC_hsv.append(self.rgb_to_hsv(self.hex_to_rgb(hex_color)))
|
|
|
|
# If MC1 color is black or very dark, use MC2 for calculations
|
|
dark_colors = ['black', 'darkslategrey', 'indigo', 'midnightblue', 'darkred']
|
|
if MC_names[0].lower() in dark_colors:
|
|
MC = MC_hex[1]
|
|
MC_name = MC_names[1]
|
|
MC_hsv = MC_hsv[1]
|
|
else:
|
|
MC = MC_hex[0]
|
|
MC_name = MC_names[0]
|
|
MC_hsv = MC_hsv[0]
|
|
|
|
# Calculate color schemes
|
|
AN1, AN2 = self.get_analogous_colors(MC_hsv)
|
|
T1, T2 = self.get_triadic_colors(MC_hsv)
|
|
C1 = self.get_complementary_color(MC_hsv)
|
|
C2 = self.get_complementary_color(self.rgb_to_hsv(self.hex_to_rgb(MC_hex[1]))) # Use MC2 for second complementary color
|
|
|
|
# Get monochromatic colors for each MC
|
|
MO = []
|
|
for color in MC_hex:
|
|
hsv = self.rgb_to_hsv(self.hex_to_rgb(color))
|
|
MO.append(self.get_monochromatic_color(hsv))
|
|
|
|
# Generate Output
|
|
output = f"MC1: {MC_hex[0]} - {MC_names[0]}, MC2: {MC_hex[1]} - {MC_names[1]}, MC3: {MC_hex[2]} - {MC_names[2]}, MC4: {MC_hex[3]} - {MC_names[3]}\n"
|
|
output += f"AN1: {AN1} - {self.get_color_name(AN1)}, AN2: {AN2} - {self.get_color_name(AN2)}\n"
|
|
output += f"T1: {T1} - {self.get_color_name(T1)}, T2: {T2} - {self.get_color_name(T2)}\n"
|
|
output += f"C1: {C1} - {self.get_color_name(C1)}, C2: {C2} - {self.get_color_name(C2)}\n"
|
|
output += f"MO1: {MO[0][0]} - {self.get_color_name(MO[0][0])}, MO2: {MO[1][0]} - {self.get_color_name(MO[1][0])}, MO3: {MO[2][0]} - {self.get_color_name(MO[2][0])}, MO4: {MO[3][0]} - {self.get_color_name(MO[3][0])}\n"
|
|
|
|
# Save to a text file
|
|
with open('color_output.txt', 'w') as f:
|
|
f.write(output)
|
|
|
|
return output
|
|
|
|
|
|
if __name__ == '__main__':
|
|
rnbw = extract_rainbow()
|
|
rnbw.main()
|