Files
longgui0318-comfyui-common-…/layer_nodes.py
T
2024-07-07 13:47:19 +08:00

271 lines
12 KiB
Python

import os
import json
import torch
import folder_paths
from .layer_utils import fuse_layer,pilimage_to_tensor
from PIL import Image
class InitLayerInfoArray:
@classmethod
def INPUT_TYPES(s):
input_dir = folder_paths.get_input_directory()
files = [f for f in os.listdir(input_dir) if os.path.isfile(os.path.join(input_dir, f))]
return {
"required": {
"width": ("INT", {"default": 0}),
"height": ("INT", {"default": 0}),
"prompt": ("STRING", {
"dynamicPrompts": False,
"multiline": True,
"default": ""
}),
"reference_bg": (sorted(files), {"image_upload": False}),
"number_of_results": ("INT", {"default": 0}),
"correct_color":("BOOLEAN", {"default": True,"lable_on":"active","lable_off":"inactive"}),
"render_strength": (["Default", "Extra Weak", "Weak", "Strong", "Extra Stong"],),
"color_strength": (["Default", "None", "Weak", "Strong", "Extra Stong"],),
"outline_strength": (["Default", "None","Extra Weak", "Weak", "Strong", "Extra Stong"],),
}
}
RETURN_TYPES = ("LAYER_INFO_ARRAY","STRING",)
RETURN_NAMES = ("layerInfoArray","layerInfoArrayJson",)
FUNCTION = "init_fc"
CATEGORY = "utils"
def init_fc(self,width,height,prompt,reference_bg,number_of_results,correct_color,render_strength,color_strength,outline_strength,):
#将上面的内容转换成json对象
layerInfoArray = {
"width": width,
"height": height,
"prompt": prompt,
"reference_bg": reference_bg,
"number_of_results": number_of_results,
"correct_color": correct_color,
"render_strength": render_strength,
"color_strength": color_strength,
"outline_strength": outline_strength,
"layers": []
}
return (layerInfoArray, json.dumps(layerInfoArray),)
class AddedLayerInfoToArray:
@classmethod
def INPUT_TYPES(s):
input_dir = folder_paths.get_input_directory()
files = [f for f in os.listdir(input_dir) if os.path.isfile(os.path.join(input_dir, f))]
return {
"required": {
"layerInfoArray":('LAYER_INFO_ARRAY', {}),
"type": (["Product", "Prop", "Human-Hand", "Human-Male", "Human-Female"],),
"image": (sorted(files), {"image_upload": False}),
"width": ("INT", {"default": 0}),
"height": ("INT", {"default": 0}),
"rotation": ("INT", {"default": 0,"min":0,"max":360,"step":1}),
"position_x": ("INT", {"default": 0}),
"position_y": ("INT", {"default": 0}),
}
}
RETURN_TYPES = ("LAYER_INFO_ARRAY","STRING",)
RETURN_NAMES = ("layerInfoArray","layerInfoArrayJson",)
FUNCTION = "add_fc"
CATEGORY = "utils"
def add_fc(self,layerInfoArray,type,image,width,height,rotation,position_x,position_y):
layer = {
"type": type,
"image":image,
"width": width,
"height": height,
"rotation": rotation,
"position_x": position_x,
"position_y": position_y,
}
layerInfoArray = json.loads(json.dumps(layerInfoArray))
layerInfoArray["layers"].append(layer)
return (layerInfoArray, json.dumps(layerInfoArray),)
class LayerInfoArrayFuse:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"layerInfoArrayJson":("STRING",{"default": ""}),
}
}
RETURN_TYPES = ("IMAGE","MASK","IMAGE","MASK","IMAGE","LAYER_IMAGES","STRING","BOOLEAN","INT","INT","INT")
RETURN_NAMES = ("fuseImage","fuseMask","fuseProductImage","fuseProductMask","referenceBGImage","layerImages","prompt","correctColor","renderStrength","colorStrength","outlineStrength")
FUNCTION = "fuse_fc"
CATEGORY = "utils"
def fuse_fc(self, layerInfoArrayJson,):
layerInfoArray = json.loads(layerInfoArrayJson)
fuse_image, fuse_product_image,reference_bg_image,layer_index_images = fuse_layer(layerInfoArray)
fuse_image, fuse_mask = pilimage_to_tensor(fuse_image, needMask=True)
fuse_product_image, fuse_product_mask = pilimage_to_tensor(fuse_product_image, needMask=True)
reference_bg_image, _ = pilimage_to_tensor(reference_bg_image)
return (fuse_image, fuse_mask, fuse_product_image, fuse_product_mask,reference_bg_image, layer_index_images, layerInfoArray["prompt"], layerInfoArray["correct_color"], 0, 0, 0,)
#this class code from ComfyUI_IPAdapter_plus.IPAdapterPlus.IPAdapterAdvanced
class LayerImageSeleted:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"layer_images": ("LAYER_IMAGES",),
"layer_filter_type": (["all","Product", "Prop", "Human-Hand", "Human-Male", "Human-Female"],),
"layer_need_fuse":("BOOLEAN", {"default": True,"lable_on":"yes","lable_off":"no"}),
"layer_canvas": ("IMAGE",),
},
}
RETURN_TYPES = ("IMAGE","MASK",)
RETURN_NAMES = ("image","mask",)
FUNCTION = "select_fc"
CATEGORY = "utils"
def select_fc(self, layer_images, layer_filter_type, layer_need_fuse, layer_canvas):
layer_filter_data = []
for layer in layer_images:
if layer_filter_type == "all" or layer["type"] == layer_filter_type:
layer_filter_data.append(layer)
if len(layer_filter_data) == 0:
image, mask = pilimage_to_tensor(layer_canvas, needMask=True, justMask=False, empty=True)
image = image.to(layer_canvas.device, dtype=layer_canvas.dtype)
mask = mask.to(layer_canvas.device, dtype=layer_canvas.dtype)
return (image, mask,)
fuse_img = None
for layer in layer_filter_data:
if fuse_img == None:
fuse_img = layer["deformationImage"]
else:
fuse_img = Image.alpha_composite(fuse_img, layer['deformationImage'])
if fuse_img is not None:
layer_img, layer_mask = pilimage_to_tensor(fuse_img, needMask=True)
# 取反 0 1 互换
layer_mask = 1. - layer_mask
return (layer_img, layer_mask,)
else:
image, mask = pilimage_to_tensor(layer_canvas, needMask=True, justMask=False, empty=True)
image = image.to(layer_canvas.device, dtype=layer_canvas.dtype)
mask = mask.to(layer_canvas.device, dtype=layer_canvas.dtype)
return (image, mask,)
#this class code from ComfyUI_IPAdapter_plus.IPAdapterPlus.IPAdapterAdvanced
class LayerImagesIPAdapterAdvanced:
@classmethod
def INPUT_TYPES(s):
_WEIGHT_TYPES = []
try:
from custom_nodes.ComfyUI_IPAdapter_plus.IPAdapterPlus import WEIGHT_TYPES
_WEIGHT_TYPES.extend(WEIGHT_TYPES)
except:
pass
return {
"required": {
"layer_images": ("LAYER_IMAGES",),
"layer_filter_type": (["all","Product", "Prop", "Human-Hand", "Human-Male", "Human-Female"],),
"layer_need_fuse":("BOOLEAN", {"default": True,"lable_on":"yes","lable_off":"no"}),
"layer_canvas": ("IMAGE",),
"model": ("MODEL", ),
"ipadapter": ("IPADAPTER", ),
"weight": ("FLOAT", { "default": 1.0, "min": -1, "max": 5, "step": 0.05 }),
"weight_type": (_WEIGHT_TYPES, ),
"combine_embeds": (["concat", "add", "subtract", "average", "norm average"],),
"start_at": ("FLOAT", { "default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001 }),
"end_at": ("FLOAT", { "default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001 }),
"embeds_scaling": (['V only', 'K+V', 'K+V w/ C penalty', 'K+mean(V) w/ C penalty'], ),
},
"optional": {
"image_negative": ("IMAGE",),
"clip_vision": ("CLIP_VISION",),
}
}
RETURN_TYPES = ("MODEL","LAYER_IMAGES","MASK")
RETURN_NAMES = ("MODEL","layerImages","extendedMASK")
FUNCTION = "apply_ipadapter"
CATEGORY = "ipadapter"
def apply_ipadapter(self,layer_images,layer_filter_type,layer_need_fuse,layer_canvas, model, ipadapter, start_at=0.0, end_at=1.0, weight=1.0, weight_style=1.0, weight_composition=1.0, expand_style=False, weight_type="linear", combine_embeds="concat", weight_faceidv2=None, image_style=None, image_composition=None, image_negative=None, clip_vision=None, insightface=None, embeds_scaling='V only', layer_weights=None, ipadapter_params=None, encode_batch_size=0, style_boost=None):
layer_filter_data = []
remain = []
for layer in layer_images:
if layer_filter_type=="all" or layer["type"] == layer_filter_type:
layer_filter_data.append(layer)
else:
remain.append(layer)
if len(layer_filter_data) == 0:
_,extended_mask = pilimage_to_tensor(layer_canvas, needMask=True,justMask=True,empty=True)
extended_mask = extended_mask.to(layer_canvas.device,dtype=layer_canvas.dtype)
return (model,remain,extended_mask,)
need_process_images = []
if layer_need_fuse:
extended_mask = None
fuse_img = None
for layer in layer_filter_data:
if fuse_img == None:
fuse_img = layer["deformationImage"]
else:
fuse_img = Image.alpha_composite(fuse_img, layer['deformationImage'])
if fuse_img is not None:
layer_img,layer_mask = pilimage_to_tensor(fuse_img, needMask=True)
#取反 0 1 互换
layer_mask = 1. - layer_mask
need_process_images.append((layer_img,layer_mask))
extended_mask = layer_mask
else:
fuse_img = None
for layer in layer_filter_data:
img_pil = layer["deformationImage"]
if fuse_img == None:
fuse_img = img_pil
else:
fuse_img = Image.alpha_composite(fuse_img, img_pil)
layer_img,_ = pilimage_to_tensor(layer["originalImage"])
_,layer_mask = pilimage_to_tensor(img_pil, needMask=True,justMask=True)
layer_mask = 1. - layer_mask
need_process_images.append((layer_img,layer_mask))
if fuse_img is not None:
_,extended_mask = pilimage_to_tensor(fuse_img, needMask=True,justMask=True)
extended_mask = 1. - extended_mask
if extended_mask is None:
_,extended_mask = pilimage_to_tensor(layer_canvas, needMask=True,justMask=True,empty=True)
extended_mask = extended_mask.to(layer_canvas.device,dtype=layer_canvas.dtype)
if len(need_process_images) == 0:
return (model,remain,extended_mask,)
try:
from custom_nodes.ComfyUI_IPAdapter_plus.IPAdapterPlus import IPAdapterAdvanced
except:
raise Exception("ComfyUI_IPAdapter_plus.IPAdapterPlus not found,you should install it first.")
ipadapterObj = IPAdapterAdvanced()
for layer in need_process_images:
model ,_ = ipadapterObj.apply_ipadapter(model, ipadapter, start_at, end_at, weight, weight_style, weight_composition, expand_style, weight_type, combine_embeds, weight_faceidv2, layer_img, image_style, image_composition, image_negative, clip_vision, layer_mask, insightface, embeds_scaling, layer_weights, ipadapter_params, encode_batch_size, style_boost)
return (model,remain,extended_mask,)
NODE_CLASS_MAPPINGS = {
"Init Layer Info Array":InitLayerInfoArray,
"Added Layer Info To Array":AddedLayerInfoToArray,
"Layer Info Array Fuse":LayerInfoArrayFuse,
"Layer Image Seleted":LayerImageSeleted,
"Layer Images IPAdapter Advanced":LayerImagesIPAdapterAdvanced,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"Init Layer Info Array":"Init Layer Info Array",
"Added Layer Info To Array": "Added Layer Info To Array",
"Layer Info Array Fuse": "Layer Info Array Fuse",
"Layer Image Seleted":"Layer Image Seleted",
"Layer Images IPAdapter Advanced": "Layer Images IPAdapter Advanced",
}