Spaces:
Runtime error
Runtime error
import io | |
import math | |
from PIL import Image, ImageDraw | |
from lama_cleaner.helper import load_img | |
from lama_cleaner.plugins.base_plugin import BasePlugin | |
def keep_ratio_resize(img, size, resample=Image.BILINEAR): | |
if img.width > img.height: | |
w = size | |
h = int(img.height * size / img.width) | |
else: | |
h = size | |
w = int(img.width * size / img.height) | |
return img.resize((w, h), resample) | |
def cubic_bezier(p1, p2, duration: int, frames: int): | |
""" | |
Args: | |
p1: | |
p2: | |
duration: Total duration of the curve | |
frames: | |
Returns: | |
""" | |
x0, y0 = (0, 0) | |
x1, y1 = p1 | |
x2, y2 = p2 | |
x3, y3 = (1, 1) | |
def cal_y(t): | |
return ( | |
math.pow(1 - t, 3) * y0 | |
+ 3 * math.pow(1 - t, 2) * t * y1 | |
+ 3 * (1 - t) * math.pow(t, 2) * y2 | |
+ math.pow(t, 3) * y3 | |
) | |
def cal_x(t): | |
return ( | |
math.pow(1 - t, 3) * x0 | |
+ 3 * math.pow(1 - t, 2) * t * x1 | |
+ 3 * (1 - t) * math.pow(t, 2) * x2 | |
+ math.pow(t, 3) * x3 | |
) | |
res = [] | |
for t in range(0, 1 * frames, duration): | |
t = t / frames | |
res.append((cal_x(t), cal_y(t))) | |
res.append((1, 0)) | |
return res | |
def make_compare_gif( | |
clean_img: Image.Image, | |
src_img: Image.Image, | |
max_side_length: int = 600, | |
splitter_width: int = 5, | |
splitter_color=(255, 203, 0, int(255 * 0.73)), | |
): | |
if clean_img.size != src_img.size: | |
clean_img = clean_img.resize(src_img.size, Image.BILINEAR) | |
duration_per_frame = 20 | |
num_frames = 50 | |
# erase-in-out | |
cubic_bezier_points = cubic_bezier((0.33, 0), (0.66, 1), 1, num_frames) | |
cubic_bezier_points.reverse() | |
max_side_length = min(max_side_length, max(clean_img.size)) | |
src_img = keep_ratio_resize(src_img, max_side_length) | |
clean_img = keep_ratio_resize(clean_img, max_side_length) | |
width, height = src_img.size | |
# Generate images to make Gif from right to left | |
images = [] | |
for i in range(num_frames): | |
new_frame = Image.new("RGB", (width, height)) | |
new_frame.paste(clean_img, (0, 0)) | |
left = int(cubic_bezier_points[i][0] * width) | |
cropped_src_img = src_img.crop((left, 0, width, height)) | |
new_frame.paste(cropped_src_img, (left, 0, width, height)) | |
if i != num_frames - 1: | |
# draw a yellow splitter on the edge of the cropped image | |
draw = ImageDraw.Draw(new_frame) | |
draw.line( | |
[(left, 0), (left, height)], width=splitter_width, fill=splitter_color | |
) | |
images.append(new_frame) | |
for i in range(30): | |
images.append(src_img) | |
cubic_bezier_points.reverse() | |
# Generate images to make Gif from left to right | |
for i in range(num_frames): | |
new_frame = Image.new("RGB", (width, height)) | |
new_frame.paste(src_img, (0, 0)) | |
right = int(cubic_bezier_points[i][0] * width) | |
cropped_src_img = clean_img.crop((0, 0, right, height)) | |
new_frame.paste(cropped_src_img, (0, 0, right, height)) | |
if i != num_frames - 1: | |
# draw a yellow splitter on the edge of the cropped image | |
draw = ImageDraw.Draw(new_frame) | |
draw.line( | |
[(right, 0), (right, height)], width=splitter_width, fill=splitter_color | |
) | |
images.append(new_frame) | |
for _ in range(30): | |
images.append(clean_img) | |
img_byte_arr = io.BytesIO() | |
clean_img.save( | |
img_byte_arr, | |
format="GIF", | |
save_all=True, | |
include_color_table=True, | |
append_images=images, | |
optimize=False, | |
duration=duration_per_frame, | |
loop=0, | |
) | |
return img_byte_arr.getvalue() | |
class MakeGIF(BasePlugin): | |
name = "MakeGIF" | |
def __call__(self, rgb_np_img, files, form): | |
origin_image = rgb_np_img | |
clean_image_bytes = files["clean_img"].read() | |
clean_image, _ = load_img(clean_image_bytes) | |
gif_bytes = make_compare_gif( | |
Image.fromarray(origin_image), Image.fromarray(clean_image) | |
) | |
return gif_bytes | |