redoudou commited on
Commit
c5586d0
·
1 Parent(s): db82151

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +226 -0
app.py ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import cv2
3
+ import numpy
4
+ import os
5
+ import random
6
+ from basicsr.archs.rrdbnet_arch import RRDBNet
7
+ from basicsr.utils.download_util import load_file_from_url
8
+
9
+ from realesrgan import RealESRGANer
10
+ from realesrgan.archs.srvgg_arch import SRVGGNetCompact
11
+
12
+
13
+ last_file = None
14
+ img_mode = "RGBA"
15
+ SECRET_TOKEN = os.getenv('SECRET_TOKEN', 'default_secret')
16
+
17
+ def realesrgan(secret_token, img, model_name, denoise_strength, face_enhance, outscale):
18
+ """Real-ESRGAN function to restore (and upscale) images.
19
+ """
20
+ if secret_token != SECRET_TOKEN:
21
+ raise gr.Error(
22
+ f'Invalid secret token. Please fork the original space if you want to use it for yourself.')
23
+
24
+ if not img:
25
+ return
26
+
27
+ # Define model parameters
28
+ if model_name == 'RealESRGAN_x4plus': # x4 RRDBNet model
29
+ model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=4)
30
+ netscale = 4
31
+ file_url = ['https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth']
32
+ elif model_name == 'RealESRNet_x4plus': # x4 RRDBNet model
33
+ model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=4)
34
+ netscale = 4
35
+ file_url = ['https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.1/RealESRNet_x4plus.pth']
36
+ elif model_name == 'RealESRGAN_x4plus_anime_6B': # x4 RRDBNet model with 6 blocks
37
+ model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=6, num_grow_ch=32, scale=4)
38
+ netscale = 4
39
+ file_url = ['https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth']
40
+ elif model_name == 'RealESRGAN_x2plus': # x2 RRDBNet model
41
+ model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=2)
42
+ netscale = 2
43
+ file_url = ['https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.1/RealESRGAN_x2plus.pth']
44
+ elif model_name == 'realesr-general-x4v3': # x4 VGG-style model (S size)
45
+ model = SRVGGNetCompact(num_in_ch=3, num_out_ch=3, num_feat=64, num_conv=32, upscale=4, act_type='prelu')
46
+ netscale = 4
47
+ file_url = [
48
+ 'https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-wdn-x4v3.pth',
49
+ 'https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth'
50
+ ]
51
+
52
+ # Determine model paths
53
+ model_path = os.path.join('weights', model_name + '.pth')
54
+ if not os.path.isfile(model_path):
55
+ ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
56
+ for url in file_url:
57
+ # model_path will be updated
58
+ model_path = load_file_from_url(
59
+ url=url, model_dir=os.path.join(ROOT_DIR, 'weights'), progress=True, file_name=None)
60
+
61
+ # Use dni to control the denoise strength
62
+ dni_weight = None
63
+ if model_name == 'realesr-general-x4v3' and denoise_strength != 1:
64
+ wdn_model_path = model_path.replace('realesr-general-x4v3', 'realesr-general-wdn-x4v3')
65
+ model_path = [model_path, wdn_model_path]
66
+ dni_weight = [denoise_strength, 1 - denoise_strength]
67
+
68
+ # Restorer Class
69
+ upsampler = RealESRGANer(
70
+ scale=netscale,
71
+ model_path=model_path,
72
+ dni_weight=dni_weight,
73
+ model=model,
74
+ tile=0,
75
+ tile_pad=10,
76
+ pre_pad=10,
77
+ half=False,
78
+ gpu_id=None
79
+ )
80
+
81
+ # Use GFPGAN for face enhancement
82
+ if face_enhance:
83
+ from gfpgan import GFPGANer
84
+ face_enhancer = GFPGANer(
85
+ model_path='https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth',
86
+ upscale=outscale,
87
+ arch='clean',
88
+ channel_multiplier=2,
89
+ bg_upsampler=upsampler)
90
+
91
+ # Convert the input PIL image to cv2 image, so that it can be processed by realesrgan
92
+ cv_img = numpy.array(img)
93
+ img = cv2.cvtColor(cv_img, cv2.COLOR_RGBA2BGRA)
94
+
95
+ # Apply restoration
96
+ try:
97
+ if face_enhance:
98
+ _, _, output = face_enhancer.enhance(img, has_aligned=False, only_center_face=False, paste_back=True)
99
+ else:
100
+ output, _ = upsampler.enhance(img, outscale=outscale)
101
+ except RuntimeError as error:
102
+ print('Error', error)
103
+ print('If you encounter CUDA out of memory, try to set --tile with a smaller number.')
104
+ else:
105
+ # Save restored image and return it to the output Image component
106
+ if img_mode == 'RGBA': # RGBA images should be saved in png format
107
+ extension = 'png'
108
+ else:
109
+ extension = 'jpg'
110
+
111
+ out_filename = f"output_{rnd_string(8)}.{extension}"
112
+ cv2.imwrite(out_filename, output)
113
+ global last_file
114
+ last_file = out_filename
115
+ return out_filename
116
+
117
+
118
+ def rnd_string(x):
119
+ """Returns a string of 'x' random characters
120
+ """
121
+ characters = "abcdefghijklmnopqrstuvwxyz_0123456789"
122
+ result = "".join((random.choice(characters)) for i in range(x))
123
+ return result
124
+
125
+
126
+ def reset():
127
+ """Resets the Image components of the Gradio interface and deletes
128
+ the last processed image
129
+ """
130
+ global last_file
131
+ if last_file:
132
+ print(f"Deleting {last_file} ...")
133
+ os.remove(last_file)
134
+ last_file = None
135
+ return gr.update(value=None), gr.update(value=None)
136
+
137
+
138
+ def has_transparency(img):
139
+ """This function works by first checking to see if a "transparency" property is defined
140
+ in the image's info -- if so, we return "True". Then, if the image is using indexed colors
141
+ (such as in GIFs), it gets the index of the transparent color in the palette
142
+ (img.info.get("transparency", -1)) and checks if it's used anywhere in the canvas
143
+ (img.getcolors()). If the image is in RGBA mode, then presumably it has transparency in
144
+ it, but it double-checks by getting the minimum and maximum values of every color channel
145
+ (img.getextrema()), and checks if the alpha channel's smallest value falls below 255.
146
+ https://stackoverflow.com/questions/43864101/python-pil-check-if-image-is-transparent
147
+ """
148
+ if img.info.get("transparency", None) is not None:
149
+ return True
150
+ if img.mode == "P":
151
+ transparent = img.info.get("transparency", -1)
152
+ for _, index in img.getcolors():
153
+ if index == transparent:
154
+ return True
155
+ elif img.mode == "RGBA":
156
+ extrema = img.getextrema()
157
+ if extrema[3][0] < 255:
158
+ return True
159
+ return False
160
+
161
+
162
+ def image_properties(img):
163
+ """Returns the dimensions (width and height) and color mode of the input image and
164
+ also sets the global img_mode variable to be used by the realesrgan function
165
+ """
166
+ global img_mode
167
+ if img:
168
+ if has_transparency(img):
169
+ img_mode = "RGBA"
170
+ else:
171
+ img_mode = "RGB"
172
+ properties = f"Width: {img.size[0]}, Height: {img.size[1]} | Color Mode: {img_mode}"
173
+ return properties
174
+
175
+
176
+ def main():
177
+ # Gradio Interface
178
+ with gr.Blocks(title="Upscaling Service", theme="dark") as demo:
179
+
180
+ gr.Markdown(
181
+ """This Space is a fork of "Real-ESRGAN-Demo", so if you want to use it please refer to [havas79/Real-ESRGAN_Demo](https://huggingface.co/spaces/havas79/Real-ESRGAN_Demo), thank you!"""
182
+ )
183
+ secret_token = gr.Text(
184
+ label='Secret Token',
185
+ max_lines=1,
186
+ placeholder='Enter your secret token',
187
+ )
188
+ with gr.Accordion("Options/Parameters"):
189
+ with gr.Row():
190
+ model_name = gr.Dropdown(label="Real-ESRGAN inference model to be used",
191
+ choices=["RealESRGAN_x4plus", "RealESRNet_x4plus", "RealESRGAN_x4plus_anime_6B",
192
+ "RealESRGAN_x2plus", "realesr-general-x4v3"],
193
+ value="realesr-general-x4v3", show_label=True)
194
+ denoise_strength = gr.Slider(label="Denoise Strength (Used only with the realesr-general-x4v3 model)",
195
+ minimum=0, maximum=1, step=0.1, value=0.5)
196
+ outscale = gr.Slider(label="Image Upscaling Factor",
197
+ minimum=1, maximum=10, step=1, value=4, show_label=True)
198
+ face_enhance = gr.Checkbox(label="Face Enhancement using GFPGAN (Doesn't work for anime images)",
199
+ value=False, show_label=True)
200
+
201
+ with gr.Row():
202
+ with gr.Group():
203
+ input_image = gr.Image(label="Source Image", type="pil", image_mode="RGBA")
204
+ input_image_properties = gr.Textbox(label="Image Properties", max_lines=1)
205
+ output_image = gr.Image(label="Restored Image", image_mode="RGBA")
206
+ with gr.Row():
207
+ restore_btn = gr.Button("Upscale")
208
+
209
+ # Event listeners:
210
+ input_image.change(fn=image_properties, inputs=input_image, outputs=input_image_properties)
211
+ restore_btn.click(fn=realesrgan,
212
+ inputs=[secret_token, input_image, model_name, denoise_strength, face_enhance, outscale],
213
+ outputs=output_image,
214
+ api_name="upscale")
215
+
216
+ gr.Markdown(
217
+ """*Please note that support for animated GIFs is not yet implemented. Should an animated GIF is chosen for restoration,
218
+ the demo will output only the first frame saved in PNG format (to preserve probable transparency).*
219
+ """
220
+ )
221
+
222
+ demo.launch()
223
+
224
+
225
+ if __name__ == "__main__":
226
+ main()