diff --git a/README.MD b/README.MD index 55afa70..1098678 100644 --- a/README.MD +++ b/README.MD @@ -12,6 +12,8 @@ Nodes are divided into four groups according to their functions: LayerStyle, Lay [中文说明点这里](./README_CN.MD) ## Update +* Commit [MaskMotionBlur](#MaskMotionBlur) node. +* Commit [SoftLight](#SoftLight) node. * Commit [ChannelShake](#ChannelShake) node, that is filter, can produce channel dislocation effect similar like Tiktok logo. * Commit [MaskGradient](#MaskGradient) node, can create a gradient in the mask. * Commit [GetColorTone](#GetColorTone) node, can obtain the main color or average color of the image. @@ -205,6 +207,7 @@ Output: ### MaskGrow Grow and shrink edges and blur the mask +![image](image/mask_grow_example.png) Node options: ![image](image/mask_grow_node.png) @@ -214,6 +217,7 @@ Node options: ### MaskEdgeShrink Smooth transition and shrink the mask edges while preserving edge details. +![image](image/mask_edge_shrink_example.png) Node options: ![image](image/mask_edge_shrink_node.png) @@ -226,6 +230,15 @@ Node options: Comparison of MaskGrow and MaskEdgeShrink ![image](image/mask_edge_compare.png) +### MaskMotionBlur +Create motion blur on the mask. +![image](image/mask_motion_blur_example.png) + +Node options: +![image](image/mask_motion_blur_node.png) +* invert_mask: Whether to reverse the mask. +* blur: The size of blur. +* angle: The angle of blur. ### MaskGradient Create a gradient for the mask from one side. @@ -387,6 +400,17 @@ This node allows any type of input. ![image](image/layerfilter_nodes.png) +### SoftLight +Soft light effect, the bright highlights on the screen appear blurry. +![image](image/soft_light_example.png) + +Node options: +![image](image/soft_light_node.png) +* soft: Size of soft light. +* threshold: Soft light range. the light appears from the brightest part of the picture. in lower value, the range will be larger, and in higher value, the range will be smaller. +* opacity: Opacity of the soft light. + + ### ChannelShake Channel misalignment. similar to the effect of Tiktok logo. ![image](image/channel_shake_example.png) diff --git a/README_CN.MD b/README_CN.MD index ffcd081..3a099a2 100644 --- a/README_CN.MD +++ b/README_CN.MD @@ -9,6 +9,8 @@ ComfyUI * [LayerFilter](#LayerFilter)½Úµã×éÌṩͼÏñЧ¹ûÂ˾µ¡£ ## ¸üÐÂ˵Ã÷ +* Ìí¼Ó[MaskMotionBlur](#MaskMotionBlur)½Úµã¡£ +* Ìí¼Ó[SoftLight](#SoftLight)½Úµã¡£ * Ìí¼Ó[ChannelShake](#ChannelShake)½Úµã£¬ÕâÊÇÒ»¸öÂ˾µ£¬ÄܲúÉúÀàËÆ¶¶ÒôlogoµÄͨµÀ´íλЧ¹û¡£ * Ìí¼Ó[MaskGradient](#MaskGradient)½Úµã£¬¿Éʹmask²úÉú½¥±ä¡£ * Ìí¼Ó[GetColorTone](#GetColorTone)½Úµã£¬¿ÉÒÔ»ñȡͼƬµÄÖ÷É«»òƽ¾ùÉ«¡£Ìí¼Ó[MaskGrow](#MaskGrow)ºÍ[MaskEdgeShrink](#MaskEdgeShrink)½Úµã¡£ @@ -198,6 +200,7 @@ ComfyUI ### MaskGrow ¶Ômask½øÐÐÀ©ÕÅÊÕËõ±ßÔµºÍÄ£ºý´¦Àí +![image](image/mask_grow_example.png) ½ÚµãÑ¡Ïî˵Ã÷: ![image](image/mask_grow_node.png) @@ -207,6 +210,7 @@ ComfyUI ### MaskEdgeShrink ʹmask±ßԵƽ»¬µØ¹ý¶ÉÊÕËõ£¬²¢±£Áô±ßԵϸ½Ú¡£ +![image](image/mask_edge_shrink_example.png) ½ÚµãÑ¡Ïî˵Ã÷: ![image](image/mask_edge_shrink_node.png) @@ -219,6 +223,16 @@ ComfyUI MaskGrowÓëMaskEdgeShrinkЧ¹û¶Ô±È ![image](image/mask_edge_compare.png) +### MaskMotionBlur +ʹmask²úÉúÔ˶¯Ä£ºý¡£ +![image](image/mask_motion_blur_example.png) + +½ÚµãÑ¡Ïî˵Ã÷: +![image](image/mask_motion_blur_node.png) +* invert_mask: ÊÇ·ñ·´×ªÕÚÕÖ¡£ +* blur: Ä£ºý´óС¡£ +* angle: Ä£ºý½Ç¶È¡£ + ### MaskGradient ʹmask´ÓÒ»²à²úÉú½¥±ä¡£ ![image](image/mask_gradient_example.png) @@ -377,6 +391,16 @@ mask ![image](image/layerfilter_nodes.png) +### SoftLight +Èá¹âЧ¹û¡£ +![image](image/soft_light_example.png) + +½ÚµãÑ¡Ïî˵Ã÷: +![image](image/soft_light_node.png) +* soft: Èá¹â´óС¡£ +* threshold: Èá¹â·¶Î§¡£Èá¹â´Ó»­Ãæ×îÃ÷ÁÁµÄ²¿·Ö³ÊÏÖ¡£ÊýÖµÔ½µÍ·¶Î§Ô½´ó£¬Ô½¸ß·¶Î§Ô½Ð¡¡£ +* opacity: Èá¹âµÄ²»Í¸Ã÷¶È¡£ + ### ChannelShake ͨµÀ´íλ¡£ÀàËÆ¶¶ÒôlogoµÄЧ¹û¡£ ![image](image/channel_shake_example.png) @@ -421,9 +445,6 @@ mask LayerMask: * text mask -* mask subtract -* mask combine -* mask diffrent LayerFilter: * emboss diff --git a/image/layerfilter_nodes.png b/image/layerfilter_nodes.png index 2db04e9..5204e5c 100644 Binary files a/image/layerfilter_nodes.png and b/image/layerfilter_nodes.png differ diff --git a/image/layermask_nodes.png b/image/layermask_nodes.png index 693862d..e0e65db 100644 Binary files a/image/layermask_nodes.png and b/image/layermask_nodes.png differ diff --git a/image/mask_edge_shrink_example.png b/image/mask_edge_shrink_example.png new file mode 100644 index 0000000..f6c04a4 Binary files /dev/null and b/image/mask_edge_shrink_example.png differ diff --git a/image/mask_grow_example.png b/image/mask_grow_example.png new file mode 100644 index 0000000..5f23bc0 Binary files /dev/null and b/image/mask_grow_example.png differ diff --git a/image/mask_motion_blur_example.png b/image/mask_motion_blur_example.png new file mode 100644 index 0000000..12558d4 Binary files /dev/null and b/image/mask_motion_blur_example.png differ diff --git a/image/mask_motion_blur_node.png b/image/mask_motion_blur_node.png new file mode 100644 index 0000000..2b96293 Binary files /dev/null and b/image/mask_motion_blur_node.png differ diff --git a/image/soft_light_example.png b/image/soft_light_example.png new file mode 100644 index 0000000..1d1a714 Binary files /dev/null and b/image/soft_light_example.png differ diff --git a/image/soft_light_node.png b/image/soft_light_node.png new file mode 100644 index 0000000..f27bfab Binary files /dev/null and b/image/soft_light_node.png differ diff --git a/py/channel_shake.py b/py/channel_shake.py index 35784b8..83e1726 100644 --- a/py/channel_shake.py +++ b/py/channel_shake.py @@ -14,7 +14,7 @@ class ChannelShake: "required": { "image": ("IMAGE", ), # "distance": ("INT", {"default": 20, "min": 1, "max": 999, "step": 1}), # è·�离 - "angle": ("FLOAT", {"default": 40, "min": -360, "max": 360, "step": 0.01}), # 角度 + "angle": ("FLOAT", {"default": 40, "min": -360, "max": 360, "step": 0.1}), # 角度 "mode": (channel_mode,), # 模å¼� }, "optional": { diff --git a/py/imagefunc.py b/py/imagefunc.py index 34e1686..67c8b5a 100644 --- a/py/imagefunc.py +++ b/py/imagefunc.py @@ -250,6 +250,19 @@ def get_image_color_average(image:Image) -> str: ret_color = RGB_to_Hex(color) return ret_color +def get_image_bright_average(image:Image) -> int: + image = image.convert('L') + width, height = image.size + total_bright = 0 + pixels = 0 + for y in range(height): + for x in range(width): + b = image.getpixel((x, y)) + if b > 1: # 排除死黑 + pixels += 1 + total_bright += b + return int(total_bright / pixels) + '''Mask Functions''' def expand_mask(mask:torch.Tensor, grow:int, blur:int) -> torch.Tensor: @@ -345,6 +358,17 @@ def max_inscribed_rect(image:Image) -> tuple: x1, y1, x2, y2 = min(x1, x2), min(y1, y2), max(x1, x2), max(y1, y2) return (x1, y1, x2 - x1, y2 - y1) +def gray_threshold(image:Image, thresh:int=127, otsu:bool=False) -> Image: + cv2_image = pil2cv2(image) + gray = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2GRAY) + if otsu: + _, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) + else: + _, thresh = cv2.threshold(gray, thresh, 255, cv2.THRESH_TOZERO) + + return cv22pil(thresh).convert('L') + + '''Color Functions''' def RGB_to_Hex(RGB) -> str: diff --git a/py/mask_motion_blur.py b/py/mask_motion_blur.py new file mode 100644 index 0000000..50a8888 --- /dev/null +++ b/py/mask_motion_blur.py @@ -0,0 +1,45 @@ +import copy + +from .imagefunc import * + +class MaskMotionBlur: + + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(self): + + return { + "required": { + "mask": ("MASK",), + "invert_mask": ("BOOLEAN", {"default": True}), # å��转mask + "blur": ("INT", {"default": 20, "min": 1, "max": 9999, "step": 1}), + "angle": ("FLOAT", {"default": 0, "min": -360, "max": 360, "step": 0.1}), + }, + "optional": { + } + } + + RETURN_TYPES = ("MASK",) + RETURN_NAMES = ("mask",) + FUNCTION = 'mask_motion_blur' + CATEGORY = '😺dzNodes/LayerMask' + OUTPUT_NODE = True + + def mask_motion_blur(self, mask, invert_mask, blur, angle,): + + if invert_mask: + mask = 1 - mask + _mask = mask2image(mask).convert('RGB') + _blurimage = motion_blur(_mask, angle, blur) + ret_mask = image2mask(_blurimage) + return (ret_mask,) + +NODE_CLASS_MAPPINGS = { + "LayerMask: MaskMotionBlur": MaskMotionBlur +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "LayerMask: MaskMotionBlur": "LayerMask: MaskMotionBlur" +} \ No newline at end of file diff --git a/py/soft_light.py b/py/soft_light.py new file mode 100644 index 0000000..fb06890 --- /dev/null +++ b/py/soft_light.py @@ -0,0 +1,54 @@ +from .imagefunc import * + +class SoftLight: + + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(self): + + return { + "required": { + "image": ("IMAGE", ), # + + "soft": ("FLOAT", {"default": 1, "min": 0.2, "max": 10, "step": 0.01}), # 模糊 + "threshold": ("INT", {"default": -10, "min": -255, "max": 255, "step": 1}), # 高光阈值 + "opacity": ("INT", {"default": 100, "min": 0, "max": 100, "step": 1}), # é€�明度 + }, + "optional": { + } + } + + RETURN_TYPES = ("IMAGE",) + RETURN_NAMES = ("image",) + FUNCTION = 'soft_light' + CATEGORY = '😺dzNodes/LayerFilter' + OUTPUT_NODE = True + + def soft_light(self, image, soft, threshold, opacity,): + blend_mode = 'screen' + _canvas = tensor2pil(image).convert('RGB') + blur = int((_canvas.width + _canvas.height) / 200 * soft) + _otsumask = gray_threshold(_canvas, otsu=True) + _removebkgd = remove_background(_canvas, _otsumask, '#000000').convert('L') + auto_threshold = get_image_bright_average(_removebkgd) + light_mask = gray_threshold(_canvas, auto_threshold + threshold) + highlight_mask = gray_threshold(_canvas, auto_threshold + (255 - auto_threshold) // 2 + threshold // 2) + blurimage = gaussian_blur(_canvas, soft).convert('RGB') + light = chop_image(_canvas, blurimage, blend_mode=blend_mode, opacity=opacity) + highlight = chop_image(light, blurimage, blend_mode=blend_mode, opacity=opacity) + _canvas.paste(highlight, mask=gaussian_blur(light_mask, blur * 2).convert('L')) + _canvas.paste(highlight, mask=gaussian_blur(highlight_mask, blur).convert('L')) + ret_image = _canvas + log('SoftLight Processed.') + + return (pil2tensor(ret_image),) + +NODE_CLASS_MAPPINGS = { + "LayerFilter: SoftLight": SoftLight +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "LayerFilter: SoftLight": "LayerFilter: SoftLight" +} \ No newline at end of file