UnSinnlos commited on
Commit
2f0b1ec
·
verified ·
1 Parent(s): 0c7d06c

**Optionen** (alle optional, mit Standardwerten):

Browse files

- `--blur` (float, Standard 1.2): Stärke des Gaußschen Weichzeichners vor Kantenerkennung
- `--edge` {canny, sobel, laplace}, Standard canny
- `--canny-low` (int, 80) / `--canny-high` (int, 160)
- `--sobel-ksize` {3,5,7}, Standard 3
- `--laplace-ksize` {3,5,7}, Standard 3
- `--threshold` {otsu,fixed,adaptive,posterize}, Standard otsu
- `--fixed-thresh` (0–255), Standard 128
- `--posterize-levels` (2–6), Standard 3
- `--adaptive-block` (ungerade int), Standard 25
- `--adaptive-C` (int), Standard 7
- `--line-thickness` (int), Standard 2
- `--line-jitter` (float 0–1), Standard 0.15
- `--hatch` (Flag): Schraffur aktivieren
- `--hatch-angle` (Grad), Standard 45
- `--hatch-spacing` (Pixel), Standard 8
- `--hatch-thickness` (Pixel), Standard 1
- `--invert` (Flag): invertiert das Endbild
- `--contrast-boost` (float), Standard 1.0 (Gamma-Korrektur vor Threshold)
- `--suffix` (string), Standard "_sketch"
- `--seed` (int), Standard 42
- `--jobs` (int), Standard 0 (seriell)
- `--preview` (Flag): zeigt interaktive Vorschau
- `--dryrun` (Flag): zeigt Parameter, führt nichts aus
- `--selftest` (Flag): führt interne Tests mit synthetischen Bildern durch

---

## Verarbeitungs-Pipeline (Schritte exakt implementieren):

1. **Laden & Umwandlung**
- Lade Bild (BGR)
- Konvertiere in Graustufen (float32 0..1)

2. **Optional: Kontrastverstärkung**
- Falls `contrast-boost` ≠ 1.0 → Gamma-Korrektur anwenden

3. **Weichzeichnen**
- Gaußscher Weichzeichner mit Sigma = `--blur`

4. **Schwellwert/Posterize**
- Je nach Option:
- Otsu → binäres Bild automatisch
- Fixed → fester Schwellwert
- Adaptive → cv2.ADAPTIVE_THRESH_GAUSSIAN_C
- Posterize → Tonwertreduktion auf n Stufen

5. **Kantenerkennung**
- `canny`: Canny mit low/high
- `sobel`: Gradientenmagnitude, normieren, threshold automatisch
- `laplace`: Absolutwert, normieren, threshold automatisch

6. **Linienstilisierung**
- Morphologische Dilatation → `line-thickness`
- Handgezeichneter Effekt: leichte Koordinatenverschiebung mittels geglättetem Zufallsfeld (`line-jitter`)

7. **Schraffur (optional)**
- Erzeuge diagonales Linienmuster mit Abstand `hatch-spacing`, Dicke `hatch-thickness`, Rotation `hatch-angle`
- Moduliere Deckung basierend auf Tonwertmaske aus Schritt 4 (dunkle Bereiche → dichter schraffiert)
- Linien nicht über Kanten legen

8. **Komposition**
- Starte mit weißem Canvas
- Zeichne schwarze Linien (Edges)
- Füge Schraffur hinzu, ohne helle Flächen zu übermalen
- Optional invertieren (`--invert`)

9. **Speichern / Vorschau**
- Ergebnisse als PNG speichern, Dateiname = Originalname + `--suffix`
- Bei Preview → Fenster öffnen, Taste schließt

---

## Implementierungshinweise

- Strukturiere Code in klar getrennte Funktionen mit Type Hints und Docstrings:
`load_image`, `to_grayscale`, `apply_contrast`, `gaussian_blur`, `threshold_stage`, `detect_edges`, `stylize_edges`, `generate_hatching`, `compose_final`, `save_image`, `process_path`.
- Verwende `numpy.random.default_rng(seed)` für deterministische Effekte.
- Unterstütze sowohl Einzelbilder als auch Ordnerverarbeitung.
- Fehler sollen mit verständlichen Meldungen ausgegeben werden.
- Debug-Modus: Wenn `--suffix` “_debug” enthält, speichere zusätzliche Zwischenschritte (`_gray.png`, `_thresh.png`, `_edges.png`, `_lines.png`, `_hatch.png`).
- Implementiere `--selftest`: Erzeuge synthetisches Testbild (Kreise, Rechtecke, Verlauf), teste 3 Presets (Canny+Otsu, Sobel+Posterize+Hatch, Canny+Adaptive+Invert).

---

## Ästhetische Anforderungen

- Kanten sollen kräftig und leicht unregelmäßig sein (kein steriler Canny-Look).
- Schraffuren sollen dunkle Flächen füllen, aber helle freilassen.
- Standardparameter sollen auf typischen Fotos sofort gute Ergebnisse liefern.

Schreibe jetzt den **vollständigen Code für `sketchify.py`**.

Files changed (2) hide show
  1. README.md +8 -5
  2. index.html +302 -18
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Sketchify Magic Wand
3
- emoji: 🐨
4
- colorFrom: red
5
- colorTo: green
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: Sketchify Magic Wand
3
+ colorFrom: blue
4
+ colorTo: purple
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://deepsite.hf.co).
index.html CHANGED
@@ -1,19 +1,303 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Sketchify - AI Image to Sketch Converter</title>
7
+ <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
10
+ <script src="https://unpkg.com/feather-icons"></script>
11
+ <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script>
12
+ <style>
13
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
14
+ body {
15
+ font-family: 'Inter', sans-serif;
16
+ }
17
+ .gradient-bg {
18
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
19
+ }
20
+ .glass-effect {
21
+ background: rgba(255, 255, 255, 0.1);
22
+ backdrop-filter: blur(10px);
23
+ border: 1px solid rgba(255, 255, 255, 0.2);
24
+ }
25
+ .sketch-border {
26
+ border: 2px solid #2d3748;
27
+ box-shadow: 4px 4px 0px #2d3748;
28
+ }
29
+ .upload-area {
30
+ border: 2px dashed #cbd5e0;
31
+ transition: all 0.3s ease;
32
+ }
33
+ .upload-area:hover, .upload-area.dragover {
34
+ border-color: #667eea;
35
+ background-color: rgba(102, 126, 234, 0.05);
36
+ }
37
+ .loading-spinner {
38
+ border: 3px solid #f3f4f6;
39
+ border-top: 3px solid #667eea;
40
+ border-radius: 50%;
41
+ animation: spin 1s linear infinite;
42
+ }
43
+ @keyframes spin {
44
+ 0% { transform: rotate(0deg); }
45
+ 100% { transform: rotate(360deg); }
46
+ }
47
+ .parameter-slider {
48
+ -webkit-appearance: none;
49
+ width: 100%;
50
+ height: 6px;
51
+ border-radius: 3px;
52
+ background: #e2e8f0;
53
+ outline: none;
54
+ }
55
+ .parameter-slider::-webkit-slider-thumb {
56
+ -webkit-appearance: none;
57
+ width: 20px;
58
+ height: 20px;
59
+ border-radius: 50%;
60
+ background: #667eea;
61
+ cursor: pointer;
62
+ border: 2px solid white;
63
+ box-shadow: 0 2px 4px rgba(0,0,0,0.2);
64
+ }
65
+ </style>
66
+ </head>
67
+ <body class="min-h-screen gradient-bg">
68
+ <div id="vanta-bg" class="fixed inset-0 z-0"></div>
69
+
70
+ <!-- Navigation -->
71
+ <nav class="relative z-10 glass-effect rounded-2xl mx-4 mt-4 p-4">
72
+ <div class="flex justify-between items-center">
73
+ <div class="flex items-center space-x-2">
74
+ <i data-feather="pen-tool" class="text-white"></i>
75
+ <h1 class="text-2xl font-bold text-white">Sketchify</h1>
76
+ </div>
77
+ <div class="flex space-x-4">
78
+ <button class="text-white hover:text-gray-200 transition-colors">
79
+ <i data-feather="help-circle"></i>
80
+ </button>
81
+ <button class="text-white hover:text-gray-200 transition-colors">
82
+ <i data-feather="settings"></i>
83
+ </button>
84
+ </div>
85
+ </div>
86
+ </nav>
87
+
88
+ <!-- Main Content -->
89
+ <main class="relative z-10 container mx-auto px-4 py-8">
90
+ <div class="max-w-6xl mx-auto">
91
+ <!-- Hero Section -->
92
+ <div class="text-center mb-12">
93
+ <h2 class="text-5xl font-bold text-white mb-4">Transform Photos into Artistic Sketches</h2>
94
+ <p class="text-xl text-gray-200 mb-8">Upload any image and watch it transform into a beautiful hand-drawn sketch with AI magic</p>
95
+ </div>
96
+
97
+ <!-- Upload & Preview Section -->
98
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-12">
99
+ <!-- Upload Area -->
100
+ <div class="glass-effect rounded-2xl p-8">
101
+ <div class="upload-area rounded-xl p-8 text-center cursor-pointer" id="uploadArea">
102
+ <i data-feather="upload-cloud" class="w-16 h-16 text-gray-400 mx-auto mb-4"></i>
103
+ <h3 class="text-xl font-semibold text-white mb-2">Drop your image here</h3>
104
+ <p class="text-gray-300 mb-4">or click to browse files</p>
105
+ <input type="file" id="fileInput" class="hidden" accept="image/*">
106
+ <button class="bg-blue-500 hover:bg-blue-600 text-white px-6 py-3 rounded-lg font-medium transition-colors">
107
+ Select Image
108
+ </button>
109
+ </div>
110
+
111
+ <!-- Parameters -->
112
+ <div class="mt-8">
113
+ <h4 class="text-lg font-semibold text-white mb-4">Sketch Parameters</h4>
114
+
115
+ <!-- Edge Detection -->
116
+ <div class="mb-6">
117
+ <label class="block text-gray-200 mb-2">Edge Detection Method</label>
118
+ <select class="w-full bg-white/10 border border-gray-300/30 rounded-lg px-4 py-2 text-white">
119
+ <option value="canny">Canny</option>
120
+ <option value="sobel">Sobel</option>
121
+ <option value="laplace">Laplace</option>
122
+ </select>
123
+ </div>
124
+
125
+ <!-- Blur Strength -->
126
+ <div class="mb-6">
127
+ <div class="flex justify-between text-gray-200 mb-2">
128
+ <span>Blur Strength</span>
129
+ <span id="blurValue">1.2</span>
130
+ </div>
131
+ <input type="range" min="0.1" max="3.0" step="0.1" value="1.2" class="parameter-slider" id="blurSlider">
132
+ </div>
133
+
134
+ <!-- Line Thickness -->
135
+ <div class="mb-6">
136
+ <div class="flex justify-between text-gray-200 mb-2">
137
+ <span>Line Thickness</span>
138
+ <span id="thicknessValue">2</span>
139
+ </div>
140
+ <input type="range" min="1" max="10" value="2" class="parameter-slider" id="thicknessSlider">
141
+ </div>
142
+
143
+ <!-- Toggles -->
144
+ <div class="grid grid-cols-2 gap-4">
145
+ <label class="flex items-center text-gray-200">
146
+ <input type="checkbox" class="mr-2">
147
+ <span>Hatching</span>
148
+ </label>
149
+ <label class="flex items-center text-gray-200">
150
+ <input type="checkbox">
151
+ <span class="ml-2">Invert</span>
152
+ </label>
153
+ </div>
154
+ </div>
155
+ </div>
156
+
157
+ <!-- Preview Area -->
158
+ <div class="glass-effect rounded-2xl p-8">
159
+ <h3 class="text-xl font-semibold text-white mb-4">Preview</h3>
160
+ <div class="bg-black/20 rounded-xl p-8 min-h-[400px] flex items-center justify-center" id="previewArea">
161
+ <div class="text-center text-gray-400">
162
+ <i data-feather="image" class="w-16 h-16 mx-auto mb-4"></i>
163
+ <p>Your sketch will appear here</p>
164
+ </div>
165
+ </div>
166
+
167
+ <!-- Action Buttons -->
168
+ <div class="mt-6 flex space-x-4">
169
+ <button class="flex-1 bg-green-500 hover:bg-green-600 text-white py-3 rounded-lg font-medium transition-colors flex items-center justify-center">
170
+ <i data-feather="play" class="w-4 h-4 mr-2"></i>
171
+ Generate Sketch
172
+ </button>
173
+ <button class="flex-1 bg-gray-500 hover:bg-gray-600 text-white py-3 rounded-lg font-medium transition-colors">
174
+ <i data-feather="download" class="w-4 h-4 mr-2"></i>
175
+ Download
176
+ </button>
177
+ </div>
178
+ </div>
179
+ </div>
180
+
181
+ <!-- Features Section -->
182
+ <div class="glass-effect rounded-2xl p-8 mb-12">
183
+ <h3 class="text-2xl font-bold text-white text-center mb-8">Powerful Sketch Features</h3>
184
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
185
+ <div class="text-center p-6">
186
+ <i data-feather="zap" class="w-12 h-12 text-blue-400 mx-auto mb-4"></i>
187
+ <h4 class="text-lg font-semibold text-white mb-2">Real-time Processing</h4>
188
+ <p class="text-gray-300">See your image transform instantly with live preview</p>
189
+ </div>
190
+ <div class="text-center p-6">
191
+ <i data-feather="sliders" class="w-12 h-12 text-green-400 mx-auto mb-4"></i>
192
+ <h4 class="text-lg font-semibold text-white mb-2">Advanced Controls</h4>
193
+ <p class="text-gray-300">Fine-tune every aspect of your sketch with precision</p>
194
+ </div>
195
+ <div class="text-center p-6">
196
+ <i data-feather="download-cloud" class="w-12 h-12 text-purple-400 mx-auto mb-4"></i>
197
+ <h4 class="text-lg font-semibold text-white mb-2">Multiple Export</h4>
198
+ <p class="text-gray-300">Save in various formats optimized for different uses</p>
199
+ </div>
200
+ </div>
201
+ </div>
202
+ </main>
203
+
204
+ <!-- Footer -->
205
+ <footer class="relative z-10 text-center py-6 text-gray-300">
206
+ <p>Made with <i data-feather="heart" class="w-4 h-4 inline text-red-400"></i> using AI magic</p>
207
+ </footer>
208
+
209
+ <script>
210
+ // Initialize Vanta.js background
211
+ VANTA.GLOBE({
212
+ el: "#vanta-bg",
213
+ mouseControls: true,
214
+ touchControls: true,
215
+ gyroControls: false,
216
+ minHeight: 200.00,
217
+ minWidth: 200.00,
218
+ scale: 1.00,
219
+ scaleMobile: 1.00,
220
+ color: 0x667eea,
221
+ backgroundColor: 0x0
222
+ });
223
+
224
+ // Initialize Feather Icons
225
+ feather.replace();
226
+
227
+ // Upload area functionality
228
+ const uploadArea = document.getElementById('uploadArea');
229
+ const fileInput = document.getElementById('fileInput');
230
+ const previewArea = document.getElementById('previewArea');
231
+
232
+ uploadArea.addEventListener('click', () => fileInput.click());
233
+
234
+ uploadArea.addEventListener('dragover', (e) => {
235
+ e.preventDefault();
236
+ uploadArea.classList.add('dragover');
237
+ });
238
+
239
+ uploadArea.addEventListener('dragleave', () => {
240
+ uploadArea.classList.remove('dragover');
241
+ });
242
+
243
+ uploadArea.addEventListener('drop', (e) => {
244
+ e.preventDefault();
245
+ uploadArea.classList.remove('dragover');
246
+ const files = e.dataTransfer.files;
247
+ if (files.length > 0) {
248
+ handleImageUpload(files[0]);
249
+ }
250
+ });
251
+
252
+ fileInput.addEventListener('change', (e) => {
253
+ if (e.target.files.length > 0) {
254
+ handleImageUpload(e.target.files[0]);
255
+ }
256
+ });
257
+
258
+ function handleImageUpload(file) {
259
+ if (!file.type.match('image.*')) {
260
+ alert('Please upload an image file');
261
+ return;
262
+ }
263
+
264
+ const reader = new FileReader();
265
+ reader.onload = (e) => {
266
+ previewArea.innerHTML = `
267
+ <img src="${e.target.result}" alt="Preview" class="max-w-full max-h-80 rounded-lg sketch-border">
268
+ `;
269
+ };
270
+ reader.readAsDataURL(file);
271
+ }
272
+
273
+ // Parameter sliders
274
+ const blurSlider = document.getElementById('blurSlider');
275
+ const blurValue = document.getElementById('blurValue');
276
+ const thicknessSlider = document.getElementById('thicknessSlider');
277
+ const thicknessValue = document.getElementById('thicknessValue');
278
+
279
+ blurSlider.addEventListener('input', (e) => {
280
+ blurValue.textContent = e.target.value;
281
+ });
282
+
283
+ thicknessSlider.addEventListener('input', (e) => {
284
+ thicknessValue.textContent = e.target.value;
285
+ });
286
+
287
+ // Add some interactive animations
288
+ document.addEventListener('DOMContentLoaded', () => {
289
+ const elements = document.querySelectorAll('.glass-effect');
290
+ elements.forEach((el, index) => {
291
+ el.style.opacity = '0';
292
+ el.style.transform = 'translateY(20px)';
293
+
294
+ setTimeout(() => {
295
+ el.style.transition = 'all 0.6s ease';
296
+ el.style.opacity = '1';
297
+ el.style.transform = 'translateY(0)';
298
+ }, index * 100);
299
+ });
300
+ });
301
+ </script>
302
+ </body>
303
  </html>