Waikul commited on
Commit
9eb7512
·
verified ·
1 Parent(s): a5fc99d

Delete watermark-remover-free

Browse files
watermark-remover-free/.DS_Store DELETED
Binary file (6.15 kB)
 
watermark-remover-free/Dockerfile DELETED
@@ -1,14 +0,0 @@
1
- FROM python:3.11-slim
2
-
3
- WORKDIR /app
4
- COPY requirements.txt ./
5
- RUN pip install --no-cache-dir -r requirements.txt
6
-
7
- COPY server.py ./
8
- COPY templates ./templates
9
- COPY static ./static
10
-
11
- ENV PORT=7860
12
- EXPOSE 7860
13
-
14
- CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "7860"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
watermark-remover-free/README.md DELETED
@@ -1,30 +0,0 @@
1
- # Watermark Remover (Free Deploy)
2
-
3
- This is a free, self-contained web + API for watermark removal using OpenCV inpainting.
4
- You can deploy **for free** on Hugging Face Spaces (Docker) or run locally.
5
-
6
- ## Quick Deploy: Hugging Face Spaces (Docker)
7
- 1. Create a new Space -> **Docker**
8
- 2. Upload all files from this zip (`server.py`, `requirements.txt`, `Dockerfile`, `templates/`, `static/`)
9
- 3. Wait for the build to finish. The app will be available at `https://<user>-<space>.hf.space`
10
- 4. API endpoint: `POST /api/remove-watermark` (multipart/form-data)
11
-
12
- ### API (form-data fields)
13
- - `image`: file (required)
14
- - `mask`: file (optional; white=remove, black=keep)
15
- - `engine`: `opencv` (default) or `lama` (requires LaMa server URL)
16
- - `method`: `telea` (default) or `ns` (OpenCV only)
17
- - `radius`: int (OpenCV only; default 3)
18
- - `auto_mask`: 1 or 0 (default 1)
19
-
20
- > Note: LaMa backend is optional and requires a separate running service. For free CPU Spaces, use `opencv`.
21
-
22
- ## Local Run
23
- ```bash
24
- pip install -r requirements.txt
25
- uvicorn server:app --port 7860
26
- # open http://localhost:7860
27
- ```
28
-
29
- ## Legal
30
- Use only on content you have rights to edit.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
watermark-remover-free/requirements.txt DELETED
@@ -1,8 +0,0 @@
1
- fastapi==0.112.2
2
- uvicorn[standard]==0.30.6
3
- python-multipart==0.0.9
4
- Jinja2==3.1.4
5
- opencv-python==4.10.0.84
6
- numpy==1.26.4
7
- Pillow==10.4.0
8
- requests==2.32.3
 
 
 
 
 
 
 
 
 
watermark-remover-free/server.py DELETED
@@ -1,121 +0,0 @@
1
- import io
2
- import os
3
- from typing import Optional
4
-
5
- import cv2
6
- import numpy as np
7
- from PIL import Image
8
- import requests
9
- from fastapi import FastAPI, File, Form, UploadFile, HTTPException, Request
10
- from fastapi.responses import StreamingResponse, HTMLResponse, JSONResponse
11
- from fastapi.staticfiles import StaticFiles
12
- from fastapi.templating import Jinja2Templates
13
-
14
- app = FastAPI(title="Watermark Remover API")
15
-
16
- # Serve static + templates
17
- app.mount("/static", StaticFiles(directory="static"), name="static")
18
- templates = Jinja2Templates(directory="templates")
19
-
20
- LAMA_URL = os.getenv("LAMA_URL", "http://localhost:5000") # optional
21
-
22
- def read_image_to_cv2(file: UploadFile) -> np.ndarray:
23
- data = file.file.read()
24
- img_arr = np.frombuffer(data, np.uint8)
25
- img = cv2.imdecode(img_arr, cv2.IMREAD_COLOR)
26
- if img is None:
27
- raise HTTPException(400, detail="Invalid image file")
28
- return img
29
-
30
- def pil_bytes_from_cv2(img: np.ndarray, fmt: str = "PNG") -> io.BytesIO:
31
- img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
32
- pil_img = Image.fromarray(img_rgb)
33
- buf = io.BytesIO()
34
- pil_img.save(buf, format=fmt)
35
- buf.seek(0)
36
- return buf
37
-
38
- def auto_text_mask(img: np.ndarray) -> np.ndarray:
39
- """Simple heuristic mask for text/logo-like overlays."""
40
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
41
- gray = cv2.equalizeHist(gray)
42
- mser = cv2.MSER_create(_delta=5, _min_area=60, _max_area=10000)
43
- regions, _ = mser.detectRegions(gray)
44
- mask = np.zeros(gray.shape, dtype=np.uint8)
45
- for p in regions:
46
- hull = cv2.convexHull(p.reshape(-1, 1, 2))
47
- cv2.drawContours(mask, [hull], -1, 255, thickness=-1)
48
- kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
49
- mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1)
50
- mask = cv2.dilate(mask, kernel, iterations=1)
51
- return mask
52
-
53
- def inpaint_opencv(img: np.ndarray, mask: np.ndarray, method: str = "telea", radius: int = 3) -> np.ndarray:
54
- flag = cv2.INPAINT_TELEA if method.lower() == "telea" else cv2.INPAINT_NS
55
- if mask.ndim == 3:
56
- mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
57
- _, mask_bin = cv2.threshold(mask, 1, 255, cv2.THRESH_BINARY)
58
- result = cv2.inpaint(img, mask_bin, radius, flag)
59
- return result
60
-
61
- def call_lama_server(img: np.ndarray, mask: np.ndarray) -> np.ndarray:
62
- if mask.ndim == 3:
63
- mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
64
- _, mask_bin = cv2.threshold(mask, 1, 255, cv2.THRESH_BINARY)
65
-
66
- def to_png_bytes(arr: np.ndarray) -> bytes:
67
- a = arr
68
- if a.ndim == 2:
69
- a = cv2.cvtColor(a, cv2.COLOR_GRAY2BGR)
70
- ok, buf = cv2.imencode('.png', a)
71
- if not ok:
72
- raise HTTPException(500, detail="Encoding error")
73
- return buf.tobytes()
74
-
75
- files = {
76
- 'image': ('image.png', to_png_bytes(img), 'image/png'),
77
- 'mask': ('mask.png', to_png_bytes(mask_bin), 'image/png'),
78
- }
79
- data = {'method': 'lama'}
80
- try:
81
- resp = requests.post(f"{LAMA_URL}/inpaint", data=data, files=files, timeout=120)
82
- resp.raise_for_status()
83
- except Exception as e:
84
- raise HTTPException(502, detail=f"LaMa server error: {e}")
85
- nparr = np.frombuffer(resp.content, np.uint8)
86
- out = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
87
- if out is None:
88
- raise HTTPException(502, detail="Invalid response from LaMa server")
89
- return out
90
-
91
- @app.get("/", response_class=HTMLResponse)
92
- def index(request: Request):
93
- return templates.TemplateResponse("index.html", {"request": request})
94
-
95
- @app.get("/health")
96
- def health():
97
- return JSONResponse({"ok": True})
98
-
99
- @app.post("/api/remove-watermark")
100
- def remove_watermark(
101
- image: UploadFile = File(...),
102
- mask: Optional[UploadFile] = File(None),
103
- engine: str = Form("opencv"), # "opencv" | "lama"
104
- method: str = Form("telea"), # opencv: telea | ns
105
- radius: int = Form(3),
106
- auto_mask: int = Form(1), # 1=true, 0=false
107
- ):
108
- img = read_image_to_cv2(image)
109
-
110
- if mask is not None:
111
- mask_img = read_image_to_cv2(mask)
112
- else:
113
- mask_img = auto_text_mask(img) if auto_mask else np.zeros(img.shape[:2], dtype=np.uint8)
114
-
115
- if engine == "lama":
116
- out = call_lama_server(img, mask_img)
117
- else:
118
- out = inpaint_opencv(img, mask_img, method=method, radius=radius)
119
-
120
- buf = pil_bytes_from_cv2(out, fmt="PNG")
121
- return StreamingResponse(buf, media_type="image/png")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
watermark-remover-free/static/style.css DELETED
@@ -1,8 +0,0 @@
1
- body { font-family: system-ui, Arial, sans-serif; padding: 24px; }
2
- main { max-width: 840px; margin: auto; }
3
- h1 { margin-bottom: 16px; }
4
- form label { display: block; margin: 8px 0; }
5
- .row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
6
- button { padding: 8px 12px; }
7
- .hidden { display: none; }
8
- #output img { max-width: 100%; height: auto; margin-top: 12px; border: 1px solid #ddd; }
 
 
 
 
 
 
 
 
 
watermark-remover-free/templates/index.html DELETED
@@ -1,61 +0,0 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <title>Watermark Remover</title>
7
- <link rel="stylesheet" href="/static/style.css" />
8
- </head>
9
- <body>
10
- <main>
11
- <h1>Watermark Remover</h1>
12
- <form id="form">
13
- <label>Image <input type="file" name="image" accept="image/*" required></label>
14
- <label>Mask (optional) <input type="file" name="mask" accept="image/*"></label>
15
- <div class="row">
16
- <label>Engine
17
- <select name="engine">
18
- <option value="opencv" selected>OpenCV (fast, free)</option>
19
- <option value="lama">LaMa (needs separate server)</option>
20
- </select>
21
- </label>
22
- <label>Method
23
- <select name="method">
24
- <option value="telea" selected>Telea</option>
25
- <option value="ns">Navier-Stokes</option>
26
- </select>
27
- </label>
28
- <label>Radius <input type="number" name="radius" value="3" min="1" max="50"></label>
29
- <label>Auto Mask <input type="checkbox" name="auto_mask" checked></label>
30
- </div>
31
- <button type="submit">Remove</button>
32
- </form>
33
-
34
- <section id="output" class="hidden">
35
- <h2>Result</h2>
36
- <img id="result-img" alt="result" />
37
- <a id="download" download="result.png">Download</a>
38
- </section>
39
- </main>
40
-
41
- <script>
42
- const form = document.getElementById('form');
43
- const out = document.getElementById('output');
44
- const img = document.getElementById('result-img');
45
- const dl = document.getElementById('download');
46
-
47
- form.addEventListener('submit', async (e) => {
48
- e.preventDefault();
49
- const data = new FormData(form);
50
- data.set('auto_mask', form.auto_mask.checked ? 1 : 0);
51
- const res = await fetch('/api/remove-watermark', { method: 'POST', body: data });
52
- if (!res.ok) { alert('Failed: ' + res.status); return; }
53
- const blob = await res.blob();
54
- const url = URL.createObjectURL(blob);
55
- img.src = url;
56
- dl.href = url;
57
- out.classList.remove('hidden');
58
- });
59
- </script>
60
- </body>
61
- </html>