Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import numpy as np | |
| from PIL import Image, ImageDraw, ImageFilter, ImageEnhance | |
| import cv2 | |
| import math | |
| import random | |
| from typing import Tuple, Optional | |
| def create_spiral_illusion(width: int = 512, height: int = 512, | |
| spiral_count: int = 5, | |
| rotation_speed: float = 0.5, | |
| color_scheme: str = "rainbow") -> Image.Image: | |
| """Create a spiral optical illusion.""" | |
| img = Image.new('RGB', (width, height), color='white') | |
| draw = ImageDraw.Draw(img) | |
| center_x, center_y = width // 2, height // 2 | |
| max_radius = min(width, height) // 2 | |
| colors = { | |
| "rainbow": ['#FF0000', '#FF7F00', '#FFFF00', '#00FF00', '#0000FF', '#4B0082', '#9400D3'], | |
| "blue": ['#000080', '#0000FF', '#4169E1', '#1E90FF', '#00BFFF', '#87CEEB'], | |
| "warm": ['#FF0000', '#FF4500', '#FF6347', '#FF7F50', '#FFA500', '#FFD700'], | |
| "cool": ['#00CED1', '#48D1CC', '#40E0D0', '#00FFFF', '#00CED1', '#4682B4'] | |
| } | |
| palette = colors.get(color_scheme, colors["rainbow"]) | |
| for i in range(max_radius): | |
| angle = (i * rotation_speed) % (2 * math.pi) | |
| spiral_offset = math.sin(i * 0.1) * 10 | |
| for j in range(spiral_count): | |
| spiral_angle = angle + (j * 2 * math.pi / spiral_count) | |
| x = center_x + (i + spiral_offset) * math.cos(spiral_angle) | |
| y = center_y + (i + spiral_offset) * math.sin(spiral_angle) | |
| color_idx = (i + j * 20) % len(palette) | |
| draw.ellipse([x-3, y-3, x+3, y+3], fill=palette[color_idx]) | |
| return img | |
| def create_wave_distortion(input_image: Image.Image, | |
| wave_amplitude: float = 20, | |
| wave_frequency: float = 0.05, | |
| direction: str = "horizontal") -> Image.Image: | |
| """Apply wave distortion to create illusion effect.""" | |
| img_array = np.array(input_image) | |
| h, w = img_array.shape[:2] | |
| output = np.zeros_like(img_array) | |
| for y in range(h): | |
| for x in range(w): | |
| if direction == "horizontal": | |
| offset = int(wave_amplitude * math.sin(x * wave_frequency)) | |
| new_x = (x + offset) % w | |
| output[y, x] = img_array[y, new_x] | |
| else: | |
| offset = int(wave_amplitude * math.sin(y * wave_frequency)) | |
| new_y = (y + offset) % h | |
| output[y, x] = img_array[new_y, x] | |
| return Image.fromarray(output) | |
| def create_tunnel_illusion(width: int = 512, height: int = 512, | |
| rings: int = 20, | |
| perspective: float = 0.8) -> Image.Image: | |
| """Create a tunnel/depth illusion.""" | |
| img = Image.new('RGB', (width, height), color='black') | |
| draw = ImageDraw.Draw(img) | |
| center_x, center_y = width // 2, height // 2 | |
| for i in range(rings, 0, -1): | |
| radius = int((width // 2) * (i / rings) ** perspective) | |
| # Alternating colors for depth effect | |
| if i % 2 == 0: | |
| color = (255, 255, 255) | |
| else: | |
| gray_value = int(255 * (1 - i / rings)) | |
| color = (gray_value, gray_value, gray_value) | |
| draw.ellipse([center_x - radius, center_y - radius, | |
| center_x + radius, center_y + radius], | |
| outline=color, width=max(1, int(rings / 10))) | |
| return img | |
| def create_moire_pattern(width: int = 512, height: int = 512, | |
| line_spacing: int = 10, | |
| angle_offset: float = 5) -> Image.Image: | |
| """Create a moirΓ© pattern illusion.""" | |
| img = Image.new('RGB', (width, height), color='white') | |
| draw = ImageDraw.Draw(img) | |
| # First set of lines | |
| for x in range(0, width, line_spacing): | |
| draw.line([(x, 0), (x, height)], fill='black', width=2) | |
| # Second set of lines at slight angle | |
| angle_rad = math.radians(angle_offset) | |
| for i in range(-width, width * 2, line_spacing): | |
| x1 = i | |
| y1 = 0 | |
| x2 = i + height * math.tan(angle_rad) | |
| y2 = height | |
| # Clip to image bounds | |
| points = [] | |
| for x, y in [(x1, y1), (x2, y2)]: | |
| x = max(0, min(width - 1, int(x))) | |
| y = max(0, min(height - 1, int(y))) | |
| points.append((x, y)) | |
| if len(points) == 2: | |
| draw.line(points, fill='black', width=2) | |
| return img | |
| def create_rotating_grid_illusion(width: int = 512, height: int = 512, | |
| grid_size: int = 20, | |
| rotation: float = 15) -> Image.Image: | |
| """Create a rotating grid illusion.""" | |
| img = Image.new('RGB', (width, height), color='white') | |
| draw = ImageDraw.Draw(img) | |
| center_x, center_y = width // 2, height // 2 | |
| angle_rad = math.radians(rotation) | |
| # Draw grid with rotation | |
| for i in range(-width, width, grid_size): | |
| for j in range(-height, height, grid_size): | |
| # Rotate grid points around center | |
| x1 = center_x + i * math.cos(angle_rad) - j * math.sin(angle_rad) | |
| y1 = center_y + i * math.sin(angle_rad) + j * math.cos(angle_rad) | |
| x2 = center_x + (i + grid_size) * math.cos(angle_rad) - j * math.sin(angle_rad) | |
| y2 = center_y + (i + grid_size) * math.sin(angle_rad) + j * math.cos(angle_rad) | |
| # Only draw if within bounds | |
| if (0 <= x1 <= width and 0 <= y1 <= height) or (0 <= x2 <= width and 0 <= y2 <= height): | |
| draw.line([(x1, y1), (x2, y2)], fill='black', width=1) | |
| x3 = center_x + i * math.cos(angle_rad) - (j + grid_size) * math.sin(angle_rad) | |
| y3 = center_y + i * math.sin(angle_rad) + (j + grid_size) * math.cos(angle_rad) | |
| if (0 <= x1 <= width and 0 <= y1 <= height) or (0 <= x3 <= width and 0 <= y3 <= height): | |
| draw.line([(x1, y1), (x3, y3)], fill='black', width=1) | |
| return img | |
| def apply_illusion(input_image: Optional[Image.Image], | |
| illusion_type: str, | |
| intensity: float = 1.0, | |
| **params) -> Image.Image: | |
| """Apply selected illusion effect to image or generate new illusion.""" | |
| if input_image is None and illusion_type not in ["spiral", "tunnel", "moire", "rotating_grid"]: | |
| # Create a default pattern for image-based effects | |
| input_image = create_gradient_pattern() | |
| if illusion_type == "spiral": | |
| return create_spiral_illusion( | |
| spiral_count=int(params.get('spiral_count', 5)), | |
| rotation_speed=params.get('rotation_speed', 0.5), | |
| color_scheme=params.get('color_scheme', 'rainbow') | |
| ) | |
| elif illusion_type == "wave": | |
| return create_wave_distortion( | |
| input_image, | |
| wave_amplitude=int(params.get('wave_amplitude', 20)), | |
| wave_frequency=params.get('wave_frequency', 0.05), | |
| direction=params.get('direction', 'horizontal') | |
| ) | |
| elif illusion_type == "tunnel": | |
| return create_tunnel_illusion( | |
| rings=int(params.get('rings', 20)), | |
| perspective=params.get('perspective', 0.8) | |
| ) | |
| elif illusion_type == "moire": | |
| return create_moire_pattern( | |
| line_spacing=int(params.get('line_spacing', 10)), | |
| angle_offset=params.get('angle_offset', 5) | |
| ) | |
| elif illusion_type == "rotating_grid": | |
| return create_rotating_grid_illusion( | |
| grid_size=int(params.get('grid_size', 20)), | |
| rotation=params.get('rotation', 15) | |
| ) | |
| elif illusion_type == "kaleidoscope": | |
| return create_kaleidoscope(input_image, segments=int(params.get('segments', 6))) | |
| elif illusion_type == "pinch": | |
| return create_pinch_distortion(input_image, strength=params.get('strength', 0.5)) | |
| elif illusion_type == "twirl": | |
| return create_twirl_effect(input_image, angle=params.get('twirl_angle', 180)) | |
| return input_image | |
| def create_gradient_pattern(width: int = 512, height: int = 512) -> Image.Image: | |
| """Create a gradient pattern as default input.""" | |
| img = Image.new('RGB', (width, height)) | |
| draw = ImageDraw.Draw(img) | |
| for x in range(width): | |
| for y in range(height): | |
| r = int(255 * x / width) | |
| g = int(255 * y / height) | |
| b = int(255 * (x + y) / (width + height)) | |
| draw.point((x, y), fill=(r, g, b)) | |
| return img | |
| def create_kaleidoscope(input_image: Image.Image, segments: int = 6) -> Image.Image: | |
| """Create kaleidoscope effect.""" | |
| width, height = input_image.size | |
| result = Image.new('RGB', (width, height)) | |
| center_x, center_y = width // 2, height // 2 | |
| for i in range(segments): | |
| angle = (360 / segments) * i | |
| # Rotate and copy segment | |
| rotated = input_image.rotate(angle, expand=False) | |
| # Create mask for this segment | |
| mask = Image.new('L', (width, height), 0) | |
| mask_draw = ImageDraw.Draw(mask) | |
| start_angle = i * (360 / segments) | |
| end_angle = (i + 1) * (360 / segments) | |
| # Draw pie slice | |
| mask_draw.pieslice([0, 0, width, height], start_angle, end_angle, fill=255) | |
| # Apply to result | |
| result.paste(rotated, mask=mask) | |
| return result | |
| def create_pinch_distortion(input_image: Image.Image, strength: float = 0.5) -> Image.Image: | |
| """Create pinch/bulge distortion.""" | |
| img_array = np.array(input_image) | |
| h, w = img_array.shape[:2] | |
| output = np.zeros_like(img_array) | |
| center_x, center_y = w // 2, h // 2 | |
| max_radius = min(w, h) // 2 | |
| for y in range(h): | |
| for x in range(w): | |
| dx = x - center_x | |
| dy = y - center_y | |
| distance = math.sqrt(dx**2 + dy**2) | |
| if distance < max_radius: | |
| factor = 1 - strength * (1 - distance / max_radius) | |
| new_x = int(center_x + dx * factor) | |
| new_y = int(center_y + dy * factor) | |
| if 0 <= new_x < w and 0 <= new_y < h: | |
| output[y, x] = img_array[new_y, new_x] | |
| else: | |
| output[y, x] = img_array[y, x] | |
| return Image.fromarray(output) | |
| def create_twirl_effect(input_image: Image.Image, angle: float = 180) -> Image.Image: | |
| """Create twirl/swirl distortion.""" | |
| img_array = np.array(input_image) | |
| h, w = img_array.shape[:2] | |
| output = np.zeros_like(img_array) | |
| center_x, center_y = w // 2, h // 2 | |
| max_radius = min(w, h) // 2 | |
| for y in range(h): | |
| for x in range(w): | |
| dx = x - center_x | |
| dy = y - center_y | |
| distance = math.sqrt(dx**2 + dy**2) | |
| if distance < max_radius: | |
| current_angle = math.atan2(dy, dx) | |
| twist_angle = (angle * math.pi / 180) * (1 - distance / max_radius) | |
| new_angle = current_angle + twist_angle | |
| new_x = int(center_x + distance * math.cos(new_angle)) | |
| new_y = int(center_y + distance * math.sin(new_angle)) | |
| if 0 <= new_x < w and 0 <= new_y < h: | |
| output[y, x] = img_array[new_y, new_x] | |
| else: | |
| output[y, x] = img_array[y, x] | |
| return Image.fromarray(output) | |
| # Create the Gradio interface | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# π Illusion Diffusion Studio") | |
| gr.Markdown("Create stunning optical illusions and mind-bending visual effects! Upload an image or generate patterns from scratch.") | |
| gr.HTML('<div style="text-align: center; margin-bottom: 20px;"><a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="color: #007bff; text-decoration: none; font-weight: bold;">Built with anycoder</a></div>') | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### π€ Input Image (Optional)") | |
| input_image = gr.Image( | |
| label="Upload Image", | |
| type="pil", | |
| sources=["upload", "webcam", "clipboard"], | |
| height=300 | |
| ) | |
| gr.Markdown("### π¨ Illusion Type") | |
| illusion_type = gr.Dropdown( | |
| choices=[ | |
| ("Spiral Illusion", "spiral"), | |
| ("Wave Distortion", "wave"), | |
| ("Tunnel Effect", "tunnel"), | |
| ("MoirΓ© Pattern", "moire"), | |
| ("Rotating Grid", "rotating_grid"), | |
| ("Kaleidoscope", "kaleidoscope"), | |
| ("Pinch Distortion", "pinch"), | |
| ("Twirl Effect", "twirl") | |
| ], | |
| value="spiral", | |
| label="Select Illusion Type" | |
| ) | |
| gr.Markdown("### βοΈ Parameters") | |
| with gr.Group(visible=True) as spiral_params: | |
| spiral_count = gr.Slider(3, 10, value=5, step=1, label="Spiral Count") | |
| rotation_speed = gr.Slider(0.1, 2.0, value=0.5, step=0.1, label="Rotation Speed") | |
| color_scheme = gr.Dropdown( | |
| ["rainbow", "blue", "warm", "cool"], | |
| value="rainbow", | |
| label="Color Scheme" | |
| ) | |
| with gr.Group(visible=False) as wave_params: | |
| wave_amplitude = gr.Slider(5, 50, value=20, step=5, label="Wave Amplitude") | |
| wave_frequency = gr.Slider(0.01, 0.2, value=0.05, step=0.01, label="Wave Frequency") | |
| direction = gr.Radio(["horizontal", "vertical"], value="horizontal", label="Direction") | |
| with gr.Group(visible=False) as tunnel_params: | |
| rings = gr.Slider(10, 50, value=20, step=5, label="Number of Rings") | |
| perspective = gr.Slider(0.5, 1.5, value=0.8, step=0.1, label="Perspective") | |
| with gr.Group(visible=False) as moire_params: | |
| line_spacing = gr.Slider(5, 30, value=10, step=5, label="Line Spacing") | |
| angle_offset = gr.Slider(1, 20, value=5, step=1, label="Angle Offset") | |
| with gr.Group(visible=False) as grid_params: | |
| grid_size = gr.Slider(10, 50, value=20, step=5, label="Grid Size") | |
| rotation = gr.Slider(5, 45, value=15, step=5, label="Rotation Angle") | |
| with gr.Group(visible=False) as kaleidoscope_params: | |
| segments = gr.Slider(3, 12, value=6, step=1, label="Segments") | |
| with gr.Group(visible=False) as pinch_params: | |
| strength = gr.Slider(0.1, 1.0, value=0.5, step=0.1, label="Pinch Strength") | |
| with gr.Group(visible=False) as twirl_params: | |
| twirl_angle = gr.Slider(90, 360, value=180, step=30, label="Twirl Angle") | |
| generate_btn = gr.Button("π Generate Illusion", variant="primary", size="lg") | |
| gr.Markdown("### π― Quick Examples") | |
| gr.Examples( | |
| examples=[ | |
| [None, "spiral", 5, 0.5, "rainbow"], | |
| [None, "wave", 20, 0.05, "horizontal"], | |
| [None, "tunnel", 20, 0.8, ""], | |
| [None, "moire", 10, 5, ""], | |
| [None, "rotating_grid", 20, 15, ""], | |
| ], | |
| inputs=[input_image, illusion_type, spiral_count, rotation_speed, color_scheme], | |
| label="Try these presets!" | |
| ) | |
| with gr.Column(scale=1): | |
| gr.Markdown("### β¨ Output") | |
| output_image = gr.Image( | |
| label="Generated Illusion", | |
| type="pil", | |
| height=400, | |
| interactive=True | |
| ) | |
| with gr.Row(): | |
| download_btn = gr.DownloadButton( | |
| "πΎ Download", | |
| variant="secondary" | |
| ) | |
| clear_btn = gr.Button("ποΈ Clear", variant="secondary") | |
| gr.Markdown("### π Effect Info") | |
| info_text = gr.Markdown( | |
| "Select an illusion type and adjust parameters to create your optical illusion. " | |
| "Some effects work best with uploaded images, while others generate patterns from scratch." | |
| ) | |
| # Update parameter visibility based on illusion type | |
| def update_params(illusion_type): | |
| return { | |
| spiral_params: gr.Group(visible=(illusion_type == "spiral")), | |
| wave_params: gr.Group(visible=(illusion_type == "wave")), | |
| tunnel_params: gr.Group(visible=(illusion_type == "tunnel")), | |
| moire_params: gr.Group(visible=(illusion_type == "moire")), | |
| grid_params: gr.Group(visible=(illusion_type == "rotating_grid")), | |
| kaleidoscope_params: gr.Group(visible=(illusion_type == "kaleidoscope")), | |
| pinch_params: gr.Group(visible=(illusion_type == "pinch")), | |
| twirl_params: gr.Group(visible=(illusion_type == "twirl")) | |
| } | |
| def generate_illusion(img, ill_type, *params): | |
| param_dict = {} | |
| if ill_type == "spiral": | |
| param_dict = { | |
| 'spiral_count': params[0], | |
| 'rotation_speed': params[1], | |
| 'color_scheme': params[2] | |
| } | |
| elif ill_type == "wave": | |
| param_dict = { | |
| 'wave_amplitude': params[0], | |
| 'wave_frequency': params[1], | |
| 'direction': params[2] | |
| } | |
| elif ill_type == "tunnel": | |
| param_dict = { | |
| 'rings': params[0], | |
| 'perspective': params[1] | |
| } | |
| elif ill_type == "moire": | |
| param_dict = { | |
| 'line_spacing': params[0], | |
| 'angle_offset': params[1] | |
| } | |
| elif ill_type == "rotating_grid": | |
| param_dict = { | |
| 'grid_size': params[0], | |
| 'rotation': params[1] | |
| } | |
| elif ill_type == "kaleidoscope": | |
| param_dict = { | |
| 'segments': params[0] | |
| } | |
| elif ill_type == "pinch": | |
| param_dict = { | |
| 'strength': params[0] | |
| } | |
| elif ill_type == "twirl": | |
| param_dict = { | |
| 'twirl_angle': params[0] | |
| } | |
| result = apply_illusion(img, ill_type, **param_dict) | |
| return result | |
| # Event handlers | |
| illusion_type.change( | |
| update_params, | |
| illusion_type, | |
| [spiral_params, wave_params, tunnel_params, moire_params, | |
| grid_params, kaleidoscope_params, pinch_params, twirl_params] | |
| ) | |
| generate_btn.click( | |
| generate_illusion, | |
| inputs=[input_image, illusion_type, | |
| spiral_count, rotation_speed, color_scheme, | |
| wave_amplitude, wave_frequency, direction, | |
| rings, perspective, | |
| line_spacing, angle_offset, | |
| grid_size, rotation, | |
| segments, | |
| strength, | |
| twirl_angle], | |
| outputs=output_image, | |
| api_visibility="public" | |
| ) | |
| clear_btn.click( | |
| lambda: [None, None], | |
| outputs=[input_image, output_image] | |
| ) | |
| # Launch the app with Gradio 6 syntax | |
| demo.launch( | |
| theme=gr.themes.Soft( | |
| primary_hue="indigo", | |
| secondary_hue="purple", | |
| neutral_hue="slate", | |
| text_size="lg", | |
| spacing_size="lg", | |
| radius_size="md" | |
| ), | |
| footer_links=[ | |
| {"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"} | |
| ] | |
| ) |