Spaces:
Sleeping
Sleeping
| 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() |