diff --git a/__init__.py b/__init__.py index 967abc8..7a4bc54 100644 --- a/__init__.py +++ b/__init__.py @@ -6,30 +6,30 @@ import threading root_path = os.path.dirname(__file__) parent_dir = os.path.dirname(root_path) sys.path.append(root_path) -from .comfyui.nodes import * -from .comfyui.style_loader_node import * +from .facechain.nodes import * +from .facechain.style_loader_node import * NODE_CLASS_MAPPINGS = { - "FC_FaceFusion": FCFaceFusion, - "FC_StyleLoraLoad": FCStyleLoraLoad, - "FC_FaceDetection": FCFaceDetection, - "FC_CropMask": FCCropMask, - "FC_Segment": FCSegment, - "FC_ReplaceImage": FCReplaceImage, - "FC_CropBottom": FCCropBottom, - "FC_CropFace": FCCropFace, - "FC_CropAndPaste": FCCropAndPaste, - "FC_MaskOP": FCMaskOP, + "FC FaceFusion": FCFaceFusion, + "FC StyleLoraLoad": FCStyleLoraLoad, + "FC FaceDetectCrop": FaceDetectCrop, + "FC FaceSegment": FCFaceSegment, + "FC CropMask": FCCropMask, + "FC ReplaceImage": FCReplaceImage, + "FC CropBottom": FCCropBottom, + "FC CropAndPaste": FCCropAndPaste, + "FC MaskOP": FCMaskOP, } NODE_DISPLAY_NAME_MAPPINGS = { - "FC_FaceFusion": "FC FaceFusion", - "FC_StyleLoraLoad": "FC StyleLoraLoad", - "FC_FaceDetection": "FC FaceDetection", - "FC_CropMask": "FC CropMask", - "FC_ReplaceImage": "FC ReplaceImage", - "FC_CropBottom": "FC CropBottom", - "FC_CropAndPaste": "FC CropAndPaste", - "FC_MaskOP": "FC MaskOP", + "FC FaceFusion": "FC FaceFusion", + "FC StyleLoraLoad": "FC StyleLoraLoad", + "FC FaceDetectCrop": "FC FaceDetectCrop", + "FC FaceSegment": "FC FaceSegment", + "FC CropMask": "FC CropMask", + "FC ReplaceImage": "FC ReplaceImage", + "FC CropBottom": "FC CropBottom", + "FC CropAndPaste": "FC CropAndPaste", + "FC MaskOP": "FC MaskOP", } __all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS'] diff --git a/facechain/common/model_processor.py b/facechain/common/model_processor.py new file mode 100644 index 0000000..3f1ee6d --- /dev/null +++ b/facechain/common/model_processor.py @@ -0,0 +1,31 @@ +import numpy as np +from facechain.model_holder import * + +def facechain_detect_crop(source_image_pil, face_index, crop_ratio): + det_result = get_face_detection()(source_image_pil) + bboxes = det_result['boxes'] + keypoints = det_result['keypoints'] + area = 0 + # for i in range(len(bboxes)): + # bbox = bboxes[i] + # area_tmp = (bbox[2] - bbox[0]) * (bbox[3] - bbox[1]) + # if area_tmp > area: + # area = area_tmp + # idx = i + bbox = bboxes[face_index] + keypoint = keypoints[face_index] + points_array = np.zeros((5, 2)) + for k in range(5): + points_array[k, 0] = keypoint[2 * k] + points_array[k, 1] = keypoint[2 * k + 1] + w, h = source_image_pil.size + face_w = bbox[2] - bbox[0] + face_h = bbox[3] - bbox[1] + bbox[0] = np.clip(np.array(bbox[0], np.int32) - face_w * (crop_ratio - 1) / 2, 0, w - 1) + bbox[1] = np.clip(np.array(bbox[1], np.int32) - face_h * (crop_ratio - 1) / 2, 0, h - 1) + bbox[2] = np.clip(np.array(bbox[2], np.int32) + face_w * (crop_ratio - 1) / 2, 0, w - 1) + bbox[3] = np.clip(np.array(bbox[3], np.int32) + face_h * (crop_ratio - 1) / 2, 0, h - 1) + bbox = np.array(bbox, np.int32) + source_image_pil.crop(bbox[0],bbox[1],bbox[2],bbox[3]) + return source_image_pil, bbox, points_array + # result_image = source_image[:, bbox[1]:bbox[3], bbox[0]:bbox[2], :] diff --git a/facechain/nodes.py b/facechain/nodes.py index f245450..875bcf9 100644 --- a/facechain/nodes.py +++ b/facechain/nodes.py @@ -3,16 +3,18 @@ import json import os import cv2 +from facechain.common.model_processor import facechain_detect_crop from skimage import transform from modelscope.outputs import OutputKeys import pydevd_pycharm + pydevd_pycharm.settrace('49.7.62.197', port=10090, stdoutToServer=True, stderrToServer=True) from .model_holder import * from .utils.img_utils import * from .utils.convert_utils import * -import pydevd_pycharm -pydevd_pycharm.settrace('49.7.62.197', port=10090, stdoutToServer=True, stderrToServer=True) +from .common import * + class FCLoraMerge: @classmethod def INPUT_TYPES(s): @@ -72,32 +74,23 @@ class FCFaceFusion: result_image = Image.fromarray(cv2.cvtColor(result_image, cv2.COLOR_BGR2RGB)) return (img_to_tensor(result_image),) -class FCFaceDetection: +class FaceDetectCrop: @classmethod def INPUT_TYPES(s): return { "required": { "source_image": ("IMAGE",), - "face_index": ("INT", {"default": 0, "min": 0, "max": 10, "step": 1}) + "face_index": ("INT", {"default": 0, "min": 0, "max": 10, "step": 1}), + "crop_ratio": ("FLOAT", {"default": 1.0, "min": 0, "max": 10, "step": 0.1}) } } - RETURN_TYPES = ("IMAGE", "BOX",) + RETURN_TYPES = ("IMAGE", "BOX", "KEY_POINT") FUNCTION = "face_detection" CATEGORY = "facechain/model" - def face_detection(self, source_image, face_index): - pil_source = tensor_to_img(source_image) - result_dec = get_face_detection()(pil_source) - keypoints = result_dec['keypoints'] - boxes = result_dec['boxes'] - scores = result_dec['scores'] - keypoint = keypoints[face_index] - score = scores[face_index] - box = boxes[face_index] - box = np.array(box, np.int32) - crop_result = source_image[:, box[1]:box[3], box[0]:box[2], :] - return (crop_result, box) + def face_detection(self, source_image, face_index, crop_ratio): + return (facechain_detect_crop(source_image, face_index, crop_ratio)) class FCCropMask: @classmethod @@ -148,8 +141,7 @@ class FCFaceSwap(): FUNCTION = "crop_mask" CATEGORY = "facechain/mask" - -class FCSegment: +class FCFaceSegment: @classmethod def INPUT_TYPES(s): return { @@ -158,7 +150,7 @@ class FCSegment: } } - RETURN_TYPES = ("MASK",) + RETURN_TYPES = ("IMAGE", "MASK",) FUNCTION = "fc_segment" CATEGORY = "facechain/model" @@ -227,9 +219,10 @@ class FCSegment: return soft_mask def fc_segment(self, source_image): - source_image = tensor_to_img(source_image) - mask = self.segment(get_segmentation(), source_image, ksize=0.1) - return (mask_np2_to_mask_tensor(mask),) + pil_source_image = tensor_to_img(source_image) + mask = self.segment(get_segmentation(), pil_source_image, ksize=0.1) + seg_image = tensor_to_np(source_image) * mask[:, :, None] + return (image_np_to_image_tensor(seg_image), mask_np2_to_mask_tensor(mask),) class FCReplaceImage: @classmethod @@ -294,50 +287,6 @@ class FCCropBottom: crop_result = crop_bottom(source_image, width) return (img_to_tensor(crop_result),) -class FCCropFace: - @classmethod - def INPUT_TYPES(s): - return { - "required": { - "source_image": ("IMAGE",), - "crop_ratio": ("FLOAT", {"default": 1.0, "min": 0, "max": 10, "step": 0.1}) - } - } - - RETURN_TYPES = ("IMAGE", "BOX", "KEY_POINT") - FUNCTION = "face_crop" - CATEGORY = "facechain/crop" - - def face_crop(self, source_image, crop_ratio): - source_image_pil = tensor_to_img(source_image) - det_result = get_face_detection()(source_image_pil) - bboxes = det_result['boxes'] - keypoints = det_result['keypoints'] - area = 0 - idx = 0 - for i in range(len(bboxes)): - bbox = bboxes[i] - area_tmp = (bbox[2] - bbox[0]) * (bbox[3] - bbox[1]) - if area_tmp > area: - area = area_tmp - idx = i - bbox = bboxes[idx] - keypoint = keypoints[idx] - points_array = np.zeros((5, 2)) - for k in range(5): - points_array[k, 0] = keypoint[2 * k] - points_array[k, 1] = keypoint[2 * k + 1] - w, h = source_image_pil.size - face_w = bbox[2] - bbox[0] - face_h = bbox[3] - bbox[1] - bbox[0] = np.clip(np.array(bbox[0], np.int32) - face_w * (crop_ratio - 1) / 2, 0, w - 1) - bbox[1] = np.clip(np.array(bbox[1], np.int32) - face_h * (crop_ratio - 1) / 2, 0, h - 1) - bbox[2] = np.clip(np.array(bbox[2], np.int32) + face_w * (crop_ratio - 1) / 2, 0, w - 1) - bbox[3] = np.clip(np.array(bbox[3], np.int32) + face_h * (crop_ratio - 1) / 2, 0, h - 1) - bbox = np.array(bbox, np.int32) - result_image = source_image[:, bbox[1]:bbox[3], bbox[0]:bbox[2], :] - return result_image, bbox, points_array - class FCCropAndPaste: @classmethod def INPUT_TYPES(s): diff --git a/workflow/__init__.py b/workflow/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/workflow/develop_work_flow.json b/workflow/develop_work_flow.json new file mode 100644 index 0000000..79fc54b --- /dev/null +++ b/workflow/develop_work_flow.json @@ -0,0 +1,1263 @@ +{ + "last_node_id": 44, + "last_link_id": 67, + "nodes": [ + { + "id": 15, + "type": "Control Net Stacker", + "pos": [ + -153.31365728149393, + 258.61234644012467 + ], + "size": { + "0": 315, + "1": 146 + }, + "flags": {}, + "order": 15, + "mode": 0, + "inputs": [ + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 19 + }, + { + "name": "image", + "type": "IMAGE", + "link": 42 + }, + { + "name": "cnet_stack", + "type": "CONTROL_NET_STACK", + "link": null + } + ], + "outputs": [ + { + "name": "CNET_STACK", + "type": "CONTROL_NET_STACK", + "links": [ + 20 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "Control Net Stacker" + }, + "widgets_values": [ + 1, + 0, + 1 + ], + "color": "#223322", + "bgcolor": "#335533", + "shape": 1 + }, + { + "id": 27, + "type": "MaskToImage", + "pos": [ + -610, + 566 + ], + "size": { + "0": 210, + "1": 26 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "mask", + "type": "MASK", + "link": 59 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 39 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "MaskToImage" + } + }, + { + "id": 18, + "type": "PreviewImage", + "pos": [ + -981, + 660 + ], + "size": { + "0": 210, + "1": 246 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 54 + } + ], + "properties": { + "Node name for S&R": "PreviewImage" + } + }, + { + "id": 28, + "type": "PreviewImage", + "pos": [ + -613, + 635 + ], + "size": { + "0": 210, + "1": 246 + }, + "flags": {}, + "order": 16, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 39 + } + ], + "properties": { + "Node name for S&R": "PreviewImage" + } + }, + { + "id": 26, + "type": "PreviewImage", + "pos": [ + -380, + 648 + ], + "size": { + "0": 210, + "1": 246 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 57 + } + ], + "properties": { + "Node name for S&R": "PreviewImage" + } + }, + { + "id": 5, + "type": "OpenposePreprocessor", + "pos": [ + -160, + 467 + ], + "size": { + "0": 315, + "1": 130 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 58 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 17, + 42 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "OpenposePreprocessor" + }, + "widgets_values": [ + "enable", + "enable", + "enable", + 512 + ] + }, + { + "id": 4, + "type": "KSampler Adv. (Efficient)", + "pos": [ + 882, + 193 + ], + "size": { + "0": 325, + "1": 634 + }, + "flags": {}, + "order": 18, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 47 + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 48 + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 50 + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 24 + }, + { + "name": "optional_vae", + "type": "VAE", + "link": 51 + }, + { + "name": "script", + "type": "SCRIPT", + "link": null + } + ], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": null, + "shape": 3 + }, + { + "name": "CONDITIONING+", + "type": "CONDITIONING", + "links": null, + "shape": 3 + }, + { + "name": "CONDITIONING-", + "type": "CONDITIONING", + "links": null, + "shape": 3 + }, + { + "name": "LATENT", + "type": "LATENT", + "links": null, + "shape": 3 + }, + { + "name": "VAE", + "type": "VAE", + "links": null, + "shape": 3 + }, + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 44 + ], + "shape": 3, + "slot_index": 5 + } + ], + "properties": { + "Node name for S&R": "KSampler Adv. (Efficient)" + }, + "widgets_values": [ + "enable", + -1, + null, + 20, + 7, + "euler", + "normal", + 0, + 10000, + "disable", + "auto", + "true" + ], + "color": "#332222", + "bgcolor": "#553333", + "shape": 1 + }, + { + "id": 30, + "type": "PreviewImage", + "pos": [ + 1287, + 316 + ], + "size": { + "0": 210, + "1": 246 + }, + "flags": {}, + "order": 19, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 44 + } + ], + "properties": { + "Node name for S&R": "PreviewImage" + } + }, + { + "id": 8, + "type": "ControlNetLoader", + "pos": [ + -139, + 134 + ], + "size": { + "0": 315, + "1": 58 + }, + "flags": {}, + "order": 0, + "mode": 0, + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 19 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "ControlNetLoader" + }, + "widgets_values": [ + "control_v11p_sd15_openpose.pth" + ] + }, + { + "id": 31, + "type": "LoRA Stacker", + "pos": [ + 37, + -166 + ], + "size": { + "0": 315, + "1": 178 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [ + { + "name": "lora_stack", + "type": "LORA_STACK", + "link": null + } + ], + "outputs": [ + { + "name": "LORA_STACK", + "type": "LORA_STACK", + "links": [ + 45 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "LoRA Stacker" + }, + "widgets_values": [ + "simple", + 2, + "FilmVelvia3.safetensors", + 0.2, + 1, + 1, + "dahuang_ep.safetensors", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1, + "None", + 1, + 1, + 1 + ], + "color": "#222233", + "bgcolor": "#333355", + "shape": 1 + }, + { + "id": 14, + "type": "PreviewImage", + "pos": [ + -105, + 663 + ], + "size": { + "0": 210, + "1": 246 + }, + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 17 + } + ], + "properties": { + "Node name for S&R": "PreviewImage" + } + }, + { + "id": 9, + "type": "LoadImage", + "pos": [ + -1312, + 331 + ], + "size": { + "0": 315, + "1": 314 + }, + "flags": {}, + "order": 2, + "mode": 0, + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 52, + 55 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": null, + "shape": 3 + } + ], + "properties": { + "Node name for S&R": "LoadImage" + }, + "widgets_values": [ + "fc_temp.jpeg", + "image" + ] + }, + { + "id": 35, + "type": "FC FaceDetection", + "pos": [ + -960, + 449 + ], + "size": { + "0": 315, + "1": 78 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [ + { + "name": "source_image", + "type": "IMAGE", + "link": 52 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 54 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "BOX", + "type": "BOX", + "links": [ + 56 + ], + "shape": 3, + "slot_index": 1 + } + ], + "properties": { + "Node name for S&R": "FC FaceDetection" + }, + "widgets_values": [ + 0 + ] + }, + { + "id": 36, + "type": "FC CropMask", + "pos": [ + -512.8261237915037, + 299.6577564270021 + ], + "size": { + "0": 210, + "1": 46 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 55 + }, + { + "name": "face_box", + "type": "BOX", + "link": 56 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 57, + 58 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [ + 59 + ], + "shape": 3, + "slot_index": 1 + } + ], + "properties": { + "Node name for S&R": "FC CropMask" + } + }, + { + "id": 1, + "type": "Efficient Loader", + "pos": [ + 299, + 172 + ], + "size": { + "0": 400, + "1": 462 + }, + "flags": {}, + "order": 17, + "mode": 0, + "inputs": [ + { + "name": "lora_stack", + "type": "LORA_STACK", + "link": 45 + }, + { + "name": "cnet_stack", + "type": "CONTROL_NET_STACK", + "link": 20 + } + ], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 47 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "CONDITIONING+", + "type": "CONDITIONING", + "links": [ + 48 + ], + "shape": 3, + "slot_index": 1 + }, + { + "name": "CONDITIONING-", + "type": "CONDITIONING", + "links": [ + 50 + ], + "shape": 3, + "slot_index": 2 + }, + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 24 + ], + "shape": 3, + "slot_index": 3 + }, + { + "name": "VAE", + "type": "VAE", + "links": [ + 51 + ], + "shape": 3, + "slot_index": 4 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [], + "shape": 3, + "slot_index": 5 + }, + { + "name": "DEPENDENCIES", + "type": "DEPENDENCIES", + "links": null, + "shape": 3 + } + ], + "properties": { + "Node name for S&R": "Efficient Loader" + }, + "widgets_values": [ + "majicmixRealistic_v7.safetensors", + "Baked VAE", + -1, + "None", + 1, + 1, + " raw photo, masterpiece, chinese, simple background, high-class pure color background, solo, medium shot, high detail face, photorealistic, best quality, wearing T-shi", + "nsfw, paintings, sketches, (worst quality:2), (low quality:2) lowers, normal quality, ((monochrome)), ((grayscale)), logo, word, character, childre", + "none", + "A1111", + 512, + 512, + 1 + ], + "color": "#223322", + "bgcolor": "#335533", + "shape": 1 + }, + { + "id": 41, + "type": "FC SegmentFace", + "pos": [ + -821, + 1058 + ], + "size": { + "0": 229.20001220703125, + "1": 46 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [ + { + "name": "source_image", + "type": "IMAGE", + "link": 64 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 65 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [ + 66 + ], + "shape": 3, + "slot_index": 1 + } + ], + "properties": { + "Node name for S&R": "FC SegmentFace" + } + }, + { + "id": 32, + "type": "LoadImage", + "pos": [ + -1282, + 1061 + ], + "size": { + "0": 315, + "1": 314 + }, + "flags": {}, + "order": 3, + "mode": 0, + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 64 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": null, + "shape": 3 + } + ], + "properties": { + "Node name for S&R": "LoadImage" + }, + "widgets_values": [ + "3.png", + "image" + ] + }, + { + "id": 42, + "type": "PreviewImage", + "pos": [ + -174, + 988 + ], + "size": [ + 210, + 246 + ], + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 65 + } + ], + "properties": { + "Node name for S&R": "PreviewImage" + } + }, + { + "id": 44, + "type": "PreviewImage", + "pos": [ + -741, + 1317 + ], + "size": [ + 210, + 246 + ], + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 67 + } + ], + "properties": { + "Node name for S&R": "PreviewImage" + } + }, + { + "id": 43, + "type": "MaskToImage", + "pos": [ + -432, + 1310 + ], + "size": { + "0": 210, + "1": 26 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "mask", + "type": "MASK", + "link": 66 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 67 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "MaskToImage" + } + } + ], + "links": [ + [ + 17, + 5, + 0, + 14, + 0, + "IMAGE" + ], + [ + 19, + 8, + 0, + 15, + 0, + "CONTROL_NET" + ], + [ + 20, + 15, + 0, + 1, + 1, + "CONTROL_NET_STACK" + ], + [ + 24, + 1, + 3, + 4, + 3, + "LATENT" + ], + [ + 39, + 27, + 0, + 28, + 0, + "IMAGE" + ], + [ + 42, + 5, + 0, + 15, + 1, + "IMAGE" + ], + [ + 44, + 4, + 5, + 30, + 0, + "IMAGE" + ], + [ + 45, + 31, + 0, + 1, + 0, + "LORA_STACK" + ], + [ + 47, + 1, + 0, + 4, + 0, + "MODEL" + ], + [ + 48, + 1, + 1, + 4, + 1, + "CONDITIONING" + ], + [ + 50, + 1, + 2, + 4, + 2, + "CONDITIONING" + ], + [ + 51, + 1, + 4, + 4, + 4, + "VAE" + ], + [ + 52, + 9, + 0, + 35, + 0, + "IMAGE" + ], + [ + 54, + 35, + 0, + 18, + 0, + "IMAGE" + ], + [ + 55, + 9, + 0, + 36, + 0, + "IMAGE" + ], + [ + 56, + 35, + 1, + 36, + 1, + "BOX" + ], + [ + 57, + 36, + 0, + 26, + 0, + "IMAGE" + ], + [ + 58, + 36, + 0, + 5, + 0, + "IMAGE" + ], + [ + 59, + 36, + 1, + 27, + 0, + "MASK" + ], + [ + 64, + 32, + 0, + 41, + 0, + "IMAGE" + ], + [ + 65, + 41, + 0, + 42, + 0, + "IMAGE" + ], + [ + 66, + 41, + 1, + 43, + 0, + "MASK" + ], + [ + 67, + 43, + 0, + 44, + 0, + "IMAGE" + ] + ], + "groups": [ + { + "title": "Group", + "bounding": [ + -164, + 83, + 375, + 603 + ], + "color": "#3f789e", + "font_size": 24, + "locked": false + } + ], + "config": {}, + "extra": {}, + "version": 0.4 +} \ No newline at end of file