7.1 KiB
7.1 KiB
Documentation
- Class name: Image Overlay
- Category: Efficiency Nodes/Image
- Output node: False
Image Overlay节点用于将一个图像叠加到另一个图像上,并提供多种自定义选项,如调整大小、旋转、透明度调整和可选的遮罩。该节点通过对叠加图像应用变换和混合技术,然后将其与基础图像合并,从而实现创建复合图像。
Input types
Required
- base_image
- 作为叠加图像应用目标的基础图像。它充当复合图像的背景。
- Comfy dtype: IMAGE
- Python dtype: torch.Tensor
- overlay_image
- 要叠加到基础图像上的图像。在叠加之前,可以调整此图像的大小、旋转角度和透明度。
- Comfy dtype: IMAGE
- Python dtype: torch.Tensor
- overlay_resize
- 指定如何调整叠加图像的大小以适应基础图像,选项包括适应尺寸、按因子缩放或调整到特定的宽度和高度。
- Comfy dtype: COMBO[STRING]
- Python dtype: str
- resize_method
- 用于调整叠加图像大小的方法,影响调整后图像的质量和外观。
- Comfy dtype: COMBO[STRING]
- Python dtype: str
- rescale_factor
- 当选择"按rescale_factor调整大小"选项时,叠加图像的缩放因子。
- Comfy dtype: FLOAT
- Python dtype: float
- width
- 当选择"调整到指定宽度和高度"选项时,叠加图像调整后的宽度。
- Comfy dtype: INT
- Python dtype: int
- height
- 当选择"调整到指定宽度和高度"选项时,叠加图像调整后的高度。
- Comfy dtype: INT
- Python dtype: int
- x_offset
- 叠加图像在基础图像上放置的水平偏移量。
- Comfy dtype: INT
- Python dtype: int
- y_offset
- 叠加图像在基础图像上放置的垂直偏移量。
- Comfy dtype: INT
- Python dtype: int
- rotation
- 在应用到基础图像之前,叠加图像旋转的角度(以度为单位)。
- Comfy dtype: INT
- Python dtype: float
- opacity
- 叠加图像的不透明度,允许创建透明叠加效果。
- Comfy dtype: FLOAT
- Python dtype: float
Optional
- optional_mask
- 可选的遮罩,可应用于叠加图像,控制叠加图像不同部分的透明度。
- Comfy dtype: MASK
- Python dtype: Optional[torch.Tensor]
Output types
- image
- 应用叠加后的基础图像,反映了所有指定的变换和调整。
- Comfy dtype: IMAGE
- Python dtype: torch.Tensor
Usage tips
- Infra type:
GPU - Common nodes: unknown
Source code
class TSC_ImageOverlay:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"base_image": ("IMAGE",),
"overlay_image": ("IMAGE",),
"overlay_resize": (["None", "Fit", "Resize by rescale_factor", "Resize to width & heigth"],),
"resize_method": (["nearest-exact", "bilinear", "area"],),
"rescale_factor": ("FLOAT", {"default": 1, "min": 0.01, "max": 16.0, "step": 0.1}),
"width": ("INT", {"default": 512, "min": 0, "max": MAX_RESOLUTION, "step": 64}),
"height": ("INT", {"default": 512, "min": 0, "max": MAX_RESOLUTION, "step": 64}),
"x_offset": ("INT", {"default": 0, "min": -48000, "max": 48000, "step": 10}),
"y_offset": ("INT", {"default": 0, "min": -48000, "max": 48000, "step": 10}),
"rotation": ("INT", {"default": 0, "min": -180, "max": 180, "step": 5}),
"opacity": ("FLOAT", {"default": 0, "min": 0, "max": 100, "step": 5}),
},
"optional": {"optional_mask": ("MASK",),}
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "apply_overlay_image"
CATEGORY = "Efficiency Nodes/Image"
def apply_overlay_image(self, base_image, overlay_image, overlay_resize, resize_method, rescale_factor,
width, height, x_offset, y_offset, rotation, opacity, optional_mask=None):
# Pack tuples and assign variables
size = width, height
location = x_offset, y_offset
mask = optional_mask
# Check for different sizing options
if overlay_resize != "None":
#Extract overlay_image size and store in Tuple "overlay_image_size" (WxH)
overlay_image_size = overlay_image.size()
overlay_image_size = (overlay_image_size[2], overlay_image_size[1])
if overlay_resize == "Fit":
h_ratio = base_image.size()[1] / overlay_image_size[1]
w_ratio = base_image.size()[2] / overlay_image_size[0]
ratio = min(h_ratio, w_ratio)
overlay_image_size = tuple(round(dimension * ratio) for dimension in overlay_image_size)
elif overlay_resize == "Resize by rescale_factor":
overlay_image_size = tuple(int(dimension * rescale_factor) for dimension in overlay_image_size)
elif overlay_resize == "Resize to width & heigth":
overlay_image_size = (size[0], size[1])
samples = overlay_image.movedim(-1, 1)
overlay_image = comfy.utils.common_upscale(samples, overlay_image_size[0], overlay_image_size[1], resize_method, False)
overlay_image = overlay_image.movedim(1, -1)
overlay_image = tensor2pil(overlay_image)
# Add Alpha channel to overlay
overlay_image = overlay_image.convert('RGBA')
overlay_image.putalpha(Image.new("L", overlay_image.size, 255))
# If mask connected, check if the overlay_image image has an alpha channel
if mask is not None:
# Convert mask to pil and resize
mask = tensor2pil(mask)
mask = mask.resize(overlay_image.size)
# Apply mask as overlay's alpha
overlay_image.putalpha(ImageOps.invert(mask))
# Rotate the overlay image
overlay_image = overlay_image.rotate(rotation, expand=True)
# Apply opacity on overlay image
r, g, b, a = overlay_image.split()
a = a.point(lambda x: max(0, int(x * (1 - opacity / 100))))
overlay_image.putalpha(a)
# Split the base_image tensor along the first dimension to get a list of tensors
base_image_list = torch.unbind(base_image, dim=0)
# Convert each tensor to a PIL image, apply the overlay, and then convert it back to a tensor
processed_base_image_list = []
for tensor in base_image_list:
# Convert tensor to PIL Image
image = tensor2pil(tensor)
# Paste the overlay image onto the base image
if mask is None:
image.paste(overlay_image, location)
else:
image.paste(overlay_image, location, overlay_image)
# Convert PIL Image back to tensor
processed_tensor = pil2tensor(image)
# Append to list
processed_base_image_list.append(processed_tensor)
# Combine the processed images back into a single tensor
base_image = torch.stack([tensor.squeeze() for tensor in processed_base_image_list])
# Return the edited base image
return (base_image,)