Files
TTPlanetPig-Comfyui_Object_…/node.py
T
2024-11-15 22:18:21 +08:00

163 lines
6.7 KiB
Python

import cv2
import numpy as np
from PIL import Image, ImageFilter, ImageChops, ImageEnhance
import node_helpers
import torch
def pil2tensor(image: Image) -> torch.Tensor:
return torch.from_numpy(np.array(image).astype(np.float32) / 255.0).unsqueeze(0)
def tensor2pil(t_image: torch.Tensor) -> Image:
return Image.fromarray(np.clip(255.0 * t_image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8))
class TTP_Expand_And_Mask:
def __init__(self, *args, **kwargs):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image": ("IMAGE",), # 输入一张图片
"fill_mode": (["duplicate", "white"], {"default": "duplicate", "label": "Fill Mode"}),
# fill_mode是一个字符串列表参数,可以选择"duplicate"或"white"
"direction": (["left", "right", "top", "bottom"], {"default": "right", "label": "Expansion Direction"}),
# direction是一个字符串列表参数,可以选择扩展方向:"left", "right", "top", "bottom"
"num_blocks": ("INT", {"default": 1, "min": 1, "max": 2, "step": 1, "label": "Number of Blocks"}),
# num_blocks表示要添加扩展块的数量,可选择1或2
"fill_alpha_decision": ("BOOLEAN", {"default": False, "label": "Fill Alpha with White"}),
# fill_alpha_decision为一个布尔值参数,用来决定是否将输出图像透明区域填充为白色
}
}
RETURN_TYPES = ("IMAGE", "MASK")
RETURN_NAMES = ("EXPANDED_IMAGE", "MASK")
FUNCTION = "expand_and_mask"
CATEGORY = "TTP/Image"
def expand_and_mask(self, image, fill_mode="duplicate", direction="right", num_blocks=1, fill_alpha_decision=False):
pil_image = tensor2pil(image)
width, height = pil_image.size
has_alpha = (pil_image.mode == 'RGBA')
def create_fill_image():
if pil_image.mode == 'RGBA':
return Image.new("RGBA", (width, height), color=(255, 255, 255, 255))
elif pil_image.mode == 'RGB':
return Image.new("RGB", (width, height), color=(255, 255, 255))
elif pil_image.mode == 'L':
return Image.new("L", (width, height), color=255)
else:
raise ValueError(f"Unsupported image mode for fill: {pil_image.mode}")
if fill_mode == "duplicate":
fill_image = pil_image.copy()
elif fill_mode == "white":
fill_image = create_fill_image()
else:
fill_image = pil_image.copy()
if direction in ["left", "right"]:
new_width = width + width * num_blocks
new_height = height
else: # direction in ["top", "bottom"]
new_width = width
new_height = height + height * num_blocks
expanded_image_mode = pil_image.mode
expanded_image = Image.new(expanded_image_mode, (new_width, new_height))
if direction == "left":
for i in range(num_blocks):
expanded_image.paste(fill_image, (width * i, 0))
expanded_image.paste(pil_image, (width * num_blocks, 0))
elif direction == "right":
expanded_image.paste(pil_image, (0, 0))
for i in range(num_blocks):
expanded_image.paste(fill_image, (width + width * i, 0))
elif direction == "top":
for i in range(num_blocks):
expanded_image.paste(fill_image, (0, height * i))
expanded_image.paste(pil_image, (0, height * num_blocks))
elif direction == "bottom":
expanded_image.paste(pil_image, (0, 0))
for i in range(num_blocks):
expanded_image.paste(fill_image, (0, height + height * i))
else:
raise ValueError(f"Unsupported direction: {direction}")
mask_array = np.zeros((new_height, new_width), dtype=np.float32)
if has_alpha:
alpha_array = np.array(pil_image.getchannel("A"), dtype=np.float32) / 255.0
alpha_mask_array = 1.0 - alpha_array
if direction == "left":
mask_array[:, width * num_blocks:width * num_blocks + width] = alpha_mask_array
elif direction == "right":
mask_array[:, :width] = alpha_mask_array
elif direction == "top":
mask_array[height * num_blocks:height * num_blocks + height, :] = alpha_mask_array
elif direction == "bottom":
mask_array[:height, :] = alpha_mask_array
if direction == "left":
mask_array[:, :width * num_blocks] = 1.0
elif direction == "right":
mask_array[:, width:] = 1.0
elif direction == "top":
mask_array[:height * num_blocks, :] = 1.0
elif direction == "bottom":
mask_array[height:, :] = 1.0
mask_tensor = torch.from_numpy(mask_array).unsqueeze(0).unsqueeze(0)
if fill_alpha_decision and has_alpha:
expanded_image = expanded_image.convert('RGBA') # 确保图像是RGBA模式
background = Image.new('RGBA', expanded_image.size, (255, 255, 255, 255))
expanded_image = Image.alpha_composite(background, expanded_image)
expanded_image = expanded_image.convert('RGB') # 转换为RGB模式
expanded_image_mode = 'RGB'
expanded_image_tensor = pil2tensor(expanded_image)
return (expanded_image_tensor, mask_tensor)
class TTP_text_mix:
def __init__(self, *args, **kwargs):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"text1": ("STRING", {"default": "", "multiline": True, "label": "Text Box 1"}),
"text2": ("STRING", {"default": "", "multiline": True, "label": "Text Box 2"}),
"text3": ("STRING", {"default": "", "multiline": True, "label": "Text Box 3"}),
"template": ("STRING", {"default": "", "multiline": True, "label": "Template Text Box"}),
}
}
RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING")
RETURN_NAMES = ("text1", "text2", "text3", "final_text")
FUNCTION = "mix_texts"
CATEGORY = "TTP/text"
def mix_texts(self, text1, text2, text3, template):
# 使用replace方法替换模板中的占位符{text1}和{text2}
final_text = template.replace("{text1}", text1).replace("{text2}", text2).replace("{text3}", text3)
return (text1, text2, text3, final_text)
NODE_CLASS_MAPPINGS = {
"TTP_Expand_And_Mask": TTP_Expand_And_Mask,
"TTP_text_mix": TTP_text_mix
}
NODE_DISPLAY_NAME_MAPPINGS = {
"TTP_Expand_And_Mask": "TTP_Expand_And_Mask",
"TTP_text_mix": "TTP_text_mix"
}