Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import numpy as np | |
| import tempfile | |
| import os | |
| from PIL import Image | |
| import sys | |
| # Import your modules (you'll need to include them in the space) | |
| from strings import * | |
| def process_string_art(image, n_hooks=180, radius=250, quantization=30): | |
| """Process uploaded image and return string art result""" | |
| # Save uploaded image temporarily | |
| with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp_input: | |
| image.save(tmp_input.name) | |
| input_path = tmp_input.name | |
| # Create temporary output prefix | |
| output_prefix = tempfile.mktemp() | |
| try: | |
| # Build adjacency matrix | |
| sparse, hooks, edge_codes = build_arc_adjecency_matrix(n_hooks, radius) | |
| # Process image | |
| shrinkage = 0.75 | |
| img = image_from_pil(image, int(radius * 2 * shrinkage)) | |
| sparse_b = build_image_vector(img, radius) | |
| # Solve linear system | |
| result = scipy.sparse.linalg.lsqr(sparse, np.array(sparse_b.todense()).flatten()) | |
| x = result[0] | |
| # Apply quantization | |
| x = np.clip(x, 0, 1e6) | |
| max_edge_weight_orig = np.max(x) | |
| x_quantized = (x / np.max(x) * quantization).round() | |
| clip_factor = 0.3 | |
| x_quantized = np.clip(x_quantized, 0, int(np.max(x_quantized) * clip_factor)) | |
| x = x_quantized / quantization * max_edge_weight_orig | |
| # Reconstruct final image | |
| brightness_correction = 1.2 | |
| final_image = reconstruct(x * brightness_correction, sparse, radius) | |
| # Calculate statistics | |
| arc_count = int(np.sum(x_quantized)) | |
| unique_arcs = len(x_quantized[x_quantized > 0]) | |
| # Convert to PIL Image for return | |
| final_pil = Image.fromarray(np.clip(final_image, 0, 255).astype(np.uint8)) | |
| stats = f"Total arcs: {arc_count}\nUnique arc types: {unique_arcs}" | |
| return final_pil, stats | |
| finally: | |
| # Cleanup | |
| if os.path.exists(input_path): | |
| os.unlink(input_path) | |
| def image_from_pil(pil_image, size): | |
| """Convert PIL image to grayscale numpy array""" | |
| img = pil_image.convert('L') # Convert to grayscale | |
| img = img.resize((size, size), Image.Resampling.LANCZOS) | |
| return np.array(img) | |
| # Create Gradio interface | |
| iface = gr.Interface( | |
| fn=process_string_art, | |
| inputs=[ | |
| gr.Image(type="pil", label="Upload Image"), | |
| gr.Slider(50, 360, value=180, step=10, label="Number of Hooks"), | |
| gr.Slider(100, 500, value=250, step=50, label="Circle Radius"), | |
| gr.Slider(10, 100, value=30, step=5, label="Quantization Level") | |
| ], | |
| outputs=[ | |
| gr.Image(type="pil", label="String Art Result"), | |
| gr.Textbox(label="Statistics") | |
| ], | |
| title="String Art Generator", | |
| description="Convert any image into string art patterns! Upload a square image and adjust parameters.", | |
| examples=[ | |
| # You can add example images here | |
| ] | |
| ) | |
| if __name__ == "__main__": | |
| iface.launch() |