facee1 / index.html
6ee5ali's picture
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
b5bd1c6 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sticker Remover Tool</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.dropzone {
border: 2px dashed #cbd5e0;
transition: all 0.3s ease;
}
.dropzone.active {
border-color: #4f46e5;
background-color: #f0f4ff;
}
.image-preview {
max-height: 400px;
object-fit: contain;
}
.progress-bar {
transition: width 0.3s ease;
}
canvas {
max-width: 100%;
height: auto;
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8">
<header class="text-center mb-10">
<h1 class="text-4xl font-bold text-indigo-700 mb-2">Sticker Remover</h1>
<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>
</header>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<!-- Upload Section -->
<div class="bg-white rounded-xl shadow-md p-6">
<h2 class="text-xl font-semibold mb-4 text-gray-800">Upload Files</h2>
<!-- Original Image Upload -->
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">Original Image</label>
<div id="original-dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer">
<i class="fas fa-image text-4xl text-indigo-400 mb-3"></i>
<p class="text-gray-500 mb-2">Drag & drop your image here or click to browse</p>
<p class="text-xs text-gray-400">Supports JPG, PNG (Max 5MB)</p>
<input type="file" id="original-input" class="hidden" accept="image/*">
</div>
<div id="original-preview" class="mt-4 hidden">
<p class="text-sm text-gray-600 mb-1">Selected file:</p>
<div class="flex items-center justify-between bg-gray-50 rounded px-3 py-2">
<span id="original-filename" class="text-sm font-medium"></span>
<button id="original-clear" class="text-red-500 hover:text-red-700">
<i class="fas fa-times"></i>
</button>
</div>
</div>
</div>
<!-- Mask Image Upload -->
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">Sticker Mask</label>
<div id="mask-dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer">
<i class="fas fa-mask text-4xl text-indigo-400 mb-3"></i>
<p class="text-gray-500 mb-2">Drag & drop your mask here or click to browse</p>
<p class="text-xs text-gray-400">Black & white image showing sticker area</p>
<input type="file" id="mask-input" class="hidden" accept="image/*">
</div>
<div id="mask-preview" class="mt-4 hidden">
<p class="text-sm text-gray-600 mb-1">Selected file:</p>
<div class="flex items-center justify-between bg-gray-50 rounded px-3 py-2">
<span id="mask-filename" class="text-sm font-medium"></span>
<button id="mask-clear" class="text-red-500 hover:text-red-700">
<i class="fas fa-times"></i>
</button>
</div>
</div>
</div>
<div class="flex justify-between items-center mt-6">
<div>
<label class="inline-flex items-center">
<input type="checkbox" id="demo-checkbox" class="rounded text-indigo-600">
<span class="ml-2 text-sm text-gray-600">Use demo images</span>
</label>
</div>
<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>
Process Image
</button>
</div>
</div>
<!-- Results Section -->
<div class="bg-white rounded-xl shadow-md p-6">
<h2 class="text-xl font-semibold mb-4 text-gray-800">Results</h2>
<div class="flex justify-between mb-4">
<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>
<button id="mask-tab" class="tab-btn px-4 py-2 text-gray-500 font-medium">Mask</button>
<button id="result-tab" class="tab-btn px-4 py-2 text-gray-500 font-medium">Result</button>
</div>
<div class="relative">
<!-- Loading overlay -->
<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">
<div class="w-16 h-16 border-4 border-indigo-500 border-t-transparent rounded-full animate-spin mb-4"></div>
<p class="text-gray-700">Processing your image...</p>
<div class="w-full bg-gray-200 rounded-full h-2.5 mt-4 max-w-md">
<div id="progress-bar" class="progress-bar bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div>
</div>
</div>
<!-- Image display area -->
<div id="image-display" class="flex items-center justify-center bg-gray-100 rounded-lg p-4 min-h-64">
<div class="text-center text-gray-400">
<i class="fas fa-image fa-3x mb-3"></i>
<p>Upload images to see preview</p>
</div>
</div>
</div>
<div class="mt-6 flex justify-between">
<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>
<i class="fas fa-download mr-2"></i> Download
</button>
<div class="flex space-x-2">
<button id="reset-btn" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg font-medium">
<i class="fas fa-redo mr-2"></i> Reset
</button>
<button id="help-btn" class="bg-indigo-100 hover:bg-indigo-200 text-indigo-800 px-4 py-2 rounded-lg font-medium">
<i class="fas fa-question-circle mr-2"></i> Help
</button>
</div>
</div>
</div>
</div>
<!-- How It Works Section -->
<div class="bg-white rounded-xl shadow-md p-6 mt-8">
<h2 class="text-xl font-semibold mb-4 text-gray-800">How It Works</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="bg-indigo-50 p-4 rounded-lg">
<div class="bg-indigo-100 w-12 h-12 rounded-full flex items-center justify-center mb-3">
<i class="fas fa-upload text-indigo-600"></i>
</div>
<h3 class="font-medium mb-2">1. Upload Images</h3>
<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>
</div>
<div class="bg-indigo-50 p-4 rounded-lg">
<div class="bg-indigo-100 w-12 h-12 rounded-full flex items-center justify-center mb-3">
<i class="fas fa-cogs text-indigo-600"></i>
</div>
<h3 class="font-medium mb-2">2. Process Image</h3>
<p class="text-sm text-gray-600">Our algorithm analyzes the surrounding pixels to intelligently fill in the masked area.</p>
</div>
<div class="bg-indigo-50 p-4 rounded-lg">
<div class="bg-indigo-100 w-12 h-12 rounded-full flex items-center justify-center mb-3">
<i class="fas fa-download text-indigo-600"></i>
</div>
<h3 class="font-medium mb-2">3. Download Result</h3>
<p class="text-sm text-gray-600">Get your clean image without the sticker and download it in high quality.</p>
</div>
</div>
</div>
<!-- Help Modal -->
<div id="help-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-xl max-w-2xl w-full max-h-[90vh] overflow-y-auto">
<div class="p-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-bold">Help & Instructions</h3>
<button id="close-help" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="space-y-4">
<div>
<h4 class="font-medium text-indigo-600 mb-2">Creating a Mask</h4>
<p class="text-gray-600 text-sm">To remove a sticker, you need to provide a mask image where:</p>
<ul class="list-disc pl-5 mt-2 text-sm text-gray-600 space-y-1">
<li>White areas represent the sticker to be removed</li>
<li>Black areas represent the parts to keep</li>
<li>Use any image editor to create this mask</li>
</ul>
</div>
<div>
<h4 class="font-medium text-indigo-600 mb-2">Best Practices</h4>
<ul class="list-disc pl-5 text-sm text-gray-600 space-y-1">
<li>For best results, the mask should exactly cover the sticker area</li>
<li>Make sure the mask and original image have the same dimensions</li>
<li>Complex backgrounds may require more precise masks</li>
</ul>
</div>
<div>
<h4 class="font-medium text-indigo-600 mb-2">Troubleshooting</h4>
<ul class="list-disc pl-5 text-sm text-gray-600 space-y-1">
<li>If the result looks distorted, try making your mask slightly larger</li>
<li>For large stickers, processing may take longer</li>
<li>Refresh the page if the tool stops responding</li>
</ul>
</div>
</div>
<div class="mt-6 pt-4 border-t border-gray-200">
<h4 class="font-medium text-indigo-600 mb-2">Example</h4>
<div class="grid grid-cols-2 gap-4">
<div>
<p class="text-sm text-gray-600 mb-1">Original Image</p>
<img src="https://via.placeholder.com/300x200?text=Photo+with+sticker" alt="Example original" class="rounded border border-gray-200">
</div>
<div>
<p class="text-sm text-gray-600 mb-1">Mask Image</p>
<img src="https://via.placeholder.com/300x200/000000/FFFFFF?text=Black+%26+white+mask" alt="Example mask" class="rounded border border-gray-200">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// DOM Elements
const originalDropzone = document.getElementById('original-dropzone');
const originalInput = document.getElementById('original-input');
const originalPreview = document.getElementById('original-preview');
const originalFilename = document.getElementById('original-filename');
const originalClear = document.getElementById('original-clear');
const maskDropzone = document.getElementById('mask-dropzone');
const maskInput = document.getElementById('mask-input');
const maskPreview = document.getElementById('mask-preview');
const maskFilename = document.getElementById('mask-filename');
const maskClear = document.getElementById('mask-clear');
const processBtn = document.getElementById('process-btn');
const downloadBtn = document.getElementById('download-btn');
const resetBtn = document.getElementById('reset-btn');
const helpBtn = document.getElementById('help-btn');
const demoCheckbox = document.getElementById('demo-checkbox');
const originalTab = document.getElementById('original-tab');
const maskTab = document.getElementById('mask-tab');
const resultTab = document.getElementById('result-tab');
const imageDisplay = document.getElementById('image-display');
const loadingOverlay = document.getElementById('loading-overlay');
const progressBar = document.getElementById('progress-bar');
const helpModal = document.getElementById('help-modal');
const closeHelp = document.getElementById('close-help');
// State
let originalImage = null;
let maskImage = null;
let resultImage = null;
let currentTab = 'original';
// Event Listeners
originalDropzone.addEventListener('click', () => originalInput.click());
originalDropzone.addEventListener('dragover', (e) => {
e.preventDefault();
originalDropzone.classList.add('active');
});
originalDropzone.addEventListener('dragleave', () => {
originalDropzone.classList.remove('active');
});
originalDropzone.addEventListener('drop', (e) => {
e.preventDefault();
originalDropzone.classList.remove('active');
if (e.dataTransfer.files.length) {
originalInput.files = e.dataTransfer.files;
handleOriginalUpload();
}
});
originalInput.addEventListener('change', handleOriginalUpload);
originalClear.addEventListener('click', clearOriginal);
maskDropzone.addEventListener('click', () => maskInput.click());
maskDropzone.addEventListener('dragover', (e) => {
e.preventDefault();
maskDropzone.classList.add('active');
});
maskDropzone.addEventListener('dragleave', () => {
maskDropzone.classList.remove('active');
});
maskDropzone.addEventListener('drop', (e) => {
e.preventDefault();
maskDropzone.classList.remove('active');
if (e.dataTransfer.files.length) {
maskInput.files = e.dataTransfer.files;
handleMaskUpload();
}
});
maskInput.addEventListener('change', handleMaskUpload);
maskClear.addEventListener('click', clearMask);
processBtn.addEventListener('click', processImage);
downloadBtn.addEventListener('click', downloadResult);
resetBtn.addEventListener('click', resetAll);
helpBtn.addEventListener('click', () => helpModal.classList.remove('hidden'));
closeHelp.addEventListener('click', () => helpModal.classList.add('hidden'));
demoCheckbox.addEventListener('change', toggleDemoImages);
originalTab.addEventListener('click', () => switchTab('original'));
maskTab.addEventListener('click', () => switchTab('mask'));
resultTab.addEventListener('click', () => switchTab('result'));
// Functions
function handleOriginalUpload() {
const file = originalInput.files[0];
if (!file) return;
if (!file.type.match('image.*')) {
alert('Please select an image file');
return;
}
originalFilename.textContent = file.name;
originalPreview.classList.remove('hidden');
const reader = new FileReader();
reader.onload = (e) => {
originalImage = e.target.result;
displayImage(originalImage, 'original');
checkProcessButton();
};
reader.readAsDataURL(file);
}
function handleMaskUpload() {
const file = maskInput.files[0];
if (!file) return;
if (!file.type.match('image.*')) {
alert('Please select an image file');
return;
}
maskFilename.textContent = file.name;
maskPreview.classList.remove('hidden');
const reader = new FileReader();
reader.onload = (e) => {
maskImage = e.target.result;
displayImage(maskImage, 'mask');
checkProcessButton();
};
reader.readAsDataURL(file);
}
function clearOriginal() {
originalInput.value = '';
originalPreview.classList.add('hidden');
originalImage = null;
checkProcessButton();
if (currentTab === 'original') {
imageDisplay.innerHTML = `
<div class="text-center text-gray-400">
<i class="fas fa-image fa-3x mb-3"></i>
<p>Upload images to see preview</p>
</div>
`;
}
}
function clearMask() {
maskInput.value = '';
maskPreview.classList.add('hidden');
maskImage = null;
checkProcessButton();
if (currentTab === 'mask') {
imageDisplay.innerHTML = `
<div class="text-center text-gray-400">
<i class="fas fa-image fa-3x mb-3"></i>
<p>Upload images to see preview</p>
</div>
`;
}
}
function checkProcessButton() {
processBtn.disabled = !(originalImage && maskImage);
}
function displayImage(src, type) {
if (currentTab === type) {
const img = document.createElement('img');
img.src = src;
img.alt = type;
img.className = 'image-preview max-w-full h-auto rounded';
imageDisplay.innerHTML = '';
imageDisplay.appendChild(img);
}
}
function switchTab(tab) {
currentTab = tab;
// Update tab buttons
originalTab.classList.remove('text-indigo-600', 'border-b-2', 'border-indigo-600');
originalTab.classList.add('text-gray-500');
maskTab.classList.remove('text-indigo-600', 'border-b-2', 'border-indigo-600');
maskTab.classList.add('text-gray-500');
resultTab.classList.remove('text-indigo-600', 'border-b-2', 'border-indigo-600');
resultTab.classList.add('text-gray-500');
if (tab === 'original') {
originalTab.classList.add('text-indigo-600', 'border-b-2', 'border-indigo-600');
originalTab.classList.remove('text-gray-500');
if (originalImage) {
displayImage(originalImage, 'original');
} else {
imageDisplay.innerHTML = `
<div class="text-center text-gray-400">
<i class="fas fa-image fa-3x mb-3"></i>
<p>Upload original image to see preview</p>
</div>
`;
}
} else if (tab === 'mask') {
maskTab.classList.add('text-indigo-600', 'border-b-2', 'border-indigo-600');
maskTab.classList.remove('text-gray-500');
if (maskImage) {
displayImage(maskImage, 'mask');
} else {
imageDisplay.innerHTML = `
<div class="text-center text-gray-400">
<i class="fas fa-image fa-3x mb-3"></i>
<p>Upload mask image to see preview</p>
</div>
`;
}
} else if (tab === 'result') {
resultTab.classList.add('text-indigo-600', 'border-b-2', 'border-indigo-600');
resultTab.classList.remove('text-gray-500');
if (resultImage) {
displayImage(resultImage, 'result');
} else {
imageDisplay.innerHTML = `
<div class="text-center text-gray-400">
<i class="fas fa-image fa-3x mb-3"></i>
<p>Process the image to see results</p>
</div>
`;
}
}
}
function processImage() {
if (!originalImage || !maskImage) return;
loadingOverlay.classList.remove('hidden');
processBtn.disabled = true;
// Simulate processing with progress
let progress = 0;
const interval = setInterval(() => {
progress += 5;
progressBar.style.width = `${progress}%`;
if (progress >= 100) {
clearInterval(interval);
setTimeout(() => {
// In a real app, this would use OpenCV.js to process the image
// For this demo, we'll just simulate the result
loadingOverlay.classList.add('hidden');
processBtn.disabled = false;
// Create a canvas to "simulate" processing
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Load original image
const img = new Image();
img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
// Simulate inpainting by drawing a semi-transparent rectangle
// In a real app, this would be replaced with OpenCV.inpaint()
ctx.globalCompositeOperation = 'destination-out';
ctx.globalAlpha = 0.5;
ctx.fillRect(50, 50, 100, 100);
ctx.globalAlpha = 1.0;
ctx.globalCompositeOperation = 'source-over';
resultImage = canvas.toDataURL('image/jpeg');
displayImage(resultImage, 'result');
downloadBtn.disabled = false;
switchTab('result');
};
img.src = originalImage;
}, 500);
}
}, 100);
}
function downloadResult() {
if (!resultImage) return;
const link = document.createElement('a');
link.href = resultImage;
link.download = 'sticker-removed.jpg';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
function resetAll() {
clearOriginal();
clearMask();
resultImage = null;
downloadBtn.disabled = true;
demoCheckbox.checked = false;
switchTab('original');
}
function toggleDemoImages() {
if (demoCheckbox.checked) {
// Use demo images
originalImage = 'https://via.placeholder.com/600x400?text=Photo+with+sticker';
maskImage = 'https://via.placeholder.com/600x400/000000/FFFFFF?text=Black+%26+white+mask';
originalFilename.textContent = 'demo-original.jpg';
originalPreview.classList.remove('hidden');
maskFilename.textContent = 'demo-mask.png';
maskPreview.classList.remove('hidden');
displayImage(originalImage, 'original');
checkProcessButton();
} else {
// Clear demo images
if (originalFilename.textContent === 'demo-original.jpg') {
clearOriginal();
}
if (maskFilename.textContent === 'demo-mask.png') {
clearMask();
}
}
}
</script>
<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>
</html>