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
+
Node options:

@@ -214,6 +217,7 @@ Node options:
### MaskEdgeShrink
Smooth transition and shrink the mask edges while preserving edge details.
+
Node options:

@@ -226,6 +230,15 @@ Node options:
Comparison of MaskGrow and MaskEdgeShrink

+### MaskMotionBlur
+Create motion blur on the mask.
+
+
+Node options:
+
+* 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.

+### SoftLight
+Soft light effect, the bright highlights on the screen appear blurry.
+
+
+Node options:
+
+* 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.

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½øÐÐÀ©ÕÅÊÕËõ±ßÔµºÍÄ£ºý´¦Àí
+
½ÚµãÑ¡Ïî˵Ã÷:

@@ -207,6 +210,7 @@ ComfyUI
### MaskEdgeShrink
ʹmask±ßԵƽ»¬µØ¹ý¶ÉÊÕËõ£¬²¢±£Áô±ßԵϸ½Ú¡£
+
½ÚµãÑ¡Ïî˵Ã÷:

@@ -219,6 +223,16 @@ ComfyUI
MaskGrowÓëMaskEdgeShrinkЧ¹û¶Ô±È

+### MaskMotionBlur
+ʹmask²úÉúÔ˶¯Ä£ºý¡£
+
+
+½ÚµãÑ¡Ïî˵Ã÷:
+
+* invert_mask: ÊÇ·ñ·´×ªÕÚÕÖ¡£
+* blur: Ä£ºý´óС¡£
+* angle: Ä£ºý½Ç¶È¡£
+
### MaskGradient
ʹmask´ÓÒ»²à²úÉú½¥±ä¡£

@@ -377,6 +391,16 @@ mask

+### SoftLight
+Èá¹âЧ¹û¡£
+
+
+½ÚµãÑ¡Ïî˵Ã÷:
+
+* soft: Èá¹â´óС¡£
+* threshold: Èá¹â·¶Î§¡£Èá¹â´Ó»Ãæ×îÃ÷ÁÁµÄ²¿·Ö³ÊÏÖ¡£ÊýÖµÔ½µÍ·¶Î§Ô½´ó£¬Ô½¸ß·¶Î§Ô½Ð¡¡£
+* opacity: Èá¹âµÄ²»Í¸Ã÷¶È¡£
+
### ChannelShake
ͨµÀ´íλ¡£ÀàËÆ¶¶ÒôlogoµÄЧ¹û¡£

@@ -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