Merlimhhs commited on
Commit
8b0d315
·
verified ·
1 Parent(s): 9beba74

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +162 -59
app.py CHANGED
@@ -1,71 +1,174 @@
1
- import gradio as gr
2
  import os
3
  import zipfile
 
 
 
4
  import cv2
5
- import urllib.request
 
 
 
6
  from basicsr.archs.rrdbnet_arch import RRDBNet
7
  from realesrgan import RealESRGANer
8
 
9
- # Baixa o modelo específico para estética anime/ilustração se ele não estiver no servidor
10
- model_path = 'RealESRGAN_x4plus_anime_6B.pth'
11
- if not os.path.isfile(model_path):
12
- url = 'https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth'
13
- urllib.request.urlretrieve(url, model_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
- # Configura a arquitetura neural
16
- model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=6, num_grow_ch=32, scale=4)
 
 
17
 
18
- # Inicializa o motor de Upscale
19
- upsampler = RealESRGANer(
20
- scale=4,
21
- model_path=model_path,
22
- model=model,
23
- half=False # Essencial manter como False para rodar no plano grátis (CPU)
24
- )
25
 
26
  def process_batch(files):
 
 
 
 
 
27
  if not files:
28
- return None
29
-
30
- out_dir = "imagens_prontas"
31
- os.makedirs(out_dir, exist_ok=True)
32
-
33
- # Limpa a pasta antes de uma nova rodada para não misturar os lotes
34
- for f in os.listdir(out_dir):
35
- os.remove(os.path.join(out_dir, f))
36
-
37
- # Processa cada imagem enviada
38
- for file in files:
39
- filename = os.path.basename(file.name)
40
- img = cv2.imread(file.name, cv2.IMREAD_UNCHANGED)
41
-
42
- if img is not None:
43
- # Aplica o upscale 4x
44
- output, _ = upsampler.enhance(img, outscale=4)
45
- cv2.imwrite(os.path.join(out_dir, filename), output)
46
-
47
- # Cria o arquivo ZIP final
48
- zip_filename = "Imagens_Alta_Resolucao.zip"
49
- with zipfile.ZipFile(zip_filename, 'w') as zipf:
50
- for folderName, subfolders, filenames in os.walk(out_dir):
51
- for filename in filenames:
52
- filePath = os.path.join(folderName, filename)
53
- zipf.write(filePath, os.path.basename(filePath))
54
-
55
- return zip_filename
56
-
57
- # Constrói a interface visual do celular
58
- with gr.Blocks(theme=gr.themes.Soft()) as app:
59
- gr.Markdown("# 🚀 Upscale em Lote")
60
- gr.Markdown("Envie várias imagens de uma vez. O servidor processará o upscale preservando a arte original e entregará um arquivo ZIP.")
61
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  with gr.Row():
63
- with gr.Column():
64
- image_inputs = gr.File(label="1. Selecione as imagens", file_count="multiple", type="filepath")
65
- btn_process = gr.Button("2. Iniciar Upscale", variant="primary")
66
- with gr.Column():
67
- zip_output = gr.File(label="3. Download do ZIP Pronto")
68
-
69
- btn_process.click(fn=process_batch, inputs=image_inputs, outputs=zip_output)
70
-
71
- app.launch()
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
  import zipfile
3
+ import tempfile
4
+ from pathlib import Path
5
+
6
  import cv2
7
+ import gradio as gr
8
+ import numpy as np
9
+ import torch
10
+ from huggingface_hub import hf_hub_download
11
  from basicsr.archs.rrdbnet_arch import RRDBNet
12
  from realesrgan import RealESRGANer
13
 
14
+ # =========================
15
+ # CONFIG
16
+ # =========================
17
+ OUTSCALE = 2 # saída final em 2x
18
+
19
+ HF_REPO_ID = os.getenv("HF_REPO_ID", "xinntao/Real-ESRGAN")
20
+ HF_FILENAME = os.getenv("HF_FILENAME", "RealESRGAN_x4plus_anime_6B.pth")
21
+ CACHE_DIR = os.getenv("HF_HOME", "/tmp/hf-cache")
22
+
23
+
24
+ def download_model() -> str:
25
+ return hf_hub_download(
26
+ repo_id=HF_REPO_ID,
27
+ filename=HF_FILENAME,
28
+ cache_dir=CACHE_DIR,
29
+ )
30
+
31
+
32
+ def build_upsampler():
33
+ device = "cuda" if torch.cuda.is_available() else "cpu"
34
+ use_half = device == "cuda"
35
+
36
+ model_path = download_model()
37
+
38
+ # Modelo anime 6B
39
+ model = RRDBNet(
40
+ num_in_ch=3,
41
+ num_out_ch=3,
42
+ num_feat=64,
43
+ num_block=6,
44
+ num_grow_ch=32,
45
+ scale=4,
46
+ )
47
+
48
+ upsampler = RealESRGANer(
49
+ scale=4,
50
+ model_path=model_path,
51
+ model=model,
52
+ tile=256,
53
+ tile_pad=10,
54
+ pre_pad=0,
55
+ half=use_half,
56
+ device=device,
57
+ )
58
+ return upsampler
59
+
60
+
61
+ UPSAMPLER = build_upsampler()
62
+
63
+
64
+ def upscale_one_image(image: np.ndarray) -> np.ndarray:
65
+ if image is None:
66
+ return None
67
+
68
+ if image.dtype != np.uint8:
69
+ image = np.clip(image, 0, 1)
70
+ image = (image * 255).astype(np.uint8)
71
+
72
+ # Suporte a alpha
73
+ if image.ndim == 3 and image.shape[2] == 4:
74
+ rgb = image[:, :, :3]
75
+ alpha = image[:, :, 3]
76
+
77
+ bgr = cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR)
78
+ out_bgr, _ = UPSAMPLER.enhance(bgr, outscale=OUTSCALE)
79
+ out_rgb = cv2.cvtColor(out_bgr, cv2.COLOR_BGR2RGB)
80
+
81
+ alpha_up = cv2.resize(
82
+ alpha,
83
+ (alpha.shape[1] * OUTSCALE, alpha.shape[0] * OUTSCALE),
84
+ interpolation=cv2.INTER_CUBIC,
85
+ )
86
+ return np.dstack([out_rgb, alpha_up])
87
 
88
+ bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
89
+ out_bgr, _ = UPSAMPLER.enhance(bgr, outscale=OUTSCALE)
90
+ out_rgb = cv2.cvtColor(out_bgr, cv2.COLOR_BGR2RGB)
91
+ return out_rgb
92
 
 
 
 
 
 
 
 
93
 
94
  def process_batch(files):
95
+ """
96
+ Recebe uma lista de arquivos, processa um por um e retorna:
97
+ - galeria com previews
98
+ - caminho do zip final
99
+ """
100
  if not files:
101
+ return [], None
102
+
103
+ previews = []
104
+
105
+ with tempfile.TemporaryDirectory() as tmpdir:
106
+ tmpdir = Path(tmpdir)
107
+ out_dir = tmpdir / "upscaled"
108
+ out_dir.mkdir(parents=True, exist_ok=True)
109
+
110
+ for file_obj in files:
111
+ in_path = Path(file_obj.name)
112
+ image = cv2.imread(str(in_path), cv2.IMREAD_UNCHANGED)
113
+
114
+ if image is None:
115
+ continue
116
+
117
+ # OpenCV em BGR/BGRA; converter para RGB/RGBA para o pipeline
118
+ if image.ndim == 3 and image.shape[2] == 4:
119
+ image = cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA)
120
+ elif image.ndim == 3:
121
+ image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
122
+
123
+ result = upscale_one_image(image)
124
+ if result is None:
125
+ continue
126
+
127
+ out_name = f"{in_path.stem}_2x.png"
128
+ out_path = out_dir / out_name
129
+
130
+ if result.ndim == 3 and result.shape[2] == 4:
131
+ # RGBA -> BGRA para salvar via OpenCV
132
+ save_img = cv2.cvtColor(result, cv2.COLOR_RGBA2BGRA)
133
+ else:
134
+ # RGB -> BGR para salvar via OpenCV
135
+ save_img = cv2.cvtColor(result, cv2.COLOR_RGB2BGR)
136
+
137
+ cv2.imwrite(str(out_path), save_img)
138
+
139
+ previews.append((result, out_name))
140
+
141
+ zip_path = tmpdir / "upscaled_images.zip"
142
+ with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED) as zf:
143
+ for img_file in out_dir.iterdir():
144
+ zf.write(img_file, arcname=img_file.name)
145
+
146
+ # Copia o zip para um caminho persistente temporário do Gradio
147
+ final_zip = Path(tempfile.gettempdir()) / "upscaled_images.zip"
148
+ final_zip.write_bytes(zip_path.read_bytes())
149
+
150
+ return previews, str(final_zip)
151
+
152
+
153
+ with gr.Blocks() as demo:
154
+ gr.Markdown("# Anime Upscaler 2x\nUpload em lote com saída em ZIP.")
155
+
156
  with gr.Row():
157
+ files_in = gr.Files(
158
+ label="Envie várias imagens",
159
+ file_types=["image"],
160
+ file_count="multiple",
161
+ )
162
+
163
+ run_btn = gr.Button("Processar")
164
+ gallery_out = gr.Gallery(label="Prévia", columns=2, height=420)
165
+ zip_out = gr.File(label="Baixar ZIP")
166
+
167
+ run_btn.click(
168
+ fn=process_batch,
169
+ inputs=files_in,
170
+ outputs=[gallery_out, zip_out],
171
+ )
172
+
173
+ if __name__ == "__main__":
174
+ demo.launch()