Gertie01's picture
Update app.py
779f4e6 verified
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"}
]
)