string-art / app.py
aboalaa147's picture
Create app.py
4bb0dc0 verified
raw
history blame
5.45 kB
import gradio as gr
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import io
from stringart import StringArtGenerator
def generate_string_art(image, num_nails, iterations, weight, shape):
"""Generate string art from uploaded image"""
if image is None:
return None
try:
# Initialize generator
generator = StringArtGenerator()
# Convert PIL image to numpy array and set it directly
np_img = np.array(image)
generator.image = image
generator.data = np.flipud(np_img).transpose()
# Preprocess
generator.preprocess()
generator.set_nails(int(num_nails))
generator.set_iterations(int(iterations))
generator.set_weight(int(weight))
generator.set_shape(shape)
generator.set_seed(42)
# Generate pattern
pattern = generator.generate()
if len(pattern) == 0:
return None
# Create visualization
lines_x = []
lines_y = []
for i in range(len(pattern)-1):
lines_x.extend([pattern[i][0], pattern[i+1][0], None])
lines_y.extend([pattern[i][1], pattern[i+1][1], None])
# Create plot
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8))
# Original image
ax1.imshow(generator.image, cmap='gray')
ax1.set_title('Original Image (Preprocessed)')
ax1.axis('off')
# String art
xmin, ymin = 0., 0.
xmax = generator.data.shape[0]
ymax = generator.data.shape[1]
ax2.set_xlim([xmin, xmax])
ax2.set_ylim([ymin, ymax])
ax2.set_aspect('equal')
ax2.axis('off')
ax2.set_title(f'String Art ({len(pattern)} connections)')
ax2.set_facecolor('white')
# Plot all lines at once for better performance
ax2.plot(lines_x, lines_y, linewidth=0.15, color='black', alpha=0.8)
plt.tight_layout()
# Save to buffer
buf = io.BytesIO()
plt.savefig(buf, format='png', bbox_inches='tight', dpi=150, facecolor='white')
buf.seek(0)
plt.close()
# Return image
result_image = Image.open(buf)
return result_image
except Exception as e:
print(f"Error: {str(e)}")
return None
# Create Gradio interface
with gr.Blocks(
title="String Art Generator",
theme=gr.themes.Soft(),
css="""
.gradio-container {
max-width: 1200px !important;
}
"""
) as demo:
gr.Markdown("""
# 🎨 String Art Generator
Transform your images into beautiful string art! Upload an image and watch as an algorithm recreates it using virtual string connections between nails.
**How it works:** The algorithm places nails around a circle/rectangle, then iteratively finds the darkest paths between nails to recreate your image.
""")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### πŸ“€ Input")
image_input = gr.Image(
type="pil",
label="Upload Your Image",
sources=["upload"],
height=300
)
gr.Markdown("### βš™οΈ Settings")
with gr.Row():
num_nails = gr.Slider(
minimum=50,
maximum=200,
value=120,
step=10,
label="Number of Nails",
info="More nails = more detail, but slower processing"
)
iterations = gr.Slider(
minimum=500,
maximum=3000,
value=1500,
step=100,
label="Iterations",
info="More iterations = better quality, but slower"
)
with gr.Row():
weight = gr.Slider(
minimum=5,
maximum=40,
value=20,
step=5,
label="Line Weight",
info="Thickness of virtual string"
)
shape = gr.Dropdown(
choices=["circle", "rectangle"],
value="circle",
label="Nail Arrangement",
info="Shape for nail placement"
)
generate_btn = gr.Button(
"🎨 Generate String Art",
variant="primary",
size="lg"
)
gr.Markdown("""
### πŸ’‘ Tips:
- High contrast images work best
- Simple compositions are ideal
- Processing may take 1-3 minutes
- Start with lower settings for faster results
""")
with gr.Column(scale=1):
gr.Markdown("### 🎯 Result")
output_image = gr.Image(
label="Generated String Art",
height=600
)
generate_btn.click(
fn=generate_string_art,
inputs=[image_input, num_nails, iterations, weight, shape],
outputs=output_image,
show_progress=True
)
if __name__ == "__main__":
demo.launch()