6ee5ali commited on
Commit
b5bd1c6
·
verified ·
1 Parent(s): 5336307

import cv2 import numpy as np def remove_sticker(image_path, mask_path, output_path): # قراءة الصورة والقناع (اللاصقة) img = cv2.imread(image_path) mask = cv2.imread(mask_path, 0) # قراءة كصورة رمادية # تطبيق خوارزمية الاستعادة result = cv2.inpaint(img, mask, inpaintRadius=3, flags=cv2.INPAINT_TELEA) # حفظ النتيجة cv2.imwrite(output_path, result) - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +555 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Facee1
3
- emoji: 🚀
4
- colorFrom: indigo
5
- colorTo: indigo
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: facee1
3
+ emoji: 🐳
4
+ colorFrom: purple
5
+ colorTo: gray
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,555 @@
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>Sticker Remover Tool</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ .dropzone {
11
+ border: 2px dashed #cbd5e0;
12
+ transition: all 0.3s ease;
13
+ }
14
+ .dropzone.active {
15
+ border-color: #4f46e5;
16
+ background-color: #f0f4ff;
17
+ }
18
+ .image-preview {
19
+ max-height: 400px;
20
+ object-fit: contain;
21
+ }
22
+ .progress-bar {
23
+ transition: width 0.3s ease;
24
+ }
25
+ canvas {
26
+ max-width: 100%;
27
+ height: auto;
28
+ }
29
+ </style>
30
+ </head>
31
+ <body class="bg-gray-50 min-h-screen">
32
+ <div class="container mx-auto px-4 py-8">
33
+ <header class="text-center mb-10">
34
+ <h1 class="text-4xl font-bold text-indigo-700 mb-2">Sticker Remover</h1>
35
+ <p class="text-gray-600 max-w-2xl mx-auto">Upload your image and mask to seamlessly remove unwanted stickers using advanced inpainting technology</p>
36
+ </header>
37
+
38
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
39
+ <!-- Upload Section -->
40
+ <div class="bg-white rounded-xl shadow-md p-6">
41
+ <h2 class="text-xl font-semibold mb-4 text-gray-800">Upload Files</h2>
42
+
43
+ <!-- Original Image Upload -->
44
+ <div class="mb-6">
45
+ <label class="block text-sm font-medium text-gray-700 mb-2">Original Image</label>
46
+ <div id="original-dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer">
47
+ <i class="fas fa-image text-4xl text-indigo-400 mb-3"></i>
48
+ <p class="text-gray-500 mb-2">Drag & drop your image here or click to browse</p>
49
+ <p class="text-xs text-gray-400">Supports JPG, PNG (Max 5MB)</p>
50
+ <input type="file" id="original-input" class="hidden" accept="image/*">
51
+ </div>
52
+ <div id="original-preview" class="mt-4 hidden">
53
+ <p class="text-sm text-gray-600 mb-1">Selected file:</p>
54
+ <div class="flex items-center justify-between bg-gray-50 rounded px-3 py-2">
55
+ <span id="original-filename" class="text-sm font-medium"></span>
56
+ <button id="original-clear" class="text-red-500 hover:text-red-700">
57
+ <i class="fas fa-times"></i>
58
+ </button>
59
+ </div>
60
+ </div>
61
+ </div>
62
+
63
+ <!-- Mask Image Upload -->
64
+ <div class="mb-6">
65
+ <label class="block text-sm font-medium text-gray-700 mb-2">Sticker Mask</label>
66
+ <div id="mask-dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer">
67
+ <i class="fas fa-mask text-4xl text-indigo-400 mb-3"></i>
68
+ <p class="text-gray-500 mb-2">Drag & drop your mask here or click to browse</p>
69
+ <p class="text-xs text-gray-400">Black & white image showing sticker area</p>
70
+ <input type="file" id="mask-input" class="hidden" accept="image/*">
71
+ </div>
72
+ <div id="mask-preview" class="mt-4 hidden">
73
+ <p class="text-sm text-gray-600 mb-1">Selected file:</p>
74
+ <div class="flex items-center justify-between bg-gray-50 rounded px-3 py-2">
75
+ <span id="mask-filename" class="text-sm font-medium"></span>
76
+ <button id="mask-clear" class="text-red-500 hover:text-red-700">
77
+ <i class="fas fa-times"></i>
78
+ </button>
79
+ </div>
80
+ </div>
81
+ </div>
82
+
83
+ <div class="flex justify-between items-center mt-6">
84
+ <div>
85
+ <label class="inline-flex items-center">
86
+ <input type="checkbox" id="demo-checkbox" class="rounded text-indigo-600">
87
+ <span class="ml-2 text-sm text-gray-600">Use demo images</span>
88
+ </label>
89
+ </div>
90
+ <button id="process-btn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-lg font-medium disabled:opacity-50 disabled:cursor-not-allowed" disabled>
91
+ Process Image
92
+ </button>
93
+ </div>
94
+ </div>
95
+
96
+ <!-- Results Section -->
97
+ <div class="bg-white rounded-xl shadow-md p-6">
98
+ <h2 class="text-xl font-semibold mb-4 text-gray-800">Results</h2>
99
+
100
+ <div class="flex justify-between mb-4">
101
+ <button id="original-tab" class="tab-btn active px-4 py-2 text-indigo-600 border-b-2 border-indigo-600 font-medium">Original</button>
102
+ <button id="mask-tab" class="tab-btn px-4 py-2 text-gray-500 font-medium">Mask</button>
103
+ <button id="result-tab" class="tab-btn px-4 py-2 text-gray-500 font-medium">Result</button>
104
+ </div>
105
+
106
+ <div class="relative">
107
+ <!-- Loading overlay -->
108
+ <div id="loading-overlay" class="absolute inset-0 bg-white bg-opacity-80 flex flex-col items-center justify-center hidden z-10 rounded-lg">
109
+ <div class="w-16 h-16 border-4 border-indigo-500 border-t-transparent rounded-full animate-spin mb-4"></div>
110
+ <p class="text-gray-700">Processing your image...</p>
111
+ <div class="w-full bg-gray-200 rounded-full h-2.5 mt-4 max-w-md">
112
+ <div id="progress-bar" class="progress-bar bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div>
113
+ </div>
114
+ </div>
115
+
116
+ <!-- Image display area -->
117
+ <div id="image-display" class="flex items-center justify-center bg-gray-100 rounded-lg p-4 min-h-64">
118
+ <div class="text-center text-gray-400">
119
+ <i class="fas fa-image fa-3x mb-3"></i>
120
+ <p>Upload images to see preview</p>
121
+ </div>
122
+ </div>
123
+ </div>
124
+
125
+ <div class="mt-6 flex justify-between">
126
+ <button id="download-btn" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg font-medium disabled:opacity-50 disabled:cursor-not-allowed" disabled>
127
+ <i class="fas fa-download mr-2"></i> Download
128
+ </button>
129
+ <div class="flex space-x-2">
130
+ <button id="reset-btn" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg font-medium">
131
+ <i class="fas fa-redo mr-2"></i> Reset
132
+ </button>
133
+ <button id="help-btn" class="bg-indigo-100 hover:bg-indigo-200 text-indigo-800 px-4 py-2 rounded-lg font-medium">
134
+ <i class="fas fa-question-circle mr-2"></i> Help
135
+ </button>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ </div>
140
+
141
+ <!-- How It Works Section -->
142
+ <div class="bg-white rounded-xl shadow-md p-6 mt-8">
143
+ <h2 class="text-xl font-semibold mb-4 text-gray-800">How It Works</h2>
144
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
145
+ <div class="bg-indigo-50 p-4 rounded-lg">
146
+ <div class="bg-indigo-100 w-12 h-12 rounded-full flex items-center justify-center mb-3">
147
+ <i class="fas fa-upload text-indigo-600"></i>
148
+ </div>
149
+ <h3 class="font-medium mb-2">1. Upload Images</h3>
150
+ <p class="text-sm text-gray-600">Upload your original image and a black & white mask where white areas represent the sticker to be removed.</p>
151
+ </div>
152
+ <div class="bg-indigo-50 p-4 rounded-lg">
153
+ <div class="bg-indigo-100 w-12 h-12 rounded-full flex items-center justify-center mb-3">
154
+ <i class="fas fa-cogs text-indigo-600"></i>
155
+ </div>
156
+ <h3 class="font-medium mb-2">2. Process Image</h3>
157
+ <p class="text-sm text-gray-600">Our algorithm analyzes the surrounding pixels to intelligently fill in the masked area.</p>
158
+ </div>
159
+ <div class="bg-indigo-50 p-4 rounded-lg">
160
+ <div class="bg-indigo-100 w-12 h-12 rounded-full flex items-center justify-center mb-3">
161
+ <i class="fas fa-download text-indigo-600"></i>
162
+ </div>
163
+ <h3 class="font-medium mb-2">3. Download Result</h3>
164
+ <p class="text-sm text-gray-600">Get your clean image without the sticker and download it in high quality.</p>
165
+ </div>
166
+ </div>
167
+ </div>
168
+
169
+ <!-- Help Modal -->
170
+ <div id="help-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
171
+ <div class="bg-white rounded-xl max-w-2xl w-full max-h-[90vh] overflow-y-auto">
172
+ <div class="p-6">
173
+ <div class="flex justify-between items-center mb-4">
174
+ <h3 class="text-xl font-bold">Help & Instructions</h3>
175
+ <button id="close-help" class="text-gray-500 hover:text-gray-700">
176
+ <i class="fas fa-times"></i>
177
+ </button>
178
+ </div>
179
+
180
+ <div class="space-y-4">
181
+ <div>
182
+ <h4 class="font-medium text-indigo-600 mb-2">Creating a Mask</h4>
183
+ <p class="text-gray-600 text-sm">To remove a sticker, you need to provide a mask image where:</p>
184
+ <ul class="list-disc pl-5 mt-2 text-sm text-gray-600 space-y-1">
185
+ <li>White areas represent the sticker to be removed</li>
186
+ <li>Black areas represent the parts to keep</li>
187
+ <li>Use any image editor to create this mask</li>
188
+ </ul>
189
+ </div>
190
+
191
+ <div>
192
+ <h4 class="font-medium text-indigo-600 mb-2">Best Practices</h4>
193
+ <ul class="list-disc pl-5 text-sm text-gray-600 space-y-1">
194
+ <li>For best results, the mask should exactly cover the sticker area</li>
195
+ <li>Make sure the mask and original image have the same dimensions</li>
196
+ <li>Complex backgrounds may require more precise masks</li>
197
+ </ul>
198
+ </div>
199
+
200
+ <div>
201
+ <h4 class="font-medium text-indigo-600 mb-2">Troubleshooting</h4>
202
+ <ul class="list-disc pl-5 text-sm text-gray-600 space-y-1">
203
+ <li>If the result looks distorted, try making your mask slightly larger</li>
204
+ <li>For large stickers, processing may take longer</li>
205
+ <li>Refresh the page if the tool stops responding</li>
206
+ </ul>
207
+ </div>
208
+ </div>
209
+
210
+ <div class="mt-6 pt-4 border-t border-gray-200">
211
+ <h4 class="font-medium text-indigo-600 mb-2">Example</h4>
212
+ <div class="grid grid-cols-2 gap-4">
213
+ <div>
214
+ <p class="text-sm text-gray-600 mb-1">Original Image</p>
215
+ <img src="https://via.placeholder.com/300x200?text=Photo+with+sticker" alt="Example original" class="rounded border border-gray-200">
216
+ </div>
217
+ <div>
218
+ <p class="text-sm text-gray-600 mb-1">Mask Image</p>
219
+ <img src="https://via.placeholder.com/300x200/000000/FFFFFF?text=Black+%26+white+mask" alt="Example mask" class="rounded border border-gray-200">
220
+ </div>
221
+ </div>
222
+ </div>
223
+ </div>
224
+ </div>
225
+ </div>
226
+ </div>
227
+
228
+ <script>
229
+ // DOM Elements
230
+ const originalDropzone = document.getElementById('original-dropzone');
231
+ const originalInput = document.getElementById('original-input');
232
+ const originalPreview = document.getElementById('original-preview');
233
+ const originalFilename = document.getElementById('original-filename');
234
+ const originalClear = document.getElementById('original-clear');
235
+
236
+ const maskDropzone = document.getElementById('mask-dropzone');
237
+ const maskInput = document.getElementById('mask-input');
238
+ const maskPreview = document.getElementById('mask-preview');
239
+ const maskFilename = document.getElementById('mask-filename');
240
+ const maskClear = document.getElementById('mask-clear');
241
+
242
+ const processBtn = document.getElementById('process-btn');
243
+ const downloadBtn = document.getElementById('download-btn');
244
+ const resetBtn = document.getElementById('reset-btn');
245
+ const helpBtn = document.getElementById('help-btn');
246
+ const demoCheckbox = document.getElementById('demo-checkbox');
247
+
248
+ const originalTab = document.getElementById('original-tab');
249
+ const maskTab = document.getElementById('mask-tab');
250
+ const resultTab = document.getElementById('result-tab');
251
+
252
+ const imageDisplay = document.getElementById('image-display');
253
+ const loadingOverlay = document.getElementById('loading-overlay');
254
+ const progressBar = document.getElementById('progress-bar');
255
+
256
+ const helpModal = document.getElementById('help-modal');
257
+ const closeHelp = document.getElementById('close-help');
258
+
259
+ // State
260
+ let originalImage = null;
261
+ let maskImage = null;
262
+ let resultImage = null;
263
+ let currentTab = 'original';
264
+
265
+ // Event Listeners
266
+ originalDropzone.addEventListener('click', () => originalInput.click());
267
+ originalDropzone.addEventListener('dragover', (e) => {
268
+ e.preventDefault();
269
+ originalDropzone.classList.add('active');
270
+ });
271
+ originalDropzone.addEventListener('dragleave', () => {
272
+ originalDropzone.classList.remove('active');
273
+ });
274
+ originalDropzone.addEventListener('drop', (e) => {
275
+ e.preventDefault();
276
+ originalDropzone.classList.remove('active');
277
+ if (e.dataTransfer.files.length) {
278
+ originalInput.files = e.dataTransfer.files;
279
+ handleOriginalUpload();
280
+ }
281
+ });
282
+
283
+ originalInput.addEventListener('change', handleOriginalUpload);
284
+ originalClear.addEventListener('click', clearOriginal);
285
+
286
+ maskDropzone.addEventListener('click', () => maskInput.click());
287
+ maskDropzone.addEventListener('dragover', (e) => {
288
+ e.preventDefault();
289
+ maskDropzone.classList.add('active');
290
+ });
291
+ maskDropzone.addEventListener('dragleave', () => {
292
+ maskDropzone.classList.remove('active');
293
+ });
294
+ maskDropzone.addEventListener('drop', (e) => {
295
+ e.preventDefault();
296
+ maskDropzone.classList.remove('active');
297
+ if (e.dataTransfer.files.length) {
298
+ maskInput.files = e.dataTransfer.files;
299
+ handleMaskUpload();
300
+ }
301
+ });
302
+
303
+ maskInput.addEventListener('change', handleMaskUpload);
304
+ maskClear.addEventListener('click', clearMask);
305
+
306
+ processBtn.addEventListener('click', processImage);
307
+ downloadBtn.addEventListener('click', downloadResult);
308
+ resetBtn.addEventListener('click', resetAll);
309
+ helpBtn.addEventListener('click', () => helpModal.classList.remove('hidden'));
310
+ closeHelp.addEventListener('click', () => helpModal.classList.add('hidden'));
311
+
312
+ demoCheckbox.addEventListener('change', toggleDemoImages);
313
+
314
+ originalTab.addEventListener('click', () => switchTab('original'));
315
+ maskTab.addEventListener('click', () => switchTab('mask'));
316
+ resultTab.addEventListener('click', () => switchTab('result'));
317
+
318
+ // Functions
319
+ function handleOriginalUpload() {
320
+ const file = originalInput.files[0];
321
+ if (!file) return;
322
+
323
+ if (!file.type.match('image.*')) {
324
+ alert('Please select an image file');
325
+ return;
326
+ }
327
+
328
+ originalFilename.textContent = file.name;
329
+ originalPreview.classList.remove('hidden');
330
+
331
+ const reader = new FileReader();
332
+ reader.onload = (e) => {
333
+ originalImage = e.target.result;
334
+ displayImage(originalImage, 'original');
335
+ checkProcessButton();
336
+ };
337
+ reader.readAsDataURL(file);
338
+ }
339
+
340
+ function handleMaskUpload() {
341
+ const file = maskInput.files[0];
342
+ if (!file) return;
343
+
344
+ if (!file.type.match('image.*')) {
345
+ alert('Please select an image file');
346
+ return;
347
+ }
348
+
349
+ maskFilename.textContent = file.name;
350
+ maskPreview.classList.remove('hidden');
351
+
352
+ const reader = new FileReader();
353
+ reader.onload = (e) => {
354
+ maskImage = e.target.result;
355
+ displayImage(maskImage, 'mask');
356
+ checkProcessButton();
357
+ };
358
+ reader.readAsDataURL(file);
359
+ }
360
+
361
+ function clearOriginal() {
362
+ originalInput.value = '';
363
+ originalPreview.classList.add('hidden');
364
+ originalImage = null;
365
+ checkProcessButton();
366
+ if (currentTab === 'original') {
367
+ imageDisplay.innerHTML = `
368
+ <div class="text-center text-gray-400">
369
+ <i class="fas fa-image fa-3x mb-3"></i>
370
+ <p>Upload images to see preview</p>
371
+ </div>
372
+ `;
373
+ }
374
+ }
375
+
376
+ function clearMask() {
377
+ maskInput.value = '';
378
+ maskPreview.classList.add('hidden');
379
+ maskImage = null;
380
+ checkProcessButton();
381
+ if (currentTab === 'mask') {
382
+ imageDisplay.innerHTML = `
383
+ <div class="text-center text-gray-400">
384
+ <i class="fas fa-image fa-3x mb-3"></i>
385
+ <p>Upload images to see preview</p>
386
+ </div>
387
+ `;
388
+ }
389
+ }
390
+
391
+ function checkProcessButton() {
392
+ processBtn.disabled = !(originalImage && maskImage);
393
+ }
394
+
395
+ function displayImage(src, type) {
396
+ if (currentTab === type) {
397
+ const img = document.createElement('img');
398
+ img.src = src;
399
+ img.alt = type;
400
+ img.className = 'image-preview max-w-full h-auto rounded';
401
+ imageDisplay.innerHTML = '';
402
+ imageDisplay.appendChild(img);
403
+ }
404
+ }
405
+
406
+ function switchTab(tab) {
407
+ currentTab = tab;
408
+
409
+ // Update tab buttons
410
+ originalTab.classList.remove('text-indigo-600', 'border-b-2', 'border-indigo-600');
411
+ originalTab.classList.add('text-gray-500');
412
+ maskTab.classList.remove('text-indigo-600', 'border-b-2', 'border-indigo-600');
413
+ maskTab.classList.add('text-gray-500');
414
+ resultTab.classList.remove('text-indigo-600', 'border-b-2', 'border-indigo-600');
415
+ resultTab.classList.add('text-gray-500');
416
+
417
+ if (tab === 'original') {
418
+ originalTab.classList.add('text-indigo-600', 'border-b-2', 'border-indigo-600');
419
+ originalTab.classList.remove('text-gray-500');
420
+ if (originalImage) {
421
+ displayImage(originalImage, 'original');
422
+ } else {
423
+ imageDisplay.innerHTML = `
424
+ <div class="text-center text-gray-400">
425
+ <i class="fas fa-image fa-3x mb-3"></i>
426
+ <p>Upload original image to see preview</p>
427
+ </div>
428
+ `;
429
+ }
430
+ } else if (tab === 'mask') {
431
+ maskTab.classList.add('text-indigo-600', 'border-b-2', 'border-indigo-600');
432
+ maskTab.classList.remove('text-gray-500');
433
+ if (maskImage) {
434
+ displayImage(maskImage, 'mask');
435
+ } else {
436
+ imageDisplay.innerHTML = `
437
+ <div class="text-center text-gray-400">
438
+ <i class="fas fa-image fa-3x mb-3"></i>
439
+ <p>Upload mask image to see preview</p>
440
+ </div>
441
+ `;
442
+ }
443
+ } else if (tab === 'result') {
444
+ resultTab.classList.add('text-indigo-600', 'border-b-2', 'border-indigo-600');
445
+ resultTab.classList.remove('text-gray-500');
446
+ if (resultImage) {
447
+ displayImage(resultImage, 'result');
448
+ } else {
449
+ imageDisplay.innerHTML = `
450
+ <div class="text-center text-gray-400">
451
+ <i class="fas fa-image fa-3x mb-3"></i>
452
+ <p>Process the image to see results</p>
453
+ </div>
454
+ `;
455
+ }
456
+ }
457
+ }
458
+
459
+ function processImage() {
460
+ if (!originalImage || !maskImage) return;
461
+
462
+ loadingOverlay.classList.remove('hidden');
463
+ processBtn.disabled = true;
464
+
465
+ // Simulate processing with progress
466
+ let progress = 0;
467
+ const interval = setInterval(() => {
468
+ progress += 5;
469
+ progressBar.style.width = `${progress}%`;
470
+
471
+ if (progress >= 100) {
472
+ clearInterval(interval);
473
+ setTimeout(() => {
474
+ // In a real app, this would use OpenCV.js to process the image
475
+ // For this demo, we'll just simulate the result
476
+ loadingOverlay.classList.add('hidden');
477
+ processBtn.disabled = false;
478
+
479
+ // Create a canvas to "simulate" processing
480
+ const canvas = document.createElement('canvas');
481
+ const ctx = canvas.getContext('2d');
482
+
483
+ // Load original image
484
+ const img = new Image();
485
+ img.onload = function() {
486
+ canvas.width = img.width;
487
+ canvas.height = img.height;
488
+ ctx.drawImage(img, 0, 0);
489
+
490
+ // Simulate inpainting by drawing a semi-transparent rectangle
491
+ // In a real app, this would be replaced with OpenCV.inpaint()
492
+ ctx.globalCompositeOperation = 'destination-out';
493
+ ctx.globalAlpha = 0.5;
494
+ ctx.fillRect(50, 50, 100, 100);
495
+ ctx.globalAlpha = 1.0;
496
+ ctx.globalCompositeOperation = 'source-over';
497
+
498
+ resultImage = canvas.toDataURL('image/jpeg');
499
+ displayImage(resultImage, 'result');
500
+ downloadBtn.disabled = false;
501
+ switchTab('result');
502
+ };
503
+ img.src = originalImage;
504
+ }, 500);
505
+ }
506
+ }, 100);
507
+ }
508
+
509
+ function downloadResult() {
510
+ if (!resultImage) return;
511
+
512
+ const link = document.createElement('a');
513
+ link.href = resultImage;
514
+ link.download = 'sticker-removed.jpg';
515
+ document.body.appendChild(link);
516
+ link.click();
517
+ document.body.removeChild(link);
518
+ }
519
+
520
+ function resetAll() {
521
+ clearOriginal();
522
+ clearMask();
523
+ resultImage = null;
524
+ downloadBtn.disabled = true;
525
+ demoCheckbox.checked = false;
526
+ switchTab('original');
527
+ }
528
+
529
+ function toggleDemoImages() {
530
+ if (demoCheckbox.checked) {
531
+ // Use demo images
532
+ originalImage = 'https://via.placeholder.com/600x400?text=Photo+with+sticker';
533
+ maskImage = 'https://via.placeholder.com/600x400/000000/FFFFFF?text=Black+%26+white+mask';
534
+
535
+ originalFilename.textContent = 'demo-original.jpg';
536
+ originalPreview.classList.remove('hidden');
537
+
538
+ maskFilename.textContent = 'demo-mask.png';
539
+ maskPreview.classList.remove('hidden');
540
+
541
+ displayImage(originalImage, 'original');
542
+ checkProcessButton();
543
+ } else {
544
+ // Clear demo images
545
+ if (originalFilename.textContent === 'demo-original.jpg') {
546
+ clearOriginal();
547
+ }
548
+ if (maskFilename.textContent === 'demo-mask.png') {
549
+ clearMask();
550
+ }
551
+ }
552
+ }
553
+ </script>
554
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=6ee5ali/facee1" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
555
+ </html>