diff --git a/README.md b/README.md
index fbe4579..52d5ef7 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,11 @@ If you have any questions or suggestions, you can reach us through:
- QQ Group: 10419777
- WeChat Group:
+## V1.2.0 Update
+1. Add PM_SuperColorTransfer node to simplify the color transfer process
+2. Add PM_SuperMakeUpTransfer node to simplify the process of makeup transfer
+
+
## V1.1.0 Update
1. faceskin adds blur option
2. Add PM_FaceShapMatch node. same as easyphot faceshap match
diff --git a/README_zh-CN.md b/README_zh-CN.md
index 8709170..5754929 100644
--- a/README_zh-CN.md
+++ b/README_zh-CN.md
@@ -15,6 +15,10 @@ English | [简体中文](./README_zh-CN.md)
- QQ 群:10419777
- 微信群:
+## V1.2.0 Update
+1. 增加PM_SuperColorTransfer 节点,简化了颜色迁移的流程
+2. 增加PM_SuperMakeUpTransfer 节点,简化了进行装扮迁移的流程
+
## v1.1.0 更新
1. faceskin 增加模糊选项
2. 增加 PM_FaceShapMatch节点 与easyphoto的FaceshapMatch一致
diff --git a/__init__.py b/__init__.py
index 46d0e23..5753945 100644
--- a/__init__.py
+++ b/__init__.py
@@ -77,6 +77,8 @@ NODE_CLASS_MAPPINGS = {
"PM_GetImageInfo": GetImageInfoPM,
"PM_MakeUpTransfer": MakeUpTransferPM,
"PM_FaceShapMatch": FaceShapMatchPM,
+ "PM_SuperColorTransfer": SuperColorTransferPM,
+ "PM_SuperMakeUpTransfer": SuperMakeUpTransferPM,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"PM_RetinaFace": "RetinaFace PM",
@@ -95,7 +97,9 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"PM_ImageResizeTarget": "ImageResizeTarget PM",
"PM_GetImageInfo": "GetImageInfo PM",
"PM_MakeUpTransfer": "MakeUpTransfer PM",
- "PM_FaceShapMatch":"FaceShapMatch PM"
+ "PM_FaceShapMatch": "FaceShapMatch PM",
+ "PM_SuperColorTransfer": "SuperColorTransfer PM",
+ "PM_SuperMakeUpTransfer": "SuperMakeUpTransfer PM",
}
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
diff --git a/images/wechat.jpg b/images/wechat.jpg
index 03229da..7bed7b3 100644
Binary files a/images/wechat.jpg and b/images/wechat.jpg differ
diff --git a/portrait/nodes.py b/portrait/nodes.py
index 4a1c92a..0007818 100644
--- a/portrait/nodes.py
+++ b/portrait/nodes.py
@@ -6,8 +6,9 @@ from .utils.face_process_utils import call_face_crop, color_transfer, Face_Skin
from .utils.img_utils import img_to_tensor, tensor_to_img, tensor_to_np, np_to_tensor, np_to_mask, img_to_mask, img_to_np
from .model_holder import *
-# import pydevd_pycharm
-# pydevd_pycharm.settrace('49.7.62.197', port=10090, stdoutToServer=True, stderrToServer=True)
+import pydevd_pycharm
+
+pydevd_pycharm.settrace('49.7.62.197', port=10090, stdoutToServer=True, stderrToServer=True)
class RetinaFacePM:
@classmethod
@@ -348,8 +349,6 @@ class MakeUpTransferPM:
CATEGORY = "protrait/model"
def makeup_transfer(self, source_image, makeup_image):
- source_image = tensor_to_img(source_image).resize([256, 256])
- makeup_image = tensor_to_img(makeup_image).resize([256, 256])
result = get_pagan_interface().transfer(source_image, makeup_image)
return (img_to_tensor(result),)
@@ -389,3 +388,73 @@ class FaceShapMatchPM:
input_image_uint8 = np.array(source_image) * face_skin_mask + np.array(match_image) * (1 - face_skin_mask)
return (np_to_tensor(input_image_uint8),)
+
+class SuperColorTransferPM:
+
+ @classmethod
+ def INPUT_TYPES(s):
+ return \
+ {
+ "required": {
+ "main_image": ("IMAGE",),
+ "transfer_image": ("IMAGE",),
+ },
+ "optional": {
+ "avatar_box": ("BOX",),
+ },
+ }
+
+ RETURN_TYPES = ("IMAGE",)
+
+ FUNCTION = "super_color_transfer"
+ CATEGORY = "protrait/model"
+
+ def super_color_transfer(self, main_image, transfer_image, avatar_box=None):
+ origin_np = tensor_to_np(main_image)
+ if avatar_box is not None:
+ main_image = main_image[:, avatar_box[1]:avatar_box[3], avatar_box[0]:avatar_box[2], :]
+ transfer_image = transfer_image[:, avatar_box[1]:avatar_box[3], avatar_box[0]:avatar_box[2], :]
+
+ transfer_result = color_transfer(tensor_to_np(main_image), tensor_to_np(transfer_image)) # 进行颜色迁移
+
+ face_skin_img = get_face_skin()(Image.fromarray(transfer_result), get_retinaface_detection(), [[1, 2, 3, 4, 5, 10, 12, 13]])[0]
+ face_skin_np = img_to_np(face_skin_img)
+ face_skin_np = cv2.blur(face_skin_np, (32, 32)) / 255
+
+ masked_img_np = tensor_to_np(main_image) * (1 - face_skin_np) + transfer_result * face_skin_np
+
+ origin_np[avatar_box[1]:avatar_box[3], avatar_box[0]:avatar_box[2], :] = masked_img_np
+
+ return (np_to_tensor(origin_np),)
+
+class SuperMakeUpTransferPM:
+
+ @classmethod
+ def INPUT_TYPES(s):
+ return \
+ {
+ "required": {
+ "main_image": ("IMAGE",),
+ "makeup_image": ("IMAGE",),
+ },
+ "optional": {
+ "avatar_box": ("BOX",),
+ },
+ }
+
+ RETURN_TYPES = ("IMAGE",)
+ FUNCTION = "super_makeup_transfer"
+ CATEGORY = "protrait/model"
+
+ def super_makeup_transfer(self, main_image, makeup_image, avatar_box=None):
+ box_width, box_height = avatar_box[2] - avatar_box[0], avatar_box[3] - avatar_box[1]
+ origin_np = tensor_to_np(main_image)
+ if avatar_box is not None:
+ main_image = main_image[:, avatar_box[1]:avatar_box[3], avatar_box[0]:avatar_box[2], :]
+ makeup_image = makeup_image[:, avatar_box[1]:avatar_box[3], avatar_box[0]:avatar_box[2], :]
+ resize_source_box_image = tensor_to_img(main_image).resize([256, 256])
+ resize_makeup_box_image = tensor_to_img(makeup_image).resize([256, 256])
+ transfer_image = get_pagan_interface().transfer(resize_source_box_image, resize_makeup_box_image)
+ box_size_transfer = transfer_image.resize([box_width, box_height], Image.Resampling.LANCZOS)
+ origin_np[avatar_box[1]:avatar_box[3], avatar_box[0]:avatar_box[2], :] = img_to_np(box_size_transfer)
+ return (np_to_tensor(origin_np),)