Compare commits
54
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fde067c9f5 | ||
|
|
f233cae900 | ||
|
|
94dcf5b2d9 | ||
|
|
db728d3b70 | ||
|
|
9a7cdbd756 | ||
|
|
74dce3296d | ||
|
|
e30f28d20e | ||
|
|
baa3724ae2 | ||
|
|
9453492f02 | ||
|
|
b2d44fb139 | ||
|
|
1d09d46f16 | ||
|
|
bac4d69fba | ||
|
|
0c06d3e3bf | ||
|
|
7861f289c5 | ||
|
|
fd5f4737fe | ||
|
|
fb2a1e3283 | ||
|
|
75cb3303a9 | ||
|
|
2763361b55 | ||
|
|
3f70c7eb6b | ||
|
|
5beb93db0a | ||
|
|
98d3b8ac13 | ||
|
|
c871825137 | ||
|
|
26245524ea | ||
|
|
2292031e5f | ||
|
|
017dcee81b | ||
|
|
6d6eb679d5 | ||
|
|
2abacd7fde | ||
|
|
6a2d356ed7 | ||
|
|
97c93eff3d | ||
|
|
2598a6efe4 | ||
|
|
dedd32d29e | ||
|
|
a839966e9f | ||
|
|
c8e3535869 | ||
|
|
359e72cd2e | ||
|
|
a11d54294f | ||
|
|
6013eb426c | ||
|
|
0b005db217 | ||
|
|
658f057ccd | ||
|
|
5b77e1cf3d | ||
|
|
a6dbede699 | ||
|
|
dc01281d85 | ||
|
|
948b679e70 | ||
|
|
6335f3c3d4 | ||
|
|
3744780d0b | ||
|
|
425924bcbb | ||
|
|
d364f2874a | ||
|
|
e75c9a402a | ||
|
|
e45b89d111 | ||
|
|
3c61c01ba1 | ||
|
|
a41dfa668c | ||
|
|
e54e9ea579 | ||
|
|
d9ade2e531 | ||
|
|
4abaf4cd92 | ||
|
|
60bebf7b02 |
@@ -1,2 +1,3 @@
|
||||
__pycache__
|
||||
.idea
|
||||
*.DS_Store
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# [Portrait-Maker](https://github.com/THtianhao/ComfyUI-Portrait-Maker)
|
||||
This project is an adaptation of [EasyPhoto](https://github.com/aigc-apps/sd-webui-EasyPhoto), which breaks down the process of [EasyPhoto](https://github.com/aigc-apps/sd-webui-EasyPhoto) and will add a series of operations on human portraits in the future.
|
||||

|
||||

|
||||
|
||||
English | [简体中文](./README_zh-CN.md)
|
||||
|
||||
@@ -11,13 +11,21 @@ If you have any questions or suggestions, you can reach us through:
|
||||
- Email: tototianhao@gmail.com
|
||||
- telegram: https://t.me/+JoFE2vqHU4phZjg1
|
||||
- QQ Group: 10419777
|
||||
- WeChat Group: <img src="./images/wechat.jpg" width="200">
|
||||
- WeChat Group: <img src="./images/wechat.jpg" width="300">
|
||||
|
||||
## 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
|
||||
3. Add v1.2.0 workflow
|
||||
|
||||
|
||||
## V1.1.0 Update
|
||||
1. faceskin adds blur option
|
||||
2. Add PM_FaceShapMatch node. See node introduction for details.
|
||||
3. Add PM_MakeUpTransfer node. See node introduction for details.
|
||||
3. Add a super-resolution model to the PM_PortraitEnhancement node. This super-resolution model can not highlight faces.
|
||||
2. Add PM_FaceShapMatch node. same as easyphot faceshap match
|
||||
3. Add PM_MakeUpTransfer node. same as easyphoto makeup transfer.
|
||||
4. Add a super-resolution model to the PM_PortraitEnhancement node. This super-resolution model can not highlight faces.
|
||||
5. Add v1.1.0 workflow
|
||||
6. RetinaFace supports face selection
|
||||
|
||||
## V1.0.0 Update
|
||||
1. Added log for model downloads.
|
||||
@@ -33,10 +41,6 @@ If you have any questions or suggestions, you can reach us through:
|
||||
## Installation
|
||||
**Note: When you start the plugin for the first time, it will download all the models required by EasyPhoto. You can see the download progress in the terminal. Please do not interrupt the download (no hash verification for startup speed). If the download is interrupted, you need to manually delete the files downloaded halfway last time and download them again.**
|
||||
|
||||
### For Windows users
|
||||
|
||||
If you are using a project extracted from a zip package while using ComfyUI, you won't be able to use this plugin. This project relies on ModelScope, but the virtual environment provided in the official ComfyUI zip package cannot install ModelScope. Furthermore, the ComfyUI author has responded, stating that this issue cannot be resolved.[aliyunsdkcor error](https://github.com/ltdrdata/ComfyUI-Impact-Pack/issues/223) If Windows users wish to use this plugin for analyzing and composing ComfyUI workflows, they will need to create their own virtual environment. (I am using Python 3.10.6.).Of course, if you know a solution, feel free to submit a pull request (PR).
|
||||
|
||||
### install step
|
||||
1. First, install ComfyUI.
|
||||
|
||||
@@ -67,6 +71,7 @@ Click "Load" in the right panel of ComfyUI and select the ./workflow/easyphoto_w
|
||||
* RetainFace PM: Perform matting using models from Model Scope. [Link](https://www.modelscope.cn/models/damo/cv_resnet50_face-detection_retinaface/summary)
|
||||
* image: Input image
|
||||
* multi_user_facecrop_ratio: Multiplicative factor for extracting the head region.
|
||||
* face_index : Choose which face
|
||||
|
||||
* FaceFusion PM: Merge faces from two images.
|
||||
* image: Input image
|
||||
@@ -123,6 +128,8 @@ Click "Load" in the right panel of ComfyUI and select the ./workflow/easyphoto_w
|
||||
* Face Shape Match PM: Apply a certain level of fusion between the diffused image and the original image to reduce differences around the face.
|
||||
|
||||
* Makeup Transfer PM: Use a GAN network model to perform makeup transfer.
|
||||
* SuperMakeUpTransfer PM:(Multi-node integration) makeup by merging two pictures
|
||||
* SuperColorTransfer PM:(Multi-node integration) transfer the colors of two pictures
|
||||
## Contribution
|
||||
|
||||
If you find any issues or have suggestions for improvement, feel free to contribute. Follow these steps:
|
||||
|
||||
+15
-9
@@ -2,7 +2,7 @@
|
||||
|
||||
这个项目改编于[EasyPhoto](https://github.com/aigc-apps/sd-webui-EasyPhoto),对于[EasyPhoto](https://github.com/aigc-apps/sd-webui-EasyPhoto)进行了流程上的拆解,后续会加入其他项目处理人物头像上的系列操作。
|
||||
|
||||

|
||||

|
||||
|
||||
English | [简体中文](./README_zh-CN.md)
|
||||
|
||||
@@ -13,13 +13,20 @@ English | [简体中文](./README_zh-CN.md)
|
||||
- 电子邮件:tototianhao@gmail.com
|
||||
- telegram: https://t.me/+JoFE2vqHU4phZjg1
|
||||
- QQ 群:10419777
|
||||
- 微信群: <img src="./images/wechat.jpg" width="200">
|
||||
- 微信群: <img src="./images/wechat.jpg" width="300">
|
||||
|
||||
## V1.2.0 Update
|
||||
1. 增加PM_SuperColorTransfer 节点,简化了颜色迁移的流程
|
||||
2. 增加PM_SuperMakeUpTransfer 节点,简化了进行装扮迁移的流程
|
||||
3. 增加v1.2.0 workflow
|
||||
|
||||
## v1.1.0 更新
|
||||
1. faceskin 增加模糊选项
|
||||
2. 增加 PM_FaceShapMatch节点 详情查看节点介绍
|
||||
3. 增加 PM_MakeUpTransfer节点 详情查看节点介绍
|
||||
3. PM_PortraitEnhancement节点增加一种超分模型,此超分模型可以对人脸不做高光
|
||||
2. 增加 PM_FaceShapMatch节点 与easyphoto的FaceshapMatch一致
|
||||
3. 增加 PM_MakeUpTransfer节点 与easyphoto的MakeupTransfer一致
|
||||
4. PM_PortraitEnhancement节点增加一种超分模型,此超分模型可以对人脸不做高光
|
||||
5. 增加v1.1.0 workflow
|
||||
6. RetinaFace 支持选择人脸
|
||||
|
||||
## v1.0.0 更新
|
||||
|
||||
@@ -37,10 +44,6 @@ English | [简体中文](./README_zh-CN.md)
|
||||
|
||||
**注意:初次启动插件的时候会下载EasyPhoto所需要的所有模型,在terminal中可以看到下载进度,请不要中断下载,(为了启动速度,没有做hash校验),如果中断下载,需要手动删除上次下载一半的文件,重新下载。**
|
||||
|
||||
### windows用户
|
||||
|
||||
如果在使用ComfyUI的时候使用zip包解压后的项目,是无法使用本插件的,本项目依赖modelscope,但是ComfyUI官方zip包中的虚拟环境无法安装modelscope,并且ComfyUI作者已经回复了表示无法解决此问题[aliyunsdkcor error](https://github.com/ltdrdata/ComfyUI-Impact-Pack/issues/223)如果windows用户想使用本插件来分析、组合ComfyUI的流程,请自己创建虚拟环境。(我使用的是python3.10.6),当然如果您知道解决的方法,欢迎提交pr
|
||||
|
||||
### 步骤
|
||||
1. 首先安装ComfyUI
|
||||
|
||||
@@ -70,6 +73,7 @@ Easyphoto工作位置: [./workflow/easyphoto.json](./workflows/easyphoto.json )
|
||||
* RetainFace PM:使用Model Scope中的模型进行抠图 [链接](https://www.modelscope.cn/models/damo/cv_resnet50_face-detection_retinaface/summary)
|
||||
* image:输入图像
|
||||
* multi_user_facecrop_ratio:提取头像区域的倍数
|
||||
* face_index : 选择第几个人脸
|
||||
* FaceFusion PM:将两张图像的人脸进行融合
|
||||
* image:输入图像
|
||||
* user_image:要融合的头像
|
||||
@@ -110,6 +114,8 @@ Easyphoto工作位置: [./workflow/easyphoto.json](./workflows/easyphoto.json )
|
||||
* GetImageInfo PM: 提取图片的宽高
|
||||
* FaceShapMatchPM: 扩散后的图片和原图片进行一定的融合,减少脸旁边的差异
|
||||
* MakeUpTransferPM: 使用gan网络模型对妆容进行一定的迁移
|
||||
* SuperMakeUpTransferPM:(多节点的整合)融合两张图片的装扮
|
||||
* SuperColorTransferPM:(多节点的整合)迁移两张图片的颜色
|
||||
|
||||
## 贡献
|
||||
|
||||
|
||||
+10
-30
@@ -1,12 +1,9 @@
|
||||
import sys
|
||||
import os
|
||||
import os, sys
|
||||
|
||||
main_path = os.path.dirname(__file__)
|
||||
sys.path.append(main_path)
|
||||
|
||||
import subprocess
|
||||
import threading
|
||||
|
||||
import portrait.install
|
||||
import requests
|
||||
from tqdm import tqdm
|
||||
from portrait.nodes import *
|
||||
@@ -14,30 +11,6 @@ from portrait.nodes import *
|
||||
# import pydevd_pycharm
|
||||
# pydevd_pycharm.settrace('49.7.62.197', port=10090, stdoutToServer=True, stderrToServer=True)
|
||||
|
||||
|
||||
def handle_stream(stream, prefix):
|
||||
for line in stream:
|
||||
print(prefix, line, end="")
|
||||
|
||||
def run_script(cmd, cwd='.'):
|
||||
process = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1)
|
||||
|
||||
stdout_thread = threading.Thread(target=handle_stream, args=(process.stdout, ""))
|
||||
stderr_thread = threading.Thread(target=handle_stream, args=(process.stderr, "[!]"))
|
||||
|
||||
stdout_thread.start()
|
||||
stderr_thread.start()
|
||||
|
||||
stdout_thread.join()
|
||||
stderr_thread.join()
|
||||
|
||||
return process.wait()
|
||||
|
||||
print("## installing dependencies")
|
||||
|
||||
requirements_path = os.path.join(main_path, "requirements.txt")
|
||||
run_script([sys.executable, '-s', '-m', 'pip', 'install', '-q', '-r', requirements_path])
|
||||
|
||||
def urldownload_progressbar(url, file_path):
|
||||
response = requests.get(url, stream=True)
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
@@ -77,6 +50,9 @@ NODE_CLASS_MAPPINGS = {
|
||||
"PM_GetImageInfo": GetImageInfoPM,
|
||||
"PM_MakeUpTransfer": MakeUpTransferPM,
|
||||
"PM_FaceShapMatch": FaceShapMatchPM,
|
||||
"PM_SuperColorTransfer": SuperColorTransferPM,
|
||||
"PM_SuperMakeUpTransfer": SuperMakeUpTransferPM,
|
||||
"PM_Similarity": SimilarityPM,
|
||||
}
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"PM_RetinaFace": "RetinaFace PM",
|
||||
@@ -95,7 +71,11 @@ 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",
|
||||
"PM_Similarity": "Similarity PM",
|
||||
|
||||
}
|
||||
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 156 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 754 KiB |
Regular → Executable
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 679 KiB |
Binary file not shown.
+2
-2
@@ -6,7 +6,7 @@ utils_path = os.path.join(root_path, "utils")
|
||||
models_path = os.path.join(root_path, "models")
|
||||
# save_dirs
|
||||
urls = [
|
||||
"https://pai-aigc-photog.oss-cn-hangzhou.aliyuncs.com/webui/ChilloutMix-ni-fp16.safetensors",
|
||||
# "https://pai-aigc-photog.oss-cn-hangzhou.aliyuncs.com/webui/ChilloutMix-ni-fp16.safetensors",
|
||||
"https://pai-aigc-photog.oss-cn-hangzhou.aliyuncs.com/webui/control_v11p_sd15_openpose.pth",
|
||||
"https://pai-aigc-photog.oss-cn-hangzhou.aliyuncs.com/webui/control_v11p_sd15_canny.pth",
|
||||
"https://pai-aigc-photog.oss-cn-hangzhou.aliyuncs.com/webui/control_v11f1e_sd15_tile.pth",
|
||||
@@ -23,7 +23,7 @@ urls = [
|
||||
|
||||
]
|
||||
filenames = [
|
||||
os.path.join(folder_names_and_paths['checkpoints'][0][0], "Chilloutmix-Ni-pruned-fp16-fix.safetensors"),
|
||||
# os.path.join(folder_names_and_paths['checkpoints'][0][0], "Chilloutmix-Ni-pruned-fp16-fix.safetensors"),
|
||||
os.path.join(folder_names_and_paths['controlnet'][0][0], "control_v11p_sd15_openpose.pth"),
|
||||
os.path.join(folder_names_and_paths['controlnet'][0][0], "control_v11p_sd15_canny.pth"),
|
||||
os.path.join(folder_names_and_paths['controlnet'][0][0], "control_v11f1e_sd15_tile.pth"),
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import threading
|
||||
import locale
|
||||
import traceback
|
||||
import re
|
||||
|
||||
from .config import root_path
|
||||
|
||||
plugin_name = os.path.basename(root_path)
|
||||
windows_not_install = ['mmcv_full\n']
|
||||
|
||||
def log(msg, end=None, file=None):
|
||||
print(f'{plugin_name} :', msg, end=end, file=file)
|
||||
|
||||
def handle_stream(stream, is_stdout):
|
||||
stream.reconfigure(encoding=locale.getpreferredencoding(), errors='replace')
|
||||
|
||||
for msg in stream:
|
||||
if is_stdout:
|
||||
log(msg, end="", file=sys.stdout)
|
||||
else:
|
||||
log(msg, end="", file=sys.stderr)
|
||||
|
||||
def process_wrap(cmd_str, cwd=None, handler=None):
|
||||
log(f"EXECUTE: {cmd_str} in '{cwd}'")
|
||||
process = subprocess.Popen(cmd_str, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1)
|
||||
|
||||
if handler is None:
|
||||
handler = handle_stream
|
||||
|
||||
stdout_thread = threading.Thread(target=handler, args=(process.stdout, True))
|
||||
stderr_thread = threading.Thread(target=handler, args=(process.stderr, False))
|
||||
|
||||
stdout_thread.start()
|
||||
stderr_thread.start()
|
||||
|
||||
stdout_thread.join()
|
||||
stderr_thread.join()
|
||||
|
||||
return process.wait()
|
||||
|
||||
# ---
|
||||
pip_list = None
|
||||
|
||||
def get_installed_packages():
|
||||
global pip_list
|
||||
if pip_list is None:
|
||||
try:
|
||||
result = subprocess.check_output([sys.executable, '-m', 'pip', 'list'], universal_newlines=True)
|
||||
pip_list = set([line.split()[0].lower() for line in result.split('\n') if line.strip()])
|
||||
except subprocess.CalledProcessError as e:
|
||||
log(f"Failed to retrieve the information of installed pip packages.")
|
||||
return set()
|
||||
|
||||
return pip_list
|
||||
|
||||
def mmcv_install():
|
||||
process_wrap(pip_install + ['-U', 'openmim'], cwd=root_path)
|
||||
process_wrap(mim_install + ['mmcv-full'], cwd=root_path)
|
||||
pass
|
||||
|
||||
def is_installed(name):
|
||||
name = name.strip()
|
||||
pattern = r'([^<>!=]+)([<>!=]=?)'
|
||||
match = re.search(pattern, name)
|
||||
|
||||
if match:
|
||||
name = match.group(1)
|
||||
|
||||
result = name.lower() in get_installed_packages()
|
||||
return result
|
||||
|
||||
def check_and_install_requirements(file_path):
|
||||
log(file_path)
|
||||
version = sys.version_info[:2]
|
||||
if os.path.exists(file_path):
|
||||
with open(file_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
for line in lines:
|
||||
log(line)
|
||||
if not is_installed(line):
|
||||
if platform.system() == "Windows" and version[1] == 11 and 'insightface' in line:
|
||||
process_wrap(pip_install + ['insightface-0.7.3-cp311-cp311-win_amd64.whl'], cwd=root_path)
|
||||
continue
|
||||
if platform.system() == "Windows" and line in windows_not_install:
|
||||
log(f"windows skip {line}")
|
||||
continue
|
||||
log(f"install {line}")
|
||||
process_wrap(pip_install + [line], cwd=root_path)
|
||||
return False
|
||||
return True
|
||||
|
||||
try:
|
||||
import platform
|
||||
|
||||
log("### : Check dependencies")
|
||||
if "python_embed" in sys.executable or "python_embedded" in sys.executable:
|
||||
pip_install = [sys.executable, '-s', '-m', 'pip', 'install', '-q']
|
||||
mim_install = [sys.executable, '-s', '-m', 'mim', 'install', '-q']
|
||||
else:
|
||||
pip_install = [sys.executable, '-m', 'pip', 'install', '-q']
|
||||
mim_install = [sys.executable, '-m', 'mim', 'install', '-q']
|
||||
|
||||
subpack_req = os.path.join(root_path, "requirements.txt")
|
||||
# mmcv_install()
|
||||
check_and_install_requirements(subpack_req)
|
||||
if sys.argv[0] == 'install.py':
|
||||
sys.path.append('..') # for portable version
|
||||
|
||||
except Exception as e:
|
||||
log("Dependency installation has failed. Please install manually.")
|
||||
traceback.print_exc()
|
||||
@@ -16,6 +16,7 @@ skin_retouching = None
|
||||
portrait_enhancement = None
|
||||
psgan_interface = None
|
||||
real_gan_sr = None
|
||||
face_recognition = None
|
||||
|
||||
def get_retinaface_detection():
|
||||
global retinaface_detection
|
||||
@@ -72,3 +73,10 @@ def get_pagan_interface():
|
||||
makeup_transfer_model_path = os.path.join(models_path, "makeup_transfer.pth")
|
||||
psgan_interface = PSGAN_Inference("cuda", makeup_transfer_model_path, get_retinaface_detection(), get_face_skin(), face_landmarks_model_path)
|
||||
return psgan_interface
|
||||
|
||||
def get_face_recognition():
|
||||
global face_recognition
|
||||
if face_recognition is None:
|
||||
face_recognition = pipeline("face_recognition", model="bubbliiiing/cv_retinafce_recognition", model_revision="v1.0.3")
|
||||
return face_recognition
|
||||
|
||||
|
||||
+164
-28
@@ -7,13 +7,15 @@ from .utils.img_utils import img_to_tensor, tensor_to_img, tensor_to_np, np_to_t
|
||||
from .model_holder import *
|
||||
|
||||
# import pydevd_pycharm
|
||||
#
|
||||
# pydevd_pycharm.settrace('49.7.62.197', port=10090, stdoutToServer=True, stderrToServer=True)
|
||||
|
||||
class RetinaFacePM:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {"image": ("IMAGE",),
|
||||
"multi_user_facecrop_ratio": ("FLOAT", {"default": 1, "min": 0, "max": 10, "step": 0.01})
|
||||
"multi_user_facecrop_ratio": ("FLOAT", {"default": 1, "min": 0, "max": 10, "step": 0.01}),
|
||||
"face_index": ("INT", {"default": 0, "min": 0, "max": 10, "step": 1})
|
||||
}}
|
||||
|
||||
RETURN_TYPES = ("IMAGE", "MASK", "BOX")
|
||||
@@ -21,12 +23,14 @@ class RetinaFacePM:
|
||||
FUNCTION = "retain_face"
|
||||
CATEGORY = "protrait/model"
|
||||
|
||||
def retain_face(self, image, multi_user_facecrop_ratio):
|
||||
def retain_face(self, image, multi_user_facecrop_ratio, face_index):
|
||||
np_image = np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8)
|
||||
image = Image.fromarray(np_image)
|
||||
retinaface_boxes, retinaface_keypoints, retinaface_masks, retinaface_tensor = call_face_crop(get_retinaface_detection(), image, multi_user_facecrop_ratio)
|
||||
crop_image = image.crop(retinaface_boxes[0])
|
||||
return (img_to_tensor(crop_image), retinaface_tensor, retinaface_boxes[0])
|
||||
retinaface_boxes, retinaface_keypoints, retinaface_masks, retinaface_mask_nps = call_face_crop(get_retinaface_detection(), image, multi_user_facecrop_ratio)
|
||||
crop_image = image.crop(retinaface_boxes[face_index])
|
||||
retinaface_mask = np_to_mask(retinaface_mask_nps[face_index])
|
||||
retinaface_boxe = retinaface_boxes[face_index]
|
||||
return (img_to_tensor(crop_image), retinaface_mask, retinaface_boxe)
|
||||
|
||||
class FaceFusionPM:
|
||||
|
||||
@@ -42,21 +46,46 @@ class FaceFusionPM:
|
||||
|
||||
CATEGORY = "protrait/model"
|
||||
|
||||
def resize(self, tensor):
|
||||
image = tensor_to_img(tensor)
|
||||
short_side = max(image.width, image.height)
|
||||
resize = float(short_side / 640)
|
||||
new_size = (int(image.width // resize), int(image.height // resize))
|
||||
resize_image = image.resize(new_size, Image.Resampling.LANCZOS)
|
||||
return img_to_np(resize_image)
|
||||
|
||||
def img_face_fusion(self, source_image, swap_image, mode):
|
||||
if mode == "ali":
|
||||
source_image = tensor_to_img(source_image)
|
||||
swap_image = tensor_to_img(swap_image)
|
||||
fusion_image = get_image_face_fusion()(dict(template=source_image, user=swap_image))[
|
||||
source_image_pil = tensor_to_img(source_image)
|
||||
swap_image_pil = tensor_to_img(swap_image)
|
||||
fusion_image = get_image_face_fusion()(dict(template=source_image_pil, user=swap_image_pil))[
|
||||
OutputKeys.OUTPUT_IMG]
|
||||
result_image = Image.fromarray(cv2.cvtColor(fusion_image, cv2.COLOR_BGR2RGB))
|
||||
return (img_to_tensor(result_image),)
|
||||
else:
|
||||
width, height = source_image.shape[2], source_image.shape[1]
|
||||
need_resize = False
|
||||
source_np = tensor_to_np(source_image)
|
||||
swap_np = tensor_to_np(swap_image)
|
||||
if source_image.shape[2] > 640 or source_image.shape[1] > 640:
|
||||
source_np = self.resize(source_image)
|
||||
need_resize = True
|
||||
if swap_image.shape[2] > 640 or swap_image.shape[1] > 640:
|
||||
swap_np = self.resize(swap_image)
|
||||
get_face_analysis().prepare(ctx_id=0, det_size=(640, 640))
|
||||
source_image = tensor_to_np(source_image)
|
||||
faces = get_face_analysis().get(source_image)
|
||||
swap_image = tensor_to_np(swap_image)
|
||||
swap_face = get_face_analysis().get(swap_image)
|
||||
result_image = get_roop().get(source_image, faces[0], swap_face[0], paste_back=True)
|
||||
faces = get_face_analysis().get(source_np)
|
||||
swap_faces = get_face_analysis().get(swap_np)
|
||||
if len(faces) == 0:
|
||||
raise RuntimeError("No face was recognized in the source image / source image 没有识别到人脸")
|
||||
if len(swap_faces) == 0:
|
||||
print("No face was recognized in the swap faces / swap faces没有识别到人脸, 用原脸替换!!!!!!!!!")
|
||||
return (source_image,)
|
||||
result_image = get_roop().get(source_np, faces[0], swap_faces[0], paste_back=True)
|
||||
if need_resize:
|
||||
image = Image.fromarray(result_image)
|
||||
new_size = width, height
|
||||
result_image = image.resize(new_size, Image.Resampling.LANCZOS)
|
||||
result_image = img_to_np(result_image)
|
||||
return (np_to_tensor(result_image),)
|
||||
|
||||
class RatioMerge2ImagePM:
|
||||
@@ -73,7 +102,7 @@ class RatioMerge2ImagePM:
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_ratio_merge"
|
||||
|
||||
CATEGORY = "protrait/model"
|
||||
CATEGORY = "protrait/other"
|
||||
|
||||
def image_ratio_merge(self, image1, image2, fusion_rate):
|
||||
rate_fusion_image = image1 * (1 - fusion_rate) + image2 * fusion_rate
|
||||
@@ -132,7 +161,7 @@ class ExpandMaskFaceWidthPM:
|
||||
RETURN_TYPES = ("MASK", "BOX")
|
||||
FUNCTION = "expand_mask_face_width"
|
||||
|
||||
CATEGORY = "protrait/model"
|
||||
CATEGORY = "protrait/other"
|
||||
|
||||
def expand_mask_face_width(self, mask, box, expand_width):
|
||||
h, w = mask.shape[1], mask.shape[2]
|
||||
@@ -160,7 +189,7 @@ class BoxCropImagePM:
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_NAMES = ("crop_image",)
|
||||
FUNCTION = "box_crop_image"
|
||||
CATEGORY = "protrait/model"
|
||||
CATEGORY = "protrait/other"
|
||||
|
||||
def box_crop_image(self, image, box):
|
||||
image = image[:, box[1]:box[3], box[0]:box[2], :]
|
||||
@@ -178,7 +207,7 @@ class ColorTransferPM:
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "color_transfer"
|
||||
|
||||
CATEGORY = "protrait/model"
|
||||
CATEGORY = "protrait/other"
|
||||
|
||||
def color_transfer(self, transfer_from, transfer_to):
|
||||
transfer_result = color_transfer(tensor_to_np(transfer_from), tensor_to_np(transfer_to)) # 进行颜色迁移
|
||||
@@ -219,7 +248,7 @@ class MaskDilateErodePM:
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "mask_dilate_erode"
|
||||
|
||||
CATEGORY = "protrait/model"
|
||||
CATEGORY = "protrait/other"
|
||||
|
||||
def mask_dilate_erode(self, mask):
|
||||
out_mask = Image.fromarray(np.uint8(cv2.dilate(tensor_to_np(mask), np.ones((96, 96), np.uint8), iterations=1) - cv2.erode(tensor_to_np(mask), np.ones((48, 48), np.uint8), iterations=1)))
|
||||
@@ -271,13 +300,13 @@ class ImageScaleShortPM:
|
||||
return {"required": {
|
||||
"image": ("IMAGE",),
|
||||
"size": ("INT", {"default": 512, "min": 0, "max": 2048, "step": 1}),
|
||||
"crop_face": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||
"crop_face": ("BOOLEAN", {"default": False}),
|
||||
}}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_scale_short"
|
||||
|
||||
CATEGORY = "protrait/model"
|
||||
CATEGORY = "protrait/other"
|
||||
|
||||
def image_scale_short(self, image, size, crop_face):
|
||||
input_image = tensor_to_img(image)
|
||||
@@ -304,7 +333,7 @@ class ImageResizeTargetPM:
|
||||
|
||||
FUNCTION = "image_resize_target"
|
||||
|
||||
CATEGORY = "protrait/model"
|
||||
CATEGORY = "protrait/other"
|
||||
|
||||
def image_resize_target(self, image, width, height):
|
||||
imagepi = tensor_to_img(image)
|
||||
@@ -323,7 +352,7 @@ class GetImageInfoPM:
|
||||
|
||||
FUNCTION = "get_image_info"
|
||||
|
||||
CATEGORY = "protrait/model"
|
||||
CATEGORY = "protrait/other"
|
||||
|
||||
def get_image_info(self, image):
|
||||
width = image.shape[2]
|
||||
@@ -345,8 +374,8 @@ 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])
|
||||
source_image = tensor_to_img(source_image)
|
||||
makeup_image = tensor_to_img(makeup_image)
|
||||
result = get_pagan_interface().transfer(source_image, makeup_image)
|
||||
return (img_to_tensor(result),)
|
||||
|
||||
@@ -368,9 +397,9 @@ class FaceShapMatchPM:
|
||||
|
||||
def faceshap_match(self, source_image, match_image, face_box):
|
||||
# detect face area
|
||||
source_image = tensor_to_img(source_image)
|
||||
match_image = tensor_to_img(match_image)
|
||||
face_skin_mask = get_face_skin()(source_image, get_retinaface_detection(), needs_index=[[1, 2, 3, 4, 5, 7, 8, 10, 11, 12, 13]])[0]
|
||||
source_image_copy = tensor_to_img(source_image)
|
||||
match_image_copy = tensor_to_img(match_image)
|
||||
face_skin_mask = get_face_skin()(source_image_copy, get_retinaface_detection(), needs_index=[[1, 2, 3, 4, 5, 7, 8, 10, 11, 12, 13]])[0]
|
||||
face_width = face_box[2] - face_box[0]
|
||||
kernel_size = np.ones((int(face_width // 10), int(face_width // 10)), np.uint8)
|
||||
|
||||
@@ -383,6 +412,113 @@ class FaceShapMatchPM:
|
||||
|
||||
# paste back to photo, Using I2I generation controlled solely by OpenPose, even with a very small denoise amplitude,
|
||||
# still carries the risk of introducing NSFW and global incoherence.!!! important!!!
|
||||
input_image_uint8 = np.array(source_image) * face_skin_mask + np.array(match_image) * (1 - face_skin_mask)
|
||||
input_image_uint8 = np.array(source_image_copy) * face_skin_mask + np.array(match_image_copy) * (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/super"
|
||||
|
||||
def super_color_transfer(self, main_image, transfer_image, avatar_box=None):
|
||||
origin_np = tensor_to_np(main_image)
|
||||
result_np = None
|
||||
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
|
||||
result_np = masked_img_np
|
||||
|
||||
if avatar_box is not None:
|
||||
origin_np[avatar_box[1]:avatar_box[3], avatar_box[0]:avatar_box[2], :] = masked_img_np
|
||||
result_np = origin_np
|
||||
|
||||
return (np_to_tensor(result_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/super"
|
||||
|
||||
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),)
|
||||
|
||||
class SimilarityPM:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return \
|
||||
{
|
||||
"required": {
|
||||
"main_image": ("IMAGE",),
|
||||
"compare_image": ("IMAGE",),
|
||||
"model": (["sim"],),
|
||||
"result_prefix": ("STRING", {"default": ""}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
|
||||
FUNCTION = "similarity_compare"
|
||||
CATEGORY = "protrait/model"
|
||||
|
||||
def similarity_compare(self, main_image, compare_image, model, result_prefix):
|
||||
main_image_copy = tensor_to_img(main_image)
|
||||
compare_image_copy = tensor_to_img(compare_image)
|
||||
score = None
|
||||
result = None
|
||||
if model == "sim":
|
||||
root_embedding = get_face_recognition()(dict(user=Image.fromarray(np.uint8(main_image_copy))))[OutputKeys.IMG_EMBEDDING]
|
||||
compare_embedding = get_face_recognition()(dict(user=Image.fromarray(np.uint8(compare_image_copy))))[OutputKeys.IMG_EMBEDDING]
|
||||
score = float(np.dot(root_embedding, np.transpose(compare_embedding))[0][0])
|
||||
if result_prefix == "":
|
||||
result = str(round(score, 2))
|
||||
else:
|
||||
result = f"{result_prefix}_{round(score, 2)}"
|
||||
return (result,)
|
||||
|
||||
@@ -65,9 +65,8 @@ def safe_get_box_mask_keypoints(image, retinaface_result, crop_ratio, face_seg,
|
||||
retinaface_boxs = [retinaface_boxs[index] for index in argindex]
|
||||
retinaface_keypoints = [retinaface_keypoints[index] for index in argindex]
|
||||
retinaface_mask_pils = [retinaface_mask_pils[index] for index in argindex]
|
||||
retinaface_mask_np = [retinaface_masks[index] for index in argindex]
|
||||
mask_tensor = np_to_mask(retinaface_mask_np[0])
|
||||
return retinaface_boxs, retinaface_keypoints, retinaface_mask_pils, mask_tensor
|
||||
retinaface_mask_nps = [retinaface_masks[index] for index in argindex]
|
||||
return retinaface_boxs, retinaface_keypoints, retinaface_mask_pils, retinaface_mask_nps
|
||||
|
||||
else:
|
||||
retinaface_box = np.array([])
|
||||
@@ -120,9 +119,9 @@ def call_face_crop(retinaface_detection, image, crop_ratio, prefix="tmp"):
|
||||
# retinaface detect
|
||||
retinaface_result = retinaface_detection(image)
|
||||
# get mask and keypoints
|
||||
retinaface_box, retinaface_keypoints, retinaface_mask_pil, retinaface_mask_tensor = safe_get_box_mask_keypoints(image, retinaface_result, crop_ratio, None, "crop")
|
||||
retinaface_box, retinaface_keypoints, retinaface_mask_pil, retinaface_mask_nps = safe_get_box_mask_keypoints(image, retinaface_result, crop_ratio, None, "crop")
|
||||
|
||||
return retinaface_box, retinaface_keypoints, retinaface_mask_pil, retinaface_mask_tensor
|
||||
return retinaface_box, retinaface_keypoints, retinaface_mask_pil, retinaface_mask_nps
|
||||
|
||||
def color_transfer(sc, dc):
|
||||
"""
|
||||
|
||||
@@ -456,7 +456,7 @@ class PreProcess:
|
||||
lms = lms[:, ::-1]
|
||||
|
||||
mask, diff = self.process(mask, lms, device=self.device)
|
||||
image = image.resize((self.img_size, self.img_size), Image.ANTIALIAS)
|
||||
image = image.resize((self.img_size, self.img_size), Image.Resampling.NEAREST)
|
||||
image = self.transform(image)
|
||||
real = to_var(image.unsqueeze(0))
|
||||
return [real, mask, diff], face_on_image, crop_face
|
||||
@@ -830,7 +830,7 @@ class PostProcess:
|
||||
|
||||
height, width = source.shape[:2]
|
||||
small_source = cv2.resize(source, (self.img_size, self.img_size))
|
||||
laplacian_diff = source.astype(np.float) - cv2.resize(small_source, (width, height)).astype(np.float)
|
||||
laplacian_diff = source.astype(np.float64) - cv2.resize(small_source, (width, height)).astype(np.float64)
|
||||
result = (cv2.resize(result, (width, height)) + laplacian_diff).round().clip(0, 255).astype(np.uint8)
|
||||
if self.denoise:
|
||||
result = cv2.fastNlMeansDenoisingColored(result)
|
||||
|
||||
+3
-1
@@ -1,3 +1,4 @@
|
||||
aliyun-python-sdk-core-v3==2.13.10
|
||||
opencv-python
|
||||
tensorflow-cpu
|
||||
tensorflow
|
||||
@@ -7,4 +8,5 @@ modelscope
|
||||
scikit-image
|
||||
matplotlib
|
||||
insightface
|
||||
diffusers==0.18.2
|
||||
diffusers==0.18.2
|
||||
sentencepiece
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"last_node_id": 231,
|
||||
"last_link_id": 419,
|
||||
"last_link_id": 424,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 50,
|
||||
@@ -443,7 +443,7 @@
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 79,
|
||||
"order": 77,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -486,7 +486,7 @@
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 76,
|
||||
"order": 74,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -620,7 +620,7 @@
|
||||
"1": 82
|
||||
},
|
||||
"flags": {},
|
||||
"order": 75,
|
||||
"order": 73,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -663,7 +663,7 @@
|
||||
"1": 246
|
||||
},
|
||||
"flags": {},
|
||||
"order": 78,
|
||||
"order": 76,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -724,7 +724,7 @@
|
||||
"1": 166
|
||||
},
|
||||
"flags": {},
|
||||
"order": 77,
|
||||
"order": 75,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -793,7 +793,7 @@
|
||||
"1": 166
|
||||
},
|
||||
"flags": {},
|
||||
"order": 80,
|
||||
"order": 78,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -856,7 +856,7 @@
|
||||
"1": 474.0000305175781
|
||||
},
|
||||
"flags": {},
|
||||
"order": 81,
|
||||
"order": 79,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -907,33 +907,6 @@
|
||||
"color": "#323",
|
||||
"bgcolor": "#535"
|
||||
},
|
||||
{
|
||||
"id": 145,
|
||||
"type": "PreviewImage",
|
||||
"pos": [
|
||||
4959.059430539544,
|
||||
2873.60691902383
|
||||
],
|
||||
"size": {
|
||||
"0": 360.20330810546875,
|
||||
"1": 542.2775268554688
|
||||
},
|
||||
"flags": {},
|
||||
"order": 83,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 246
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "PreviewImage"
|
||||
},
|
||||
"color": "#323",
|
||||
"bgcolor": "#535"
|
||||
},
|
||||
{
|
||||
"id": 147,
|
||||
"type": "LoraLoader",
|
||||
@@ -1239,7 +1212,7 @@
|
||||
"1": 86
|
||||
},
|
||||
"flags": {},
|
||||
"order": 66,
|
||||
"order": 64,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -1356,7 +1329,7 @@
|
||||
"1": 272.66497802734375
|
||||
},
|
||||
"flags": {},
|
||||
"order": 68,
|
||||
"order": 66,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -1383,7 +1356,7 @@
|
||||
"1": 312.9284362792969
|
||||
},
|
||||
"flags": {},
|
||||
"order": 70,
|
||||
"order": 68,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -1410,13 +1383,13 @@
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 60,
|
||||
"order": 58,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 403
|
||||
"link": 420
|
||||
},
|
||||
{
|
||||
"name": "box",
|
||||
@@ -1483,7 +1456,7 @@
|
||||
"1": 313.27972412109375
|
||||
},
|
||||
"flags": {},
|
||||
"order": 72,
|
||||
"order": 70,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -1510,7 +1483,7 @@
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 62,
|
||||
"order": 60,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -1554,7 +1527,7 @@
|
||||
"1": 311.90179443359375
|
||||
},
|
||||
"flags": {},
|
||||
"order": 64,
|
||||
"order": 62,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -1812,51 +1785,6 @@
|
||||
"color": "#323",
|
||||
"bgcolor": "#535"
|
||||
},
|
||||
{
|
||||
"id": 144,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
4652.0594305395425,
|
||||
2881.6069190238295
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 82,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 244
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 245
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
246,
|
||||
271,
|
||||
312
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
},
|
||||
"color": "#323",
|
||||
"bgcolor": "#535"
|
||||
},
|
||||
{
|
||||
"id": 178,
|
||||
"type": "PreviewImage",
|
||||
@@ -1893,7 +1821,7 @@
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 26
|
||||
"1": 58
|
||||
},
|
||||
"flags": {},
|
||||
"order": 110,
|
||||
@@ -1919,6 +1847,9 @@
|
||||
"properties": {
|
||||
"Node name for S&R": "PM_PortraitEnhancement"
|
||||
},
|
||||
"widgets_values": [
|
||||
"pgen"
|
||||
],
|
||||
"color": "#2a363b",
|
||||
"bgcolor": "#3f5159"
|
||||
},
|
||||
@@ -2061,13 +1992,13 @@
|
||||
"1": 66
|
||||
},
|
||||
"flags": {},
|
||||
"order": 69,
|
||||
"order": 67,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "origin_image",
|
||||
"type": "IMAGE",
|
||||
"link": 402
|
||||
"link": 421
|
||||
},
|
||||
{
|
||||
"name": "box_area",
|
||||
@@ -2112,7 +2043,7 @@
|
||||
"1": 78
|
||||
},
|
||||
"flags": {},
|
||||
"order": 71,
|
||||
"order": 69,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -2158,7 +2089,7 @@
|
||||
"1": 325.4287414550781
|
||||
},
|
||||
"flags": {},
|
||||
"order": 74,
|
||||
"order": 72,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -2185,7 +2116,7 @@
|
||||
"1": 78
|
||||
},
|
||||
"flags": {},
|
||||
"order": 73,
|
||||
"order": 71,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -2378,7 +2309,7 @@
|
||||
"1": 332.3785095214844
|
||||
},
|
||||
"flags": {},
|
||||
"order": 61,
|
||||
"order": 59,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -2672,7 +2603,7 @@
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 271
|
||||
"link": 423
|
||||
},
|
||||
{
|
||||
"name": "box",
|
||||
@@ -2968,7 +2899,7 @@
|
||||
"1": 26
|
||||
},
|
||||
"flags": {},
|
||||
"order": 65,
|
||||
"order": 63,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -3033,7 +2964,7 @@
|
||||
"1": 82
|
||||
},
|
||||
"flags": {},
|
||||
"order": 63,
|
||||
"order": 61,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -3095,8 +3026,8 @@
|
||||
"id": 6,
|
||||
"type": "LoadImage",
|
||||
"pos": [
|
||||
683,
|
||||
370
|
||||
249.94248304953703,
|
||||
302.33370767033864
|
||||
],
|
||||
"size": {
|
||||
"0": 303.5721130371094,
|
||||
@@ -3301,7 +3232,7 @@
|
||||
"1": 289.9919128417969
|
||||
},
|
||||
"flags": {},
|
||||
"order": 67,
|
||||
"order": 65,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -3459,10 +3390,10 @@
|
||||
2380,
|
||||
1020
|
||||
],
|
||||
"size": [
|
||||
374.8711860380299,
|
||||
444.2354070414972
|
||||
],
|
||||
"size": {
|
||||
"0": 374.8711853027344,
|
||||
"1": 444.23541259765625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 44,
|
||||
"mode": 0,
|
||||
@@ -3845,7 +3776,7 @@
|
||||
{
|
||||
"name": "origin_image",
|
||||
"type": "IMAGE",
|
||||
"link": 312
|
||||
"link": 424
|
||||
},
|
||||
{
|
||||
"name": "box_area",
|
||||
@@ -3932,10 +3863,10 @@
|
||||
7570.006255877076,
|
||||
1602.40493563089
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
246
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 246
|
||||
},
|
||||
"flags": {},
|
||||
"order": 103,
|
||||
"mode": 0,
|
||||
@@ -4353,95 +4284,28 @@
|
||||
"bgcolor": "#535"
|
||||
},
|
||||
{
|
||||
"id": 61,
|
||||
"type": "VAEDecode",
|
||||
"id": 145,
|
||||
"type": "PreviewImage",
|
||||
"pos": [
|
||||
3798,
|
||||
-70
|
||||
4605,
|
||||
2907
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
"0": 360.20330810546875,
|
||||
"1": 542.2775268554688
|
||||
},
|
||||
"flags": {},
|
||||
"order": 55,
|
||||
"order": 81,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 79
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 142
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
82,
|
||||
419
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
"link": 246
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
},
|
||||
"color": "#323",
|
||||
"bgcolor": "#535"
|
||||
},
|
||||
{
|
||||
"id": 224,
|
||||
"type": "PM_FaceShapMatch",
|
||||
"pos": [
|
||||
4244,
|
||||
-66
|
||||
],
|
||||
"size": {
|
||||
"0": 229.20001220703125,
|
||||
"1": 66
|
||||
},
|
||||
"flags": {},
|
||||
"order": 58,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "source_image",
|
||||
"type": "IMAGE",
|
||||
"link": 419
|
||||
},
|
||||
{
|
||||
"name": "match_image",
|
||||
"type": "IMAGE",
|
||||
"link": 400
|
||||
},
|
||||
{
|
||||
"name": "face_box",
|
||||
"type": "BOX",
|
||||
"link": 398
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
401,
|
||||
402,
|
||||
403
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "PM_FaceShapMatch"
|
||||
"Node name for S&R": "PreviewImage"
|
||||
},
|
||||
"color": "#323",
|
||||
"bgcolor": "#535"
|
||||
@@ -4450,8 +4314,8 @@
|
||||
"id": 223,
|
||||
"type": "Reroute",
|
||||
"pos": [
|
||||
4088,
|
||||
-28
|
||||
5004,
|
||||
2846
|
||||
],
|
||||
"size": [
|
||||
75,
|
||||
@@ -4484,19 +4348,158 @@
|
||||
"color": "#323",
|
||||
"bgcolor": "#535"
|
||||
},
|
||||
{
|
||||
"id": 61,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
3798,
|
||||
-70
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 55,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 79
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 142
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
82,
|
||||
420,
|
||||
421
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
},
|
||||
"color": "#323",
|
||||
"bgcolor": "#535"
|
||||
},
|
||||
{
|
||||
"id": 224,
|
||||
"type": "PM_FaceShapMatch",
|
||||
"pos": [
|
||||
5097,
|
||||
2791
|
||||
],
|
||||
"size": {
|
||||
"0": 229.20001220703125,
|
||||
"1": 66
|
||||
},
|
||||
"flags": {},
|
||||
"order": 82,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "source_image",
|
||||
"type": "IMAGE",
|
||||
"link": 422
|
||||
},
|
||||
{
|
||||
"name": "match_image",
|
||||
"type": "IMAGE",
|
||||
"link": 400
|
||||
},
|
||||
{
|
||||
"name": "face_box",
|
||||
"type": "BOX",
|
||||
"link": 398
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
401,
|
||||
423,
|
||||
424
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "PM_FaceShapMatch"
|
||||
},
|
||||
"color": "#323",
|
||||
"bgcolor": "#535"
|
||||
},
|
||||
{
|
||||
"id": 144,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
4678,
|
||||
2799
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 80,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 244
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 245
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
246,
|
||||
422
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
},
|
||||
"color": "#323",
|
||||
"bgcolor": "#535"
|
||||
},
|
||||
{
|
||||
"id": 225,
|
||||
"type": "PreviewImage",
|
||||
"pos": [
|
||||
4148,
|
||||
101
|
||||
],
|
||||
"size": [
|
||||
370.333740234375,
|
||||
482.09925079345703
|
||||
5014,
|
||||
2933
|
||||
],
|
||||
"size": {
|
||||
"0": 370.333740234375,
|
||||
"1": 482.0992431640625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 59,
|
||||
"order": 83,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -5201,14 +5204,6 @@
|
||||
1,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
271,
|
||||
144,
|
||||
0,
|
||||
159,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
272,
|
||||
159,
|
||||
@@ -5385,14 +5380,6 @@
|
||||
2,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
312,
|
||||
144,
|
||||
0,
|
||||
168,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
319,
|
||||
17,
|
||||
@@ -5737,22 +5724,6 @@
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
402,
|
||||
224,
|
||||
0,
|
||||
131,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
403,
|
||||
224,
|
||||
0,
|
||||
112,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
414,
|
||||
195,
|
||||
@@ -5794,20 +5765,52 @@
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
419,
|
||||
420,
|
||||
61,
|
||||
0,
|
||||
112,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
421,
|
||||
61,
|
||||
0,
|
||||
131,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
422,
|
||||
144,
|
||||
0,
|
||||
224,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
423,
|
||||
224,
|
||||
0,
|
||||
159,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
424,
|
||||
224,
|
||||
0,
|
||||
168,
|
||||
0,
|
||||
"IMAGE"
|
||||
]
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"title": "Roop Image",
|
||||
"bounding": [
|
||||
672,
|
||||
295,
|
||||
239,
|
||||
227,
|
||||
333,
|
||||
410
|
||||
],
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user