diff --git a/README.MD b/README.MD index ad2674e..bebe5ee 100644 --- a/README.MD +++ b/README.MD @@ -1382,6 +1382,7 @@ Generate a mask based on the selected color. Node Options: ![image](image/mask_by_color_node.jpg) * image: Input image. +* mask: This input is optional, if there is a mask, only the colors inside the mask are included in the range. * color: Color selector. Click on the color block to select a color, and you can use the straws on the color picker panel to pick up the screen color. Note: When using straws, maximize the browser window. * color_in_HEX4: Enter color values. If this item has input, it will be used first, ignoring the color selected by the ```color``` . * threshold: Mask range threshold, the larger the value, the larger the mask range. diff --git a/README_CN.MD b/README_CN.MD index 789ad52..024c017 100644 --- a/README_CN.MD +++ b/README_CN.MD @@ -1368,6 +1368,7 @@ PersonMaskUltra的V2升级版,增加了VITMatte边缘处理方法。(注意: 节点选项说明: ![image](image/mask_by_color_node.jpg) * image: 图像输入。 +* mask: 遮罩输入。此输入是可选项,如果有遮罩则仅遮罩内的颜色被纳入范围。 * color: 颜色选择器。点击色块选择颜色,可以使用选色器面板上的吸管拾取屏幕颜色。注意:使用吸管时,需将浏览器窗口最大化。 * color_in_HEX4: 输入色值。如果此项有输入,则优先使用,忽略```color```选取的颜色。 * threshold: 遮罩范围阈值,数值越大,遮罩范围越大。 diff --git a/image/mask_by_color_example.jpg b/image/mask_by_color_example.jpg index 4dcb74c..a7688db 100644 Binary files a/image/mask_by_color_example.jpg and b/image/mask_by_color_example.jpg differ diff --git a/image/mask_by_color_node.jpg b/image/mask_by_color_node.jpg index 7a0e341..fc6561a 100644 Binary files a/image/mask_by_color_node.jpg and b/image/mask_by_color_node.jpg differ diff --git a/py/mask_by_color.py b/py/mask_by_color.py index 03e253d..8888c1b 100644 --- a/py/mask_by_color.py +++ b/py/mask_by_color.py @@ -15,6 +15,9 @@ class MaskByColor: "fix_gap": ("INT", {"default": 2, "min": 0, "max": 32, "step": 1}), "fix_threshold": ("FLOAT", {"default": 0.75, "min": 0.01, "max": 0.99, "step": 0.01}), "invert_mask": ("BOOLEAN", {"default": False}), # 反转mask + }, + "optional": { + "mask": ("MASK",), # } } @@ -24,20 +27,41 @@ class MaskByColor: CATEGORY = '😺dzNodes/LayerMask' def mask_by_color(self, image, color, color_in_HEX, threshold, - fix_gap, fix_threshold, invert_mask): + fix_gap, fix_threshold, invert_mask, mask=None): if color_in_HEX != "" and color_in_HEX.startswith('#') and len(color_in_HEX) == 7: color = color_in_HEX ret_masks = [] + l_images = [] + l_masks = [] - for i in image: - img = tensor2pil(i.unsqueeze(0)) - mask = create_mask_from_color_tensor(img, color, threshold) + for l in image: + l_images.append(torch.unsqueeze(l, 0)) + m = tensor2pil(l) + if m.mode == 'RGBA': + l_masks.append(m.split()[-1]) + else: + l_masks.append(Image.new('L', m.size, 'white')) + if mask is not None: + if mask.dim() == 2: + mask = torch.unsqueeze(mask, 0) + l_masks = [] + for m in mask: + if invert_mask: + m = 1 - m + l_masks.append(tensor2pil(torch.unsqueeze(m, 0)).convert('L')) + + for i in range(len(l_images)): + img = l_images[i] if i < len(l_images) else l_images[-1] + img = tensor2pil(img) + _mask = l_masks[i] if i < len(l_masks) else l_masks[-1] + + mask = Image.new('L', _mask.size, 'black') + mask.paste(create_mask_from_color_tensor(img, color, threshold), mask=_mask) mask = image2mask(mask) if invert_mask: mask = 1 - mask - if fix_gap: mask = mask_fix(mask, 1, fix_gap, fix_threshold, fix_threshold) ret_masks.append(mask) diff --git a/workflow/mask_by_color_example.json b/workflow/mask_by_color_example.json new file mode 100644 index 0000000..fccc72c --- /dev/null +++ b/workflow/mask_by_color_example.json @@ -0,0 +1,216 @@ +{ + "last_node_id": 14, + "last_link_id": 17, + "nodes": [ + { + "id": 13, + "type": "LayerMask: RmBgUltra V2", + "pos": [ + 391, + 687 + ], + "size": { + "0": 315, + "1": 198 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 14 + } + ], + "outputs": [ + { + "name": "image", + "type": "IMAGE", + "links": null, + "shape": 3 + }, + { + "name": "mask", + "type": "MASK", + "links": [ + 17 + ], + "shape": 3, + "slot_index": 1 + } + ], + "properties": { + "Node name for S&R": "LayerMask: RmBgUltra V2" + }, + "widgets_values": [ + "VITMatte", + 6, + 6, + 0.01, + 0.99, + false + ] + }, + { + "id": 9, + "type": "LayerMask: MaskPreview", + "pos": [ + 1145, + 509 + ], + "size": { + "0": 438.5014343261719, + "1": 316.36749267578125 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [ + { + "name": "mask", + "type": "MASK", + "link": 13 + } + ], + "properties": { + "Node name for S&R": "LayerMask: MaskPreview" + } + }, + { + "id": 2, + "type": "LoadImage", + "pos": [ + -103, + 516 + ], + "size": [ + 419.90505599864827, + 365.47580918489507 + ], + "flags": {}, + "order": 0, + "mode": 0, + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 12, + 14 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": null, + "shape": 3 + } + ], + "properties": { + "Node name for S&R": "LoadImage" + }, + "widgets_values": [ + "1344x768_redcar (1).png", + "image" + ] + }, + { + "id": 12, + "type": "LayerMask: MaskByColor", + "pos": [ + 774, + 519 + ], + "size": { + "0": 293.6735534667969, + "1": 242.63502502441406 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 12 + }, + { + "name": "mask", + "type": "MASK", + "link": 17 + } + ], + "outputs": [ + { + "name": "mask", + "type": "MASK", + "links": [ + 13 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "LayerMask: MaskByColor" + }, + "widgets_values": [ + "#e64549", + "", + 100, + 2, + 0.75, + false + ] + } + ], + "links": [ + [ + 12, + 2, + 0, + 12, + 0, + "IMAGE" + ], + [ + 13, + 12, + 0, + 9, + 0, + "MASK" + ], + [ + 14, + 2, + 0, + 13, + 0, + "IMAGE" + ], + [ + 17, + 13, + 1, + 12, + 1, + "MASK" + ] + ], + "groups": [], + "config": {}, + "extra": { + "ds": { + "scale": 1.0610764609500107, + "offset": [ + 424.17121706587216, + -130.40930841577526 + ] + } + }, + "version": 0.4 +} \ No newline at end of file