Spaces:
Running
on
Zero
Running
on
Zero
| import os | |
| 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 stronger Gaussian blur to smooth fine details | |
| blurred_image = cv2.GaussianBlur(grayscale_image, (13, 13), 0) | |
| # Use Canny Edge Detection with higher thresholds to detect only strong edges | |
| edges = cv2.Canny(blurred_image, threshold1=100, threshold2=200) | |
| # Dilate edges to make lines thicker | |
| kernel = np.ones((5, 5), np.uint8) | |
| edges = cv2.dilate(edges, kernel, iterations=1) | |
| # 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) and ignore very small ones | |
| min_area = 250 # Minimum area to keep a component | |
| components = sorted( | |
| [ | |
| (i, stats[i, cv2.CC_STAT_AREA]) | |
| for i in range(1, num_labels) | |
| if stats[i, cv2.CC_STAT_AREA] > min_area | |
| ], | |
| 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()) | |
| if not frames: | |
| # Handle edge case where no components remain | |
| frames.append(Image.fromarray(255 - accumulated_image)) | |
| return ( | |
| frames[0], | |
| frames, | |
| gr.Slider( | |
| value=len(frames) - 1, | |
| maximum=len(frames) - 1, | |
| ), | |
| gr.Button(interactive=False), | |
| ) | |