6.6 KiB
6.6 KiB
Documentation
- Class name: SaltImagePasteCrop
- Category: SALT/Image/Process
- Output node: False
本节点主要用于图像处理中的融合和锐化操作,尤其专注于将裁剪后的图像粘贴到目标图像上,并可调整融合和锐化参数。它能够通过无缝集成裁剪部分到原始图像中来创建合成图像,并通过融合和锐化技术增强视觉连贯性。
Input types
Required
- images
- 作为粘贴操作的基础图层,这些原始图像将被用来粘贴裁剪后的图像。通过这一操作,可以创建合成图像。
- Comfy dtype: IMAGE
- Python dtype: List[PIL.Image]
- crop_images
- 这些裁剪后的图像将被粘贴到原始图像上。它们会根据指定的参数进行定位和融合,从而实现与原始图像的整合。
- Comfy dtype: IMAGE
- Python dtype: List[PIL.Image]
- crop_data_batch
- 一批数据,用于指定原始图像中每个裁剪区域的位置、大小和其他参数。这些数据对于在粘贴过程中正确对齐和整合裁剪图像至关重要。
- Comfy dtype: CROP_DATA_BATCH
- Python dtype: List[tuple]
- crop_blending
- 决定原始图像和裁剪图像之间的融合强度,影响过渡的平滑程度。
- Comfy dtype: FLOAT
- Python dtype: float
- crop_sharpening
- 指定要应用于裁剪图像的锐化级别,以增强其清晰度和细节。
- Comfy dtype: INT
- Python dtype: int
Output types
- images
- 经过融合和锐化调整后,将裁剪图像粘贴到原始图像上的结果。
- Comfy dtype: IMAGE
- Python dtype: torch.Tensor
- masks
- 指示受粘贴操作影响的区域的蒙版,对后续图像处理步骤有用。
- Comfy dtype: IMAGE
- Python dtype: torch.Tensor
Usage tips
- Infra type:
CPU - Common nodes: unknown
Source code
class SaltImagePasteCrop:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"images": ("IMAGE",),
"crop_images": ("IMAGE",),
"crop_data_batch": ("CROP_DATA_BATCH",),
"crop_blending": ("FLOAT", {"default": 0.25, "min": 0.0, "max": 1.0, "step": 0.01}),
"crop_sharpening": ("INT", {"default": 0, "min": 0, "max": 3, "step": 1}),
}
}
RETURN_TYPES = ("IMAGE", "IMAGE")
RETURN_NAMES = ("images", "masks")
FUNCTION = "image_paste_crop"
CATEGORY = f"{NAME}/Image/Process"
def image_paste_crop(self, images, crop_images, crop_data_batch=None, crop_blending=0.25, crop_sharpening=0):
pasted_images = []
pasted_masks = []
for i, image in enumerate(images):
image = tensor2pil(image)
crop_image = tensor2pil(crop_images[i].unsqueeze(0))
if crop_data_batch is not None:
crop_data = crop_data_batch[i]
pasted_image, pasted_mask = self.paste_image(image, crop_image, crop_data, crop_blending, crop_sharpening)
else:
print(f"No valid crop data found for Image {i}")
pasted_image = pil2tensor(image)
pasted_mask = pil2tensor(Image.new("RGB", image.size, (0,0,0)))
pasted_images.append(pasted_image)
pasted_masks.append(pasted_mask)
pasted_images_batch = torch.cat(pasted_images, dim=0)
pasted_masks_batch = torch.cat(pasted_masks, dim=0)
return (pasted_images_batch, pasted_masks_batch)
def paste_image(self, image, crop_image, crop_data, blend_amount=0.25, sharpen_amount=1):
def lingrad(size, direction, white_ratio):
image = Image.new('RGB', size)
draw = ImageDraw.Draw(image)
if direction == 'vertical':
black_end = int(size[1] * (1 - white_ratio))
range_start = 0
range_end = size[1]
range_step = 1
for y in range(range_start, range_end, range_step):
if y <= black_end:
color = (0, 0, 0)
else:
color_value = int(((y - black_end) / (size[1] - black_end)) * 255)
color = (color_value, color_value, color_value)
draw.line([(0, y), (size[0], y)], fill=color)
elif direction == 'horizontal':
black_end = int(size[0] * (1 - white_ratio))
range_start = 0
range_end = size[0]
range_step = 1
for x in range(range_start, range_end, range_step):
if x <= black_end:
color = (0, 0, 0)
else:
color_value = int(((x - black_end) / (size[0] - black_end)) * 255)
color = (color_value, color_value, color_value)
draw.line([(x, 0), (x, size[1])], fill=color)
return image.convert("L")
crop_size, (left, top, right, bottom) = crop_data
crop_image = crop_image.resize(crop_size)
if sharpen_amount > 0:
for _ in range(int(sharpen_amount)):
crop_image = crop_image.filter(ImageFilter.SHARPEN)
blended_image = Image.new('RGBA', image.size, (0, 0, 0, 255))
blended_mask = Image.new('L', image.size, 0)
crop_padded = Image.new('RGBA', image.size, (0, 0, 0, 0))
blended_image.paste(image, (0, 0))
crop_padded.paste(crop_image, (left, top))
crop_mask = Image.new('L', crop_image.size, 0)
if top > 0:
gradient_image = ImageOps.flip(lingrad(crop_image.size, 'vertical', blend_amount))
crop_mask = ImageChops.screen(crop_mask, gradient_image)
if left > 0:
gradient_image = ImageOps.mirror(lingrad(crop_image.size, 'horizontal', blend_amount))
crop_mask = ImageChops.screen(crop_mask, gradient_image)
if right < image.width:
gradient_image = lingrad(crop_image.size, 'horizontal', blend_amount)
crop_mask = ImageChops.screen(crop_mask, gradient_image)
if bottom < image.height:
gradient_image = lingrad(crop_image.size, 'vertical', blend_amount)
crop_mask = ImageChops.screen(crop_mask, gradient_image)
crop_mask = ImageOps.invert(crop_mask)
blended_mask.paste(crop_mask, (left, top))
blended_mask = blended_mask.convert("L")
blended_image.paste(crop_padded, (0, 0), blended_mask)
return (pil2tensor(blended_image.convert("RGB")), pil2tensor(blended_mask.convert("RGB")))