diff --git a/README.MD b/README.MD
index 334b335..0679b8a 100644
--- a/README.MD
+++ b/README.MD
@@ -70,6 +70,7 @@ When this error has occurred, please check the network environment.
## Update
**If the dependency package error after updating, please reinstall the relevant dependency packages.
+* Commit [SegformerB2ClothesUltra](#SegformerB2ClothesUltra) node, it used to segment character clothing. The model segmentation code is from[StartHua](https://github.com/StartHua/Comfyui_segformer_b2_clothes), thanks to the original author.
* [SaveImagePlus](#SaveImagePlus) node adds the output workflow to the json function, supports ```%date``` and ```%time``` to embeddint date or time to path and filename, and adds the preview switch.
* Commit [SaveImagePlus](#SaveImagePlus) node,It can customize the directory where the picture is saved, add a timestamp to the file name, select the save format, set the image compression rate, set whether to save the workflow, and optionally add invisible watermarks to the picture.
* Commit [AddBlindWaterMark](#AddBlindWaterMark), [ShowBlindWaterMark](#ShowBlindWaterMark) nodes, Add invisible watermark and decoded watermark to the picture. Commit [CreateQRCode](#CreateQRCode), [DecodeQRCode](#DecodeQRCode) nodes, It can generate two-dimensional code pictures and decode two-dimensional codes.
@@ -1304,6 +1305,39 @@ On the basis of PersonMaskUltra, the following changes have been made:
* detail_erode: Mask the erosion range inward from the edge. the larger the value, the larger the range of inward repair.
* detail_dilate: The edge of the mask expands outward. the larger the value, the wider the range of outward repair.
+### SegformerB2ClothesUltra
+
+Generate masks for characters' faces, hair, arms, legs, and clothing, mainly used for segmenting clothing.
+The model segmentation code is from[StartHua](https://github.com/StartHua/Comfyui_segformer_b2_clothes),thanks to the original author.
+Compared to the comfyui_segformer_b2_clothes, this node has ultra-high edge details. (Note: Generating images with edges exceeding 2K in size using the VITMatte method will consume a lot of memory)
+
+*Download all model files from [https://huggingface.co/mattmdjaga/segformer_b2_clothes](https://huggingface.co/mattmdjaga/segformer_b2_clothes) to ```ComfyUI/models/segformer_b2_clothes``` folder.
+
+Node Options:
+
+* face: Facial recognition switch.
+* hair: Hair recognition switch.
+* hat: Hat recognition switch.
+* sunglass: Sunglass recognition switch.
+* left_arm: Left arm recognition switch.
+* right_arm: Right arm recognition switch.
+* left_leg: Left leg recognition switch.
+* right_leg: Right leg recognition switch.
+* skirt: Skirt recognition switch.
+* pants: Pants recognition switch.
+* dress: Dress recognition switch.
+* belt: Belt recognition switch.
+* shoe: Shoes recognition switch.
+* bag: Bag recognition switch.
+* scarf: Scarf recognition switch.
+* detail_method: Edge processing methods. provides VITMatte, VITMatte(local), PyMatting, GuidedFilter. If the model has been downloaded after the first use of VITMatte, you can use VITMatte (local) afterwards.
+* detail_erode: Mask the erosion range inward from the edge. the larger the value, the larger the range of inward repair.
+* detail_dilate: The edge of the mask expands outward. the larger the value, the wider the range of outward repair.
+* black_point: Edge black sampling threshold.
+* white_point: Edge white sampling threshold.
+* process_detail: Set to false here will skip edge processing to save runtime.
+
+
### YoloV8Detect
Use the YoloV8 model to detect faces, hand box areas, or character segmentation. Supports the output of the selected number of channels.
Download the model files from [GoogleDrive](https://drive.google.com/drive/folders/1I5TISO2G1ArSkKJu1O9b4Uvj3DVgn5d2) or [BaiduNetdisk](https://pan.baidu.com/s/1ImoJrzL1zDgaCqaSzrNEtw?pwd=5xgk) to ```ComfyUI/models/yolo``` folder.
diff --git a/README_CN.MD b/README_CN.MD
index b4fa7c8..d57fba7 100644
--- a/README_CN.MD
+++ b/README_CN.MD
@@ -70,6 +70,7 @@ git clone https://github.com/chflame163/ComfyUI_LayerStyle.git
## 更新说明
**如果本插件更新后出现依赖包错误,请重新安装相关依赖包。
+* 添加 [SegformerB2ClothesUltra](#SegformerB2ClothesUltra)节点,用于分割人物服装。模型分割代码来自[StartHua](https://github.com/StartHua/Comfyui_segformer_b2_clothes),感谢原作者。
* [SaveImagePlus](#SaveImagePlus)节点增加输出工作流为json功能,支持使用```%date```和```%time```在路径和文件名嵌入时间,增加预览开关。
* 添加 [SaveImagePlus](#SaveImagePlus)节点,可自定义保存图片的目录,文件名增加时间戳,选择保存格式,设置图片压缩率,设置是否保存工作流,以及可选给图片添加隐形水印。
* 添加 [AddBlindWaterMark](#AddBlindWaterMark), [ShowBlindWaterMark](#ShowBlindWaterMark)节点,为图片增加隐形水印和解码水印。添加 [CreateQRCode](#CreateQRCode), [DecodeQRCode](#DecodeQRCode)节点,可生成二维码图片和解码二维码。
@@ -1291,6 +1292,38 @@ PersonMaskUltra的V2升级版,增加了VITMatte边缘处理方法。(注意:
* detail_dilate: 遮罩边缘向外扩张范围。数值越大,向外修复的范围越大。
+### SegformerB2ClothesUltra
+
+为人物生成脸、头发、手臂、腿以及服饰的遮罩,主要用于分割服装。模型分割代码来自[StartHua](https://github.com/StartHua/Comfyui_segformer_b2_clothes),感谢原作者。
+与comfyui_segformer_b2_clothes节点相比,这个节点具有超高的边缘细节。(注意:生成边缘超过2K尺寸的图片使用VITMatte方法将占用大量内存)
+
+*从[https://huggingface.co/mattmdjaga/segformer_b2_clothes](https://huggingface.co/mattmdjaga/segformer_b2_clothes)下载全部文件至```ComfyUI/models/segformer_b2_clothes```文件夹。
+
+节点选项说明:
+
+* face: 脸部识别。
+* hair: 头发识别。
+* hat: 帽子识别。
+* sunglass: 墨镜识别。
+* left_arm:左手臂识别。
+* right_arm:右手臂识别。
+* left_leg:左腿识别。
+* right_leg:右腿识别。
+* skirt:短裙识别。
+* pants:裤子识别。
+* dress:连衣裙识别。
+* belt:腰带识别。
+* shoe:鞋子识别。
+* bag:背包识别。
+* scarf:围巾识别。
+* detail_method: 边缘处理方法。提供了VITMatte, VITMatte(local), PyMatting, GuidedFilter。如果首次使用VITMatte后模型已经下载,之后可以使用VITMatte(local)。
+* detail_erode: 遮罩边缘向内侵蚀范围。数值越大,向内修复的范围越大。
+* detail_dilate: 遮罩边缘向外扩张范围。数值越大,向外修复的范围越大。
+* black_point: 边缘黑色采样阈值。
+* white_point: 边缘黑色采样阈值。
+* process_detail: 此处设为False将跳过边缘处理以节省运行时间。
+
+
### YoloV8Detect
使用YoloV8模型检测人脸、手部box区域,或者人物分割。支持输出所选择数量的通道。
请在 [GoogleDrive](https://drive.google.com/drive/folders/1I5TISO2G1ArSkKJu1O9b4Uvj3DVgn5d2) 或者 [百度网盘](https://pan.baidu.com/s/1ImoJrzL1zDgaCqaSzrNEtw?pwd=5xgk) 下载模型文件并放到 ```ComfyUI/models/yolo``` 文件夹。
diff --git a/image/segformer_ultra_example.jpg b/image/segformer_ultra_example.jpg
new file mode 100644
index 0000000..f2cb386
Binary files /dev/null and b/image/segformer_ultra_example.jpg differ
diff --git a/image/segformer_ultra_node.jpg b/image/segformer_ultra_node.jpg
new file mode 100644
index 0000000..387a883
Binary files /dev/null and b/image/segformer_ultra_node.jpg differ
diff --git a/py/imagefunc.py b/py/imagefunc.py
index 6202217..3912121 100644
--- a/py/imagefunc.py
+++ b/py/imagefunc.py
@@ -1272,6 +1272,8 @@ def load_RMBG_model():
net.eval()
return net
+
+
def RMBG(image:Image) -> Image:
rmbgmodel = load_RMBG_model()
w, h = image.size
diff --git a/py/segformer_ultra.py b/py/segformer_ultra.py
new file mode 100644
index 0000000..0034770
--- /dev/null
+++ b/py/segformer_ultra.py
@@ -0,0 +1,165 @@
+'''
+原始代码来自 https://github.com/StartHua/Comfyui_segformer_b2_clothes
+'''
+
+from transformers import SegformerImageProcessor, AutoModelForSemanticSegmentation
+import torch.nn as nn
+from .imagefunc import *
+
+NODE_NAME = 'SegformerB2ClothesUltra'
+
+# 切割服装
+def get_segmentation(tensor_image):
+ cloth = tensor2pil(tensor_image)
+ model_folder_path = os.path.join(folder_paths.models_dir, "segformer_b2_clothes")
+ try:
+ model_folder_path = os.path.normpath(folder_paths.folder_names_and_paths['segformer_b2_clothes'][0][0])
+ except:
+ pass
+
+ processor = SegformerImageProcessor.from_pretrained(model_folder_path)
+ model = AutoModelForSemanticSegmentation.from_pretrained(model_folder_path)
+ # 预处理和预测
+ inputs = processor(images=cloth, return_tensors="pt")
+ outputs = model(**inputs)
+ logits = outputs.logits.cpu()
+ upsampled_logits = nn.functional.interpolate(logits, size=cloth.size[::-1], mode="bilinear", align_corners=False)
+ pred_seg = upsampled_logits.argmax(dim=1)[0].numpy()
+ return pred_seg,cloth
+
+
+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": True}),
+ "hair": ("BOOLEAN", {"default": True}),
+ "hat": ("BOOLEAN", {"default": True}),
+ "sunglass": ("BOOLEAN", {"default": True}),
+ "left_arm": ("BOOLEAN", {"default": True}),
+ "right_arm": ("BOOLEAN", {"default": True}),
+ "left_leg": ("BOOLEAN", {"default": True}),
+ "right_leg": ("BOOLEAN", {"default": True}),
+ "upper_clothes": ("BOOLEAN", {"default": True}),
+ "skirt": ("BOOLEAN", {"default": True}),
+ "pants": ("BOOLEAN", {"default": True}),
+ "dress": ("BOOLEAN", {"default": True}),
+ "belt": ("BOOLEAN", {"default": True}),
+ "shoe": ("BOOLEAN", {"default": True}),
+ "bag": ("BOOLEAN", {"default": True}),
+ "scarf": ("BOOLEAN", {"default": True}),
+ "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}),
+ "white_point": ("FLOAT", {"default": 0.99, "min": 0.02, "max": 0.99, "step": 0.01}),
+ "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),)
+
+NODE_CLASS_MAPPINGS = {
+ "LayerMask: SegformerB2ClothesUltra": Segformer_B2_Clothes
+}
+
+NODE_DISPLAY_NAME_MAPPINGS = {
+ "LayerMask: SegformerB2ClothesUltra": "LayerMask: Segformer B2 Clothes Ultra"
+}