Files
CavinHuang-comfyui-nodes-docs/docs/LayerMask%3A SegformerB2ClothesUltra.md
2024-06-14 19:23:49 +08:00

8.5 KiB

Documentation

为人物生成脸、头发、手臂、腿以及服饰的遮罩,主要用于分割服装。模型分割代码来自StartHua,感谢原作者。 与comfyui_segformer_b2_clothes节点相比,这个节点具有超高的边缘细节。(注意:生成边缘超过2K尺寸的图片使用VITMatte方法将占用大量内存)

*从https://huggingface.co/mattmdjaga/segformer_b2_clothes下载全部文件至ComfyUI/models/segformer_b2_clothes文件夹。

Input types

Required

  • image

    • 图片。
    • Comfy dtype: IMAGE
    • Python dtype: torch.Tensor
  • face

    • 脸。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • hair

    • 头发。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • hat

    • 帽子。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • sunglass

    • 太阳镜。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • left_arm

    • 左臂。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • right_arm

    • 右臂。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • left_leg

    • 左腿。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • right_leg

    • 右腿。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • upper_clothes

    • 上衣。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • skirt

    • 裙子。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • pants

    • 裤子。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • dress

    • 连衣裙。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • belt

    • 腰带。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • shoe

    • 鞋子。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • bag

    • 包。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • scarf

    • 围巾。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • detail_method

    • 边缘处理方法。提供了VITMatte, VITMatte(local), PyMatting, GuidedFilter。如果首次使用VITMatte后模型已经下载,之后可以使用VITMatte(local)。
    • Comfy dtype: ['VITMatte', 'VITMatte(local)', 'PyMatting', 'GuidedFilter']
    • Python dtype: str
  • detail_erode

    • 遮罩边缘向内侵蚀范围。数值越大,向内修复的范围越大。
    • Comfy dtype: INT
    • Python dtype: int
  • detail_dilate

    • 遮罩边缘向外扩张范围。数值越大,向外修复的范围越大
    • Comfy dtype: INT
    • Python dtype: int
  • black_point

    • 边缘黑色采样阈值。
    • Comfy dtype: FLOAT
    • Python dtype: float
  • white_point

    • 边缘白色采样阈值。
    • Comfy dtype: FLOAT
    • Python dtype: float
  • process_detail

    • 此处设为False将跳过边缘处理以节省运行时间。
    • Comfy dtype: BOOLEAN
    • Python dtype: bool

Output types

  • image

    • 图片。
    • Comfy dtype: IMAGE
    • Python dtype: torch.Tensor
  • mask

    • 遮罩。
    • Comfy dtype: MASK
    • Python dtype: torch.Tensor

Usage tips

  • Infra type: CPU

Source code

class Segformer_B2_Clothes:

    def __init__(self):
        pass

    # Labels: 0: "Background", 1: "Hat", 2: "Hair", 3: "Sunglasses", 4: "Upper-clothes", 5: "Skirt",
    # 6: "Pants", 7: "Dress", 8: "Belt", 9: "Left-shoe", 10: "Right-shoe", 11: "Face",
    # 12: "Left-leg", 13: "Right-leg", 14: "Left-arm", 15: "Right-arm", 16: "Bag", 17: "Scarf"

    @classmethod
    def INPUT_TYPES(cls):
        method_list = ['VITMatte', 'VITMatte(local)', 'PyMatting', 'GuidedFilter', ]
        return {"required":
                {
                "image":("IMAGE",),
                "face": ("BOOLEAN", {"default": False}),
                "hair": ("BOOLEAN", {"default": False}),
                "hat": ("BOOLEAN", {"default": False}),
                "sunglass": ("BOOLEAN", {"default": False}),
                "left_arm": ("BOOLEAN", {"default": False}),
                "right_arm": ("BOOLEAN", {"default": False}),
                "left_leg": ("BOOLEAN", {"default": False}),
                "right_leg": ("BOOLEAN", {"default": False}),
                "upper_clothes": ("BOOLEAN", {"default": False}),
                "skirt": ("BOOLEAN", {"default": False}),
                "pants": ("BOOLEAN", {"default": False}),
                "dress": ("BOOLEAN", {"default": False}),
                "belt": ("BOOLEAN", {"default": False}),
                "shoe": ("BOOLEAN", {"default": False}),
                "bag": ("BOOLEAN", {"default": False}),
                "scarf": ("BOOLEAN", {"default": False}),
                "detail_method": (method_list,),
                "detail_erode": ("INT", {"default": 12, "min": 1, "max": 255, "step": 1}),
                "detail_dilate": ("INT", {"default": 6, "min": 1, "max": 255, "step": 1}),
                "black_point": ("FLOAT", {"default": 0.01, "min": 0.01, "max": 0.98, "step": 0.01, "display": "slider"}),
                "white_point": ("FLOAT", {"default": 0.99, "min": 0.02, "max": 0.99, "step": 0.01, "display": "slider"}),
                "process_detail": ("BOOLEAN", {"default": True}),
                }
        }

    RETURN_TYPES = ("IMAGE", "MASK", )
    RETURN_NAMES = ("image", "mask", )
    FUNCTION = "segformer_ultra"
    CATEGORY = '😺dzNodes/LayerMask'

    def segformer_ultra(self, image,
                        face, hat, hair, sunglass, upper_clothes, skirt, pants, dress, belt, shoe,
                        left_leg, right_leg, left_arm, right_arm, bag, scarf, detail_method,
                        detail_erode, detail_dilate, black_point, white_point, process_detail
                        ):

        ret_images = []
        ret_masks = []

        if detail_method == 'VITMatte(local)':
            local_files_only = True
        else:
            local_files_only = False

        for i in image:
            pred_seg, cloth = get_segmentation(i)
            i = torch.unsqueeze(i, 0)
            i = pil2tensor(tensor2pil(i).convert('RGB'))
            orig_image = tensor2pil(i).convert('RGB')

            labels_to_keep = [0]
            if not hat:
                labels_to_keep.append(1)
            if not hair:
                labels_to_keep.append(2)
            if not sunglass:
                labels_to_keep.append(3)
            if not upper_clothes:
                labels_to_keep.append(4)
            if not skirt:
                labels_to_keep.append(5)
            if not pants:
                labels_to_keep.append(6)
            if not dress:
                labels_to_keep.append(7)
            if not belt:
                labels_to_keep.append(8)
            if not shoe:
                labels_to_keep.append(9)
                labels_to_keep.append(10)
            if not face:
                labels_to_keep.append(11)
            if not left_leg:
                labels_to_keep.append(12)
            if not right_leg:
                labels_to_keep.append(13)
            if not left_arm:
                labels_to_keep.append(14)
            if not right_arm:
                labels_to_keep.append(15)
            if not bag:
                labels_to_keep.append(16)
            if not scarf:
                labels_to_keep.append(17)

            mask = np.isin(pred_seg, labels_to_keep).astype(np.uint8)

            # 创建agnostic-mask图像
            mask_image = Image.fromarray((1 - mask) * 255)
            mask_image = mask_image.convert("L")
            _mask = pil2tensor(mask_image)

            detail_range = detail_erode + detail_dilate
            if process_detail:
                if detail_method == 'GuidedFilter':
                    _mask = guided_filter_alpha(i, _mask, detail_range // 6 + 1)
                    _mask = tensor2pil(histogram_remap(_mask, black_point, white_point))
                elif detail_method == 'PyMatting':
                    _mask = tensor2pil(mask_edge_detail(i, _mask, detail_range // 8 + 1, black_point, white_point))
                else:
                    _trimap = generate_VITMatte_trimap(_mask, detail_erode, detail_dilate)
                    _mask = generate_VITMatte(orig_image, _trimap, local_files_only=local_files_only)
                    _mask = tensor2pil(histogram_remap(pil2tensor(_mask), black_point, white_point))
            else:
                _mask = mask2image(_mask)

            ret_image = RGB2RGBA(orig_image, _mask.convert('L'))
            ret_images.append(pil2tensor(ret_image))
            ret_masks.append(image2mask(_mask))

        log(f"{NODE_NAME} Processed {len(ret_images)} image(s).", message_type='finish')
        return (torch.cat(ret_images, dim=0), torch.cat(ret_masks, dim=0),)