|
import math |
|
import os |
|
from pathlib import Path |
|
from typing import Union |
|
|
|
import cv2 |
|
import numpy as np |
|
from basicsr.archs.rrdbnet_arch import RRDBNet |
|
from basicsr.archs.srvgg_arch import SRVGGNetCompact |
|
from basicsr.utils.download_util import load_file_from_url |
|
from gfpgan import GFPGANer |
|
from PIL import Image |
|
from realesrgan import RealESRGANer |
|
|
|
import internals.util.image as ImageUtil |
|
from internals.util.commons import download_image |
|
from internals.util.config import get_root_dir |
|
from models.ultrasharp.model import Ultrasharp |
|
|
|
|
|
class Upscaler: |
|
__model_esrgan_url = "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth" |
|
__model_esrgan_anime_url = "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth" |
|
__model_gfpgan_url = ( |
|
"https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth" |
|
) |
|
__model_4x_ultrasharp_url = ( |
|
"https://comic-assets.s3.ap-south-1.amazonaws.com/models/4x-UltraSharp.pth" |
|
) |
|
|
|
__loaded = False |
|
|
|
def load(self): |
|
if self.__loaded: |
|
return |
|
|
|
download_dir = Path(Path.home() / ".cache" / "realesrgan") |
|
download_dir.mkdir(parents=True, exist_ok=True) |
|
|
|
self.__model_path = self.__preload_model(self.__model_esrgan_url, download_dir) |
|
self.__model_path_anime = self.__preload_model( |
|
self.__model_esrgan_anime_url, download_dir |
|
) |
|
self.__model_path_gfpgan = self.__preload_model( |
|
self.__model_gfpgan_url, download_dir |
|
) |
|
self.__model_path_4x_ultrasharp = self.__preload_model( |
|
self.__model_4x_ultrasharp_url, download_dir |
|
) |
|
self.__loaded = True |
|
|
|
def upscale( |
|
self, |
|
image: Union[str, Image.Image], |
|
width: int, |
|
height: int, |
|
face_enhance: bool, |
|
resize_dimension: int, |
|
) -> bytes: |
|
model = SRVGGNetCompact( |
|
num_in_ch=3, |
|
num_out_ch=3, |
|
num_feat=64, |
|
num_conv=32, |
|
upscale=4, |
|
act_type="prelu", |
|
) |
|
return self.__internal_upscale( |
|
image, |
|
resize_dimension, |
|
face_enhance, |
|
width, |
|
height, |
|
self.__model_path, |
|
model, |
|
) |
|
|
|
def upscale_anime( |
|
self, |
|
image: Union[str, Image.Image], |
|
width: int, |
|
height: int, |
|
face_enhance: bool, |
|
resize_dimension: int, |
|
) -> bytes: |
|
model = RRDBNet( |
|
num_in_ch=3, |
|
num_out_ch=3, |
|
num_feat=64, |
|
num_block=23, |
|
num_grow_ch=32, |
|
scale=4, |
|
) |
|
return self.__internal_upscale( |
|
image, |
|
resize_dimension, |
|
face_enhance, |
|
width, |
|
height, |
|
self.__model_path_anime, |
|
model, |
|
) |
|
|
|
def __preload_model(self, url: str, download_dir: Path): |
|
name = url.split("/")[-1] |
|
if not os.path.exists(str(download_dir / name)): |
|
return load_file_from_url( |
|
url=url, |
|
model_dir=str(download_dir), |
|
progress=True, |
|
file_name=None, |
|
) |
|
else: |
|
return str(download_dir / name) |
|
|
|
def __internal_upscale( |
|
self, |
|
image, |
|
resize_dimension: int, |
|
face_enhance: bool, |
|
width: int, |
|
height: int, |
|
model_path: str, |
|
model, |
|
) -> bytes: |
|
if type(image) is str: |
|
image = download_image(image) |
|
w, h = image.size |
|
if max(w, h) > 1536: |
|
image = ImageUtil.resize_image(image, dimension=1536) |
|
|
|
in_path = str(Path.home() / ".cache" / "input_upscale.png") |
|
image.save(in_path) |
|
input_image = cv2.imread(in_path, cv2.IMREAD_UNCHANGED) |
|
dimension = min(input_image.shape[0], input_image.shape[1]) |
|
scale = max(math.floor(resize_dimension / dimension), 2) |
|
|
|
os.chdir(str(Path.home() / ".cache")) |
|
if scale == 4: |
|
print("Using 4x-Ultrasharp") |
|
upsampler = Ultrasharp(self.__model_path_4x_ultrasharp) |
|
else: |
|
print("Using RealESRGANer") |
|
upsampler = RealESRGANer( |
|
scale=4, |
|
model_path=model_path, |
|
model=model, |
|
half=False, |
|
gpu_id="0", |
|
tile=0, |
|
tile_pad=10, |
|
pre_pad=0, |
|
) |
|
face_enhancer = GFPGANer( |
|
model_path=self.__model_path_gfpgan, |
|
upscale=scale, |
|
arch="clean", |
|
channel_multiplier=2, |
|
bg_upsampler=upsampler, |
|
) |
|
|
|
if face_enhance: |
|
_, _, output = face_enhancer.enhance( |
|
input_image, has_aligned=False, only_center_face=False, paste_back=True |
|
) |
|
else: |
|
output, _ = upsampler.enhance(input_image, outscale=scale) |
|
os.chdir(get_root_dir()) |
|
cv2.imwrite("out.png", output) |
|
out_bytes = cv2.imencode(".png", output)[1].tobytes() |
|
return out_bytes |
|
|