158 lines
5.9 KiB
Python
158 lines
5.9 KiB
Python
import os
|
|
|
|
import numpy as np
|
|
import torch
|
|
from PIL import Image
|
|
from basicsr.utils.download_util import load_file_from_url
|
|
|
|
import modules.esrgan_model_arch as arch
|
|
from modules import shared, modelloader, images, devices
|
|
from modules.upscaler import Upscaler, UpscalerData
|
|
from modules.shared import opts
|
|
|
|
|
|
def fix_model_layers(crt_model, pretrained_net):
|
|
# this code is adapted from https://github.com/xinntao/ESRGAN
|
|
if 'conv_first.weight' in pretrained_net:
|
|
return pretrained_net
|
|
|
|
if 'model.0.weight' not in pretrained_net:
|
|
is_realesrgan = "params_ema" in pretrained_net and 'body.0.rdb1.conv1.weight' in pretrained_net["params_ema"]
|
|
if is_realesrgan:
|
|
raise Exception("The file is a RealESRGAN model, it can't be used as a ESRGAN model.")
|
|
else:
|
|
raise Exception("The file is not a ESRGAN model.")
|
|
|
|
crt_net = crt_model.state_dict()
|
|
load_net_clean = {}
|
|
for k, v in pretrained_net.items():
|
|
if k.startswith('module.'):
|
|
load_net_clean[k[7:]] = v
|
|
else:
|
|
load_net_clean[k] = v
|
|
pretrained_net = load_net_clean
|
|
|
|
tbd = []
|
|
for k, v in crt_net.items():
|
|
tbd.append(k)
|
|
|
|
# directly copy
|
|
for k, v in crt_net.items():
|
|
if k in pretrained_net and pretrained_net[k].size() == v.size():
|
|
crt_net[k] = pretrained_net[k]
|
|
tbd.remove(k)
|
|
|
|
crt_net['conv_first.weight'] = pretrained_net['model.0.weight']
|
|
crt_net['conv_first.bias'] = pretrained_net['model.0.bias']
|
|
|
|
for k in tbd.copy():
|
|
if 'RDB' in k:
|
|
ori_k = k.replace('RRDB_trunk.', 'model.1.sub.')
|
|
if '.weight' in k:
|
|
ori_k = ori_k.replace('.weight', '.0.weight')
|
|
elif '.bias' in k:
|
|
ori_k = ori_k.replace('.bias', '.0.bias')
|
|
crt_net[k] = pretrained_net[ori_k]
|
|
tbd.remove(k)
|
|
|
|
crt_net['trunk_conv.weight'] = pretrained_net['model.1.sub.23.weight']
|
|
crt_net['trunk_conv.bias'] = pretrained_net['model.1.sub.23.bias']
|
|
crt_net['upconv1.weight'] = pretrained_net['model.3.weight']
|
|
crt_net['upconv1.bias'] = pretrained_net['model.3.bias']
|
|
crt_net['upconv2.weight'] = pretrained_net['model.6.weight']
|
|
crt_net['upconv2.bias'] = pretrained_net['model.6.bias']
|
|
crt_net['HRconv.weight'] = pretrained_net['model.8.weight']
|
|
crt_net['HRconv.bias'] = pretrained_net['model.8.bias']
|
|
crt_net['conv_last.weight'] = pretrained_net['model.10.weight']
|
|
crt_net['conv_last.bias'] = pretrained_net['model.10.bias']
|
|
|
|
return crt_net
|
|
|
|
class UpscalerESRGAN(Upscaler):
|
|
def __init__(self, dirname):
|
|
self.name = "ESRGAN"
|
|
self.model_url = "https://github.com/cszn/KAIR/releases/download/v1.0/ESRGAN.pth"
|
|
self.model_name = "ESRGAN_4x"
|
|
self.scalers = []
|
|
self.user_path = dirname
|
|
super().__init__()
|
|
model_paths = self.find_models(ext_filter=[".pt", ".pth"])
|
|
scalers = []
|
|
if len(model_paths) == 0:
|
|
scaler_data = UpscalerData(self.model_name, self.model_url, self, 4)
|
|
scalers.append(scaler_data)
|
|
for file in model_paths:
|
|
if "http" in file:
|
|
name = self.model_name
|
|
else:
|
|
name = modelloader.friendly_name(file)
|
|
|
|
scaler_data = UpscalerData(name, file, self, 4)
|
|
self.scalers.append(scaler_data)
|
|
|
|
def do_upscale(self, img, selected_model):
|
|
model = self.load_model(selected_model)
|
|
if model is None:
|
|
return img
|
|
model.to(devices.device_esrgan)
|
|
img = esrgan_upscale(model, img)
|
|
return img
|
|
|
|
def load_model(self, path: str):
|
|
if "http" in path:
|
|
filename = load_file_from_url(url=self.model_url, model_dir=self.model_path,
|
|
file_name="%s.pth" % self.model_name,
|
|
progress=True)
|
|
else:
|
|
filename = path
|
|
if not os.path.exists(filename) or filename is None:
|
|
print("Unable to load %s from %s" % (self.model_path, filename))
|
|
return None
|
|
|
|
pretrained_net = torch.load(filename, map_location='cpu' if devices.device_esrgan.type == 'mps' else None)
|
|
crt_model = arch.RRDBNet(3, 3, 64, 23, gc=32)
|
|
|
|
pretrained_net = fix_model_layers(crt_model, pretrained_net)
|
|
crt_model.load_state_dict(pretrained_net)
|
|
crt_model.eval()
|
|
|
|
return crt_model
|
|
|
|
|
|
def upscale_without_tiling(model, img):
|
|
img = np.array(img)
|
|
img = img[:, :, ::-1]
|
|
img = np.moveaxis(img, 2, 0) / 255
|
|
img = torch.from_numpy(img).float()
|
|
img = img.unsqueeze(0).to(devices.device_esrgan)
|
|
with torch.no_grad():
|
|
output = model(img)
|
|
output = output.squeeze().float().cpu().clamp_(0, 1).numpy()
|
|
output = 255. * np.moveaxis(output, 0, 2)
|
|
output = output.astype(np.uint8)
|
|
output = output[:, :, ::-1]
|
|
return Image.fromarray(output, 'RGB')
|
|
|
|
|
|
def esrgan_upscale(model, img):
|
|
if opts.ESRGAN_tile == 0:
|
|
return upscale_without_tiling(model, img)
|
|
|
|
grid = images.split_grid(img, opts.ESRGAN_tile, opts.ESRGAN_tile, opts.ESRGAN_tile_overlap)
|
|
newtiles = []
|
|
scale_factor = 1
|
|
|
|
for y, h, row in grid.tiles:
|
|
newrow = []
|
|
for tiledata in row:
|
|
x, w, tile = tiledata
|
|
|
|
output = upscale_without_tiling(model, tile)
|
|
scale_factor = output.width // tile.width
|
|
|
|
newrow.append([x * scale_factor, w * scale_factor, output])
|
|
newtiles.append([y * scale_factor, h * scale_factor, newrow])
|
|
|
|
newgrid = images.Grid(newtiles, grid.tile_w * scale_factor, grid.tile_h * scale_factor, grid.image_w * scale_factor, grid.image_h * scale_factor, grid.overlap * scale_factor)
|
|
output = images.combine_grid(newgrid)
|
|
return output
|