Sketch2Image / src /img2skt.py
Zeyu Zhao
Init the repo.
4f86f8b
import io
import os
import tempfile
import cv2
import gradio as gr
import numpy as np
from PIL import Image, ImageSequence
def image_to_sketch_gif(input_image: Image.Image):
# Convert PIL image to OpenCV format
open_cv_image = np.array(input_image.convert("RGB"))
open_cv_image = cv2.cvtColor(open_cv_image, cv2.COLOR_RGB2BGR)
# Convert to grayscale
grayscale_image = cv2.cvtColor(open_cv_image, cv2.COLOR_BGR2GRAY)
# Apply Gaussian blur
blurred_image = cv2.GaussianBlur(grayscale_image, (5, 5), 0)
# Use Canny Edge Detection
edges = cv2.Canny(blurred_image, threshold1=50, threshold2=150)
# Ensure binary format
_, binary_sketch = cv2.threshold(edges, 128, 255, cv2.THRESH_BINARY)
# Find connected components
num_labels, labels, stats, _ = cv2.connectedComponentsWithStats(
binary_sketch, connectivity=8
)
# Sort components by size (excluding the background, which is label 0)
components = sorted(
[(i, stats[i, cv2.CC_STAT_AREA]) for i in range(1, num_labels)],
key=lambda x: x[1],
reverse=True,
)
# Initialize an empty canvas for accumulation
accumulated_image = np.zeros_like(binary_sketch, dtype=np.uint8)
# Store frames
frames = []
for label, _ in components:
# Add the current component to the accumulation
accumulated_image[labels == label] = 255
# Convert OpenCV image to PIL image and append to frames
pil_frame = Image.fromarray(255 - accumulated_image)
frames.append(pil_frame.copy())
# Add the input_input as the final frame
frames.append(input_image.copy())
# Save GIF to a temporary file
tmp_dir = tempfile.gettempdir() # Get system temp directory
tmp_gif_path = os.path.join(tmp_dir, "sketch_animation.gif")
frames[0].save(
tmp_gif_path,
format="GIF",
save_all=True,
append_images=frames[1:],
duration=100,
loop=0,
)
return (
tmp_gif_path,
frames,
gr.Slider(
minimum=0,
maximum=len(frames) - 1,
value=0,
step=1,
visible=False,
scale=4,
label="Frame Selector",
interactive=True,
),
gr.Button("Stop", scale=1, visible=True),
)