1
0
Fork 0
onnx-web/api/onnx_web/image.py

213 lines
5.7 KiB
Python
Raw Normal View History

2023-02-05 13:53:26 +00:00
import numpy as np
from numpy import random
from PIL import Image, ImageChops, ImageFilter, ImageOps
from typing import Tuple
2023-02-05 13:53:26 +00:00
from .params import Border, Point
def get_pixel_index(x: int, y: int, width: int) -> int:
return (y * width) + x
2023-02-05 13:53:26 +00:00
def mask_filter_none(
mask_image: Image.Image, dims: Point, origin: Point, fill="white", **kw
) -> Image.Image:
width, height = dims
2023-02-05 13:53:26 +00:00
noise = Image.new("RGB", (width, height), fill)
noise.paste(mask_image, origin)
return noise
2023-02-05 13:53:26 +00:00
def mask_filter_gaussian_multiply(
mask_image: Image.Image, dims: Point, origin: Point, rounds=3, **kw
) -> Image.Image:
"""
Gaussian blur with multiply, source image centered on white canvas.
2023-02-05 13:53:26 +00:00
"""
noise = mask_filter_none(mask_image, dims, origin)
for i in range(rounds):
blur = noise.filter(ImageFilter.GaussianBlur(5))
noise = ImageChops.multiply(noise, blur)
return noise
2023-02-05 13:53:26 +00:00
def mask_filter_gaussian_screen(
mask_image: Image.Image, dims: Point, origin: Point, rounds=3, **kw
) -> Image.Image:
"""
Gaussian blur, source image centered on white canvas.
2023-02-05 13:53:26 +00:00
"""
noise = mask_filter_none(mask_image, dims, origin)
for i in range(rounds):
2023-01-15 16:54:17 +00:00
blur = noise.filter(ImageFilter.GaussianBlur(5))
noise = ImageChops.screen(noise, blur)
return noise
2023-02-05 13:53:26 +00:00
def noise_source_fill_edge(
source_image: Image.Image, dims: Point, origin: Point, fill="white", **kw
) -> Image.Image:
"""
Identity transform, source image centered on white canvas.
2023-02-05 13:53:26 +00:00
"""
width, height = dims
2023-02-05 13:53:26 +00:00
noise = Image.new("RGB", (width, height), fill)
noise.paste(source_image, origin)
return noise
2023-02-05 13:53:26 +00:00
def noise_source_fill_mask(
source_image: Image.Image, dims: Point, origin: Point, fill="white", **kw
) -> Image.Image:
"""
Fill the whole canvas, no source or noise.
2023-02-05 13:53:26 +00:00
"""
width, height = dims
2023-02-05 13:53:26 +00:00
noise = Image.new("RGB", (width, height), fill)
return noise
2023-02-05 13:53:26 +00:00
def noise_source_gaussian(
source_image: Image.Image, dims: Point, origin: Point, rounds=3, **kw
) -> Image.Image:
"""
Gaussian blur, source image centered on white canvas.
2023-02-05 13:53:26 +00:00
"""
noise = noise_source_uniform(source_image, dims, origin)
noise.paste(source_image, origin)
for i in range(rounds):
2023-01-15 16:54:17 +00:00
noise = noise.filter(ImageFilter.GaussianBlur(5))
return noise
2023-02-05 13:53:26 +00:00
def noise_source_uniform(
source_image: Image.Image, dims: Point, origin: Point, **kw
) -> Image.Image:
width, height = dims
size = width * height
noise_r = random.uniform(0, 256, size=size)
noise_g = random.uniform(0, 256, size=size)
noise_b = random.uniform(0, 256, size=size)
2023-02-05 13:53:26 +00:00
noise = Image.new("RGB", (width, height))
for x in range(width):
for y in range(height):
i = get_pixel_index(x, y, width)
2023-02-05 13:53:26 +00:00
noise.putpixel((x, y), (int(noise_r[i]), int(noise_g[i]), int(noise_b[i])))
return noise
2023-02-05 13:53:26 +00:00
def noise_source_normal(
source_image: Image.Image, dims: Point, origin: Point, **kw
) -> Image.Image:
width, height = dims
size = width * height
noise_r = random.normal(128, 32, size=size)
noise_g = random.normal(128, 32, size=size)
noise_b = random.normal(128, 32, size=size)
2023-02-05 13:53:26 +00:00
noise = Image.new("RGB", (width, height))
for x in range(width):
for y in range(height):
i = get_pixel_index(x, y, width)
2023-02-05 13:53:26 +00:00
noise.putpixel((x, y), (int(noise_r[i]), int(noise_g[i]), int(noise_b[i])))
return noise
2023-02-05 13:53:26 +00:00
def noise_source_histogram(
source_image: Image.Image, dims: Point, origin: Point, **kw
) -> Image.Image:
r, g, b = source_image.split()
width, height = dims
2023-01-14 21:44:19 +00:00
size = width * height
hist_r = r.histogram()
hist_g = g.histogram()
hist_b = b.histogram()
2023-02-05 13:53:26 +00:00
noise_r = random.choice(
256, p=np.divide(np.copy(hist_r), np.sum(hist_r)), size=size
)
noise_g = random.choice(
256, p=np.divide(np.copy(hist_g), np.sum(hist_g)), size=size
)
noise_b = random.choice(
256, p=np.divide(np.copy(hist_b), np.sum(hist_b)), size=size
)
2023-02-05 13:53:26 +00:00
noise = Image.new("RGB", (width, height))
2023-01-14 22:14:37 +00:00
for x in range(width):
for y in range(height):
i = get_pixel_index(x, y, width)
2023-02-05 13:53:26 +00:00
noise.putpixel((x, y), (noise_r[i], noise_g[i], noise_b[i]))
return noise
# very loosely based on https://github.com/AUTOMATIC1111/stable-diffusion-webui/blob/master/scripts/outpainting_mk_2.py#L175-L232
def expand_image(
2023-02-05 13:53:26 +00:00
source_image: Image.Image,
mask_image: Image.Image,
expand: Border,
fill="white",
noise_source=noise_source_histogram,
mask_filter=mask_filter_none,
):
full_width = expand.left + source_image.width + expand.right
full_height = expand.top + source_image.height + expand.bottom
dims = (full_width, full_height)
origin = (expand.left, expand.top)
2023-02-05 13:53:26 +00:00
full_source = Image.new("RGB", dims, fill)
full_source.paste(source_image, origin)
# new mask pixels need to be filled with white so they will be replaced
full_mask = mask_filter(mask_image, dims, origin, fill="white")
full_noise = noise_source(source_image, dims, origin, fill=fill)
full_noise = ImageChops.multiply(full_noise, full_mask)
2023-02-05 13:53:26 +00:00
full_source = Image.composite(full_noise, full_source, full_mask.convert("L"))
2023-01-14 22:03:56 +00:00
return (full_source, full_mask, full_noise, (full_width, full_height))
def valid_image(
image: Image.Image,
min_dims: Tuple[int, int] = [512, 512],
max_dims: Tuple[int, int] = [512, 512],
) -> Image.Image:
min_x, min_y = min_dims
max_x, max_y = max_dims
if image.width > max_x or image.height > max_y:
image = ImageOps.contain(image, max_dims)
if image.width < min_x or image.height < min_y:
blank = Image.new(image.mode, min_dims, "black")
blank.paste(image)
image = blank
# check for square
return image