Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
app.py
CHANGED
@@ -1,364 +1,172 @@
|
|
1 |
-
# --- Imports ---
|
2 |
import os
|
3 |
import sys
|
4 |
-
import cv2
|
5 |
-
import torch
|
6 |
-
# Delay Gradio import until after installation
|
7 |
-
# import gradio as gr
|
8 |
-
import numpy as np
|
9 |
-
from PIL import Image, ImageOps # <--- IMPORT ImageOps
|
10 |
-
import io
|
11 |
-
import base64
|
12 |
-
import traceback
|
13 |
-
# Delay spaces import until after installation
|
14 |
-
# import spaces
|
15 |
|
16 |
-
#
|
17 |
-
|
18 |
-
|
19 |
-
os.system("pip uninstall -y gradio gradio-client huggingface-hub") # Uninstall all first
|
20 |
-
os.system("pip install gradio==4.13.0 gradio-client==0.8.0") # Install specific Gradio
|
21 |
-
os.system("pip install huggingface-hub==0.19.4") # Install older huggingface-hub
|
22 |
-
print("Dependency installation complete.")
|
23 |
|
24 |
-
|
25 |
import gradio as gr
|
|
|
|
|
|
|
|
|
26 |
import spaces
|
27 |
-
# from huggingface_hub import HfFolder # Example import from hub if needed
|
28 |
|
29 |
-
#
|
30 |
try:
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
except Exception as e:
|
37 |
-
print(f"
|
38 |
-
|
39 |
|
40 |
-
#
|
41 |
try:
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
MODEL_FILES = {
|
57 |
-
'realesr-general-x4v3.pth': 'https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth',
|
58 |
-
'GFPGANv1.2.pth': 'https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.2.pth',
|
59 |
-
'GFPGANv1.3.pth': 'https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth',
|
60 |
-
'GFPGANv1.4.pth': 'https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth',
|
61 |
-
'RestoreFormer.pth': 'https://github.com/TencentARC/GFPGAN/releases/download/v1.3.4/RestoreFormer.pth',
|
62 |
-
}
|
63 |
-
print("Downloading model weights...")
|
64 |
-
for filename, url in MODEL_FILES.items():
|
65 |
-
try:
|
66 |
-
if not os.path.exists(filename):
|
67 |
-
print(f"Downloading {filename}...")
|
68 |
-
os.system(f"wget -q {url} -P .") # Use -q for quiet
|
69 |
-
except Exception as e:
|
70 |
-
print(f"Error downloading {filename}: {e}")
|
71 |
-
if not os.path.exists('realesr-general-x4v3.pth'):
|
72 |
-
print("FATAL: RealESRGAN model (realesr-general-x4v3.pth) not found after download attempt. Cannot proceed.")
|
73 |
-
sys.exit(1)
|
74 |
-
print("Model weight download check complete.")
|
75 |
-
|
76 |
-
# --- Sample Image Downloads ---
|
77 |
-
SAMPLE_IMAGES = {
|
78 |
-
'lincoln.jpg': 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/ab/Abraham_Lincoln_O-77_matte_collodion_print.jpg/1024px-Abraham_Lincoln_O-77_matte_collodion_print.jpg',
|
79 |
-
'AI-generate.jpg': 'https://user-images.githubusercontent.com/17445847/187400315-87a90ac9-d231-45d6-b377-38702bd1838f.jpg',
|
80 |
-
'Blake_Lively.jpg': 'https://user-images.githubusercontent.com/17445847/187400981-8a58f7a4-ef61-42d9-af80-bc6234cef860.jpg',
|
81 |
-
'10045.png': 'https://user-images.githubusercontent.com/17445847/187401133-8a3bf269-5b4d-4432-b2f0-6d26ee1d3307.png'
|
82 |
-
}
|
83 |
-
print("Downloading sample images...")
|
84 |
-
for filename, url in SAMPLE_IMAGES.items():
|
85 |
-
try:
|
86 |
-
if not os.path.exists(filename):
|
87 |
-
torch.hub.download_url_to_file(url, filename, progress=False)
|
88 |
-
except Exception as e:
|
89 |
-
print(f"Warning: Error downloading sample image {filename}: {e}")
|
90 |
-
print("Sample image download check complete.")
|
91 |
-
|
92 |
|
93 |
-
#
|
94 |
-
upsampler = None
|
95 |
try:
|
96 |
-
print("Initializing RealESRGAN upsampler...")
|
97 |
model = SRVGGNetCompact(num_in_ch=3, num_out_ch=3, num_feat=64, num_conv=32, upscale=4, act_type='prelu')
|
98 |
model_path = 'realesr-general-x4v3.pth'
|
99 |
-
half = torch.cuda.is_available()
|
100 |
-
print(f"CUDA available: {torch.cuda.is_available()}, Using half precision: {half}")
|
101 |
upsampler = RealESRGANer(scale=4, model_path=model_path, model=model, tile=0, tile_pad=10, pre_pad=0, half=half)
|
102 |
-
print("Successfully created
|
103 |
except Exception as e:
|
104 |
-
print(f"Error creating
|
105 |
-
|
106 |
-
print("Warning: GFPGAN will run without background enhancement.")
|
107 |
-
|
108 |
-
|
109 |
-
# --- Inference Function (Handles API, PIL, Base64, EXIF) ---
|
110 |
-
@spaces.GPU(duration=90) # Keep ZeroGPU decorator
|
111 |
-
# --- MODIFIED Function Signature: Accepts filepath instead of PIL Image ---
|
112 |
-
def inference(input_image_filepath, version, scale):
|
113 |
-
"""
|
114 |
-
Processes an input image file using GFPGAN, handling EXIF and aspect ratio.
|
115 |
-
|
116 |
-
Args:
|
117 |
-
input_image_filepath (str): Path to the temporary input image file provided by Gradio.
|
118 |
-
version (str): GFPGAN model version ('v1.2', 'v1.3', 'v1.4', 'RestoreFormer').
|
119 |
-
scale (float): Rescaling factor for the final output relative to original.
|
120 |
-
|
121 |
-
Returns:
|
122 |
-
tuple: (PIL.Image.Image | None, str | None)
|
123 |
-
- Output PIL image (RGB) or None on error.
|
124 |
-
- Base64 encoded output image string (data URI) or an error message string.
|
125 |
-
"""
|
126 |
-
# --- ADDED: Load image from filepath ---
|
127 |
-
input_pil_image = None
|
128 |
-
try:
|
129 |
-
print(f"Loading image from filepath: {input_image_filepath}")
|
130 |
-
if not input_image_filepath or not isinstance(input_image_filepath, str) or not os.path.exists(input_image_filepath):
|
131 |
-
error_msg = f"Error: Input image filepath is invalid or file does not exist: '{input_image_filepath}'"
|
132 |
-
print(error_msg)
|
133 |
-
# Return None for Image output, error message for Textbox output
|
134 |
-
return None, error_msg
|
135 |
-
input_pil_image = Image.open(input_image_filepath)
|
136 |
-
print(f"Successfully loaded image. Initial mode: {input_pil_image.mode}, size: {input_pil_image.size}")
|
137 |
-
except Exception as load_err:
|
138 |
-
error_msg = f"Error loading image from filepath {input_image_filepath}: {load_err}"
|
139 |
-
print(error_msg)
|
140 |
-
print(traceback.format_exc())
|
141 |
-
# Return None for Image output, error message for Textbox output
|
142 |
-
return None, error_msg
|
143 |
-
# --- End Added Image Loading ---
|
144 |
-
|
145 |
-
# Check if loading failed (redundant due to try/except, but safe)
|
146 |
-
if input_pil_image is None:
|
147 |
-
print("Error: No input image could be loaded.")
|
148 |
-
return None, "Error: Failed to load input image."
|
149 |
-
|
150 |
-
print(f"Processing image with GFPGAN version: {version}, scale: {scale}")
|
151 |
-
|
152 |
-
# --- Handle EXIF Orientation ---
|
153 |
-
original_size_before_exif = input_pil_image.size
|
154 |
-
try:
|
155 |
-
input_pil_image = ImageOps.exif_transpose(input_pil_image)
|
156 |
-
if input_pil_image.size != original_size_before_exif:
|
157 |
-
print(f"Image size changed by EXIF transpose: {original_size_before_exif} -> {input_pil_image.size}")
|
158 |
-
except Exception as exif_err:
|
159 |
-
print(f"Warning: Could not apply EXIF transpose: {exif_err}")
|
160 |
-
# -----------------------------
|
161 |
|
162 |
-
|
163 |
-
print(f"Input size for processing (WxH): {w_orig}x{h_orig}")
|
164 |
|
165 |
-
|
|
|
|
|
166 |
try:
|
167 |
-
|
168 |
-
if
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
'
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
)
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
if target_w <= 0 or target_h <= 0:
|
232 |
-
print(f"Warning: Invalid target size ({target_w}x{target_h}) calculated from scale {scale}. Using GFPGAN output size {w_gfpgan}x{h_gfpgan}.")
|
233 |
-
target_w, target_h = w_gfpgan, h_gfpgan
|
234 |
-
|
235 |
-
if abs(target_w - w_gfpgan) > 2 or abs(target_h - h_gfpgan) > 2:
|
236 |
-
print(f"Resizing GFPGAN output ({w_gfpgan}x{h_gfpgan}) to target ({target_w}x{target_h}) based on scale {target_scale_factor}...")
|
237 |
-
interpolation = cv2.INTER_LANCZOS4 if (target_w * target_h) > (w_gfpgan * h_gfpgan) else cv2.INTER_AREA
|
238 |
-
try:
|
239 |
-
output_bgr = cv2.resize(output_bgr, (target_w, target_h), interpolation=interpolation)
|
240 |
-
except cv2.error as resize_err:
|
241 |
-
# --- MODIFIED Resize Error Handling ---
|
242 |
-
error_msg = f"Error during OpenCV resize: {resize_err}. Returning image before final resize attempt."
|
243 |
-
print(error_msg)
|
244 |
-
output_pil = Image.fromarray(cv2.cvtColor(output_bgr, cv2.COLOR_BGR2RGB))
|
245 |
-
# Still try to encode this fallback image
|
246 |
-
base64_output = None
|
247 |
-
try:
|
248 |
-
buffered = io.BytesIO()
|
249 |
-
output_pil.save(buffered, format="WEBP", quality=85)
|
250 |
-
img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
|
251 |
-
base64_output = f"data:image/webp;base64,{img_str}"
|
252 |
-
except Exception as enc_err:
|
253 |
-
print(f"Error encoding fallback image: {enc_err}")
|
254 |
-
error_msg += f" | Encoding Error: {enc_err}" # Append encoding error
|
255 |
-
# Return fallback image and combined error message
|
256 |
-
return output_pil, base64_output if base64_output else error_msg
|
257 |
-
# --- End Modified Resize Error Handling ---
|
258 |
-
|
259 |
-
# --- Convert final result back to PIL (RGB) ---
|
260 |
-
output_pil = Image.fromarray(cv2.cvtColor(output_bgr, cv2.COLOR_BGR2RGB))
|
261 |
-
print(f"Final output image size (WxH PIL): {output_pil.size}")
|
262 |
-
|
263 |
-
# --- Encode final PIL image to Base64 for API ---
|
264 |
-
# This replaces the need for gr.File saving/output
|
265 |
-
base64_output = None
|
266 |
-
try:
|
267 |
-
buffered = io.BytesIO()
|
268 |
-
output_pil.save(buffered, format="WEBP", quality=90)
|
269 |
-
img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
|
270 |
-
base64_output = f"data:image/webp;base64,{img_str}"
|
271 |
-
except Exception as enc_err:
|
272 |
-
error_msg = f"Error encoding final image to base64: {enc_err}"
|
273 |
-
print(error_msg)
|
274 |
-
print(traceback.format_exc())
|
275 |
-
# Return the PIL image anyway, but with an error message
|
276 |
-
return output_pil, error_msg
|
277 |
-
|
278 |
-
# --- MODIFIED RETURN: Return PIL image and base64 string ---
|
279 |
-
# Remove save_path which is no longer needed for outputs
|
280 |
-
# Return the base64 string for the Textbox output (or success message)
|
281 |
-
success_msg = f"Success! Output size: {output_pil.size[0]}x{output_pil.size[1]}"
|
282 |
-
return output_pil, base64_output if base64_output else success_msg
|
283 |
-
|
284 |
except Exception as error:
|
285 |
-
|
286 |
-
|
287 |
-
print(error_msg)
|
288 |
print(traceback.format_exc())
|
289 |
-
|
290 |
-
error_img = None
|
291 |
-
try:
|
292 |
-
error_img = Image.new('RGB', (100, 50), color = 'red')
|
293 |
-
except Exception: pass # Ignore if placeholder fails
|
294 |
-
return error_img, error_msg # Return placeholder/None and error string
|
295 |
-
# --- End Modified Main Exception Handling ---
|
296 |
-
|
297 |
|
298 |
-
# --- Gradio Interface Definition ---
|
299 |
-
title = "GFPGAN: Practical Face Restoration"
|
300 |
-
description = """Gradio demo for <a href='https://github.com/TencentARC/GFPGAN' target='_blank'><b>GFPGAN: Towards Real-World Blind Face Restoration with Generative Facial Prior</b></a>.
|
301 |
-
<br>Restore your <b>old photos</b> or improve <b>AI-generated faces</b>. Upload an image to start.
|
302 |
-
<br>If helpful, please ⭐ the <a href='https://github.com/TencentARC/GFPGAN' target='_blank'>Original Github Repo</a>.
|
303 |
-
<br>API endpoint available at `/predict`. Expects image filepath, version string, scale number. Returns Image and Textbox data.
|
304 |
-
"""
|
305 |
-
article = "Questions? Contact the original creators (see GFPGAN repo)."
|
306 |
|
307 |
-
|
308 |
-
|
309 |
-
# --- MODIFIED INPUTS ---
|
310 |
-
# Changed gr.Image type to 'filepath'
|
311 |
-
inputs = [
|
312 |
-
gr.Image(type="filepath", label="Input Image", sources=["upload", "clipboard"]), # <-- TYPE CHANGED
|
313 |
-
gr.Radio(
|
314 |
-
['v1.2', 'v1.3', 'v1.4', 'RestoreFormer'],
|
315 |
-
type="value", value='v1.4', label='GFPGAN Version',
|
316 |
-
info="v1.4 recommended. RestoreFormer for diverse poses."
|
317 |
-
),
|
318 |
-
gr.Number(
|
319 |
-
label="Rescaling Factor", value=2,
|
320 |
-
info="Final output size multiplier relative to original input size (e.g., 2 = 2x original WxH)."
|
321 |
-
),
|
322 |
-
]
|
323 |
-
|
324 |
-
# --- MODIFIED OUTPUTS ---
|
325 |
-
# Removed gr.File, kept gr.Image and gr.Textbox
|
326 |
-
# Made Textbox visible for easier debugging
|
327 |
-
outputs = [
|
328 |
-
gr.Image(type="pil", label="Output Image"),
|
329 |
-
# gr.File(label="Download Output Image (Server Path)"), # <-- REMOVED
|
330 |
-
gr.Textbox(label="Output Info / Base64 Data", interactive=False, visible=True) # <-- KEPT (made visible)
|
331 |
-
]
|
332 |
|
333 |
-
|
334 |
-
|
335 |
-
examples = [
|
336 |
-
['AI-generate.jpg', 'v1.4', 2],
|
337 |
-
['lincoln.jpg', 'v1.4', 2],
|
338 |
-
['Blake_Lively.jpg', 'v1.4', 2],
|
339 |
-
['10045.png', 'v1.4', 2]
|
340 |
-
]
|
341 |
|
342 |
-
|
343 |
-
|
|
|
344 |
demo = gr.Interface(
|
345 |
-
fn=inference,
|
346 |
-
inputs=
|
347 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
348 |
title=title,
|
349 |
description=description,
|
350 |
article=article,
|
351 |
-
examples=
|
352 |
-
|
353 |
-
allow_flagging='never'
|
354 |
)
|
355 |
-
|
356 |
-
# Launch the
|
357 |
print("Launching Gradio interface...")
|
358 |
-
demo.
|
359 |
-
|
360 |
-
|
361 |
except Exception as e:
|
362 |
-
|
363 |
-
print(
|
364 |
-
|
|
|
|
|
1 |
import os
|
2 |
import sys
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
+
# Force install a Gradio version that is compatible with Spaces
|
5 |
+
os.system("pip uninstall -y gradio gradio-client")
|
6 |
+
os.system("pip install gradio==4.13.0") # This version should be compatible with Spaces
|
|
|
|
|
|
|
|
|
7 |
|
8 |
+
import cv2
|
9 |
import gradio as gr
|
10 |
+
import torch
|
11 |
+
from basicsr.archs.srvgg_arch import SRVGGNetCompact
|
12 |
+
from gfpgan.utils import GFPGANer
|
13 |
+
from realesrgan.utils import RealESRGANer
|
14 |
import spaces
|
|
|
15 |
|
16 |
+
# download weights - using try/except to handle potential errors
|
17 |
try:
|
18 |
+
if not os.path.exists('realesr-general-x4v3.pth'):
|
19 |
+
os.system("wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth -P .")
|
20 |
+
if not os.path.exists('GFPGANv1.2.pth'):
|
21 |
+
os.system("wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.2.pth -P .")
|
22 |
+
if not os.path.exists('GFPGANv1.3.pth'):
|
23 |
+
os.system("wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth -P .")
|
24 |
+
if not os.path.exists('GFPGANv1.4.pth'):
|
25 |
+
os.system("wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth -P .")
|
26 |
+
if not os.path.exists('RestoreFormer.pth'):
|
27 |
+
os.system("wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.4/RestoreFormer.pth -P .")
|
28 |
+
if not os.path.exists('CodeFormer.pth'):
|
29 |
+
os.system("wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.4/CodeFormer.pth -P .")
|
30 |
except Exception as e:
|
31 |
+
print(f"Error downloading model weights: {e}")
|
|
|
32 |
|
33 |
+
# Download sample images - using try/except to handle potential errors
|
34 |
try:
|
35 |
+
torch.hub.download_url_to_file(
|
36 |
+
'https://upload.wikimedia.org/wikipedia/commons/thumb/a/ab/Abraham_Lincoln_O-77_matte_collodion_print.jpg/1024px-Abraham_Lincoln_O-77_matte_collodion_print.jpg',
|
37 |
+
'lincoln.jpg')
|
38 |
+
torch.hub.download_url_to_file(
|
39 |
+
'https://user-images.githubusercontent.com/17445847/187400315-87a90ac9-d231-45d6-b377-38702bd1838f.jpg',
|
40 |
+
'AI-generate.jpg')
|
41 |
+
torch.hub.download_url_to_file(
|
42 |
+
'https://user-images.githubusercontent.com/17445847/187400981-8a58f7a4-ef61-42d9-af80-bc6234cef860.jpg',
|
43 |
+
'Blake_Lively.jpg')
|
44 |
+
torch.hub.download_url_to_file(
|
45 |
+
'https://user-images.githubusercontent.com/17445847/187401133-8a3bf269-5b4d-4432-b2f0-6d26ee1d3307.png',
|
46 |
+
'10045.png')
|
47 |
+
except Exception as e:
|
48 |
+
print(f"Error downloading sample images: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
+
# background enhancer with RealESRGAN
|
|
|
51 |
try:
|
|
|
52 |
model = SRVGGNetCompact(num_in_ch=3, num_out_ch=3, num_feat=64, num_conv=32, upscale=4, act_type='prelu')
|
53 |
model_path = 'realesr-general-x4v3.pth'
|
54 |
+
half = True if torch.cuda.is_available() else False
|
|
|
55 |
upsampler = RealESRGANer(scale=4, model_path=model_path, model=model, tile=0, tile_pad=10, pre_pad=0, half=half)
|
56 |
+
print("Successfully created upsampler")
|
57 |
except Exception as e:
|
58 |
+
print(f"Error creating model or upsampler: {e}")
|
59 |
+
upsampler = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
|
61 |
+
os.makedirs('output', exist_ok=True)
|
|
|
62 |
|
63 |
+
# Apply the spaces.GPU decorator to enable ZeroGPU allocation
|
64 |
+
@spaces.GPU(duration=90)
|
65 |
+
def inference(img, version, scale):
|
66 |
try:
|
67 |
+
print(f"Processing image: {img}, version: {version}, scale: {scale}")
|
68 |
+
if scale > 4:
|
69 |
+
scale = 4 # avoid too large scale value
|
70 |
+
|
71 |
+
extension = os.path.splitext(os.path.basename(str(img)))[1]
|
72 |
+
img = cv2.imread(img, cv2.IMREAD_UNCHANGED)
|
73 |
+
if img is None:
|
74 |
+
print(f"Failed to read image: {img}")
|
75 |
+
return None, None
|
76 |
+
|
77 |
+
if len(img.shape) == 3 and img.shape[2] == 4:
|
78 |
+
img_mode = 'RGBA'
|
79 |
+
elif len(img.shape) == 2: # for gray inputs
|
80 |
+
img_mode = None
|
81 |
+
img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
|
82 |
+
else:
|
83 |
+
img_mode = None
|
84 |
+
|
85 |
+
h, w = img.shape[0:2]
|
86 |
+
if h > 3500 or w > 3500:
|
87 |
+
print('too large size')
|
88 |
+
return None, None
|
89 |
+
|
90 |
+
if h < 300:
|
91 |
+
img = cv2.resize(img, (w * 2, h * 2), interpolation=cv2.INTER_LANCZOS4)
|
92 |
+
|
93 |
+
if upsampler is None:
|
94 |
+
print("Upsampler not initialized")
|
95 |
+
return None, None
|
96 |
+
|
97 |
+
if version == 'v1.2':
|
98 |
+
face_enhancer = GFPGANer(
|
99 |
+
model_path='GFPGANv1.2.pth', upscale=2, arch='clean', channel_multiplier=2, bg_upsampler=upsampler)
|
100 |
+
elif version == 'v1.3':
|
101 |
+
face_enhancer = GFPGANer(
|
102 |
+
model_path='GFPGANv1.3.pth', upscale=2, arch='clean', channel_multiplier=2, bg_upsampler=upsampler)
|
103 |
+
elif version == 'v1.4':
|
104 |
+
face_enhancer = GFPGANer(
|
105 |
+
model_path='GFPGANv1.4.pth', upscale=2, arch='clean', channel_multiplier=2, bg_upsampler=upsampler)
|
106 |
+
elif version == 'RestoreFormer':
|
107 |
+
face_enhancer = GFPGANer(
|
108 |
+
model_path='RestoreFormer.pth', upscale=2, arch='RestoreFormer', channel_multiplier=2, bg_upsampler=upsampler)
|
109 |
+
else:
|
110 |
+
print(f"Unknown version: {version}")
|
111 |
+
return None, None
|
112 |
+
|
113 |
+
print(f"Using {version} for enhancement")
|
114 |
+
_, _, output = face_enhancer.enhance(img, has_aligned=False, only_center_face=False, paste_back=True)
|
115 |
+
|
116 |
+
if scale != 2:
|
117 |
+
interpolation = cv2.INTER_AREA if scale < 2 else cv2.INTER_LANCZOS4
|
118 |
+
h, w = img.shape[0:2]
|
119 |
+
output = cv2.resize(output, (int(w * scale / 2), int(h * scale / 2)), interpolation=interpolation)
|
120 |
+
|
121 |
+
if img_mode == 'RGBA': # RGBA images should be saved in png format
|
122 |
+
extension = 'png'
|
123 |
+
else:
|
124 |
+
extension = 'jpg'
|
125 |
+
save_path = f'output/out.{extension}'
|
126 |
+
|
127 |
+
cv2.imwrite(save_path, output)
|
128 |
+
output = cv2.cvtColor(output, cv2.COLOR_BGR2RGB)
|
129 |
+
return output, save_path
|
130 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
except Exception as error:
|
132 |
+
import traceback
|
133 |
+
print(f"Error in inference: {error}")
|
|
|
134 |
print(traceback.format_exc())
|
135 |
+
return None, None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
136 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
137 |
|
138 |
+
title = "GFPGAN: Practical Face Restoration Algorithm"
|
139 |
+
description = "Gradio demo Fix for <a href='https://github.com/TencentARC/GFPGAN' target='_blank'><b>GFPGAN: Towards Real-World Blind Face Restoration with Generative Facial Prior</b></a>.<br>It can be used to restore your <b>old photos</b> or improve <b>AI-generated faces</b>.<br>To use it, simply upload your image.<br>If GFPGAN is helpful, please help to ⭐ the <a href='https://github.com/Nick088Official/GFPGAN-Fix' target='_blank'>Github Repo</a> and recommend it to your friends 😊"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
|
141 |
+
# Simplified article text to avoid URL parsing issues
|
142 |
+
article = "If you have any question, please email [email protected] or [email protected] (original creators)."
|
|
|
|
|
|
|
|
|
|
|
|
|
143 |
|
144 |
+
# Create the interface with more robust error handling
|
145 |
+
try:
|
146 |
+
print("Creating Gradio interface...")
|
147 |
demo = gr.Interface(
|
148 |
+
fn=inference,
|
149 |
+
inputs=[
|
150 |
+
gr.Image(type="filepath", label="Input"),
|
151 |
+
gr.Radio(['v1.2', 'v1.3', 'v1.4', 'RestoreFormer'], type="value", value='v1.4', label='version'),
|
152 |
+
gr.Number(label="Rescaling factor", value=2),
|
153 |
+
],
|
154 |
+
outputs=[
|
155 |
+
gr.Image(type="numpy", label="Output (The whole image)"),
|
156 |
+
gr.File(label="Download the output image")
|
157 |
+
],
|
158 |
title=title,
|
159 |
description=description,
|
160 |
article=article,
|
161 |
+
examples=[['AI-generate.jpg', 'v1.4', 2], ['lincoln.jpg', 'v1.4', 2], ['Blake_Lively.jpg', 'v1.4', 2],
|
162 |
+
['10045.png', 'v1.4', 2]]
|
|
|
163 |
)
|
164 |
+
|
165 |
+
# Launch with the simplest possible configuration
|
166 |
print("Launching Gradio interface...")
|
167 |
+
demo.launch(server_name="0.0.0.0")
|
168 |
+
|
|
|
169 |
except Exception as e:
|
170 |
+
import traceback
|
171 |
+
print(f"Error setting up Gradio interface: {e}")
|
172 |
+
print(traceback.format_exc())
|