luisabwk commited on
Commit
81856ea
·
verified ·
1 Parent(s): e135efb

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -113
app.py DELETED
@@ -1,113 +0,0 @@
1
- """Gradio app for the FFDNet denoiser — roda em CPU no HF Spaces grátis."""
2
- from __future__ import annotations
3
-
4
- import os
5
- import urllib.request
6
- from pathlib import Path
7
-
8
- import gradio as gr
9
- import numpy as np
10
- import torch
11
- from PIL import Image
12
-
13
- from ffdnet_model import FFDNet
14
-
15
- WEIGHTS_DIR = Path(os.environ.get("FFDNET_WEIGHTS_DIR", "weights"))
16
-
17
- WEIGHTS = {
18
- "color": {
19
- "url": "https://github.com/cszn/KAIR/releases/download/v1.0/ffdnet_color.pth",
20
- "file": WEIGHTS_DIR / "ffdnet_color.pth",
21
- "in_nc": 3,
22
- "out_nc": 3,
23
- "nc": 96,
24
- "nb": 12,
25
- },
26
- "gray": {
27
- "url": "https://github.com/cszn/KAIR/releases/download/v1.0/ffdnet_gray.pth",
28
- "file": WEIGHTS_DIR / "ffdnet_gray.pth",
29
- "in_nc": 1,
30
- "out_nc": 1,
31
- "nc": 64,
32
- "nb": 15,
33
- },
34
- }
35
-
36
- DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
37
- _MODELS: dict[str, FFDNet] = {}
38
-
39
-
40
- def _download(url: str, target: Path) -> None:
41
- if target.exists():
42
- return
43
- target.parent.mkdir(parents=True, exist_ok=True)
44
- print(f"[ffdnet] downloading {url} -> {target}")
45
- urllib.request.urlretrieve(url, target)
46
-
47
-
48
- def _load(mode: str) -> FFDNet:
49
- if mode in _MODELS:
50
- return _MODELS[mode]
51
- cfg = WEIGHTS[mode]
52
- _download(cfg["url"], cfg["file"])
53
- model = FFDNet(in_nc=cfg["in_nc"], out_nc=cfg["out_nc"], nc=cfg["nc"], nb=cfg["nb"])
54
- state = torch.load(cfg["file"], map_location=DEVICE, weights_only=True)
55
- # Strip DataParallel prefix se existir
56
- state = {k.replace("module.", "", 1): v for k, v in state.items()}
57
- model.load_state_dict(state, strict=True)
58
- model.eval().to(DEVICE)
59
- _MODELS[mode] = model
60
- return model
61
-
62
-
63
- def denoise(image: Image.Image, noise_sigma: float, mode: str) -> Image.Image:
64
- if image is None:
65
- raise gr.Error("Envie uma imagem.")
66
- if mode not in WEIGHTS:
67
- raise gr.Error(f"Modo inválido: {mode}")
68
-
69
- model = _load(mode)
70
-
71
- pil = image.convert("RGB" if mode == "color" else "L")
72
- arr = np.array(pil)
73
- if arr.ndim == 2:
74
- arr = arr[..., None]
75
-
76
- tensor = (
77
- torch.from_numpy(arr.astype(np.float32) / 255.0)
78
- .permute(2, 0, 1)
79
- .unsqueeze(0)
80
- .to(DEVICE)
81
- )
82
- sigma = torch.tensor([float(noise_sigma) / 255.0], dtype=torch.float32, device=DEVICE)
83
-
84
- with torch.no_grad():
85
- out = model(tensor, sigma).clamp(0.0, 1.0)
86
-
87
- out_np = (out.squeeze(0).permute(1, 2, 0).cpu().numpy() * 255.0).round().astype(np.uint8)
88
- if mode == "gray":
89
- out_np = out_np[..., 0]
90
- return Image.fromarray(out_np)
91
-
92
-
93
- with gr.Blocks(title="FFDNet — Denoiser") as demo:
94
- gr.Markdown(
95
- "# FFDNet — Denoiser\n"
96
- "CNN denoiser com nível de ruído (σ) ajustável. "
97
- "Útil para limpar scans/fotos antes de OCR. "
98
- "Primeira chamada baixa os pesos (~4MB/10MB) e pode demorar alguns segundos."
99
- )
100
- with gr.Row():
101
- with gr.Column():
102
- inp = gr.Image(type="pil", label="Imagem de entrada")
103
- sigma = gr.Slider(0, 75, value=15, step=1, label="σ — nível de ruído estimado")
104
- mode = gr.Radio(choices=["color", "gray"], value="color", label="Modo")
105
- btn = gr.Button("Denoise", variant="primary")
106
- with gr.Column():
107
- out_img = gr.Image(type="pil", label="Resultado")
108
-
109
- btn.click(fn=denoise, inputs=[inp, sigma, mode], outputs=out_img, api_name="denoise")
110
-
111
-
112
- if __name__ == "__main__":
113
- demo.queue(max_size=8).launch()