# Code taken (and slightly adopted) from https://huggingface.co/spaces/havas79/Real-ESRGAN_Demo/blob/main/app.py - credit where credit is due. I am not showcasing code here, but demoing my own trained models ;)
import gradio as gr
import cv2
import numpy
import os
import random
from basicsr.archs.rrdbnet_arch import RRDBNet
from basicsr.utils.download_util import load_file_from_url
from realesrgan import RealESRGANer
from realesrgan.archs.srvgg_arch import SRVGGNetCompact
last_file = None
img_mode = "RGBA"
def realesrgan(img, model_name, face_enhance):
global last_file
# remove last upscale when doing this new upscale to prevent memory being full
if last_file:
print(f"Deleting {last_file} ...")
os.remove(last_file)
last_file = None
if not img:
return
imgwidth, imgheight = img.size
if imgwidth > 1000 or imgheight > 1000:
return error("Input Image too big")
# Define model parameters
if model_name == '2x Fast Upscale':
model = SRVGGNetCompact(num_in_ch=3, num_out_ch=3, num_feat=64, num_conv=16, upscale=2, act_type='prelu')
netscale = 2
model_name = '2xNomosUni_compact_multijpg'
elif model_name == '2x Upscale':
model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=2)
netscale = 2
model_name = '2xNomosUni_esrgan_multijpg'
# Determine model paths
model_path = os.path.join('weights', model_name + '.pth')
# Restorer Class
upsampler = RealESRGANer(
scale=netscale,
model_path=model_path,
dni_weight=None,
model=model,
tile=128,
tile_pad=10,
pre_pad=10,
half=False,
gpu_id=None,
)
# Use GFPGAN for face enhancement
if face_enhance:
from gfpgan import GFPGANer
face_enhancer = GFPGANer(
model_path='https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth',
upscale=netscale,
arch='clean',
channel_multiplier=2,
bg_upsampler=upsampler)
# Convert the input PIL image to cv2 image, so that it can be processed by realesrgan
cv_img = numpy.array(img)
img = cv2.cvtColor(cv_img, cv2.COLOR_RGBA2BGRA)
# Apply restoration
try:
if face_enhance:
_, _, output = face_enhancer.enhance(img, has_aligned=False, only_center_face=False, paste_back=True)
else:
output, _ = upsampler.enhance(img, netscale)
except RuntimeError as error:
print('Error', error)
print('If you encounter CUDA out of memory, try to set --tile with a smaller number.')
else:
# Save restored image and return it to the output Image component
extension = 'jpg'
out_filename = f"output_{rnd_string(16)}.{extension}"
cv2.imwrite(out_filename, output)
last_file = out_filename
return out_filename
def rnd_string(x):
"""Returns a string of 'x' random characters
"""
characters = "abcdefghijklmnopqrstuvwxyz_0123456789"
result = "".join((random.choice(characters)) for i in range(x))
return result
def reset():
"""Resets the Image components of the Gradio interface and deletes
the last processed image
"""
global last_file
if last_file:
print(f"Deleting {last_file} ...")
os.remove(last_file)
last_file = None
return gr.update(value=None), gr.update(value=None)
def has_transparency(img):
"""This function works by first checking to see if a "transparency" property is defined
in the image's info -- if so, we return "True". Then, if the image is using indexed colors
(such as in GIFs), it gets the index of the transparent color in the palette
(img.info.get("transparency", -1)) and checks if it's used anywhere in the canvas
(img.getcolors()). If the image is in RGBA mode, then presumably it has transparency in
it, but it double-checks by getting the minimum and maximum values of every color channel
(img.getextrema()), and checks if the alpha channel's smallest value falls below 255.
https://stackoverflow.com/questions/43864101/python-pil-check-if-image-is-transparent
"""
if img.info.get("transparency", None) is not None:
return True
if img.mode == "P":
transparent = img.info.get("transparency", -1)
for _, index in img.getcolors():
if index == transparent:
return True
elif img.mode == "RGBA":
extrema = img.getextrema()
if extrema[3][0] < 255:
return True
return False
def image_properties(img):
"""Returns the dimensions (width and height) and color mode of the input image and
also sets the global img_mode variable to be used by the realesrgan function
"""
global img_mode
if img:
if has_transparency(img):
img_mode = "RGBA"
else:
img_mode = "RGB"
properties = f"Width: {img.size[0]}, Height: {img.size[1]} | Color Mode: {img_mode}"
return properties
def main():
# Gradio Interface
with gr.Blocks(title="Self-trained ESRGAN models demo", theme="dark") as demo:
gr.Markdown(
"""#
Upscale Image
Here I demo two of my self-trained models which can be used to upscale an image.
"""
)
with gr.Group():
with gr.Group():
model_name = gr.Dropdown(label="Model to be used",
choices=["2x Fast Upscale", "2x Upscale"], value="2x Fast Upscale",
info="See model infos at the bottom of this page")
face_enhance = gr.Checkbox(label="Face Enhancement using GFPGAN (Doesn't work for anime images)",value=False, show_label=True)
with gr.Group():
input_image = gr.Image(label="Source Image", type="pil", image_mode="RGB")
input_image_properties = gr.Textbox(label="Image Properties - Demo will throw error if input image has either width or height > 1000. Output download is jpg for smaller size. Use models locally to circument these limits.", max_lines=1)
with gr.Group():
output_image = gr.Image(label="Upscaled Image", type="pil", image_mode="RGB", interactive=False)
output_image_properties = gr.Textbox(label="Image Properties", max_lines=1)
with gr.Row():
upscale_btn = gr.Button("Upscale")
reset_btn = gr.Button("Reset")
with gr.Group():
gr.Markdown(""" **Examples are not pre-cached. You need to press the Upscale Button after selecting one**""")
gr.Examples(examples="examples",inputs=[input_image, model_name, face_enhance],outputs=output_image,fn=realesrgan, cache_examples=False)
gr.Markdown(
"""
**Details**
These two 2x models are a universal Compact and ESRGAN upscaling model which I trained and released dec 23, called
2x Fast Upscale: 2xNomosUni_compact_multijpg
2x Upscale: 2xNomosUni_esrgan_multijpg
I trained these using musl's [neosr](https://github.com/muslll/neosr) and Kim's [Dataset Destroyer](https://github.com/Kim2091/helpful-scripts/tree/main/Dataset%20Destroyer) on musl's universal nomos_uni dataset.
You can find more information about upscaling model training on the [training info repo](https://github.com/Upscale-Community/training-info). If you have questions or simply be up to date on new upscaling models released can of course also join our upscaling discord community [Enhance Everything](https://discord.gg/enhance-everything-547949405949657098) and watch the model-releases channel.
You can also run these two and way more models locally on your PC with [chaiNNer](https://github.com/chaiNNer-org/chaiNNer).
This is a [google drive folder](https://drive.google.com/drive/folders/1coYgan0VDo578MVO1LUpjpsxdY3LMyJW?usp=drive_link) with most of my self trained models.
Otherwise you can also find more models on our [Open Model Database](https://openmodeldb.info/)
I called myself 'Helaman' when joining the discord server because that was my gamer name I picked when joining games like league of legends, so I just used it for discord in general and releasing models with it.
My real name is [Philip Hofmann](https://github.com/Phhofm), got into upscaling after trying out Midjourney when it came out, then found chaiNNer, then found the old database where there were only textual descriptions of upsclaing models,
but no visual outputs, this is why I gatheres a lot of upscaling models, used them, then created a [youtube vid](https://youtu.be/0TYRDmQ5LZk) in oct 22, made [reddit posts](https://www.reddit.com/r/StableDiffusion/comments/yev37i/comparison_of_upscaling_models_for_ai_generated/), made a [vitepress website](https://phhofm.github.io/upscale/) to compare the visual outputs of over 300 different upsaling models
then thought about training models myself instead of just using and comparing existing ones, so I got into upscale training, made [youtube videos](https://youtu.be/l_tZE5l90VY) about it, more [reddit posts](https://www.reddit.com/r/StableDiffusion/comments/17d88rt/selftrained_sd_upscaling_models/), released my self trained models in discord, helped with testing neosr, trained different networks/architectures like SRFormer, [DAT](https://github.com/zhengchen1999/DAT) where my model got features on the devs readme :D and so forth, just a lot of experiments/models, probably released around 50 models so far, it has been fun and fascinating.
To keep up on latest sisr (single image super resolution) networks (architectures) one can also follow the [papers with code image super resolution task](https://paperswithcode.com/task/image-super-resolution/latest) where interesting papers with code bases get published frequently. Also the [Awesome Image Super Resolution Repo](https://github.com/ChaofWang/Awesome-Super-Resolution). Its a fascinating and huge field with a lot of stuff to learn about.
Face enhance: [GFPGANv1.4](https://github.com/TencentARC/GFPGAN)
""")
# Event listeners:
input_image.change(fn=image_properties, inputs=input_image, outputs=input_image_properties)
output_image.change(fn=image_properties, inputs=output_image, outputs=output_image_properties)
upscale_btn.click(fn=realesrgan, inputs=[input_image, model_name, face_enhance], outputs=output_image)
reset_btn.click(fn=reset, inputs=[], outputs=[output_image, input_image])
demo.launch()
if __name__ == "__main__":
main()