|
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 |
|
|
|
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 |
|
|
|
|
|
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 = 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() |
|
|
|
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 = 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 |
|
|