| from PIL import Image, ImageEnhance, ImageColor, ImageOps
|
| import numpy as np
|
| import torch
|
| from server import PromptServer
|
|
|
|
|
| class PreviewTextNode:
|
| def __init__(self):
|
| pass
|
|
|
| @classmethod
|
| def INPUT_TYPES(s):
|
|
|
| return {
|
| "required": {
|
| "text": ("STRING", {"forceInput": True}),
|
| },
|
| "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
|
| }
|
|
|
| RETURN_TYPES = ("STRING",)
|
| OUTPUT_NODE = True
|
| DESCRIPTION = "The node displays the input text."
|
| FUNCTION = "preview_text"
|
|
|
| CATEGORY = "AlekPet Nodes/extras"
|
|
|
| def preview_text(self, text, prompt=None, extra_pnginfo=None):
|
| return {
|
| "ui": {
|
| "string": [
|
| text,
|
| ]
|
| },
|
| "result": (text,),
|
| }
|
|
|
|
|
|
|
| class HexToHueNode:
|
|
|
| @classmethod
|
| def INPUT_TYPES(cls):
|
| return {
|
| "required": {
|
| "color_hex": (
|
| "STRING",
|
| {"default": "#00ff33"},
|
| ),
|
| },
|
| "hidden": {"unique_id": "UNIQUE_ID"},
|
| }
|
|
|
| RETURN_TYPES = ("STRING", "FLOAT", "FLOAT", "STRING", "STRING")
|
| RETURN_NAMES = (
|
| "string_hex",
|
| "float_hue_degrees",
|
| "float_hue_norm",
|
| "string_hue_degrees",
|
| "string_hue_norm",
|
| )
|
| FUNCTION = "to_hue"
|
| DESCRIPTION = "The node convert HEX color to HUE."
|
| CATEGORY = "AlekPet Nodes/extras"
|
|
|
| def to_hue(self, color_hex, unique_id):
|
| hue_degrees = ColorsCorrectNode.hex_to_hue(color_hex)
|
| hue_norm = ColorsCorrectNode.degrees_to_hue(hue_degrees)
|
| PromptServer.instance.send_sync(
|
| "alekpet_get_color_hex", {"color_hex": color_hex, "unique_id": unique_id}
|
| )
|
| return (color_hex, hue_degrees, hue_norm, str(hue_degrees), str(hue_norm))
|
|
|
|
|
| class ColorsCorrectNode:
|
|
|
| @classmethod
|
| def INPUT_TYPES(cls):
|
| return {
|
| "required": {
|
| "image": ("IMAGE",),
|
| "brightness": (
|
| "FLOAT",
|
| {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.05},
|
| ),
|
| "contrast": (
|
| "FLOAT",
|
| {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.05},
|
| ),
|
| "saturation": (
|
| "FLOAT",
|
| {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.05},
|
| ),
|
| "gamma": (
|
| "FLOAT",
|
| {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.05},
|
| ),
|
| "hue_degrees": (
|
| "FLOAT",
|
| {"default": 0.0, "min": 0.0, "max": 360.0, "step": 0.01},
|
| ),
|
| "use_color": (
|
| "BOOLEAN",
|
| {"default": True},
|
| ),
|
| },
|
| "optional": {
|
| "hex_color": (
|
| "STRING",
|
| {"default": "#00FF33"},
|
| ),
|
| },
|
| }
|
|
|
| RETURN_TYPES = ("IMAGE",)
|
| FUNCTION = "correct"
|
| DESCRIPTION = "Node for correcting image colors."
|
| CATEGORY = "AlekPet Nodes/extras"
|
|
|
| @staticmethod
|
| def hex_to_rgb(hex_color):
|
| return ImageColor.getcolor(hex_color, "RGB")
|
|
|
| @staticmethod
|
| def hex_to_hue(hex_color):
|
| rgb = ImageColor.getcolor(hex_color, "RGB")
|
| r, g, b = [x / 255.0 for x in rgb]
|
| mx = max(r, g, b)
|
| mn = min(r, g, b)
|
| df = mx - mn
|
|
|
| if mx == mn:
|
| h = 0
|
| elif mx == r:
|
| h = (60 * ((g - b) / df) + 360) % 360
|
| elif mx == g:
|
| h = (60 * ((b - r) / df) + 120) % 360
|
| elif mx == b:
|
| h = (60 * ((r - g) / df) + 240) % 360
|
|
|
| return h
|
|
|
| @staticmethod
|
| def adjust_brightness(image, factor):
|
| enhancer = ImageEnhance.Brightness(image)
|
| return enhancer.enhance(factor)
|
|
|
| @staticmethod
|
| def adjust_contrast(image, factor):
|
| enhancer = ImageEnhance.Contrast(image)
|
| return enhancer.enhance(factor)
|
|
|
| @staticmethod
|
| def adjust_saturation(image, factor):
|
| enhancer = ImageEnhance.Color(image)
|
| return enhancer.enhance(factor)
|
|
|
| @staticmethod
|
| def adjust_gamma(image, gamma):
|
| inv_gamma = 1.0 / gamma
|
| lut = [pow(x / 255.0, inv_gamma) * 255 for x in range(256)]
|
| lut = np.array(lut * 3, dtype=np.uint8)
|
| return image.point(lut)
|
|
|
| @staticmethod
|
| def degrees_to_hue(degrees):
|
| degrees = degrees % 360
|
| hue = degrees / 360.0
|
|
|
| if hue > 0.5:
|
| hue -= 1.0
|
| if hue < -0.5:
|
| hue += 1.0
|
|
|
| return hue
|
|
|
| @staticmethod
|
| def adjust_hue(image, hue):
|
| if not (-0.5 <= hue <= 0.5):
|
| raise ValueError("hue value is not in [-0.5, 0.5].")
|
|
|
| image_array = np.array(image.convert("RGB"), dtype=np.uint8)
|
|
|
| hsv_image = Image.fromarray(image_array).convert("HSV")
|
| hsv_array = np.array(hsv_image)
|
|
|
| hsv_array[..., 0] = (hsv_array[..., 0].astype(int) + int(hue * 255)) % 256
|
|
|
| rgb_image = Image.fromarray(hsv_array, mode="HSV").convert("RGB")
|
| return rgb_image
|
|
|
| @staticmethod
|
| def tint_image(image, hex_color):
|
| return ImageOps.colorize(image.convert("L"), black="black", white=hex_color)
|
|
|
| def correct(
|
| self,
|
| image,
|
| use_color=True,
|
| hex_color="#00FF33",
|
| brightness=1.0,
|
| contrast=1.0,
|
| saturation=1.0,
|
| gamma=1.0,
|
| hue_degrees=0.0,
|
| ):
|
| i = 255.0 * image[0].cpu().numpy()
|
| image = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
|
|
|
| if use_color:
|
| image = ColorsCorrectNode.tint_image(image, hex_color)
|
|
|
| image = ColorsCorrectNode.adjust_brightness(image, brightness)
|
| image = ColorsCorrectNode.adjust_contrast(image, contrast)
|
| image = ColorsCorrectNode.adjust_saturation(image, saturation)
|
| image = ColorsCorrectNode.adjust_gamma(image, gamma)
|
|
|
| hue_norm = ColorsCorrectNode.degrees_to_hue(hue_degrees)
|
| image = ColorsCorrectNode.adjust_hue(image, hue_norm)
|
|
|
| image = ImageOps.exif_transpose(image)
|
| image = image.convert("RGB")
|
| image = np.array(image).astype(np.float32) / 255.0
|
| image = torch.from_numpy(image)[None,]
|
|
|
| return (image,)
|
|
|