Update Pasting Functions
To Support side blending, a new function was needed.
This commit is contained in:
+175
-77
@@ -1944,7 +1944,11 @@ class WAS_Tools_Class():
|
||||
text_x = cell_x + (padding / 2)
|
||||
text_y = int(cell_y + cell_size / 1.2) - font.getsize('A')[1] - padding
|
||||
|
||||
draw.rectangle((cell_x, cell_y, cell_x + cell_size - padding * 2, cell_y + cell_size - padding * 2),
|
||||
# Calculate the width and height of the cell without the border padding
|
||||
cell_width = cell_size - padding * 2
|
||||
cell_height = cell_size - padding * 2
|
||||
|
||||
draw.rectangle((cell_x, cell_y, cell_x + cell_width, cell_y + cell_height),
|
||||
fill=color, outline='black', width=1)
|
||||
draw.text((text_x + 1, text_y + 1), f"R: {color[0]} G: {color[1]} B: {color[2]}", font=font, fill='black')
|
||||
draw.text((text_x, text_y), f"R: {color[0]} G: {color[1]} B: {color[2]}", font=font, fill='white')
|
||||
@@ -2504,7 +2508,7 @@ class WAS_Image_Crop_Face:
|
||||
CATEGORY = "WAS Suite/Image/Process"
|
||||
|
||||
def image_crop_face(self, image, cascade_xml=None, crop_padding_factor=0.25):
|
||||
return self.crop_face(tensor2pil(image), cascade_xml, crop_padding_factor, use_fr)
|
||||
return self.crop_face(tensor2pil(image), cascade_xml, crop_padding_factor)
|
||||
|
||||
def crop_face(self, image, cascade_name=None, padding=0.25):
|
||||
|
||||
@@ -2645,39 +2649,83 @@ class WAS_Image_Paste_Face_Crop:
|
||||
cstr("No valid crop data found!").error.print()
|
||||
return (image, pil2tensor(Image.new("RGB", tensor2pil(image).size, (0,0,0))))
|
||||
|
||||
result_image, result_mask = self.paste_face(tensor2pil(image), tensor2pil(crop_image), crop_data[0], crop_data[1], crop_blending, crop_sharpening)
|
||||
result_image, result_mask = self.paste_image(tensor2pil(image), tensor2pil(crop_image), crop_data, crop_blending, crop_sharpening)
|
||||
return(result_image, result_mask)
|
||||
|
||||
def paste_face(self, image, face_img, original_size, face_coords, blend_amount=0.25, sharpen_amount=1):
|
||||
|
||||
def paste_image(self, image, crop_image, crop_data, blend_amount=0.25, sharpen_amount=1):
|
||||
|
||||
face_img = face_img.convert("RGB").resize(original_size)
|
||||
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):
|
||||
color_ratio = y / size[1]
|
||||
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):
|
||||
color_ratio = x / size[0]
|
||||
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(sharpen_amount):
|
||||
face_img = face_img.filter(ImageFilter.SHARPEN)
|
||||
for _ in range(int(sharpen_amount)):
|
||||
crop_image = crop_image.filter(ImageFilter.SHARPEN)
|
||||
|
||||
if blend_amount > 1.0:
|
||||
blend_amount = 1.0
|
||||
elif blend_amount < 0.0:
|
||||
blend_amount = 0.0
|
||||
blend_ratio = (max(face_img.size[0], face_img.size[1]) / 2) * float(blend_amount)
|
||||
|
||||
blend = image.convert("RGBA")
|
||||
mask = Image.new("L", image.size, 0)
|
||||
offset_x = int(original_size[0] * (blend_amount + blend_amount / 2.5))
|
||||
offset_y = int(original_size[1] * (blend_amount + blend_amount / 2.5))
|
||||
mask_block_size = (original_size[0]-offset_x, original_size[1]-offset_y)
|
||||
mask_block = Image.new("L", mask_block_size, 255)
|
||||
Image.Image.paste(mask, mask_block, (int(face_coords[0]+offset_x/2), int(face_coords[1]+offset_y/2)))
|
||||
Image.Image.paste(blend, face_img, (face_coords[0], face_coords[1]))
|
||||
|
||||
mask = mask.filter(ImageFilter.BoxBlur(radius=blend_ratio/2))
|
||||
mask = mask.filter(ImageFilter.GaussianBlur(radius=blend_ratio/2))
|
||||
|
||||
blend.putalpha(mask)
|
||||
image = Image.alpha_composite(image.convert("RGBA"), blend)
|
||||
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)
|
||||
|
||||
return (pil2tensor(image.convert('RGB')), pil2tensor(mask.convert('RGB')))
|
||||
if top > 0:
|
||||
gradient_image = ImageOps.flip(lingrad(crop_image.size, 'vertical', blend_amount))
|
||||
crop_mask = ImageChops.screen(crop_mask, gradient_image)
|
||||
gradient_image.save("top.png")
|
||||
|
||||
if left > 0:
|
||||
gradient_image = ImageOps.mirror(lingrad(crop_image.size, 'horizontal', blend_amount))
|
||||
crop_mask = ImageChops.screen(crop_mask, gradient_image)
|
||||
gradient_image.save("left.png")
|
||||
|
||||
if right < image.width:
|
||||
gradient_image = lingrad(crop_image.size, 'horizontal', blend_amount)
|
||||
crop_mask = ImageChops.screen(crop_mask, gradient_image)
|
||||
gradient_image.save("right.png")
|
||||
|
||||
if bottom < image.height:
|
||||
gradient_image = lingrad(crop_image.size, 'vertical', blend_amount)
|
||||
crop_mask = ImageChops.screen(crop_mask, gradient_image)
|
||||
gradient_image.save("bottom.png")
|
||||
|
||||
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")))
|
||||
|
||||
|
||||
# IMAGE CROP LOCATION
|
||||
@@ -2840,48 +2888,85 @@ class WAS_Image_Paste_Crop:
|
||||
cstr("No valid crop data found!").error.print()
|
||||
return (image, pil2tensor(Image.new("RGB", tensor2pil(image).size, (0,0,0))))
|
||||
|
||||
result_image, result_mask = self.paste_image(tensor2pil(image), crop_data, tensor2pil(crop_image), crop_blending, crop_sharpening)
|
||||
return (result_image, result_mask)
|
||||
result_image, result_mask = self.paste_image(tensor2pil(image), tensor2pil(crop_image), crop_data, crop_blending, crop_sharpening)
|
||||
|
||||
return (result_image, result_mask)
|
||||
|
||||
def paste_image(self, image, crop_image, crop_data, blend_amount=0.25, sharpen_amount=1):
|
||||
|
||||
def paste_image(self, image, crop_data, crop_img, blend_amount=0.25, sharpen_amount=1):
|
||||
|
||||
def inset_border(image, border_width=20, border_color=(0)):
|
||||
width, height = image.size
|
||||
bordered_image = Image.new(image.mode, (width, height), border_color)
|
||||
bordered_image.paste(image, (0, 0))
|
||||
draw = ImageDraw.Draw(bordered_image)
|
||||
draw.rectangle((0, 0, width-1, height-1), outline=border_color, width=border_width)
|
||||
return bordered_image
|
||||
def lingrad(size, direction, black_ratio):
|
||||
image = Image.new('RGB', size)
|
||||
draw = ImageDraw.Draw(image)
|
||||
if direction == 'vertical':
|
||||
black_end = int(size[1] * (1 - black_ratio))
|
||||
range_start = 0
|
||||
range_end = size[1]
|
||||
range_step = 1
|
||||
for y in range(range_start, range_end, range_step):
|
||||
color_ratio = y / size[1]
|
||||
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 - black_ratio))
|
||||
range_start = 0
|
||||
range_end = size[0]
|
||||
range_step = 1
|
||||
for x in range(range_start, range_end, range_step):
|
||||
color_ratio = x / size[0]
|
||||
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_img = crop_img.convert("RGB").resize(crop_size)
|
||||
crop_image = crop_image.resize(crop_size)
|
||||
|
||||
if sharpen_amount > 0:
|
||||
for _ in range(sharpen_amount):
|
||||
crop_img = crop_img.filter(ImageFilter.SHARPEN)
|
||||
for _ in range(int(sharpen_amount)):
|
||||
crop_image = crop_image.filter(ImageFilter.SHARPEN)
|
||||
|
||||
if blend_amount > 1.0:
|
||||
blend_amount = 1.0
|
||||
elif blend_amount < 0.0:
|
||||
blend_amount = 0.0
|
||||
blend_ratio = (max(crop_img.size) / 2) * float(blend_amount)
|
||||
|
||||
blend = image.convert("RGBA")
|
||||
mask = Image.new("L", image.size, 0)
|
||||
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)
|
||||
|
||||
mask_block = Image.new("L", crop_size, 255)
|
||||
mask_block = inset_border(mask_block, int(blend_ratio/2), (0))
|
||||
|
||||
Image.Image.paste(mask, mask_block, (top, left))
|
||||
Image.Image.paste(blend, crop_img, (top, left))
|
||||
if top > 0:
|
||||
gradient_image = ImageOps.flip(lingrad(crop_image.size, 'vertical', blend_amount))
|
||||
crop_mask = ImageChops.screen(crop_mask, gradient_image)
|
||||
gradient_image.save("top.png")
|
||||
|
||||
mask = mask.filter(ImageFilter.BoxBlur(radius=blend_ratio / 4))
|
||||
mask = mask.filter(ImageFilter.GaussianBlur(radius=blend_ratio / 4))
|
||||
if left > 0:
|
||||
gradient_image = ImageOps.mirror(lingrad(crop_image.size, 'horizontal', blend_amount))
|
||||
crop_mask = ImageChops.screen(crop_mask, gradient_image)
|
||||
gradient_image.save("left.png")
|
||||
|
||||
blend.putalpha(mask)
|
||||
image = Image.alpha_composite(image.convert("RGBA"), blend)
|
||||
|
||||
return (pil2tensor(image.convert('RGB')), pil2tensor(mask.convert('RGB')))
|
||||
if right < image.width:
|
||||
gradient_image = lingrad(crop_image.size, 'horizontal', blend_amount)
|
||||
crop_mask = ImageChops.screen(crop_mask, gradient_image)
|
||||
gradient_image.save("right.png")
|
||||
|
||||
if bottom < image.height:
|
||||
gradient_image = lingrad(crop_image.size, 'vertical', blend_amount)
|
||||
crop_mask = ImageChops.screen(crop_mask, gradient_image)
|
||||
gradient_image.save("bottom.png")
|
||||
|
||||
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")))
|
||||
|
||||
|
||||
# IMAGE PASTE CROP BY LOCATION
|
||||
|
||||
@@ -5552,8 +5637,8 @@ class WAS_Tensor_Batch_to_Image:
|
||||
class WAS_Image_To_Mask:
|
||||
|
||||
def __init__(self):
|
||||
self.channels = {'alpha': 'A', 'red': 0, 'green': 1, 'blue': 2}
|
||||
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
@@ -5566,24 +5651,37 @@ class WAS_Image_To_Mask:
|
||||
CATEGORY = "WAS Suite/Image/Masking"
|
||||
|
||||
RETURN_TYPES = ("MASK",)
|
||||
RETURN_TYPES = ("MASKS",)
|
||||
RETURN_NAMES = ("MASKS",)
|
||||
|
||||
FUNCTION = "image_to_mask"
|
||||
|
||||
def dominant_region(self, masks, threshold=128):
|
||||
if len(masks.shape) > 3 or masks.shape[0] > 1:
|
||||
regions = []
|
||||
for i in range(masks.shape[0]):
|
||||
pil_image = mask2pil(masks[i]).convert("L")
|
||||
region_mask = self.WT.Masking.dominant_region(pil_image, threshold)
|
||||
region_tensor = pil2mask(region_mask)
|
||||
regions.append(region_tensor.unsqueeze(0))
|
||||
regions_tensor = torch.cat(regions, dim=0)
|
||||
return (regions_tensor,)
|
||||
def image_to_mask(self, images, channel):
|
||||
mask_images = []
|
||||
if len(images) > 1:
|
||||
for image in images:
|
||||
r, g, b, a = tensor2pil(image).convert("RGBA").split()
|
||||
if channel == "red":
|
||||
channel_image = r
|
||||
elif channel == "green":
|
||||
channel_image = g
|
||||
elif channel == "blue":
|
||||
channel_image = b
|
||||
elif channel == "alpha":
|
||||
channel_image = a
|
||||
mask_images.append(pil2mask(tensor2pil(channel_image)).unsqueeze(0).unsqueeze(1))
|
||||
return (torch.cat(mask_images, dim=0), )
|
||||
else:
|
||||
return (pil2mask(self.WT.Masking.dominant_region(mask2pil(masks), threshold)),)
|
||||
r, g, b, a = tensor2pil(images).convert("RGBA").split()
|
||||
if channel == "red":
|
||||
channel_image = r
|
||||
elif channel == "green":
|
||||
channel_image = g
|
||||
elif channel == "blue":
|
||||
channel_image = b
|
||||
elif channel == "alpha":
|
||||
channel_image = a
|
||||
return (pil2mask(tensor2pil(channel_image)).unsqueeze(0).unsqueeze(1), )
|
||||
|
||||
|
||||
|
||||
# MASK TO IMAGE
|
||||
|
||||
|
||||
Reference in New Issue
Block a user