scunet_model.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import sys
  2. import PIL.Image
  3. import numpy as np
  4. import torch
  5. import modules.upscaler
  6. from modules import devices, modelloader, script_callbacks, errors
  7. from modules.shared import opts
  8. from modules.upscaler_utils import tiled_upscale_2
  9. class UpscalerScuNET(modules.upscaler.Upscaler):
  10. def __init__(self, dirname):
  11. self.name = "ScuNET"
  12. self.model_name = "ScuNET GAN"
  13. self.model_name2 = "ScuNET PSNR"
  14. self.model_url = "https://github.com/cszn/KAIR/releases/download/v1.0/scunet_color_real_gan.pth"
  15. self.model_url2 = "https://github.com/cszn/KAIR/releases/download/v1.0/scunet_color_real_psnr.pth"
  16. self.user_path = dirname
  17. super().__init__()
  18. model_paths = self.find_models(ext_filter=[".pth"])
  19. scalers = []
  20. add_model2 = True
  21. for file in model_paths:
  22. if file.startswith("http"):
  23. name = self.model_name
  24. else:
  25. name = modelloader.friendly_name(file)
  26. if name == self.model_name2 or file == self.model_url2:
  27. add_model2 = False
  28. try:
  29. scaler_data = modules.upscaler.UpscalerData(name, file, self, 4)
  30. scalers.append(scaler_data)
  31. except Exception:
  32. errors.report(f"Error loading ScuNET model: {file}", exc_info=True)
  33. if add_model2:
  34. scaler_data2 = modules.upscaler.UpscalerData(self.model_name2, self.model_url2, self)
  35. scalers.append(scaler_data2)
  36. self.scalers = scalers
  37. def do_upscale(self, img: PIL.Image.Image, selected_file):
  38. devices.torch_gc()
  39. try:
  40. model = self.load_model(selected_file)
  41. except Exception as e:
  42. print(f"ScuNET: Unable to load model from {selected_file}: {e}", file=sys.stderr)
  43. return img
  44. device = devices.get_device_for('scunet')
  45. tile = opts.SCUNET_tile
  46. h, w = img.height, img.width
  47. np_img = np.array(img)
  48. np_img = np_img[:, :, ::-1] # RGB to BGR
  49. np_img = np_img.transpose((2, 0, 1)) / 255 # HWC to CHW
  50. torch_img = torch.from_numpy(np_img).float().unsqueeze(0).to(device) # type: ignore
  51. if tile > h or tile > w:
  52. _img = torch.zeros(1, 3, max(h, tile), max(w, tile), dtype=torch_img.dtype, device=torch_img.device)
  53. _img[:, :, :h, :w] = torch_img # pad image
  54. torch_img = _img
  55. with torch.no_grad():
  56. torch_output = tiled_upscale_2(
  57. torch_img,
  58. model,
  59. tile_size=opts.SCUNET_tile,
  60. tile_overlap=opts.SCUNET_tile_overlap,
  61. scale=1,
  62. device=devices.get_device_for('scunet'),
  63. desc="ScuNET tiles",
  64. ).squeeze(0)
  65. torch_output = torch_output[:, :h * 1, :w * 1] # remove padding, if any
  66. np_output: np.ndarray = torch_output.float().cpu().clamp_(0, 1).numpy()
  67. del torch_img, torch_output
  68. devices.torch_gc()
  69. output = np_output.transpose((1, 2, 0)) # CHW to HWC
  70. output = output[:, :, ::-1] # BGR to RGB
  71. return PIL.Image.fromarray((output * 255).astype(np.uint8))
  72. def load_model(self, path: str):
  73. device = devices.get_device_for('scunet')
  74. if path.startswith("http"):
  75. # TODO: this doesn't use `path` at all?
  76. filename = modelloader.load_file_from_url(self.model_url, model_dir=self.model_download_path, file_name=f"{self.name}.pth")
  77. else:
  78. filename = path
  79. return modelloader.load_spandrel_model(filename, device=device, expected_architecture='SCUNet')
  80. def on_ui_settings():
  81. import gradio as gr
  82. from modules import shared
  83. shared.opts.add_option("SCUNET_tile", shared.OptionInfo(256, "Tile size for SCUNET upscalers.", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}, section=('upscaling', "Upscaling")).info("0 = no tiling"))
  84. shared.opts.add_option("SCUNET_tile_overlap", shared.OptionInfo(8, "Tile overlap for SCUNET upscalers.", gr.Slider, {"minimum": 0, "maximum": 64, "step": 1}, section=('upscaling', "Upscaling")).info("Low values = visible seam"))
  85. script_callbacks.on_ui_settings(on_ui_settings)