Commit GetColorTone, MaskGrow and MaskEdgeShink nodes.

Commit GetColorTone node, can obtain the main color or average color of the image. 
Commit MaskGrow and MaskEdgeShink node.
This commit is contained in:
chflame163
2024-01-24 20:38:44 +08:00
committed by GitHub
parent 8fb316595b
commit 7ff4f8ee10
16 changed files with 362 additions and 31 deletions
+38
View File
@@ -0,0 +1,38 @@
from .imagefunc import *
class ColorImage:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(self):
return {
"required": {
"width": ("INT", {"default": 512, "min": 4, "max": 99999, "step": 1}),
"height": ("INT", {"default": 512, "min": 4, "max": 99999, "step": 1}),
"color": ("STRING", {"default": "#000000"},),
},
"optional": {
}
}
RETURN_TYPES = ("IMAGE", )
RETURN_NAMES = ("image", )
FUNCTION = 'color_image'
CATEGORY = '😺dzNodes/LayerUtility'
OUTPUT_NODE = True
def color_image(self, width, height, color, ):
ret_image = Image.new('RGB', (width, height), color=color)
return (pil2tensor(ret_image), )
NODE_CLASS_MAPPINGS = {
"LayerUtility: ColorImage": ColorImage
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerUtility: ColorImage": "LayerUtility: ColorImage"
}
+1 -3
View File
@@ -1,8 +1,6 @@
from .imagefunc import Hex_to_RGB
mode_list = ['HEX', 'DEC']
class ColorPicker:
def __init__(self):
@@ -10,7 +8,7 @@ class ColorPicker:
@classmethod
def INPUT_TYPES(self):
mode_list = ['HEX', 'DEC']
return {
"required": {
"color": ("COLOR", {"default": "#FFFFFF"},),
+43
View File
@@ -0,0 +1,43 @@
from .imagefunc import *
class GetColorTone:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(self):
mode_list = ['main_color', 'average']
return {
"required": {
"image": ("IMAGE", ), #
"mode": (mode_list,), # 主色/平均色
},
"optional": {
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("RGB color in HEX",)
FUNCTION = 'get_color_tone'
CATEGORY = '😺dzNodes/LayerUtility'
OUTPUT_NODE = True
def get_color_tone(self, image, mode,):
_canvas = tensor2pil(image).convert('RGB')
_canvas = gaussian_blur(_canvas, int((_canvas.width + _canvas.height) / 200))
if mode == 'main_color':
ret_color = get_image_color_tone(_canvas)
else:
ret_color = get_image_color_average(_canvas)
return (ret_color,)
NODE_CLASS_MAPPINGS = {
"LayerUtility: GetColorTone": GetColorTone
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerUtility: GetColorTone": "LayerUtility: GetColorTone"
}
-4
View File
@@ -1,9 +1,5 @@
from .imagefunc import *
def process(image:Image) -> Image:
return image
class GetImageSize:
def __init__(self):
+41
View File
@@ -0,0 +1,41 @@
from .imagefunc import *
class GradientImage:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(self):
return {
"required": {
"width": ("INT", {"default": 512, "min": 4, "max": 99999, "step": 1}),
"height": ("INT", {"default": 512, "min": 4, "max": 99999, "step": 1}),
"angle": ("INT", {"default": 0, "min": -360, "max": 360, "step": 1}),
"start_color": ("STRING", {"default": "#FFFFFF"},),
"end_color": ("STRING", {"default": "#000000"},),
},
"optional": {
}
}
RETURN_TYPES = ("IMAGE", )
RETURN_NAMES = ("image", )
FUNCTION = 'gradient_image'
CATEGORY = '😺dzNodes/LayerUtility'
OUTPUT_NODE = True
def gradient_image(self, width, height, angle, start_color, end_color, ):
ret_image = gradint(start_color, end_color, width, height, angle)
return (pil2tensor(ret_image), )
NODE_CLASS_MAPPINGS = {
"LayerUtility: GradientImage": GradientImage
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerUtility: GradientImage": "LayerUtility: GradientImage"
}
+37
View File
@@ -7,6 +7,7 @@ import scipy.ndimage
import cv2
from typing import Union, List
from PIL import Image, ImageFilter, ImageChops, ImageDraw
import colorsys
def log(message):
name = 'LayerStyle'
@@ -213,6 +214,42 @@ def draw_rect(image:Image, x:int, y:int, width:int, height:int, line_color:str,
draw.rectangle((x, y, x + width, y + height), fill=box_color, outline=line_color, width=line_width, )
return image
def get_image_color_tone(image:Image) -> str:
image = image.convert('RGB')
max_score = 0.0001
dominant_color = None
for count, (r, g, b) in image.getcolors(image.size[0] * image.size[1]):
saturation = colorsys.rgb_to_hsv(r / 255.0, g / 255.0, b / 255.0)[1]
y = min(abs(r * 2104 + g * 4130 + b * 802 + 4096 + 131072) >> 13,235)
y = (y - 16.0) / (235 - 16)
if y>0.9:
continue
score = (saturation+0.1)*count
if score > max_score:
max_score = score
dominant_color = (r, g, b)
ret_color = RGB_to_Hex(dominant_color)
return ret_color
def get_image_color_average(image:Image) -> str:
image = image.convert('RGB')
width, height = image.size
total_red = 0
total_green = 0
total_blue = 0
for y in range(height):
for x in range(width):
rgb = image.getpixel((x, y))
total_red += rgb[0]
total_green += rgb[1]
total_blue += rgb[2]
average_red = total_red // (width * height)
average_green = total_green // (width * height)
average_blue = total_blue // (width * height)
color = (average_red, average_green, average_blue)
ret_color = RGB_to_Hex(color)
return ret_color
'''Mask Functions'''
+68
View File
@@ -0,0 +1,68 @@
from .imagefunc import *
class MaskEdgeShrink:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(self):
return {
"required": {
"mask": ("MASK", ), #
"invert_mask": ("BOOLEAN", {"default": True}), # 反转mask
"shrink_level": ("INT", {"default": 4, "min": 0, "max": 16, "step": 1}),
"soft": ("INT", {"default": 6, "min": 0, "max": 64, "step": 1}),
"edge_shrink": ("INT", {"default": 1, "min": 0, "max": 999, "step": 1}),
"edge_reserve": ("INT", {"default": 25, "min": 0, "max": 100, "step": 1}), # 透明度
},
"optional": {
}
}
RETURN_TYPES = ("MASK",)
RETURN_NAMES = ("mask",)
FUNCTION = 'mask_edge_shrink'
CATEGORY = '😺dzNodes/LayerMask'
OUTPUT_NODE = True
def mask_edge_shrink(self, mask, invert_mask, shrink_level, soft, edge_shrink, edge_reserve):
glow_range = shrink_level * soft
blur = 12
_inputmask = mask2image(mask)
_canvas = Image.new('RGB', size=_inputmask.size, color='black')
_layer = Image.new('RGB', size=_inputmask.size, color='white')
if invert_mask:
mask = 1 - mask
_mask = mask2image(mask).convert('L')
loop_grow = glow_range
inner_mask = _mask
for x in range(shrink_level):
_color = step_color('#FFFFFF', '#000000', shrink_level, x)
glow_mask = expand_mask(image2mask(inner_mask), -loop_grow, blur / (x+0.1)) #扩张,模糊
# 合成
color_image = Image.new("RGB", _layer.size, color=_color)
alpha = tensor2pil(mask_invert(glow_mask)).convert('L')
_glow = chop_image(_layer, color_image, 'subtract', int(step_value(1, 100, shrink_level, x)))
_layer.paste(_glow, mask=alpha)
loop_grow = loop_grow - int(glow_range / shrink_level)
# 合成layer
_edge = tensor2pil(expand_mask(mask, -edge_shrink, 0)).convert('RGB')
_layer = chop_image(_layer, _edge, 'normal', edge_reserve)
_layer.paste(_canvas, mask=ImageChops.invert(_mask))
ret_mask = image2mask(_layer)
return (ret_mask,)
NODE_CLASS_MAPPINGS = {
"LayerMask: MaskEdgeShrink": MaskEdgeShrink
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerMask: MaskEdgeShrink": "LayerMask: MaskEdgeShrink"
}
+44
View File
@@ -0,0 +1,44 @@
from .imagefunc import *
class MaskGrow:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(self):
return {
"required": {
"mask": ("MASK", ), #
"invert_mask": ("BOOLEAN", {"default": True}), # 反转mask
"grow": ("INT", {"default": 4, "min": -999, "max": 999, "step": 1}),
"blur": ("INT", {"default": 4, "min": 0, "max": 999, "step": 1}),
},
"optional": {
}
}
RETURN_TYPES = ("MASK",)
RETURN_NAMES = ("mask",)
FUNCTION = 'mask_grow'
CATEGORY = '😺dzNodes/LayerMask'
OUTPUT_NODE = True
def mask_grow(self, mask, invert_mask, grow, blur,):
if invert_mask:
mask = 1 - mask
# _mask = mask2image(mask).convert('L')
ret_mask = expand_mask(mask, grow, blur) # 扩张,模糊
return (ret_mask,)
NODE_CLASS_MAPPINGS = {
"LayerMask: MaskGrow": MaskGrow
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerMask: MaskGrow": "LayerMask: MaskGrow"
}
-4
View File
@@ -1,9 +1,5 @@
from .imagefunc import *
def process(image:Image) -> Image:
return image
class XYtoPercent:
def __init__(self):