mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-02-10 13:32:36 +08:00
Added Rainbow Scripts
This commit is contained in:
parent
e11af79bcc
commit
0a8e890d69
5
color_output.txt
Normal file
5
color_output.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
MC1: #d1a443 - peru, MC2: #16b3d8 - darkturquoise, MC3: #c0e5ed - powderblue, MC4: #5f870f - olivedrab
|
||||||
|
AN1: #b7d143 - yellowgreen, AN2: #d15d43 - indianred
|
||||||
|
T1: #43d1a4 - mediumaquamarine, T2: #a443d1 - darkorchid
|
||||||
|
C1: #4370d1 - royalblue, C2: #d83b16 - orangered
|
||||||
|
MO1: #d1c4a6 - tan, MO2: #9ecdd8 - lightsteelblue, MO3: #e0ebed - lavender, MO4: #7b8763 - gray
|
||||||
@ -10,7 +10,7 @@ from PIL import Image
|
|||||||
import base64
|
import base64
|
||||||
import io
|
import io
|
||||||
|
|
||||||
|
from custom_scripts_for_nodes.Rainbow import extract_rainbow
|
||||||
|
|
||||||
import runpod
|
import runpod
|
||||||
|
|
||||||
@ -65,21 +65,39 @@ def get_images(ws, prompt):
|
|||||||
|
|
||||||
def run_prompt(job):
|
def run_prompt(job):
|
||||||
|
|
||||||
|
data = {'images':[],'rainbow':"None"}
|
||||||
|
|
||||||
|
#Inferring from the Rainbow Script
|
||||||
|
image_string = job['input']['image_string']
|
||||||
prompt_text = job["input"]["prompt"]
|
prompt_text = job["input"]["prompt"]
|
||||||
prompt = prompt_text
|
|
||||||
ws = websocket.WebSocket()
|
if image_string != 'None':
|
||||||
ws.connect("ws://{}/ws?clientId={}".format(server_address, client_id))
|
# Decode the base64 string into bytes
|
||||||
images = get_images(ws, prompt)
|
decoded_bytes = base64.b64decode(image_string)
|
||||||
data = {'images':[]}
|
# Convert the bytes to an in-memory file-like object using io.BytesIO
|
||||||
for node_id in images:
|
image_data = io.BytesIO(decoded_bytes)
|
||||||
for image_data in images[node_id]:
|
image = Image.open(image_data)
|
||||||
image = Image.open(io.BytesIO(image_data))
|
rnbw = extract_rainbow()
|
||||||
im_file = io.BytesIO()
|
rnbw_values = rnbw.main(image)
|
||||||
image.save(im_file, format="JPEG")
|
|
||||||
im_bytes = im_file.getvalue() # im_bytes: image in binary format.
|
data['rainbow'] = rnbw_values
|
||||||
im_b64 = base64.b64encode(im_bytes)
|
|
||||||
im_b64 = str(im_b64)
|
if prompt_text != "None":
|
||||||
data['images'].append(im_b64)
|
prompt = prompt_text
|
||||||
|
ws = websocket.WebSocket()
|
||||||
|
ws.connect("ws://{}/ws?clientId={}".format(server_address, client_id))
|
||||||
|
images = get_images(ws, prompt)
|
||||||
|
|
||||||
|
|
||||||
|
for node_id in images:
|
||||||
|
for image_data in images[node_id]:
|
||||||
|
image = Image.open(io.BytesIO(image_data))
|
||||||
|
im_file = io.BytesIO()
|
||||||
|
image.save(im_file, format="JPEG")
|
||||||
|
im_bytes = im_file.getvalue() # im_bytes: image in binary format.
|
||||||
|
im_b64 = base64.b64encode(im_bytes)
|
||||||
|
im_b64 = str(im_b64)
|
||||||
|
data['images'].append(im_b64)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
135
custom_scripts_for_nodes/Rainbow.py
Normal file
135
custom_scripts_for_nodes/Rainbow.py
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
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,tensor):
|
||||||
|
# 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()
|
||||||
5
custom_scripts_for_nodes/color_output.txt
Normal file
5
custom_scripts_for_nodes/color_output.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
MC1: #9a5938 - sienna, MC2: #656771 - dimgray, MC3: #1e1413 - black, MC4: #d1ad91 - tan
|
||||||
|
AN1: #9a8a38 - olivedrab, AN2: #9a3848 - brown
|
||||||
|
T1: #389a59 - seagreen, T2: #59389a - darkslateblue
|
||||||
|
C1: #38799a - steelblue, C2: #716f65 - dimgray
|
||||||
|
MO1: #9a867d - gray, MO2: #6d6e71 - dimgray, MO3: #1e1b1b - black, MO4: #d1c6be - silver
|
||||||
5
custom_scripts_for_nodes/color_output_class.txt
Normal file
5
custom_scripts_for_nodes/color_output_class.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
MC1: #1d1413 - black, MC2: #656771 - dimgray, MC3: #995838 - sienna, MC4: #d0ad90 - tan
|
||||||
|
AN1: #696571 - dimgray, AN2: #656d71 - dimgray
|
||||||
|
T1: #716567 - dimgray, T2: #677165 - dimgray
|
||||||
|
C1: #716f65 - dimgray, C2: #716f65 - dimgray
|
||||||
|
MO1: #1d1a1a - black, MO2: #6d6e71 - dimgray, MO3: #99867c - gray, MO4: #d0c5bd - silver
|
||||||
5
custom_scripts_for_nodes/color_output_orig.txt
Normal file
5
custom_scripts_for_nodes/color_output_orig.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
MC1: #d1ad91 - tan, MC2: #9a5938 - sienna, MC3: #1e1413 - black, MC4: #656771 - dimgray
|
||||||
|
AN1: #d1cd91 - tan, AN2: #d19195 - rosybrown
|
||||||
|
T1: #91d1ad - darkseagreen, T2: #ad91d1 - mediumpurple
|
||||||
|
C1: #91b5d1 - lightsteelblue, C2: #38799a - steelblue
|
||||||
|
MO1: #d1c6be - silver, MO2: #9a867d - gray, MO3: #1e1b1b - black, MO4: #6d6e71 - dimgray
|
||||||
BIN
custom_scripts_for_nodes/input.png
Normal file
BIN
custom_scripts_for_nodes/input.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 420 KiB |
1
requirement_our.txt
Normal file
1
requirement_our.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
webcolors==1.13
|
||||||
6
test_input.json
Normal file
6
test_input.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"prompt": {"3": {"inputs": {"seed": 156680208700286, "steps": 20, "cfg": 8.0, "sampler_name": "euler", "scheduler": "normal", "denoise": 1.0, "model": ["4", 0], "positive": ["6", 0], "negative": ["7", 0], "latent_image": ["5", 0]}, "class_type": "KSampler"}, "4": {"inputs": {"ckpt_name": "sd-v1-4.ckpt"}, "class_type": "CheckpointLoaderSimple"}, "5": {"inputs": {"width": 512, "height": 512, "batch_size": 1}, "class_type": "EmptyLatentImage"}, "6": {"inputs": {"text": "beautiful scenery nature glass bottle landscape, , purple galaxy bottle,", "clip": ["4", 1]}, "class_type": "CLIPTextEncode"}, "7": {"inputs": {"text": "text, watermark", "clip": ["4", 1]}, "class_type": "CLIPTextEncode"}, "8": {"inputs": {"samples": ["3", 0], "vae": ["4", 2]}, "class_type": "VAEDecode"}, "9": {"inputs": {"filename_prefix": "ComfyUI", "images": ["8", 0]}, "class_type": "SaveImage"}},
|
||||||
|
"image_string" : "None"
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user