|
from PIL import Image, ImageFilter, ImageOps |
|
|
|
|
|
def get_crop_region(mask, pad=0): |
|
"""finds a rectangular region that contains all masked ares in an image. Returns (x1, y1, x2, y2) coordinates of the rectangle. |
|
For example, if a user has painted the top-right part of a 512x512 image, the result may be (256, 0, 512, 256)""" |
|
mask_img = mask if isinstance(mask, Image.Image) else Image.fromarray(mask) |
|
box = mask_img.getbbox() |
|
if box: |
|
x1, y1, x2, y2 = box |
|
else: |
|
x1, y1 = mask_img.size |
|
x2 = y2 = 0 |
|
return max(x1 - pad, 0), max(y1 - pad, 0), min(x2 + pad, mask_img.size[0]), min(y2 + pad, mask_img.size[1]) |
|
|
|
|
|
def expand_crop_region(crop_region, processing_width, processing_height, image_width, image_height): |
|
"""expands crop region get_crop_region() to match the ratio of the image the region will processed in; returns expanded region |
|
for example, if user drew mask in a 128x32 region, and the dimensions for processing are 512x512, the region will be expanded to 128x128.""" |
|
|
|
x1, y1, x2, y2 = crop_region |
|
|
|
ratio_crop_region = (x2 - x1) / (y2 - y1) |
|
ratio_processing = processing_width / processing_height |
|
|
|
if ratio_crop_region > ratio_processing: |
|
desired_height = (x2 - x1) / ratio_processing |
|
desired_height_diff = int(desired_height - (y2-y1)) |
|
y1 -= desired_height_diff//2 |
|
y2 += desired_height_diff - desired_height_diff//2 |
|
if y2 >= image_height: |
|
diff = y2 - image_height |
|
y2 -= diff |
|
y1 -= diff |
|
if y1 < 0: |
|
y2 -= y1 |
|
y1 -= y1 |
|
if y2 >= image_height: |
|
y2 = image_height |
|
else: |
|
desired_width = (y2 - y1) * ratio_processing |
|
desired_width_diff = int(desired_width - (x2-x1)) |
|
x1 -= desired_width_diff//2 |
|
x2 += desired_width_diff - desired_width_diff//2 |
|
if x2 >= image_width: |
|
diff = x2 - image_width |
|
x2 -= diff |
|
x1 -= diff |
|
if x1 < 0: |
|
x2 -= x1 |
|
x1 -= x1 |
|
if x2 >= image_width: |
|
x2 = image_width |
|
|
|
return x1, y1, x2, y2 |
|
|
|
|
|
def fill(image, mask): |
|
"""fills masked regions with colors from image using blur. Not extremely effective.""" |
|
|
|
image_mod = Image.new('RGBA', (image.width, image.height)) |
|
|
|
image_masked = Image.new('RGBa', (image.width, image.height)) |
|
image_masked.paste(image.convert("RGBA").convert("RGBa"), mask=ImageOps.invert(mask.convert('L'))) |
|
|
|
image_masked = image_masked.convert('RGBa') |
|
|
|
for radius, repeats in [(256, 1), (64, 1), (16, 2), (4, 4), (2, 2), (0, 1)]: |
|
blurred = image_masked.filter(ImageFilter.GaussianBlur(radius)).convert('RGBA') |
|
for _ in range(repeats): |
|
image_mod.alpha_composite(blurred) |
|
|
|
return image_mod.convert("RGB") |
|
|
|
|