File size: 5,447 Bytes
4bb0dc0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
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() |