Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,44 +1,74 @@
|
|
1 |
-
import io
|
2 |
import gradio as gr
|
3 |
-
from PIL import Image
|
4 |
-
import vtracer
|
5 |
import numpy as np
|
6 |
-
import
|
7 |
import tempfile
|
|
|
|
|
|
|
8 |
from rembg import remove
|
9 |
-
from skimage import filters, img_as_ubyte, color, measure
|
10 |
-
from skimage.restoration import denoise_bilateral
|
11 |
-
from sklearn.cluster import KMeans
|
12 |
|
13 |
-
def
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
-
|
24 |
-
if ai_edge_enhance:
|
25 |
image_np = np.array(image)
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
if smoothness > 0:
|
33 |
image_np = np.array(image)
|
34 |
-
image_np =
|
35 |
image = Image.fromarray(image_np)
|
|
|
|
|
36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
# Convert Gradio image to bytes for vtracer compatibility
|
38 |
img_byte_array = io.BytesIO()
|
39 |
image.save(img_byte_array, format='PNG')
|
40 |
img_bytes = img_byte_array.getvalue()
|
41 |
-
|
42 |
# Perform the conversion
|
43 |
svg_str = vtracer.convert_raw_image_to_svg(
|
44 |
img_bytes,
|
@@ -53,48 +83,69 @@ def convert_image(image, color_mode, hierarchical, mode, filter_speckle,
|
|
53 |
length_threshold=float(length_threshold),
|
54 |
max_iterations=int(max_iterations),
|
55 |
splice_threshold=int(splice_threshold),
|
56 |
-
path_precision=int(path_precision)
|
57 |
-
detail_level=int(detail_level)
|
58 |
)
|
59 |
-
|
60 |
# Save the SVG string to a temporary file
|
61 |
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.svg')
|
62 |
temp_file.write(svg_str.encode('utf-8'))
|
63 |
temp_file.close()
|
64 |
-
|
65 |
-
|
|
|
|
|
66 |
|
67 |
# Gradio interface
|
68 |
iface = gr.Blocks()
|
69 |
|
70 |
with iface:
|
|
|
71 |
|
72 |
-
gr.
|
73 |
-
|
74 |
-
|
75 |
-
gr.
|
76 |
-
gr.
|
77 |
-
gr.
|
78 |
-
gr.
|
79 |
-
|
80 |
-
|
81 |
-
gr.Slider(minimum=
|
82 |
-
gr.
|
83 |
-
gr.Slider(minimum=
|
84 |
-
|
85 |
-
|
86 |
-
gr.
|
87 |
-
gr.
|
88 |
-
gr.
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
gr.
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
|
100 |
iface.launch()
|
|
|
|
|
1 |
import gradio as gr
|
2 |
+
from PIL import Image, ImageFilter
|
|
|
3 |
import numpy as np
|
4 |
+
import io
|
5 |
import tempfile
|
6 |
+
import vtracer
|
7 |
+
from skimage import feature, filters, morphology
|
8 |
+
import cv2
|
9 |
from rembg import remove
|
|
|
|
|
|
|
10 |
|
11 |
+
def preprocess_image(image, blur_radius, sharpen_radius, noise_reduction, detail_level, edge_method, color_quantization, enhance_with_ai, remove_bg):
|
12 |
+
"""Advanced preprocessing of the image before vectorization."""
|
13 |
+
|
14 |
+
if blur_radius > 0:
|
15 |
+
image = image.filter(ImageFilter.GaussianBlur(blur_radius))
|
16 |
+
|
17 |
+
if sharpen_radius > 0:
|
18 |
+
image = image.filter(ImageFilter.UnsharpMask(radius=sharpen_radius, percent=150, threshold=3))
|
19 |
+
|
20 |
+
if noise_reduction > 0:
|
21 |
+
image_np = np.array(image)
|
22 |
+
image_np = cv2.fastNlMeansDenoisingColored(image_np, None, h=noise_reduction, templateWindowSize=7, searchWindowSize=21)
|
23 |
+
image = Image.fromarray(image_np)
|
24 |
|
25 |
+
if detail_level > 0:
|
26 |
+
sigma = max(0.5, 3.0 - (detail_level * 0.5))
|
27 |
+
image_np = np.array(image.convert('L'))
|
28 |
+
|
29 |
+
if edge_method == 'Canny':
|
30 |
+
edges = feature.canny(image_np, sigma=sigma)
|
31 |
+
elif edge_method == 'Sobel':
|
32 |
+
edges = filters.sobel(image_np)
|
33 |
+
elif edge_method == 'Scharr':
|
34 |
+
edges = filters.scharr(image_np)
|
35 |
+
else: # Prewitt
|
36 |
+
edges = filters.prewitt(image_np)
|
37 |
+
|
38 |
+
edges = morphology.dilation(edges, morphology.square(max(1, 6 - detail_level)))
|
39 |
+
edges_img = Image.fromarray((edges * 255).astype(np.uint8))
|
40 |
+
image = Image.blend(image.convert('RGB'), edges_img.convert('RGB'), alpha=0.5)
|
41 |
+
|
42 |
+
if color_quantization > 0:
|
43 |
+
image = quantize_colors(image, color_quantization)
|
44 |
|
45 |
+
if enhance_with_ai:
|
|
|
46 |
image_np = np.array(image)
|
47 |
+
# AI-based enhancement for smoothing edges and improving vectorization
|
48 |
+
image_np = remove(image_np)
|
49 |
+
image = Image.fromarray(image_np)
|
50 |
+
|
51 |
+
if remove_bg:
|
|
|
|
|
52 |
image_np = np.array(image)
|
53 |
+
image_np = remove(image_np)
|
54 |
image = Image.fromarray(image_np)
|
55 |
+
|
56 |
+
return image
|
57 |
|
58 |
+
def convert_image(image, blur_radius, sharpen_radius, noise_reduction, detail_level, edge_method, color_quantization,
|
59 |
+
color_mode, hierarchical, mode, filter_speckle, color_precision, layer_difference,
|
60 |
+
corner_threshold, length_threshold, max_iterations, splice_threshold, path_precision,
|
61 |
+
enhance_with_ai, remove_bg):
|
62 |
+
"""Convert an image to SVG using vtracer with customizable and advanced parameters."""
|
63 |
+
|
64 |
+
# Preprocess the image with additional detail level settings
|
65 |
+
image = preprocess_image(image, blur_radius, sharpen_radius, noise_reduction, detail_level, edge_method, color_quantization, enhance_with_ai, remove_bg)
|
66 |
+
|
67 |
# Convert Gradio image to bytes for vtracer compatibility
|
68 |
img_byte_array = io.BytesIO()
|
69 |
image.save(img_byte_array, format='PNG')
|
70 |
img_bytes = img_byte_array.getvalue()
|
71 |
+
|
72 |
# Perform the conversion
|
73 |
svg_str = vtracer.convert_raw_image_to_svg(
|
74 |
img_bytes,
|
|
|
83 |
length_threshold=float(length_threshold),
|
84 |
max_iterations=int(max_iterations),
|
85 |
splice_threshold=int(splice_threshold),
|
86 |
+
path_precision=int(path_precision)
|
|
|
87 |
)
|
88 |
+
|
89 |
# Save the SVG string to a temporary file
|
90 |
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.svg')
|
91 |
temp_file.write(svg_str.encode('utf-8'))
|
92 |
temp_file.close()
|
93 |
+
|
94 |
+
# Display the SVG in the Gradio interface and provide the download link
|
95 |
+
svg_html = f'<svg viewBox="0 0 {image.width} {image.height}">{svg_str}</svg>'
|
96 |
+
return gr.HTML(svg_html), temp_file.name
|
97 |
|
98 |
# Gradio interface
|
99 |
iface = gr.Blocks()
|
100 |
|
101 |
with iface:
|
102 |
+
gr.Markdown("# Super-Advanced Image to SVG Converter")
|
103 |
|
104 |
+
with gr.Row():
|
105 |
+
image_input = gr.Image(type="pil", label="Upload Image")
|
106 |
+
blur_radius_input = gr.Slider(minimum=0, maximum=10, value=0, step=0.1, label="Blur Radius (for smoothing)")
|
107 |
+
sharpen_radius_input = gr.Slider(minimum=0, maximum=5, value=0, step=0.1, label="Sharpen Radius")
|
108 |
+
noise_reduction_input = gr.Slider(minimum=0, maximum=30, value=0, step=1, label="Noise Reduction")
|
109 |
+
enhance_with_ai_input = gr.Checkbox(label="AI Edge Enhance", value=False)
|
110 |
+
remove_bg_input = gr.Checkbox(label="Remove Background", value=False)
|
111 |
+
|
112 |
+
with gr.Row():
|
113 |
+
detail_level_input = gr.Slider(minimum=0, maximum=10, value=5, step=1, label="Detail Level")
|
114 |
+
edge_method_input = gr.Radio(choices=["Canny", "Sobel", "Scharr", "Prewitt"], value="Canny", label="Edge Detection Method")
|
115 |
+
color_quantization_input = gr.Slider(minimum=2, maximum=64, value=0, step=2, label="Color Quantization (0 to disable)")
|
116 |
+
|
117 |
+
with gr.Row():
|
118 |
+
color_mode_input = gr.Radio(choices=["Color", "Binary"], value="Color", label="Color Mode")
|
119 |
+
hierarchical_input = gr.Radio(choices=["Stacked", "Cutout"], value="Stacked", label="Hierarchical")
|
120 |
+
mode_input = gr.Radio(choices=["Spline", "Polygon", "None"], value="Spline", label="Mode")
|
121 |
+
|
122 |
+
with gr.Row():
|
123 |
+
filter_speckle_input = gr.Slider(minimum=1, maximum=100, value=4, step=1, label="Filter Speckle")
|
124 |
+
color_precision_input = gr.Slider(minimum=1, maximum=100, value=6, step=1, label="Color Precision")
|
125 |
+
layer_difference_input = gr.Slider(minimum=1, maximum=100, value=16, step=1, label="Layer Difference")
|
126 |
+
|
127 |
+
with gr.Row():
|
128 |
+
corner_threshold_input = gr.Slider(minimum=1, maximum=100, value=60, step=1, label="Corner Threshold")
|
129 |
+
length_threshold_input = gr.Slider(minimum=1, maximum=100, value=4.0, step=0.5, label="Length Threshold")
|
130 |
+
max_iterations_input = gr.Slider(minimum=1, maximum=100, value=10, step=1, label="Max Iterations")
|
131 |
+
|
132 |
+
with gr.Row():
|
133 |
+
splice_threshold_input = gr.Slider(minimum=1, maximum=100, value=45, step=1, label="Splice Threshold")
|
134 |
+
path_precision_input = gr.Slider(minimum=1, maximum=100, value=8, step=1, label="Path Precision")
|
135 |
+
|
136 |
+
convert_button = gr.Button("Convert Image to SVG")
|
137 |
+
svg_output = gr.HTML(label="SVG Output")
|
138 |
+
download_output = gr.File(label="Download SVG")
|
139 |
+
|
140 |
+
convert_button.click(
|
141 |
+
fn=convert_image,
|
142 |
+
inputs=[
|
143 |
+
image_input, blur_radius_input, sharpen_radius_input, noise_reduction_input, detail_level_input, edge_method_input, color_quantization_input,
|
144 |
+
color_mode_input, hierarchical_input, mode_input, filter_speckle_input, color_precision_input,
|
145 |
+
layer_difference_input, corner_threshold_input, length_threshold_input, max_iterations_input,
|
146 |
+
splice_threshold_input, path_precision_input, enhance_with_ai_input, remove_bg_input
|
147 |
+
],
|
148 |
+
outputs=[svg_output, download_output]
|
149 |
+
)
|
150 |
|
151 |
iface.launch()
|