Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f83472d011 | ||
|
|
e1b8832f1b | ||
|
|
6ff747174d | ||
|
|
c1669c4b0a | ||
|
|
18a9c386a8 | ||
|
|
b659608fb3 | ||
|
|
ee5f7b34cb | ||
|
|
3ce826cabe | ||
|
|
2c20a354b6 | ||
|
|
3e1f780f51 | ||
|
|
f5ccd64ce5 | ||
|
|
194c2c14b3 | ||
|
|
0fcb49a299 | ||
|
|
9976a34454 | ||
|
|
424a09457b | ||
|
|
52f77e74a8 | ||
|
|
bfa4678bef | ||
|
|
68f9f2445e | ||
|
|
7840a3d16a | ||
|
|
b28958cdf2 | ||
|
|
667e34e7ca | ||
|
|
978def19a6 | ||
|
|
a7153c7fce | ||
|
|
00116244cb | ||
|
|
571b89257a | ||
|
|
bed7df7d99 | ||
|
|
fb3ff055e4 | ||
|
|
9ef97853f9 | ||
|
|
58fea8db69 | ||
|
|
3c6cf5290e |
34
.github/workflows/no-response.yml
vendored
Normal file
34
.github/workflows/no-response.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
name: No Response
|
||||||
|
|
||||||
|
# Modified from: https://raw.githubusercontent.com/github/docs/main/.github/workflows/no-response.yaml
|
||||||
|
|
||||||
|
# **What it does**: Closes issues that don't have enough information to be
|
||||||
|
# actionable.
|
||||||
|
# **Why we have it**: To remove the need for maintainers to remember to check
|
||||||
|
# back on issues periodically to see if contributors have
|
||||||
|
# responded.
|
||||||
|
# **Who does it impact**: Everyone that works on docs or docs-internal.
|
||||||
|
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [created]
|
||||||
|
|
||||||
|
schedule:
|
||||||
|
# Schedule for five minutes after the hour every hour
|
||||||
|
- cron: '5 * * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
noResponse:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: lee-dohm/no-response@v0.5.0
|
||||||
|
with:
|
||||||
|
token: ${{ github.token }}
|
||||||
|
closeComment: >
|
||||||
|
This issue has been automatically closed because there has been no response
|
||||||
|
to our request for more information from the original author. With only the
|
||||||
|
information that is currently in the issue, we don't have enough information
|
||||||
|
to take action. Please reach out if you have or find the answers we need so
|
||||||
|
that we can investigate further.
|
||||||
|
If you still have questions, please improve your description and re-open it.
|
||||||
|
Thanks :-)
|
||||||
9
.github/workflows/publish-pip.yml
vendored
9
.github/workflows/publish-pip.yml
vendored
@@ -18,12 +18,15 @@ jobs:
|
|||||||
- name: Install PyTorch (cpu)
|
- name: Install PyTorch (cpu)
|
||||||
run: pip install torch==1.7.0+cpu torchvision==0.8.1+cpu -f https://download.pytorch.org/whl/torch_stable.html
|
run: pip install torch==1.7.0+cpu torchvision==0.8.1+cpu -f https://download.pytorch.org/whl/torch_stable.html
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pip install -r requirements.txt
|
run: |
|
||||||
|
pip install basicsr
|
||||||
|
pip install facexlib
|
||||||
|
pip install gfpgan
|
||||||
|
pip install -r requirements.txt
|
||||||
- name: Build and install
|
- name: Build and install
|
||||||
run: rm -rf .eggs && pip install -e .
|
run: rm -rf .eggs && pip install -e .
|
||||||
- name: Build for distribution
|
- name: Build for distribution
|
||||||
# remove bdist_wheel for pip installation with compiling cuda extensions
|
run: python setup.py sdist bdist_wheel
|
||||||
run: python setup.py sdist
|
|
||||||
- name: Publish distribution to PyPI
|
- name: Publish distribution to PyPI
|
||||||
uses: pypa/gh-action-pypi-publish@master
|
uses: pypa/gh-action-pypi-publish@master
|
||||||
with:
|
with:
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,9 +5,9 @@ results/*
|
|||||||
tb_logger/*
|
tb_logger/*
|
||||||
wandb/*
|
wandb/*
|
||||||
tmp/*
|
tmp/*
|
||||||
|
realesrgan/weights/*
|
||||||
|
|
||||||
version.py
|
version.py
|
||||||
.vscode
|
|
||||||
|
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|||||||
19
.vscode/settings.json
vendored
Normal file
19
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"files.trimTrailingWhitespace": true,
|
||||||
|
"editor.wordWrap": "on",
|
||||||
|
"editor.rulers": [
|
||||||
|
80,
|
||||||
|
120
|
||||||
|
],
|
||||||
|
"editor.renderWhitespace": "all",
|
||||||
|
"editor.renderControlCharacters": true,
|
||||||
|
"python.formatting.provider": "yapf",
|
||||||
|
"python.formatting.yapfArgs": [
|
||||||
|
"--style",
|
||||||
|
"{BASED_ON_STYLE = pep8, BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF = true, SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN = true, COLUMN_LIMIT = 120}"
|
||||||
|
],
|
||||||
|
"python.linting.flake8Enabled": true,
|
||||||
|
"python.linting.flake8Args": [
|
||||||
|
"max-line-length=120"
|
||||||
|
],
|
||||||
|
}
|
||||||
45
CONTRIBUTING.md
Normal file
45
CONTRIBUTING.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Contributing to Real-ESRGAN
|
||||||
|
|
||||||
|
We like open-source and want to develop practical algorithms for general image restoration. However, individual strength is limited. So, any kinds of contributions are welcome, such as:
|
||||||
|
|
||||||
|
- New features
|
||||||
|
- New models (your fine-tuned models)
|
||||||
|
- Bug fixes
|
||||||
|
- Typo fixes
|
||||||
|
- Suggestions
|
||||||
|
- Maintenance
|
||||||
|
- Documents
|
||||||
|
- *etc*
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Fork and pull the latest Real-ESRGAN repository
|
||||||
|
1. Checkout a new branch (do not use master branch for PRs)
|
||||||
|
1. Commit your changes
|
||||||
|
1. Create a PR
|
||||||
|
|
||||||
|
**Note**:
|
||||||
|
1. Please check the code style and linting
|
||||||
|
1. The style configuration is specified in [setup.cfg](setup.cfg)
|
||||||
|
1. If you use VSCode, the settings are configured in [.vscode/settings.json](.vscode/settings.json)
|
||||||
|
1. Strongly recommend using `pre-commit hook`. It will check your code style and linting before your commit.
|
||||||
|
1. In the root path of project folder, run `pre-commit install`
|
||||||
|
1. The pre-commit configuration is listed in [.pre-commit-config.yaml](.pre-commit-config.yaml)
|
||||||
|
1. Better to [open a discussion](https://github.com/xinntao/Real-ESRGAN/discussions) before large changes.
|
||||||
|
1. Welcome to discuss :sunglasses:. I will try my best to join the discussion.
|
||||||
|
|
||||||
|
## TODO List
|
||||||
|
|
||||||
|
:zero: The most straightforward way of improving model performance is to fine-tune on some specific datasets.
|
||||||
|
|
||||||
|
Here are some TODOs:
|
||||||
|
|
||||||
|
- [ ] optimize for human faces
|
||||||
|
- [ ] optimize for texts
|
||||||
|
- [ ] support controllable restoration strength
|
||||||
|
|
||||||
|
:one: There are also [several issues](https://github.com/xinntao/Real-ESRGAN/issues) that require helpers to improve. If you can help, please let me know :smile:
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
- [AK391](https://github.com/AK391): Integrate RealESRGAN to [Huggingface Spaces](https://huggingface.co/spaces) with [Gradio](https://github.com/gradio-app/gradio). See [Gradio Web Demo](https://huggingface.co/spaces/akhaliq/Real-ESRGAN).
|
||||||
9
FAQ.md
Normal file
9
FAQ.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# FAQ
|
||||||
|
|
||||||
|
1. **What is the difference of `--netscale` and `outscale`?**
|
||||||
|
|
||||||
|
A: TODO.
|
||||||
|
|
||||||
|
1. **How to select models?**
|
||||||
|
|
||||||
|
A: TODO.
|
||||||
72
README.md
72
README.md
@@ -2,23 +2,42 @@
|
|||||||
|
|
||||||
[](https://github.com/xinntao/Real-ESRGAN/releases)
|
[](https://github.com/xinntao/Real-ESRGAN/releases)
|
||||||
[](https://pypi.org/project/realesrgan/)
|
[](https://pypi.org/project/realesrgan/)
|
||||||
[](https://github.com/xinntao/Real-ESRGAN/issues)
|
[](https://github.com/xinntao/Real-ESRGAN/issues)
|
||||||
|
[](https://github.com/xinntao/Real-ESRGAN/issues)
|
||||||
[](https://github.com/xinntao/Real-ESRGAN/blob/master/LICENSE)
|
[](https://github.com/xinntao/Real-ESRGAN/blob/master/LICENSE)
|
||||||
[](https://github.com/xinntao/Real-ESRGAN/blob/master/.github/workflows/pylint.yml)
|
[](https://github.com/xinntao/Real-ESRGAN/blob/master/.github/workflows/pylint.yml)
|
||||||
[](https://github.com/xinntao/Real-ESRGAN/blob/master/.github/workflows/publish-pip.yml)
|
[](https://github.com/xinntao/Real-ESRGAN/blob/master/.github/workflows/publish-pip.yml)
|
||||||
|
|
||||||
1. [Colab Demo](https://colab.research.google.com/drive/1k2Zod6kSHEvraybHl50Lys0LerhyTMCo?usp=sharing) for Real-ESRGAN <a href="https://colab.research.google.com/drive/1k2Zod6kSHEvraybHl50Lys0LerhyTMCo?usp=sharing"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="google colab logo"></a>.
|
1. [Colab Demo](https://colab.research.google.com/drive/1k2Zod6kSHEvraybHl50Lys0LerhyTMCo?usp=sharing) for Real-ESRGAN <a href="https://colab.research.google.com/drive/1k2Zod6kSHEvraybHl50Lys0LerhyTMCo?usp=sharing"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="google colab logo"></a>.
|
||||||
2. [Portable Windows/Linux/MacOS executable files for Intel/AMD/Nvidia GPU](https://github.com/xinntao/Real-ESRGAN/releases). You can find more information [here](#Portable-executable-files).
|
2. Portable [Windows](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/realesrgan-ncnn-vulkan-20210901-windows.zip) / [Linux](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/realesrgan-ncnn-vulkan-20210901-ubuntu.zip) / [MacOS](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/realesrgan-ncnn-vulkan-20210901-macos.zip) **executable files for Intel/AMD/Nvidia GPU**. You can find more information [here](#Portable-executable-files).
|
||||||
|
|
||||||
Real-ESRGAN aims at developing **Practical Algorithms for General Image Restoration**.<br>
|
Real-ESRGAN aims at developing **Practical Algorithms for General Image Restoration**.<br>
|
||||||
We extend the powerful ESRGAN to a practical restoration application (namely, Real-ESRGAN), which is trained with pure synthetic data.
|
We extend the powerful ESRGAN to a practical restoration application (namely, Real-ESRGAN), which is trained with pure synthetic data.
|
||||||
|
|
||||||
:triangular_flag_on_post: **Updates**
|
:art: Real-ESRGAN needs your contributions. Any contributions are welcome, such as new features/models/typo fixes/suggestions/maintenance, *etc*. See [CONTRIBUTING.md](CONTRIBUTING.md). All contributors are list [here](CONTRIBUTING.md#Contributors).
|
||||||
|
|
||||||
|
:question: Frequently Asked Questions can be found in [FAQ.md](FAQ.md).
|
||||||
|
|
||||||
|
:triangular_flag_on_post: **Updates**
|
||||||
|
- :white_check_mark: Add [*RealESRGAN_x4plus_anime_6B.pth*](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth), which is optimized for **anime** images with much smaller model size. More details and comparisons with [waifu2x](https://github.com/nihui/waifu2x-ncnn-vulkan) are in [**anime_model.md**](docs/anime_model.md)
|
||||||
|
- :white_check_mark: Support finetuning on your own data or paired data (*i.e.*, finetuning ESRGAN). See [here](Training.md#Finetune-Real-ESRGAN-on-your-own-dataset)
|
||||||
|
- :white_check_mark: Integrate [GFPGAN](https://github.com/TencentARC/GFPGAN) to support **face enhancement**.
|
||||||
|
- :white_check_mark: Integrated to [Huggingface Spaces](https://huggingface.co/spaces) with [Gradio](https://github.com/gradio-app/gradio). See [Gradio Web Demo](https://huggingface.co/spaces/akhaliq/Real-ESRGAN). Thanks [@AK391](https://github.com/AK391)
|
||||||
- :white_check_mark: Support arbitrary scale with `--outscale` (It actually further resizes outputs with `LANCZOS4`). Add *RealESRGAN_x2plus.pth* model.
|
- :white_check_mark: Support arbitrary scale with `--outscale` (It actually further resizes outputs with `LANCZOS4`). Add *RealESRGAN_x2plus.pth* model.
|
||||||
- :white_check_mark: [The inference code](inference_realesrgan.py) supports: 1) **tile** options; 2) images with **alpha channel**; 3) **gray** images; 4) **16-bit** images.
|
- :white_check_mark: [The inference code](inference_realesrgan.py) supports: 1) **tile** options; 2) images with **alpha channel**; 3) **gray** images; 4) **16-bit** images.
|
||||||
- :white_check_mark: The training codes have been released. A detailed guide can be found in [Training.md](Training.md).
|
- :white_check_mark: The training codes have been released. A detailed guide can be found in [Training.md](Training.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
If Real-ESRGAN is helpful in your photos/projects, please help to :star: this repo or recommend it to your friends. Thanks:blush: <br>
|
||||||
|
Other recommended projects:<br>
|
||||||
|
:arrow_forward: [GFPGAN](https://github.com/TencentARC/GFPGAN): A practical algorithm for real-world face restoration <br>
|
||||||
|
:arrow_forward: [BasicSR](https://github.com/xinntao/BasicSR): An ppen-source image and video restoration toolbox<br>
|
||||||
|
:arrow_forward: [facexlib](https://github.com/xinntao/facexlib): A collection that provides useful face-relation functions.<br>
|
||||||
|
:arrow_forward: [HandyView](https://github.com/xinntao/HandyView): A PyQt5-based image viewer that is handy for view and comparison. <br>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### :book: Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic Data
|
### :book: Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic Data
|
||||||
|
|
||||||
> [[Paper](https://arxiv.org/abs/2107.10833)]   [Project Page]   [Demo] <br>
|
> [[Paper](https://arxiv.org/abs/2107.10833)]   [Project Page]   [Demo] <br>
|
||||||
@@ -44,7 +63,7 @@ Here is a TODO list in the near future:
|
|||||||
|
|
||||||
- [ ] optimize for human faces
|
- [ ] optimize for human faces
|
||||||
- [ ] optimize for texts
|
- [ ] optimize for texts
|
||||||
- [ ] optimize for animation images
|
- [x] optimize for anime images
|
||||||
- [ ] support more scales
|
- [ ] support more scales
|
||||||
- [ ] support controllable restoration strength
|
- [ ] support controllable restoration strength
|
||||||
|
|
||||||
@@ -55,7 +74,7 @@ If you have some images that Real-ESRGAN could not well restored, please also op
|
|||||||
|
|
||||||
### Portable executable files
|
### Portable executable files
|
||||||
|
|
||||||
You can download **Windows/Linux/MacOS executable files for Intel/AMD/Nvidia GPU** from https://github.com/xinntao/Real-ESRGAN/releases
|
You can download [Windows](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.2/realesrgan-ncnn-vulkan-20210801-windows.zip) / [Linux](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.2/realesrgan-ncnn-vulkan-20210801-ubuntu.zip) / [MacOS](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.2/realesrgan-ncnn-vulkan-20210801-macos.zip) **executable files for Intel/AMD/Nvidia GPU**.
|
||||||
|
|
||||||
This executable file is **portable** and includes all the binaries and models required. No CUDA or PyTorch environment is needed.<br>
|
This executable file is **portable** and includes all the binaries and models required. No CUDA or PyTorch environment is needed.<br>
|
||||||
|
|
||||||
@@ -69,7 +88,7 @@ We have provided three models:
|
|||||||
|
|
||||||
1. realesrgan-x4plus (default)
|
1. realesrgan-x4plus (default)
|
||||||
2. realesrnet-x4plus
|
2. realesrnet-x4plus
|
||||||
3. esrgan-x4
|
3. realesrgan-x4plus-anime (optimized for anime images, small model size)
|
||||||
|
|
||||||
You can use the `-n` argument for other models, for example, `./realesrgan-ncnn-vulkan.exe -i input.jpg -o output.png -n realesrnet-x4plus`
|
You can use the `-n` argument for other models, for example, `./realesrgan-ncnn-vulkan.exe -i input.jpg -o output.png -n realesrnet-x4plus`
|
||||||
|
|
||||||
@@ -99,15 +118,18 @@ This executable file is based on the wonderful [Tencent/ncnn](https://github.com
|
|||||||
# Install basicsr - https://github.com/xinntao/BasicSR
|
# Install basicsr - https://github.com/xinntao/BasicSR
|
||||||
# We use BasicSR for both training and inference
|
# We use BasicSR for both training and inference
|
||||||
pip install basicsr
|
pip install basicsr
|
||||||
|
# facexlib and gfpgan are for face enhancement
|
||||||
|
pip install facexlib
|
||||||
|
pip install gfpgan
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
python setup.py develop
|
python setup.py develop
|
||||||
```
|
```
|
||||||
|
|
||||||
## :zap: Quick Inference
|
## :zap: Quick Inference
|
||||||
|
|
||||||
Download pre-trained models: [RealESRGAN_x4plus.pth](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth)
|
### Inference general images
|
||||||
|
|
||||||
Download pretrained models:
|
Download pre-trained models: [RealESRGAN_x4plus.pth](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth -P experiments/pretrained_models
|
wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth -P experiments/pretrained_models
|
||||||
@@ -116,19 +138,41 @@ wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_
|
|||||||
Inference!
|
Inference!
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python inference_realesrgan.py --model_path experiments/pretrained_models/RealESRGAN_x4plus.pth --input inputs
|
python inference_realesrgan.py --model_path experiments/pretrained_models/RealESRGAN_x4plus.pth --input inputs --face_enhance
|
||||||
|
```
|
||||||
|
|
||||||
|
Results are in the `results` folder
|
||||||
|
|
||||||
|
### Inference anime images
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://raw.githubusercontent.com/xinntao/public-figures/master/Real-ESRGAN/cmp_realesrgan_anime_1.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Pre-trained models: [RealESRGAN_x4plus_anime_6B](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth)<br>
|
||||||
|
More details and comparisons with [waifu2x](https://github.com/nihui/waifu2x-ncnn-vulkan) are in [**anime_model.md**](docs/anime_model.md)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# download model
|
||||||
|
wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth -P experiments/pretrained_models
|
||||||
|
# inference
|
||||||
|
python inference_realesrgan.py --model_path experiments/pretrained_models/RealESRGAN_x4plus_anime_6B.pth --input inputs
|
||||||
```
|
```
|
||||||
|
|
||||||
Results are in the `results` folder
|
Results are in the `results` folder
|
||||||
|
|
||||||
## :european_castle: Model Zoo
|
## :european_castle: Model Zoo
|
||||||
|
|
||||||
- [RealESRGAN-x4plus](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth)
|
- [RealESRGAN_x4plus](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth)
|
||||||
- [RealESRNet-x4plus](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.1/RealESRNet_x4plus.pth)
|
- [RealESRGAN_x4plus_netD](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.3/RealESRGAN_x4plus_netD.pth)
|
||||||
- [RealESRGAN-x2plus](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.0/RealESRGAN_x2plus.pth)
|
- [RealESRGAN_x4plus_anime_6B](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth)
|
||||||
- [official ESRGAN-x4](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.1/ESRGAN_SRx4_DF2KOST_official-ff704c30.pth)
|
- [RealESRGAN_x4plus_anime_6B_netD](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B_netD.pth)
|
||||||
|
- [RealESRNet_x4plus](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.1/RealESRNet_x4plus.pth)
|
||||||
|
- [RealESRGAN_x2plus](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.1/RealESRGAN_x2plus.pth)
|
||||||
|
- [RealESRGAN_x2plus_netD](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.3/RealESRGAN_x2plus_netD.pth)
|
||||||
|
- [official ESRGAN_x4](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.1/ESRGAN_SRx4_DF2KOST_official-ff704c30.pth)
|
||||||
|
|
||||||
## :computer: Training
|
## :computer: Training and Finetuning on your own dataset
|
||||||
|
|
||||||
A detailed guide can be found in [Training.md](Training.md).
|
A detailed guide can be found in [Training.md](Training.md).
|
||||||
|
|
||||||
|
|||||||
157
Training.md
157
Training.md
@@ -1,16 +1,24 @@
|
|||||||
# :computer: How to Train Real-ESRGAN
|
# :computer: How to Train/Finetune Real-ESRGAN
|
||||||
|
|
||||||
The training codes have been released. <br>
|
- [Train Real-ESRGAN](#train-real-esrgan)
|
||||||
Note that the codes have a lot of refactoring. So there may be some bugs/performance drops. Welcome to report issues and I will also retrain the models.
|
- [Overview](#overview)
|
||||||
|
- [Dataset Preparation](#dataset-preparation)
|
||||||
|
- [Train Real-ESRNet](#Train-Real-ESRNet)
|
||||||
|
- [Train Real-ESRGAN](#Train-Real-ESRGAN)
|
||||||
|
- [Finetune Real-ESRGAN on your own dataset](#Finetune-Real-ESRGAN-on-your-own-dataset)
|
||||||
|
- [Generate degraded images on the fly](#Generate-degraded-images-on-the-fly)
|
||||||
|
- [Use paired training data](#Use-paired-training-data)
|
||||||
|
|
||||||
## Overview
|
## Train Real-ESRGAN
|
||||||
|
|
||||||
|
### Overview
|
||||||
|
|
||||||
The training has been divided into two stages. These two stages have the same data synthesis process and training pipeline, except for the loss functions. Specifically,
|
The training has been divided into two stages. These two stages have the same data synthesis process and training pipeline, except for the loss functions. Specifically,
|
||||||
|
|
||||||
1. We first train Real-ESRNet with L1 loss from the pre-trained model ESRGAN.
|
1. We first train Real-ESRNet with L1 loss from the pre-trained model ESRGAN.
|
||||||
1. We then use the trained Real-ESRNet model as an initialization of the generator, and train the Real-ESRGAN with a combination of L1 loss, perceptual loss and GAN loss.
|
1. We then use the trained Real-ESRNet model as an initialization of the generator, and train the Real-ESRGAN with a combination of L1 loss, perceptual loss and GAN loss.
|
||||||
|
|
||||||
## Dataset Preparation
|
### Dataset Preparation
|
||||||
|
|
||||||
We use DF2K (DIV2K and Flickr2K) + OST datasets for our training. Only HR images are required. <br>
|
We use DF2K (DIV2K and Flickr2K) + OST datasets for our training. Only HR images are required. <br>
|
||||||
You can download from :
|
You can download from :
|
||||||
@@ -19,9 +27,30 @@ You can download from :
|
|||||||
2. Flickr2K: https://cv.snu.ac.kr/research/EDSR/Flickr2K.tar
|
2. Flickr2K: https://cv.snu.ac.kr/research/EDSR/Flickr2K.tar
|
||||||
3. OST: https://openmmlab.oss-cn-hangzhou.aliyuncs.com/datasets/OST_dataset.zip
|
3. OST: https://openmmlab.oss-cn-hangzhou.aliyuncs.com/datasets/OST_dataset.zip
|
||||||
|
|
||||||
For the DF2K dataset, we use a multi-scale strategy, *i.e.*, we downsample HR images to obtain several Ground-Truth images with different scales.
|
Here are steps for data preparation.
|
||||||
|
|
||||||
We then crop DF2K images into sub-images for faster IO and processing.
|
#### Step 1: [Optional] Generate multi-scale images
|
||||||
|
|
||||||
|
For the DF2K dataset, we use a multi-scale strategy, *i.e.*, we downsample HR images to obtain several Ground-Truth images with different scales. <br>
|
||||||
|
You can use the [scripts/generate_multiscale_DF2K.py](scripts/generate_multiscale_DF2K.py) script to geneate multi-scale images. <br>
|
||||||
|
Note that this step can be omitted if you just want to have a fast try.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python scripts/generate_multiscale_DF2K.py --input datasets/DF2K/DF2K_HR --output datasets/DF2K/DF2K_multiscale
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 2: [Optional] Crop to sub-images
|
||||||
|
|
||||||
|
We then crop DF2K images into sub-images for faster IO and processing.<br>
|
||||||
|
This step is optional if your IO is enough or your disk space is limited.
|
||||||
|
|
||||||
|
You can use the [scripts/extract_subimages.py](scripts/extract_subimages.py) script. Here is the example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python scripts/extract_subimages.py --input datasets/DF2K/DF2K_multiscale --output datasets/DF2K/DF2K_multiscale_sub --crop_size 400 --step 200
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 3: Prepare a txt for meta information
|
||||||
|
|
||||||
You need to prepare a txt file containing the image paths. The following are some examples in `meta_info_DF2Kmultiscale+OST_sub.txt` (As different users may have different sub-images partitions, this file is not suitable for your purpose and you need to prepare your own txt file):
|
You need to prepare a txt file containing the image paths. The following are some examples in `meta_info_DF2Kmultiscale+OST_sub.txt` (As different users may have different sub-images partitions, this file is not suitable for your purpose and you need to prepare your own txt file):
|
||||||
|
|
||||||
@@ -32,7 +61,14 @@ DF2K_HR_sub/000001_s003.png
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
## Train Real-ESRNet
|
You can use the [scripts/generate_meta_info.py](scripts/generate_meta_info.py) script to generate the txt file. <br>
|
||||||
|
You can merge several folders into one meta_info txt. Here is the example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python scripts/generate_meta_info.py --input datasets/DF2K/DF2K_HR, datasets/DF2K/DF2K_multiscale --root datasets/DF2K, datasets/DF2K --meta_info datasets/DF2K/meta_info/meta_info_DF2Kmultiscale.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Train Real-ESRNet
|
||||||
|
|
||||||
1. Download pre-trained model [ESRGAN](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.1/ESRGAN_SRx4_DF2KOST_official-ff704c30.pth) into `experiments/pretrained_models`.
|
1. Download pre-trained model [ESRGAN](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.1/ESRGAN_SRx4_DF2KOST_official-ff704c30.pth) into `experiments/pretrained_models`.
|
||||||
```bash
|
```bash
|
||||||
@@ -84,7 +120,7 @@ DF2K_HR_sub/000001_s003.png
|
|||||||
python -m torch.distributed.launch --nproc_per_node=4 --master_port=4321 realesrgan/train.py -opt options/train_realesrnet_x4plus.yml --launcher pytorch --auto_resume
|
python -m torch.distributed.launch --nproc_per_node=4 --master_port=4321 realesrgan/train.py -opt options/train_realesrnet_x4plus.yml --launcher pytorch --auto_resume
|
||||||
```
|
```
|
||||||
|
|
||||||
## Train Real-ESRGAN
|
### Train Real-ESRGAN
|
||||||
|
|
||||||
1. After the training of Real-ESRNet, you now have the file `experiments/train_RealESRNetx4plus_1000k_B12G4_fromESRGAN/model/net_g_1000000.pth`. If you need to specify the pre-trained path to other files, modify the `pretrain_network_g` value in the option file `train_realesrgan_x4plus.yml`.
|
1. After the training of Real-ESRNet, you now have the file `experiments/train_RealESRNetx4plus_1000k_B12G4_fromESRGAN/model/net_g_1000000.pth`. If you need to specify the pre-trained path to other files, modify the `pretrain_network_g` value in the option file `train_realesrgan_x4plus.yml`.
|
||||||
1. Modify the option file `train_realesrgan_x4plus.yml` accordingly. Most modifications are similar to those listed above.
|
1. Modify the option file `train_realesrgan_x4plus.yml` accordingly. Most modifications are similar to those listed above.
|
||||||
@@ -98,3 +134,106 @@ DF2K_HR_sub/000001_s003.png
|
|||||||
CUDA_VISIBLE_DEVICES=0,1,2,3 \
|
CUDA_VISIBLE_DEVICES=0,1,2,3 \
|
||||||
python -m torch.distributed.launch --nproc_per_node=4 --master_port=4321 realesrgan/train.py -opt options/train_realesrgan_x4plus.yml --launcher pytorch --auto_resume
|
python -m torch.distributed.launch --nproc_per_node=4 --master_port=4321 realesrgan/train.py -opt options/train_realesrgan_x4plus.yml --launcher pytorch --auto_resume
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Finetune Real-ESRGAN on your own dataset
|
||||||
|
|
||||||
|
You can finetune Real-ESRGAN on your own dataset. Typically, the fine-tuning process can be divided into two cases:
|
||||||
|
|
||||||
|
1. [Generate degraded images on the fly](#Generate-degraded-images-on-the-fly)
|
||||||
|
1. [Use your own **paired** data](#Use-paired-training-data)
|
||||||
|
|
||||||
|
### Generate degraded images on the fly
|
||||||
|
|
||||||
|
Only high-resolution images are required. The low-quality images are generated with the degradation process described in Real-ESRGAN during trainig.
|
||||||
|
|
||||||
|
**1. Prepare dataset**
|
||||||
|
|
||||||
|
See [this section](#dataset-preparation) for more details.
|
||||||
|
|
||||||
|
**2. Download pre-trained models**
|
||||||
|
|
||||||
|
Download pre-trained models into `experiments/pretrained_models`.
|
||||||
|
|
||||||
|
- *RealESRGAN_x4plus.pth*:
|
||||||
|
```bash
|
||||||
|
wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth -P experiments/pretrained_models
|
||||||
|
```
|
||||||
|
|
||||||
|
- *RealESRGAN_x4plus_netD.pth*:
|
||||||
|
```bash
|
||||||
|
wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.3/RealESRGAN_x4plus_netD.pth -P experiments/pretrained_models
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Finetune**
|
||||||
|
|
||||||
|
Modify [options/finetune_realesrgan_x4plus.yml](options/finetune_realesrgan_x4plus.yml) accordingly, especially the `datasets` part:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
train:
|
||||||
|
name: DF2K+OST
|
||||||
|
type: RealESRGANDataset
|
||||||
|
dataroot_gt: datasets/DF2K # modify to the root path of your folder
|
||||||
|
meta_info: realesrgan/meta_info/meta_info_DF2Kmultiscale+OST_sub.txt # modify to your own generate meta info txt
|
||||||
|
io_backend:
|
||||||
|
type: disk
|
||||||
|
```
|
||||||
|
|
||||||
|
We use four GPUs for training. We use the `--auto_resume` argument to automatically resume the training if necessary.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CUDA_VISIBLE_DEVICES=0,1,2,3 \
|
||||||
|
python -m torch.distributed.launch --nproc_per_node=4 --master_port=4321 realesrgan/train.py -opt options/finetune_realesrgan_x4plus.yml --launcher pytorch --auto_resume
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use your own paired data
|
||||||
|
|
||||||
|
You can also finetune RealESRGAN with your own paired data. It is more similar to fine-tuning ESRGAN.
|
||||||
|
|
||||||
|
**1. Prepare dataset**
|
||||||
|
|
||||||
|
Assume that you already have two folders:
|
||||||
|
|
||||||
|
- **gt folder** (Ground-truth, high-resolution images): *datasets/DF2K/DIV2K_train_HR_sub*
|
||||||
|
- **lq folder** (Low quality, low-resolution images): *datasets/DF2K/DIV2K_train_LR_bicubic_X4_sub*
|
||||||
|
|
||||||
|
Then, you can prepare the meta_info txt file using the script [scripts/generate_meta_info_pairdata.py](scripts/generate_meta_info_pairdata.py):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python scripts/generate_meta_info_pairdata.py --input datasets/DF2K/DIV2K_train_HR_sub datasets/DF2K/DIV2K_train_LR_bicubic_X4_sub --meta_info datasets/DF2K/meta_info/meta_info_DIV2K_sub_pair.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Download pre-trained models**
|
||||||
|
|
||||||
|
Download pre-trained models into `experiments/pretrained_models`.
|
||||||
|
|
||||||
|
- *RealESRGAN_x4plus.pth*
|
||||||
|
```bash
|
||||||
|
wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth -P experiments/pretrained_models
|
||||||
|
```
|
||||||
|
|
||||||
|
- *RealESRGAN_x4plus_netD.pth*
|
||||||
|
```bash
|
||||||
|
wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.3/RealESRGAN_x4plus_netD.pth -P experiments/pretrained_models
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Finetune**
|
||||||
|
|
||||||
|
Modify [options/finetune_realesrgan_x4plus_pairdata.yml](options/finetune_realesrgan_x4plus_pairdata.yml) accordingly, especially the `datasets` part:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
train:
|
||||||
|
name: DIV2K
|
||||||
|
type: RealESRGANPairedDataset
|
||||||
|
dataroot_gt: datasets/DF2K # modify to the root path of your folder
|
||||||
|
dataroot_lq: datasets/DF2K # modify to the root path of your folder
|
||||||
|
meta_info: datasets/DF2K/meta_info/meta_info_DIV2K_sub_pair.txt # modify to the root path of your folder
|
||||||
|
io_backend:
|
||||||
|
type: disk
|
||||||
|
```
|
||||||
|
|
||||||
|
We use four GPUs for training. We use the `--auto_resume` argument to automatically resume the training if necessary.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CUDA_VISIBLE_DEVICES=0,1,2,3 \
|
||||||
|
python -m torch.distributed.launch --nproc_per_node=4 --master_port=4321 realesrgan/train.py -opt options/finetune_realesrgan_x4plus_pairdata.yml --launcher pytorch --auto_resume
|
||||||
|
```
|
||||||
|
|||||||
BIN
assets/teaser-text.png
Normal file
BIN
assets/teaser-text.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 546 KiB |
68
docs/anime_model.md
Normal file
68
docs/anime_model.md
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# Anime model
|
||||||
|
|
||||||
|
:white_check_mark: We add [*RealESRGAN_x4plus_anime_6B.pth*](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth), which is optimized for **anime** images with much smaller model size.
|
||||||
|
|
||||||
|
- [How to Use](#How-to-Use)
|
||||||
|
- [PyTorch Inference](#PyTorch-Inference)
|
||||||
|
- [ncnn Executable File](#ncnn-Executable-File)
|
||||||
|
- [Comparisons with waifu2x](#Comparisons-with-waifu2x)
|
||||||
|
- [Comparions with Sliding Bars](#Comparions-with-Sliding-Bars)
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://raw.githubusercontent.com/xinntao/public-figures/master/Real-ESRGAN/cmp_realesrgan_anime_1.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
The following is a video comparison with sliding bar. You may need to use the full-screen mode for better visual quality, as the original image is large; otherwise, you may encounter aliasing issue.
|
||||||
|
|
||||||
|
https://user-images.githubusercontent.com/17445847/131535127-613250d4-f754-4e20-9720-2f9608ad0675.mp4
|
||||||
|
|
||||||
|
## How to Use
|
||||||
|
|
||||||
|
### PyTorch Inference
|
||||||
|
|
||||||
|
Pre-trained models: [RealESRGAN_x4plus_anime_6B](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# download model
|
||||||
|
wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth -P experiments/pretrained_models
|
||||||
|
# inference
|
||||||
|
python inference_realesrgan.py --model_path experiments/pretrained_models/RealESRGAN_x4plus_anime_6B.pth --input inputs
|
||||||
|
```
|
||||||
|
|
||||||
|
### ncnn Executable File
|
||||||
|
|
||||||
|
Download the latest portable [Windows](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/realesrgan-ncnn-vulkan-20210901-windows.zip) / [Linux](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/realesrgan-ncnn-vulkan-20210901-ubuntu.zip) / [MacOS](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/realesrgan-ncnn-vulkan-20210901-macos.zip) **executable files for Intel/AMD/Nvidia GPU**.
|
||||||
|
|
||||||
|
Taking the Windows as example, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./realesrgan-ncnn-vulkan.exe -i input.jpg -o output.png -n realesrgan-x4plus-anime
|
||||||
|
```
|
||||||
|
|
||||||
|
## Comparisons with waifu2x
|
||||||
|
|
||||||
|
We compare Real-ESRGAN-anime with [waifu2x](https://github.com/nihui/waifu2x-ncnn-vulkan). We use the `-n 2 -s 4` for waifu2x.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://raw.githubusercontent.com/xinntao/public-figures/master/Real-ESRGAN/cmp_realesrgan_anime_1.png">
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://raw.githubusercontent.com/xinntao/public-figures/master/Real-ESRGAN/cmp_realesrgan_anime_2.png">
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://raw.githubusercontent.com/xinntao/public-figures/master/Real-ESRGAN/cmp_realesrgan_anime_3.png">
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://raw.githubusercontent.com/xinntao/public-figures/master/Real-ESRGAN/cmp_realesrgan_anime_4.png">
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://raw.githubusercontent.com/xinntao/public-figures/master/Real-ESRGAN/cmp_realesrgan_anime_5.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## Comparisons with Sliding Bars
|
||||||
|
|
||||||
|
The following are video comparisons with sliding bar. You may need to use the full-screen mode for better visual quality, as the original image is large; otherwise, you may encounter aliasing issue.
|
||||||
|
|
||||||
|
https://user-images.githubusercontent.com/17445847/131536647-a2fbf896-b495-4a9f-b1dd-ca7bbc90101a.mp4
|
||||||
|
|
||||||
|
https://user-images.githubusercontent.com/17445847/131536742-6d9d82b6-9765-4296-a15f-18f9aeaa5465.mp4
|
||||||
11
docs/ncnn_conversion.md
Normal file
11
docs/ncnn_conversion.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Instructions on converting to NCNN models
|
||||||
|
|
||||||
|
1. Convert to onnx model with `scripts/pytorch2onnx.py`. Remember to modify codes accordingly
|
||||||
|
1. Convert onnx model to ncnn model
|
||||||
|
1. `cd ncnn-master\ncnn\build\tools\onnx`
|
||||||
|
1. `onnx2ncnn.exe realesrgan-x4.onnx realesrgan-x4-raw.param realesrgan-x4-raw.bin`
|
||||||
|
1. Optimize ncnn model
|
||||||
|
1. fp16 mode
|
||||||
|
1. `cd ncnn-master\ncnn\build\tools`
|
||||||
|
1. `ncnnoptimize.exe realesrgan-x4-raw.param realesrgan-x4-raw.bin realesrgan-x4.param realesrgan-x4.bin 1`
|
||||||
|
1. Modify the blob name in `realesrgan-x4.param`: `data` and `output`
|
||||||
@@ -2,6 +2,7 @@ import argparse
|
|||||||
import cv2
|
import cv2
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
|
from basicsr.archs.rrdbnet_arch import RRDBNet
|
||||||
|
|
||||||
from realesrgan import RealESRGANer
|
from realesrgan import RealESRGANer
|
||||||
|
|
||||||
@@ -21,7 +22,9 @@ def main():
|
|||||||
parser.add_argument('--tile', type=int, default=0, help='Tile size, 0 for no tile during testing')
|
parser.add_argument('--tile', type=int, default=0, help='Tile size, 0 for no tile during testing')
|
||||||
parser.add_argument('--tile_pad', type=int, default=10, help='Tile padding')
|
parser.add_argument('--tile_pad', type=int, default=10, help='Tile padding')
|
||||||
parser.add_argument('--pre_pad', type=int, default=0, help='Pre padding size at each border')
|
parser.add_argument('--pre_pad', type=int, default=0, help='Pre padding size at each border')
|
||||||
|
parser.add_argument('--face_enhance', action='store_true', help='Use GFPGAN to enhance face')
|
||||||
parser.add_argument('--half', action='store_true', help='Use half precision during inference')
|
parser.add_argument('--half', action='store_true', help='Use half precision during inference')
|
||||||
|
parser.add_argument('--block', type=int, default=23, help='num_block in RRDB')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--alpha_upsampler',
|
'--alpha_upsampler',
|
||||||
type=str,
|
type=str,
|
||||||
@@ -34,14 +37,32 @@ def main():
|
|||||||
help='Image extension. Options: auto | jpg | png, auto means using the same extension as inputs')
|
help='Image extension. Options: auto | jpg | png, auto means using the same extension as inputs')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if 'RealESRGAN_x4plus_anime_6B.pth' in args.model_path:
|
||||||
|
args.block = 6
|
||||||
|
elif 'RealESRGAN_x2plus.pth' in args.model_path:
|
||||||
|
args.netscale = 2
|
||||||
|
|
||||||
|
model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=args.block, num_grow_ch=32, scale=args.netscale)
|
||||||
|
|
||||||
upsampler = RealESRGANer(
|
upsampler = RealESRGANer(
|
||||||
scale=args.netscale,
|
scale=args.netscale,
|
||||||
model_path=args.model_path,
|
model_path=args.model_path,
|
||||||
|
model=model,
|
||||||
tile=args.tile,
|
tile=args.tile,
|
||||||
tile_pad=args.tile_pad,
|
tile_pad=args.tile_pad,
|
||||||
pre_pad=args.pre_pad,
|
pre_pad=args.pre_pad,
|
||||||
half=args.half)
|
half=args.half)
|
||||||
|
|
||||||
|
if args.face_enhance:
|
||||||
|
from gfpgan import GFPGANer
|
||||||
|
face_enhancer = GFPGANer(
|
||||||
|
model_path='https://github.com/TencentARC/GFPGAN/releases/download/v0.2.0/GFPGANCleanv1-NoCE-C2.pth',
|
||||||
|
upscale=args.outscale,
|
||||||
|
arch='clean',
|
||||||
|
channel_multiplier=2,
|
||||||
|
bg_upsampler=upsampler)
|
||||||
os.makedirs(args.output, exist_ok=True)
|
os.makedirs(args.output, exist_ok=True)
|
||||||
|
|
||||||
if os.path.isfile(args.input):
|
if os.path.isfile(args.input):
|
||||||
paths = [args.input]
|
paths = [args.input]
|
||||||
else:
|
else:
|
||||||
@@ -52,16 +73,27 @@ def main():
|
|||||||
print('Testing', idx, imgname)
|
print('Testing', idx, imgname)
|
||||||
|
|
||||||
img = cv2.imread(path, cv2.IMREAD_UNCHANGED)
|
img = cv2.imread(path, cv2.IMREAD_UNCHANGED)
|
||||||
|
if len(img.shape) == 3 and img.shape[2] == 4:
|
||||||
|
img_mode = 'RGBA'
|
||||||
|
else:
|
||||||
|
img_mode = None
|
||||||
|
|
||||||
h, w = img.shape[0:2]
|
h, w = img.shape[0:2]
|
||||||
if max(h, w) > 1000 and args.netscale == 4:
|
if max(h, w) > 1000 and args.netscale == 4:
|
||||||
print('WARNING: The input image is large, try X2 model for better performace.')
|
import warnings
|
||||||
|
warnings.warn('The input image is large, try X2 model for better performace.')
|
||||||
if max(h, w) < 500 and args.netscale == 2:
|
if max(h, w) < 500 and args.netscale == 2:
|
||||||
print('WARNING: The input image is small, try X4 model for better performace.')
|
import warnings
|
||||||
|
warnings.warn('The input image is small, try X4 model for better performace.')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
output, img_mode = upsampler.enhance(img, outscale=args.outscale)
|
if args.face_enhance:
|
||||||
|
_, _, output = face_enhancer.enhance(img, has_aligned=False, only_center_face=False, paste_back=True)
|
||||||
|
else:
|
||||||
|
output, _ = upsampler.enhance(img, outscale=args.outscale)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
print('Error', error)
|
print('Error', error)
|
||||||
|
print('If you encounter CUDA out of memory, try to set --tile with a smaller number.')
|
||||||
else:
|
else:
|
||||||
if args.ext == 'auto':
|
if args.ext == 'auto':
|
||||||
extension = extension[1:]
|
extension = extension[1:]
|
||||||
|
|||||||
189
options/finetune_realesrgan_x4plus.yml
Normal file
189
options/finetune_realesrgan_x4plus.yml
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
# general settings
|
||||||
|
name: finetune_RealESRGANx4plus_400k
|
||||||
|
model_type: RealESRGANModel
|
||||||
|
scale: 4
|
||||||
|
num_gpu: auto
|
||||||
|
manual_seed: 0
|
||||||
|
|
||||||
|
# ----------------- options for synthesizing training data in RealESRGANModel ----------------- #
|
||||||
|
# USM the ground-truth
|
||||||
|
l1_gt_usm: True
|
||||||
|
percep_gt_usm: True
|
||||||
|
gan_gt_usm: False
|
||||||
|
|
||||||
|
# the first degradation process
|
||||||
|
resize_prob: [0.2, 0.7, 0.1] # up, down, keep
|
||||||
|
resize_range: [0.15, 1.5]
|
||||||
|
gaussian_noise_prob: 0.5
|
||||||
|
noise_range: [1, 30]
|
||||||
|
poisson_scale_range: [0.05, 3]
|
||||||
|
gray_noise_prob: 0.4
|
||||||
|
jpeg_range: [30, 95]
|
||||||
|
|
||||||
|
# the second degradation process
|
||||||
|
second_blur_prob: 0.8
|
||||||
|
resize_prob2: [0.3, 0.4, 0.3] # up, down, keep
|
||||||
|
resize_range2: [0.3, 1.2]
|
||||||
|
gaussian_noise_prob2: 0.5
|
||||||
|
noise_range2: [1, 25]
|
||||||
|
poisson_scale_range2: [0.05, 2.5]
|
||||||
|
gray_noise_prob2: 0.4
|
||||||
|
jpeg_range2: [30, 95]
|
||||||
|
|
||||||
|
gt_size: 256
|
||||||
|
queue_size: 180
|
||||||
|
|
||||||
|
# dataset and data loader settings
|
||||||
|
datasets:
|
||||||
|
train:
|
||||||
|
name: DF2K+OST
|
||||||
|
type: RealESRGANDataset
|
||||||
|
dataroot_gt: datasets/DF2K
|
||||||
|
meta_info: datasets/DF2K/meta_info/meta_info_DF2Kmultiscale+OST_sub.txt
|
||||||
|
io_backend:
|
||||||
|
type: disk
|
||||||
|
|
||||||
|
blur_kernel_size: 21
|
||||||
|
kernel_list: ['iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso']
|
||||||
|
kernel_prob: [0.45, 0.25, 0.12, 0.03, 0.12, 0.03]
|
||||||
|
sinc_prob: 0.1
|
||||||
|
blur_sigma: [0.2, 3]
|
||||||
|
betag_range: [0.5, 4]
|
||||||
|
betap_range: [1, 2]
|
||||||
|
|
||||||
|
blur_kernel_size2: 21
|
||||||
|
kernel_list2: ['iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso']
|
||||||
|
kernel_prob2: [0.45, 0.25, 0.12, 0.03, 0.12, 0.03]
|
||||||
|
sinc_prob2: 0.1
|
||||||
|
blur_sigma2: [0.2, 1.5]
|
||||||
|
betag_range2: [0.5, 4]
|
||||||
|
betap_range2: [1, 2]
|
||||||
|
|
||||||
|
final_sinc_prob: 0.8
|
||||||
|
|
||||||
|
gt_size: 256
|
||||||
|
use_hflip: True
|
||||||
|
use_rot: False
|
||||||
|
|
||||||
|
# data loader
|
||||||
|
use_shuffle: true
|
||||||
|
num_worker_per_gpu: 5
|
||||||
|
batch_size_per_gpu: 12
|
||||||
|
dataset_enlarge_ratio: 1
|
||||||
|
prefetch_mode: ~
|
||||||
|
|
||||||
|
# Uncomment these for validation
|
||||||
|
# val:
|
||||||
|
# name: validation
|
||||||
|
# type: PairedImageDataset
|
||||||
|
# dataroot_gt: path_to_gt
|
||||||
|
# dataroot_lq: path_to_lq
|
||||||
|
# io_backend:
|
||||||
|
# type: disk
|
||||||
|
|
||||||
|
# network structures
|
||||||
|
network_g:
|
||||||
|
type: RRDBNet
|
||||||
|
num_in_ch: 3
|
||||||
|
num_out_ch: 3
|
||||||
|
num_feat: 64
|
||||||
|
num_block: 23
|
||||||
|
num_grow_ch: 32
|
||||||
|
|
||||||
|
|
||||||
|
network_d:
|
||||||
|
type: UNetDiscriminatorSN
|
||||||
|
num_in_ch: 3
|
||||||
|
num_feat: 64
|
||||||
|
skip_connection: True
|
||||||
|
|
||||||
|
# path
|
||||||
|
path:
|
||||||
|
# use the pre-trained Real-ESRNet model
|
||||||
|
pretrain_network_g: experiments/pretrained_models/RealESRNet_x4plus.pth
|
||||||
|
param_key_g: params_ema
|
||||||
|
strict_load_g: true
|
||||||
|
pretrain_network_d: experiments/pretrained_models/RealESRGAN_x4plus_netD.pth
|
||||||
|
param_key_d: params
|
||||||
|
strict_load_d: true
|
||||||
|
resume_state: ~
|
||||||
|
|
||||||
|
# training settings
|
||||||
|
train:
|
||||||
|
ema_decay: 0.999
|
||||||
|
optim_g:
|
||||||
|
type: Adam
|
||||||
|
lr: !!float 1e-4
|
||||||
|
weight_decay: 0
|
||||||
|
betas: [0.9, 0.99]
|
||||||
|
optim_d:
|
||||||
|
type: Adam
|
||||||
|
lr: !!float 1e-4
|
||||||
|
weight_decay: 0
|
||||||
|
betas: [0.9, 0.99]
|
||||||
|
|
||||||
|
scheduler:
|
||||||
|
type: MultiStepLR
|
||||||
|
milestones: [400000]
|
||||||
|
gamma: 0.5
|
||||||
|
|
||||||
|
total_iter: 400000
|
||||||
|
warmup_iter: -1 # no warm up
|
||||||
|
|
||||||
|
# losses
|
||||||
|
pixel_opt:
|
||||||
|
type: L1Loss
|
||||||
|
loss_weight: 1.0
|
||||||
|
reduction: mean
|
||||||
|
# perceptual loss (content and style losses)
|
||||||
|
perceptual_opt:
|
||||||
|
type: PerceptualLoss
|
||||||
|
layer_weights:
|
||||||
|
# before relu
|
||||||
|
'conv1_2': 0.1
|
||||||
|
'conv2_2': 0.1
|
||||||
|
'conv3_4': 1
|
||||||
|
'conv4_4': 1
|
||||||
|
'conv5_4': 1
|
||||||
|
vgg_type: vgg19
|
||||||
|
use_input_norm: true
|
||||||
|
perceptual_weight: !!float 1.0
|
||||||
|
style_weight: 0
|
||||||
|
range_norm: false
|
||||||
|
criterion: l1
|
||||||
|
# gan loss
|
||||||
|
gan_opt:
|
||||||
|
type: GANLoss
|
||||||
|
gan_type: vanilla
|
||||||
|
real_label_val: 1.0
|
||||||
|
fake_label_val: 0.0
|
||||||
|
loss_weight: !!float 1e-1
|
||||||
|
|
||||||
|
net_d_iters: 1
|
||||||
|
net_d_init_iters: 0
|
||||||
|
|
||||||
|
# Uncomment these for validation
|
||||||
|
# validation settings
|
||||||
|
# val:
|
||||||
|
# val_freq: !!float 5e3
|
||||||
|
# save_img: True
|
||||||
|
|
||||||
|
# metrics:
|
||||||
|
# psnr: # metric name, can be arbitrary
|
||||||
|
# type: calculate_psnr
|
||||||
|
# crop_border: 4
|
||||||
|
# test_y_channel: false
|
||||||
|
|
||||||
|
# logging settings
|
||||||
|
logger:
|
||||||
|
print_freq: 100
|
||||||
|
save_checkpoint_freq: !!float 5e3
|
||||||
|
use_tb_logger: true
|
||||||
|
wandb:
|
||||||
|
project: ~
|
||||||
|
resume_id: ~
|
||||||
|
|
||||||
|
# dist training settings
|
||||||
|
dist_params:
|
||||||
|
backend: nccl
|
||||||
|
port: 29500
|
||||||
151
options/finetune_realesrgan_x4plus_pairdata.yml
Normal file
151
options/finetune_realesrgan_x4plus_pairdata.yml
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
# general settings
|
||||||
|
name: finetune_RealESRGANx4plus_400k_pairdata
|
||||||
|
model_type: RealESRGANModel
|
||||||
|
scale: 4
|
||||||
|
num_gpu: auto
|
||||||
|
manual_seed: 0
|
||||||
|
|
||||||
|
# USM the ground-truth
|
||||||
|
l1_gt_usm: True
|
||||||
|
percep_gt_usm: True
|
||||||
|
gan_gt_usm: False
|
||||||
|
|
||||||
|
high_order_degradation: False # do not use the high-order degradation generation process
|
||||||
|
|
||||||
|
# dataset and data loader settings
|
||||||
|
datasets:
|
||||||
|
train:
|
||||||
|
name: DIV2K
|
||||||
|
type: RealESRGANPairedDataset
|
||||||
|
dataroot_gt: datasets/DF2K
|
||||||
|
dataroot_lq: datasets/DF2K
|
||||||
|
meta_info: datasets/DF2K/meta_info/meta_info_DIV2K_sub_pair.txt
|
||||||
|
io_backend:
|
||||||
|
type: disk
|
||||||
|
|
||||||
|
gt_size: 256
|
||||||
|
use_hflip: True
|
||||||
|
use_rot: False
|
||||||
|
|
||||||
|
# data loader
|
||||||
|
use_shuffle: true
|
||||||
|
num_worker_per_gpu: 5
|
||||||
|
batch_size_per_gpu: 12
|
||||||
|
dataset_enlarge_ratio: 1
|
||||||
|
prefetch_mode: ~
|
||||||
|
|
||||||
|
# Uncomment these for validation
|
||||||
|
# val:
|
||||||
|
# name: validation
|
||||||
|
# type: PairedImageDataset
|
||||||
|
# dataroot_gt: path_to_gt
|
||||||
|
# dataroot_lq: path_to_lq
|
||||||
|
# io_backend:
|
||||||
|
# type: disk
|
||||||
|
|
||||||
|
# network structures
|
||||||
|
network_g:
|
||||||
|
type: RRDBNet
|
||||||
|
num_in_ch: 3
|
||||||
|
num_out_ch: 3
|
||||||
|
num_feat: 64
|
||||||
|
num_block: 23
|
||||||
|
num_grow_ch: 32
|
||||||
|
|
||||||
|
|
||||||
|
network_d:
|
||||||
|
type: UNetDiscriminatorSN
|
||||||
|
num_in_ch: 3
|
||||||
|
num_feat: 64
|
||||||
|
skip_connection: True
|
||||||
|
|
||||||
|
# path
|
||||||
|
path:
|
||||||
|
# use the pre-trained Real-ESRNet model
|
||||||
|
pretrain_network_g: experiments/pretrained_models/RealESRNet_x4plus.pth
|
||||||
|
param_key_g: params_ema
|
||||||
|
strict_load_g: true
|
||||||
|
pretrain_network_d: experiments/pretrained_models/RealESRGAN_x4plus_netD.pth
|
||||||
|
param_key_d: params
|
||||||
|
strict_load_d: true
|
||||||
|
resume_state: ~
|
||||||
|
|
||||||
|
# training settings
|
||||||
|
train:
|
||||||
|
ema_decay: 0.999
|
||||||
|
optim_g:
|
||||||
|
type: Adam
|
||||||
|
lr: !!float 1e-4
|
||||||
|
weight_decay: 0
|
||||||
|
betas: [0.9, 0.99]
|
||||||
|
optim_d:
|
||||||
|
type: Adam
|
||||||
|
lr: !!float 1e-4
|
||||||
|
weight_decay: 0
|
||||||
|
betas: [0.9, 0.99]
|
||||||
|
|
||||||
|
scheduler:
|
||||||
|
type: MultiStepLR
|
||||||
|
milestones: [400000]
|
||||||
|
gamma: 0.5
|
||||||
|
|
||||||
|
total_iter: 400000
|
||||||
|
warmup_iter: -1 # no warm up
|
||||||
|
|
||||||
|
# losses
|
||||||
|
pixel_opt:
|
||||||
|
type: L1Loss
|
||||||
|
loss_weight: 1.0
|
||||||
|
reduction: mean
|
||||||
|
# perceptual loss (content and style losses)
|
||||||
|
perceptual_opt:
|
||||||
|
type: PerceptualLoss
|
||||||
|
layer_weights:
|
||||||
|
# before relu
|
||||||
|
'conv1_2': 0.1
|
||||||
|
'conv2_2': 0.1
|
||||||
|
'conv3_4': 1
|
||||||
|
'conv4_4': 1
|
||||||
|
'conv5_4': 1
|
||||||
|
vgg_type: vgg19
|
||||||
|
use_input_norm: true
|
||||||
|
perceptual_weight: !!float 1.0
|
||||||
|
style_weight: 0
|
||||||
|
range_norm: false
|
||||||
|
criterion: l1
|
||||||
|
# gan loss
|
||||||
|
gan_opt:
|
||||||
|
type: GANLoss
|
||||||
|
gan_type: vanilla
|
||||||
|
real_label_val: 1.0
|
||||||
|
fake_label_val: 0.0
|
||||||
|
loss_weight: !!float 1e-1
|
||||||
|
|
||||||
|
net_d_iters: 1
|
||||||
|
net_d_init_iters: 0
|
||||||
|
|
||||||
|
# Uncomment these for validation
|
||||||
|
# validation settings
|
||||||
|
# val:
|
||||||
|
# val_freq: !!float 5e3
|
||||||
|
# save_img: True
|
||||||
|
|
||||||
|
# metrics:
|
||||||
|
# psnr: # metric name, can be arbitrary
|
||||||
|
# type: calculate_psnr
|
||||||
|
# crop_border: 4
|
||||||
|
# test_y_channel: false
|
||||||
|
|
||||||
|
# logging settings
|
||||||
|
logger:
|
||||||
|
print_freq: 100
|
||||||
|
save_checkpoint_freq: !!float 5e3
|
||||||
|
use_tb_logger: true
|
||||||
|
wandb:
|
||||||
|
project: ~
|
||||||
|
resume_id: ~
|
||||||
|
|
||||||
|
# dist training settings
|
||||||
|
dist_params:
|
||||||
|
backend: nccl
|
||||||
|
port: 29500
|
||||||
187
options/train_realesrgan_x2plus.yml
Normal file
187
options/train_realesrgan_x2plus.yml
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
# general settings
|
||||||
|
name: train_RealESRGANx2plus_400k_B12G4
|
||||||
|
model_type: RealESRGANModel
|
||||||
|
scale: 2
|
||||||
|
num_gpu: 4
|
||||||
|
manual_seed: 0
|
||||||
|
|
||||||
|
# ----------------- options for synthesizing training data in RealESRGANModel ----------------- #
|
||||||
|
# USM the ground-truth
|
||||||
|
l1_gt_usm: True
|
||||||
|
percep_gt_usm: True
|
||||||
|
gan_gt_usm: False
|
||||||
|
|
||||||
|
# the first degradation process
|
||||||
|
resize_prob: [0.2, 0.7, 0.1] # up, down, keep
|
||||||
|
resize_range: [0.15, 1.5]
|
||||||
|
gaussian_noise_prob: 0.5
|
||||||
|
noise_range: [1, 30]
|
||||||
|
poisson_scale_range: [0.05, 3]
|
||||||
|
gray_noise_prob: 0.4
|
||||||
|
jpeg_range: [30, 95]
|
||||||
|
|
||||||
|
# the second degradation process
|
||||||
|
second_blur_prob: 0.8
|
||||||
|
resize_prob2: [0.3, 0.4, 0.3] # up, down, keep
|
||||||
|
resize_range2: [0.3, 1.2]
|
||||||
|
gaussian_noise_prob2: 0.5
|
||||||
|
noise_range2: [1, 25]
|
||||||
|
poisson_scale_range2: [0.05, 2.5]
|
||||||
|
gray_noise_prob2: 0.4
|
||||||
|
jpeg_range2: [30, 95]
|
||||||
|
|
||||||
|
gt_size: 256
|
||||||
|
queue_size: 180
|
||||||
|
|
||||||
|
# dataset and data loader settings
|
||||||
|
datasets:
|
||||||
|
train:
|
||||||
|
name: DF2K+OST
|
||||||
|
type: RealESRGANDataset
|
||||||
|
dataroot_gt: datasets/DF2K
|
||||||
|
meta_info: datasets/DF2K/meta_info/meta_info_DF2Kmultiscale+OST_sub.txt
|
||||||
|
io_backend:
|
||||||
|
type: disk
|
||||||
|
|
||||||
|
blur_kernel_size: 21
|
||||||
|
kernel_list: ['iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso']
|
||||||
|
kernel_prob: [0.45, 0.25, 0.12, 0.03, 0.12, 0.03]
|
||||||
|
sinc_prob: 0.1
|
||||||
|
blur_sigma: [0.2, 3]
|
||||||
|
betag_range: [0.5, 4]
|
||||||
|
betap_range: [1, 2]
|
||||||
|
|
||||||
|
blur_kernel_size2: 21
|
||||||
|
kernel_list2: ['iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso']
|
||||||
|
kernel_prob2: [0.45, 0.25, 0.12, 0.03, 0.12, 0.03]
|
||||||
|
sinc_prob2: 0.1
|
||||||
|
blur_sigma2: [0.2, 1.5]
|
||||||
|
betag_range2: [0.5, 4]
|
||||||
|
betap_range2: [1, 2]
|
||||||
|
|
||||||
|
final_sinc_prob: 0.8
|
||||||
|
|
||||||
|
gt_size: 256
|
||||||
|
use_hflip: True
|
||||||
|
use_rot: False
|
||||||
|
|
||||||
|
# data loader
|
||||||
|
use_shuffle: true
|
||||||
|
num_worker_per_gpu: 5
|
||||||
|
batch_size_per_gpu: 12
|
||||||
|
dataset_enlarge_ratio: 1
|
||||||
|
prefetch_mode: ~
|
||||||
|
|
||||||
|
# Uncomment these for validation
|
||||||
|
# val:
|
||||||
|
# name: validation
|
||||||
|
# type: PairedImageDataset
|
||||||
|
# dataroot_gt: path_to_gt
|
||||||
|
# dataroot_lq: path_to_lq
|
||||||
|
# io_backend:
|
||||||
|
# type: disk
|
||||||
|
|
||||||
|
# network structures
|
||||||
|
network_g:
|
||||||
|
type: RRDBNet
|
||||||
|
num_in_ch: 3
|
||||||
|
num_out_ch: 3
|
||||||
|
num_feat: 64
|
||||||
|
num_block: 23
|
||||||
|
num_grow_ch: 32
|
||||||
|
scale: 2
|
||||||
|
|
||||||
|
|
||||||
|
network_d:
|
||||||
|
type: UNetDiscriminatorSN
|
||||||
|
num_in_ch: 3
|
||||||
|
num_feat: 64
|
||||||
|
skip_connection: True
|
||||||
|
|
||||||
|
# path
|
||||||
|
path:
|
||||||
|
# use the pre-trained Real-ESRNet model
|
||||||
|
pretrain_network_g: experiments/pretrained_models/RealESRNet_x2plus.pth
|
||||||
|
param_key_g: params_ema
|
||||||
|
strict_load_g: true
|
||||||
|
resume_state: ~
|
||||||
|
|
||||||
|
# training settings
|
||||||
|
train:
|
||||||
|
ema_decay: 0.999
|
||||||
|
optim_g:
|
||||||
|
type: Adam
|
||||||
|
lr: !!float 1e-4
|
||||||
|
weight_decay: 0
|
||||||
|
betas: [0.9, 0.99]
|
||||||
|
optim_d:
|
||||||
|
type: Adam
|
||||||
|
lr: !!float 1e-4
|
||||||
|
weight_decay: 0
|
||||||
|
betas: [0.9, 0.99]
|
||||||
|
|
||||||
|
scheduler:
|
||||||
|
type: MultiStepLR
|
||||||
|
milestones: [400000]
|
||||||
|
gamma: 0.5
|
||||||
|
|
||||||
|
total_iter: 400000
|
||||||
|
warmup_iter: -1 # no warm up
|
||||||
|
|
||||||
|
# losses
|
||||||
|
pixel_opt:
|
||||||
|
type: L1Loss
|
||||||
|
loss_weight: 1.0
|
||||||
|
reduction: mean
|
||||||
|
# perceptual loss (content and style losses)
|
||||||
|
perceptual_opt:
|
||||||
|
type: PerceptualLoss
|
||||||
|
layer_weights:
|
||||||
|
# before relu
|
||||||
|
'conv1_2': 0.1
|
||||||
|
'conv2_2': 0.1
|
||||||
|
'conv3_4': 1
|
||||||
|
'conv4_4': 1
|
||||||
|
'conv5_4': 1
|
||||||
|
vgg_type: vgg19
|
||||||
|
use_input_norm: true
|
||||||
|
perceptual_weight: !!float 1.0
|
||||||
|
style_weight: 0
|
||||||
|
range_norm: false
|
||||||
|
criterion: l1
|
||||||
|
# gan loss
|
||||||
|
gan_opt:
|
||||||
|
type: GANLoss
|
||||||
|
gan_type: vanilla
|
||||||
|
real_label_val: 1.0
|
||||||
|
fake_label_val: 0.0
|
||||||
|
loss_weight: !!float 1e-1
|
||||||
|
|
||||||
|
net_d_iters: 1
|
||||||
|
net_d_init_iters: 0
|
||||||
|
|
||||||
|
# Uncomment these for validation
|
||||||
|
# validation settings
|
||||||
|
# val:
|
||||||
|
# val_freq: !!float 5e3
|
||||||
|
# save_img: True
|
||||||
|
|
||||||
|
# metrics:
|
||||||
|
# psnr: # metric name, can be arbitrary
|
||||||
|
# type: calculate_psnr
|
||||||
|
# crop_border: 4
|
||||||
|
# test_y_channel: false
|
||||||
|
|
||||||
|
# logging settings
|
||||||
|
logger:
|
||||||
|
print_freq: 100
|
||||||
|
save_checkpoint_freq: !!float 5e3
|
||||||
|
use_tb_logger: true
|
||||||
|
wandb:
|
||||||
|
project: ~
|
||||||
|
resume_id: ~
|
||||||
|
|
||||||
|
# dist training settings
|
||||||
|
dist_params:
|
||||||
|
backend: nccl
|
||||||
|
port: 29500
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# general settings
|
# general settings
|
||||||
name: train_RealESRGANx4plus_400k_B12G4_fromRealESRNet
|
name: train_RealESRGANx4plus_400k_B12G4
|
||||||
model_type: RealESRGANModel
|
model_type: RealESRGANModel
|
||||||
scale: 4
|
scale: 4
|
||||||
num_gpu: 4
|
num_gpu: 4
|
||||||
@@ -39,7 +39,7 @@ datasets:
|
|||||||
name: DF2K+OST
|
name: DF2K+OST
|
||||||
type: RealESRGANDataset
|
type: RealESRGANDataset
|
||||||
dataroot_gt: datasets/DF2K
|
dataroot_gt: datasets/DF2K
|
||||||
meta_info: realesrgan/data/meta_info/meta_info_DF2Kmultiscale+OST_sub.txt
|
meta_info: datasets/DF2K/meta_info/meta_info_DF2Kmultiscale+OST_sub.txt
|
||||||
io_backend:
|
io_backend:
|
||||||
type: disk
|
type: disk
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ network_d:
|
|||||||
# path
|
# path
|
||||||
path:
|
path:
|
||||||
# use the pre-trained Real-ESRNet model
|
# use the pre-trained Real-ESRNet model
|
||||||
pretrain_network_g: experiments/train_RealESRNetx4plus_1000k_B12G4_fromESRGAN/models/net_g_1000000.pth
|
pretrain_network_g: experiments/pretrained_models/RealESRNet_x4plus.pth
|
||||||
param_key_g: params_ema
|
param_key_g: params_ema
|
||||||
strict_load_g: true
|
strict_load_g: true
|
||||||
resume_state: ~
|
resume_state: ~
|
||||||
|
|||||||
145
options/train_realesrnet_x2plus.yml
Normal file
145
options/train_realesrnet_x2plus.yml
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# general settings
|
||||||
|
name: train_RealESRNetx2plus_1000k_B12G4
|
||||||
|
model_type: RealESRNetModel
|
||||||
|
scale: 2
|
||||||
|
num_gpu: 4
|
||||||
|
manual_seed: 0
|
||||||
|
|
||||||
|
# ----------------- options for synthesizing training data in RealESRNetModel ----------------- #
|
||||||
|
gt_usm: True # USM the ground-truth
|
||||||
|
|
||||||
|
# the first degradation process
|
||||||
|
resize_prob: [0.2, 0.7, 0.1] # up, down, keep
|
||||||
|
resize_range: [0.15, 1.5]
|
||||||
|
gaussian_noise_prob: 0.5
|
||||||
|
noise_range: [1, 30]
|
||||||
|
poisson_scale_range: [0.05, 3]
|
||||||
|
gray_noise_prob: 0.4
|
||||||
|
jpeg_range: [30, 95]
|
||||||
|
|
||||||
|
# the second degradation process
|
||||||
|
second_blur_prob: 0.8
|
||||||
|
resize_prob2: [0.3, 0.4, 0.3] # up, down, keep
|
||||||
|
resize_range2: [0.3, 1.2]
|
||||||
|
gaussian_noise_prob2: 0.5
|
||||||
|
noise_range2: [1, 25]
|
||||||
|
poisson_scale_range2: [0.05, 2.5]
|
||||||
|
gray_noise_prob2: 0.4
|
||||||
|
jpeg_range2: [30, 95]
|
||||||
|
|
||||||
|
gt_size: 256
|
||||||
|
queue_size: 180
|
||||||
|
|
||||||
|
# dataset and data loader settings
|
||||||
|
datasets:
|
||||||
|
train:
|
||||||
|
name: DF2K+OST
|
||||||
|
type: RealESRGANDataset
|
||||||
|
dataroot_gt: datasets/DF2K
|
||||||
|
meta_info: datasets/DF2K/meta_info/meta_info_DF2Kmultiscale+OST_sub.txt
|
||||||
|
io_backend:
|
||||||
|
type: disk
|
||||||
|
|
||||||
|
blur_kernel_size: 21
|
||||||
|
kernel_list: ['iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso']
|
||||||
|
kernel_prob: [0.45, 0.25, 0.12, 0.03, 0.12, 0.03]
|
||||||
|
sinc_prob: 0.1
|
||||||
|
blur_sigma: [0.2, 3]
|
||||||
|
betag_range: [0.5, 4]
|
||||||
|
betap_range: [1, 2]
|
||||||
|
|
||||||
|
blur_kernel_size2: 21
|
||||||
|
kernel_list2: ['iso', 'aniso', 'generalized_iso', 'generalized_aniso', 'plateau_iso', 'plateau_aniso']
|
||||||
|
kernel_prob2: [0.45, 0.25, 0.12, 0.03, 0.12, 0.03]
|
||||||
|
sinc_prob2: 0.1
|
||||||
|
blur_sigma2: [0.2, 1.5]
|
||||||
|
betag_range2: [0.5, 4]
|
||||||
|
betap_range2: [1, 2]
|
||||||
|
|
||||||
|
final_sinc_prob: 0.8
|
||||||
|
|
||||||
|
gt_size: 256
|
||||||
|
use_hflip: True
|
||||||
|
use_rot: False
|
||||||
|
|
||||||
|
# data loader
|
||||||
|
use_shuffle: true
|
||||||
|
num_worker_per_gpu: 5
|
||||||
|
batch_size_per_gpu: 12
|
||||||
|
dataset_enlarge_ratio: 1
|
||||||
|
prefetch_mode: ~
|
||||||
|
|
||||||
|
# Uncomment these for validation
|
||||||
|
# val:
|
||||||
|
# name: validation
|
||||||
|
# type: PairedImageDataset
|
||||||
|
# dataroot_gt: path_to_gt
|
||||||
|
# dataroot_lq: path_to_lq
|
||||||
|
# io_backend:
|
||||||
|
# type: disk
|
||||||
|
|
||||||
|
# network structures
|
||||||
|
network_g:
|
||||||
|
type: RRDBNet
|
||||||
|
num_in_ch: 3
|
||||||
|
num_out_ch: 3
|
||||||
|
num_feat: 64
|
||||||
|
num_block: 23
|
||||||
|
num_grow_ch: 32
|
||||||
|
scale: 2
|
||||||
|
|
||||||
|
# path
|
||||||
|
path:
|
||||||
|
pretrain_network_g: experiments/pretrained_models/RealESRGAN_x4plus.pth
|
||||||
|
param_key_g: params_ema
|
||||||
|
strict_load_g: False
|
||||||
|
resume_state: ~
|
||||||
|
|
||||||
|
# training settings
|
||||||
|
train:
|
||||||
|
ema_decay: 0.999
|
||||||
|
optim_g:
|
||||||
|
type: Adam
|
||||||
|
lr: !!float 2e-4
|
||||||
|
weight_decay: 0
|
||||||
|
betas: [0.9, 0.99]
|
||||||
|
|
||||||
|
scheduler:
|
||||||
|
type: MultiStepLR
|
||||||
|
milestones: [1000000]
|
||||||
|
gamma: 0.5
|
||||||
|
|
||||||
|
total_iter: 1000000
|
||||||
|
warmup_iter: -1 # no warm up
|
||||||
|
|
||||||
|
# losses
|
||||||
|
pixel_opt:
|
||||||
|
type: L1Loss
|
||||||
|
loss_weight: 1.0
|
||||||
|
reduction: mean
|
||||||
|
|
||||||
|
# Uncomment these for validation
|
||||||
|
# validation settings
|
||||||
|
# val:
|
||||||
|
# val_freq: !!float 5e3
|
||||||
|
# save_img: True
|
||||||
|
|
||||||
|
# metrics:
|
||||||
|
# psnr: # metric name, can be arbitrary
|
||||||
|
# type: calculate_psnr
|
||||||
|
# crop_border: 4
|
||||||
|
# test_y_channel: false
|
||||||
|
|
||||||
|
# logging settings
|
||||||
|
logger:
|
||||||
|
print_freq: 100
|
||||||
|
save_checkpoint_freq: !!float 5e3
|
||||||
|
use_tb_logger: true
|
||||||
|
wandb:
|
||||||
|
project: ~
|
||||||
|
resume_id: ~
|
||||||
|
|
||||||
|
# dist training settings
|
||||||
|
dist_params:
|
||||||
|
backend: nccl
|
||||||
|
port: 29500
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# general settings
|
# general settings
|
||||||
name: train_RealESRNetx4plus_1000k_B12G4_fromESRGAN
|
name: train_RealESRNetx4plus_1000k_B12G4
|
||||||
model_type: RealESRNetModel
|
model_type: RealESRNetModel
|
||||||
scale: 4
|
scale: 4
|
||||||
num_gpu: 4
|
num_gpu: 4
|
||||||
@@ -36,7 +36,7 @@ datasets:
|
|||||||
name: DF2K+OST
|
name: DF2K+OST
|
||||||
type: RealESRGANDataset
|
type: RealESRGANDataset
|
||||||
dataroot_gt: datasets/DF2K
|
dataroot_gt: datasets/DF2K
|
||||||
meta_info: realesrgan/data/meta_info/meta_info_DF2Kmultiscale+OST_sub.txt
|
meta_info: datasets/DF2K/meta_info/meta_info_DF2Kmultiscale+OST_sub.txt
|
||||||
io_backend:
|
io_backend:
|
||||||
type: disk
|
type: disk
|
||||||
|
|
||||||
|
|||||||
106
realesrgan/data/realesrgan_paired_dataset.py
Normal file
106
realesrgan/data/realesrgan_paired_dataset.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import os
|
||||||
|
from basicsr.data.data_util import paired_paths_from_folder, paired_paths_from_lmdb
|
||||||
|
from basicsr.data.transforms import augment, paired_random_crop
|
||||||
|
from basicsr.utils import FileClient, imfrombytes, img2tensor
|
||||||
|
from basicsr.utils.registry import DATASET_REGISTRY
|
||||||
|
from torch.utils import data as data
|
||||||
|
from torchvision.transforms.functional import normalize
|
||||||
|
|
||||||
|
|
||||||
|
@DATASET_REGISTRY.register()
|
||||||
|
class RealESRGANPairedDataset(data.Dataset):
|
||||||
|
"""Paired image dataset for image restoration.
|
||||||
|
|
||||||
|
Read LQ (Low Quality, e.g. LR (Low Resolution), blurry, noisy, etc) and
|
||||||
|
GT image pairs.
|
||||||
|
|
||||||
|
There are three modes:
|
||||||
|
1. 'lmdb': Use lmdb files.
|
||||||
|
If opt['io_backend'] == lmdb.
|
||||||
|
2. 'meta_info': Use meta information file to generate paths.
|
||||||
|
If opt['io_backend'] != lmdb and opt['meta_info'] is not None.
|
||||||
|
3. 'folder': Scan folders to generate paths.
|
||||||
|
The rest.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
opt (dict): Config for train datasets. It contains the following keys:
|
||||||
|
dataroot_gt (str): Data root path for gt.
|
||||||
|
dataroot_lq (str): Data root path for lq.
|
||||||
|
meta_info (str): Path for meta information file.
|
||||||
|
io_backend (dict): IO backend type and other kwarg.
|
||||||
|
filename_tmpl (str): Template for each filename. Note that the
|
||||||
|
template excludes the file extension. Default: '{}'.
|
||||||
|
gt_size (int): Cropped patched size for gt patches.
|
||||||
|
use_hflip (bool): Use horizontal flips.
|
||||||
|
use_rot (bool): Use rotation (use vertical flip and transposing h
|
||||||
|
and w for implementation).
|
||||||
|
|
||||||
|
scale (bool): Scale, which will be added automatically.
|
||||||
|
phase (str): 'train' or 'val'.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, opt):
|
||||||
|
super(RealESRGANPairedDataset, self).__init__()
|
||||||
|
self.opt = opt
|
||||||
|
# file client (io backend)
|
||||||
|
self.file_client = None
|
||||||
|
self.io_backend_opt = opt['io_backend']
|
||||||
|
self.mean = opt['mean'] if 'mean' in opt else None
|
||||||
|
self.std = opt['std'] if 'std' in opt else None
|
||||||
|
|
||||||
|
self.gt_folder, self.lq_folder = opt['dataroot_gt'], opt['dataroot_lq']
|
||||||
|
if 'filename_tmpl' in opt:
|
||||||
|
self.filename_tmpl = opt['filename_tmpl']
|
||||||
|
else:
|
||||||
|
self.filename_tmpl = '{}'
|
||||||
|
|
||||||
|
if self.io_backend_opt['type'] == 'lmdb':
|
||||||
|
self.io_backend_opt['db_paths'] = [self.lq_folder, self.gt_folder]
|
||||||
|
self.io_backend_opt['client_keys'] = ['lq', 'gt']
|
||||||
|
self.paths = paired_paths_from_lmdb([self.lq_folder, self.gt_folder], ['lq', 'gt'])
|
||||||
|
elif 'meta_info' in self.opt and self.opt['meta_info'] is not None:
|
||||||
|
with open(self.opt['meta_info']) as fin:
|
||||||
|
paths = [line.strip() for line in fin]
|
||||||
|
self.paths = []
|
||||||
|
for path in paths:
|
||||||
|
gt_path, lq_path = path.split(', ')
|
||||||
|
gt_path = os.path.join(self.gt_folder, gt_path)
|
||||||
|
lq_path = os.path.join(self.lq_folder, lq_path)
|
||||||
|
self.paths.append(dict([('gt_path', gt_path), ('lq_path', lq_path)]))
|
||||||
|
else:
|
||||||
|
self.paths = paired_paths_from_folder([self.lq_folder, self.gt_folder], ['lq', 'gt'], self.filename_tmpl)
|
||||||
|
|
||||||
|
def __getitem__(self, index):
|
||||||
|
if self.file_client is None:
|
||||||
|
self.file_client = FileClient(self.io_backend_opt.pop('type'), **self.io_backend_opt)
|
||||||
|
|
||||||
|
scale = self.opt['scale']
|
||||||
|
|
||||||
|
# Load gt and lq images. Dimension order: HWC; channel order: BGR;
|
||||||
|
# image range: [0, 1], float32.
|
||||||
|
gt_path = self.paths[index]['gt_path']
|
||||||
|
img_bytes = self.file_client.get(gt_path, 'gt')
|
||||||
|
img_gt = imfrombytes(img_bytes, float32=True)
|
||||||
|
lq_path = self.paths[index]['lq_path']
|
||||||
|
img_bytes = self.file_client.get(lq_path, 'lq')
|
||||||
|
img_lq = imfrombytes(img_bytes, float32=True)
|
||||||
|
|
||||||
|
# augmentation for training
|
||||||
|
if self.opt['phase'] == 'train':
|
||||||
|
gt_size = self.opt['gt_size']
|
||||||
|
# random crop
|
||||||
|
img_gt, img_lq = paired_random_crop(img_gt, img_lq, gt_size, scale, gt_path)
|
||||||
|
# flip, rotation
|
||||||
|
img_gt, img_lq = augment([img_gt, img_lq], self.opt['use_hflip'], self.opt['use_rot'])
|
||||||
|
|
||||||
|
# BGR to RGB, HWC to CHW, numpy to tensor
|
||||||
|
img_gt, img_lq = img2tensor([img_gt, img_lq], bgr2rgb=True, float32=True)
|
||||||
|
# normalize
|
||||||
|
if self.mean is not None or self.std is not None:
|
||||||
|
normalize(img_lq, self.mean, self.std, inplace=True)
|
||||||
|
normalize(img_gt, self.mean, self.std, inplace=True)
|
||||||
|
|
||||||
|
return {'lq': img_lq, 'gt': img_gt, 'lq_path': lq_path, 'gt_path': gt_path}
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.paths)
|
||||||
@@ -19,7 +19,7 @@ class RealESRGANModel(SRGANModel):
|
|||||||
super(RealESRGANModel, self).__init__(opt)
|
super(RealESRGANModel, self).__init__(opt)
|
||||||
self.jpeger = DiffJPEG(differentiable=False).cuda()
|
self.jpeger = DiffJPEG(differentiable=False).cuda()
|
||||||
self.usm_sharpener = USMSharp().cuda()
|
self.usm_sharpener = USMSharp().cuda()
|
||||||
self.queue_size = opt['queue_size']
|
self.queue_size = opt.get('queue_size', 180)
|
||||||
|
|
||||||
@torch.no_grad()
|
@torch.no_grad()
|
||||||
def _dequeue_and_enqueue(self):
|
def _dequeue_and_enqueue(self):
|
||||||
@@ -55,7 +55,7 @@ class RealESRGANModel(SRGANModel):
|
|||||||
|
|
||||||
@torch.no_grad()
|
@torch.no_grad()
|
||||||
def feed_data(self, data):
|
def feed_data(self, data):
|
||||||
if self.is_train:
|
if self.is_train and self.opt.get('high_order_degradation', True):
|
||||||
# training data synthesis
|
# training data synthesis
|
||||||
self.gt = data['gt'].to(self.device)
|
self.gt = data['gt'].to(self.device)
|
||||||
self.gt_usm = self.usm_sharpener(self.gt)
|
self.gt_usm = self.usm_sharpener(self.gt)
|
||||||
@@ -166,6 +166,7 @@ class RealESRGANModel(SRGANModel):
|
|||||||
self.lq = data['lq'].to(self.device)
|
self.lq = data['lq'].to(self.device)
|
||||||
if 'gt' in data:
|
if 'gt' in data:
|
||||||
self.gt = data['gt'].to(self.device)
|
self.gt = data['gt'].to(self.device)
|
||||||
|
self.gt_usm = self.usm_sharpener(self.gt)
|
||||||
|
|
||||||
def nondist_validation(self, dataloader, current_iter, tb_logger, save_img):
|
def nondist_validation(self, dataloader, current_iter, tb_logger, save_img):
|
||||||
# do not use the synthetic process during validation
|
# do not use the synthetic process during validation
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class RealESRNetModel(SRModel):
|
|||||||
super(RealESRNetModel, self).__init__(opt)
|
super(RealESRNetModel, self).__init__(opt)
|
||||||
self.jpeger = DiffJPEG(differentiable=False).cuda()
|
self.jpeger = DiffJPEG(differentiable=False).cuda()
|
||||||
self.usm_sharpener = USMSharp().cuda()
|
self.usm_sharpener = USMSharp().cuda()
|
||||||
self.queue_size = opt['queue_size']
|
self.queue_size = opt.get('queue_size', 180)
|
||||||
|
|
||||||
@torch.no_grad()
|
@torch.no_grad()
|
||||||
def _dequeue_and_enqueue(self):
|
def _dequeue_and_enqueue(self):
|
||||||
@@ -54,7 +54,7 @@ class RealESRNetModel(SRModel):
|
|||||||
|
|
||||||
@torch.no_grad()
|
@torch.no_grad()
|
||||||
def feed_data(self, data):
|
def feed_data(self, data):
|
||||||
if self.is_train:
|
if self.is_train and self.opt.get('high_order_degradation', True):
|
||||||
# training data synthesis
|
# training data synthesis
|
||||||
self.gt = data['gt'].to(self.device)
|
self.gt = data['gt'].to(self.device)
|
||||||
# USM the GT images
|
# USM the GT images
|
||||||
@@ -164,6 +164,7 @@ class RealESRNetModel(SRModel):
|
|||||||
self.lq = data['lq'].to(self.device)
|
self.lq = data['lq'].to(self.device)
|
||||||
if 'gt' in data:
|
if 'gt' in data:
|
||||||
self.gt = data['gt'].to(self.device)
|
self.gt = data['gt'].to(self.device)
|
||||||
|
self.gt_usm = self.usm_sharpener(self.gt)
|
||||||
|
|
||||||
def nondist_validation(self, dataloader, current_iter, tb_logger, save_img):
|
def nondist_validation(self, dataloader, current_iter, tb_logger, save_img):
|
||||||
# do not use the synthetic process during validation
|
# do not use the synthetic process during validation
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|||||||
|
|
||||||
class RealESRGANer():
|
class RealESRGANer():
|
||||||
|
|
||||||
def __init__(self, scale, model_path, tile=0, tile_pad=10, pre_pad=10, half=False):
|
def __init__(self, scale, model_path, model=None, tile=0, tile_pad=10, pre_pad=10, half=False):
|
||||||
self.scale = scale
|
self.scale = scale
|
||||||
self.tile_size = tile
|
self.tile_size = tile
|
||||||
self.tile_pad = tile_pad
|
self.tile_pad = tile_pad
|
||||||
@@ -23,7 +23,8 @@ class RealESRGANer():
|
|||||||
|
|
||||||
# initialize model
|
# initialize model
|
||||||
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
||||||
model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=scale)
|
if model is None:
|
||||||
|
model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=scale)
|
||||||
|
|
||||||
if model_path.startswith('https://'):
|
if model_path.startswith('https://'):
|
||||||
model_path = load_file_from_url(
|
model_path = load_file_from_url(
|
||||||
@@ -143,7 +144,7 @@ class RealESRGANer():
|
|||||||
h_input, w_input = img.shape[0:2]
|
h_input, w_input = img.shape[0:2]
|
||||||
# img: numpy
|
# img: numpy
|
||||||
img = img.astype(np.float32)
|
img = img.astype(np.float32)
|
||||||
if np.max(img) > 255: # 16-bit image
|
if np.max(img) > 256: # 16-bit image
|
||||||
max_range = 65535
|
max_range = 65535
|
||||||
print('\tInput is a 16-bit image')
|
print('\tInput is a 16-bit image')
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
basicsr
|
basicsr>=1.3.3.11
|
||||||
|
facexlib>=0.2.0.3
|
||||||
|
gfpgan>=0.2.1
|
||||||
numpy
|
numpy
|
||||||
opencv-python
|
opencv-python
|
||||||
|
Pillow
|
||||||
torch>=1.7
|
torch>=1.7
|
||||||
|
torchvision
|
||||||
|
tqdm
|
||||||
|
|||||||
151
scripts/extract_subimages.py
Normal file
151
scripts/extract_subimages.py
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
import argparse
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from basicsr.utils import scandir
|
||||||
|
from multiprocessing import Pool
|
||||||
|
from os import path as osp
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
"""A multi-thread tool to crop large images to sub-images for faster IO.
|
||||||
|
|
||||||
|
opt (dict): Configuration dict. It contains:
|
||||||
|
n_thread (int): Thread number.
|
||||||
|
compression_level (int): CV_IMWRITE_PNG_COMPRESSION from 0 to 9.
|
||||||
|
A higher value means a smaller size and longer compression time.
|
||||||
|
Use 0 for faster CPU decompression. Default: 3, same in cv2.
|
||||||
|
|
||||||
|
input_folder (str): Path to the input folder.
|
||||||
|
save_folder (str): Path to save folder.
|
||||||
|
crop_size (int): Crop size.
|
||||||
|
step (int): Step for overlapped sliding window.
|
||||||
|
thresh_size (int): Threshold size. Patches whose size is lower
|
||||||
|
than thresh_size will be dropped.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
For each folder, run this script.
|
||||||
|
Typically, there are four folders to be processed for DIV2K dataset.
|
||||||
|
DIV2K_train_HR
|
||||||
|
DIV2K_train_LR_bicubic/X2
|
||||||
|
DIV2K_train_LR_bicubic/X3
|
||||||
|
DIV2K_train_LR_bicubic/X4
|
||||||
|
After process, each sub_folder should have the same number of
|
||||||
|
subimages.
|
||||||
|
Remember to modify opt configurations according to your settings.
|
||||||
|
"""
|
||||||
|
|
||||||
|
opt = {}
|
||||||
|
opt['n_thread'] = args.n_thread
|
||||||
|
opt['compression_level'] = args.compression_level
|
||||||
|
|
||||||
|
# HR images
|
||||||
|
opt['input_folder'] = args.input
|
||||||
|
opt['save_folder'] = args.output
|
||||||
|
opt['crop_size'] = args.crop_size
|
||||||
|
opt['step'] = args.step
|
||||||
|
opt['thresh_size'] = args.thresh_size
|
||||||
|
extract_subimages(opt)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_subimages(opt):
|
||||||
|
"""Crop images to subimages.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
opt (dict): Configuration dict. It contains:
|
||||||
|
input_folder (str): Path to the input folder.
|
||||||
|
save_folder (str): Path to save folder.
|
||||||
|
n_thread (int): Thread number.
|
||||||
|
"""
|
||||||
|
input_folder = opt['input_folder']
|
||||||
|
save_folder = opt['save_folder']
|
||||||
|
if not osp.exists(save_folder):
|
||||||
|
os.makedirs(save_folder)
|
||||||
|
print(f'mkdir {save_folder} ...')
|
||||||
|
else:
|
||||||
|
print(f'Folder {save_folder} already exists. Exit.')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
img_list = list(scandir(input_folder, full_path=True))
|
||||||
|
|
||||||
|
pbar = tqdm(total=len(img_list), unit='image', desc='Extract')
|
||||||
|
pool = Pool(opt['n_thread'])
|
||||||
|
for path in img_list:
|
||||||
|
pool.apply_async(worker, args=(path, opt), callback=lambda arg: pbar.update(1))
|
||||||
|
pool.close()
|
||||||
|
pool.join()
|
||||||
|
pbar.close()
|
||||||
|
print('All processes done.')
|
||||||
|
|
||||||
|
|
||||||
|
def worker(path, opt):
|
||||||
|
"""Worker for each process.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (str): Image path.
|
||||||
|
opt (dict): Configuration dict. It contains:
|
||||||
|
crop_size (int): Crop size.
|
||||||
|
step (int): Step for overlapped sliding window.
|
||||||
|
thresh_size (int): Threshold size. Patches whose size is lower
|
||||||
|
than thresh_size will be dropped.
|
||||||
|
save_folder (str): Path to save folder.
|
||||||
|
compression_level (int): for cv2.IMWRITE_PNG_COMPRESSION.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
process_info (str): Process information displayed in progress bar.
|
||||||
|
"""
|
||||||
|
crop_size = opt['crop_size']
|
||||||
|
step = opt['step']
|
||||||
|
thresh_size = opt['thresh_size']
|
||||||
|
img_name, extension = osp.splitext(osp.basename(path))
|
||||||
|
|
||||||
|
# remove the x2, x3, x4 and x8 in the filename for DIV2K
|
||||||
|
img_name = img_name.replace('x2', '').replace('x3', '').replace('x4', '').replace('x8', '')
|
||||||
|
|
||||||
|
img = cv2.imread(path, cv2.IMREAD_UNCHANGED)
|
||||||
|
|
||||||
|
if img.ndim == 2:
|
||||||
|
h, w = img.shape
|
||||||
|
elif img.ndim == 3:
|
||||||
|
h, w, c = img.shape
|
||||||
|
else:
|
||||||
|
raise ValueError(f'Image ndim should be 2 or 3, but got {img.ndim}')
|
||||||
|
|
||||||
|
h_space = np.arange(0, h - crop_size + 1, step)
|
||||||
|
if h - (h_space[-1] + crop_size) > thresh_size:
|
||||||
|
h_space = np.append(h_space, h - crop_size)
|
||||||
|
w_space = np.arange(0, w - crop_size + 1, step)
|
||||||
|
if w - (w_space[-1] + crop_size) > thresh_size:
|
||||||
|
w_space = np.append(w_space, w - crop_size)
|
||||||
|
|
||||||
|
index = 0
|
||||||
|
for x in h_space:
|
||||||
|
for y in w_space:
|
||||||
|
index += 1
|
||||||
|
cropped_img = img[x:x + crop_size, y:y + crop_size, ...]
|
||||||
|
cropped_img = np.ascontiguousarray(cropped_img)
|
||||||
|
cv2.imwrite(
|
||||||
|
osp.join(opt['save_folder'], f'{img_name}_s{index:03d}{extension}'), cropped_img,
|
||||||
|
[cv2.IMWRITE_PNG_COMPRESSION, opt['compression_level']])
|
||||||
|
process_info = f'Processing {img_name} ...'
|
||||||
|
return process_info
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--input', type=str, default='datasets/DF2K/DF2K_HR', help='Input folder')
|
||||||
|
parser.add_argument('--output', type=str, default='datasets/DF2K/DF2K_HR_sub', help='Output folder')
|
||||||
|
parser.add_argument('--crop_size', type=int, default=480, help='Crop size')
|
||||||
|
parser.add_argument('--step', type=int, default=240, help='Step for overlapped sliding window')
|
||||||
|
parser.add_argument(
|
||||||
|
'--thresh_size',
|
||||||
|
type=int,
|
||||||
|
default=0,
|
||||||
|
help='Threshold size. Patches whose size is lower than thresh_size will be dropped.')
|
||||||
|
parser.add_argument('--n_thread', type=int, default=20, help='Thread number.')
|
||||||
|
parser.add_argument('--compression_level', type=int, default=3, help='Compression level')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
main(args)
|
||||||
56
scripts/generate_meta_info.py
Normal file
56
scripts/generate_meta_info.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import argparse
|
||||||
|
import cv2
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
txt_file = open(args.meta_info, 'w')
|
||||||
|
for folder, root in zip(args.input, args.root):
|
||||||
|
img_paths = sorted(glob.glob(os.path.join(folder, '*')))
|
||||||
|
for img_path in img_paths:
|
||||||
|
status = True
|
||||||
|
if args.check:
|
||||||
|
try:
|
||||||
|
img = cv2.imread(img_path)
|
||||||
|
except Exception as error:
|
||||||
|
print(f'Read {img_path} error: {error}')
|
||||||
|
status = False
|
||||||
|
if img is None:
|
||||||
|
status = False
|
||||||
|
print(f'Img is None: {img_path}')
|
||||||
|
if status:
|
||||||
|
img_name = os.path.relpath(img_path, root)
|
||||||
|
print(img_name)
|
||||||
|
txt_file.write(f'{img_name}\n')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
"""Generate meta info (txt file) for only Ground-Truth images.
|
||||||
|
|
||||||
|
It can also generate meta info from several folders into one txt file.
|
||||||
|
"""
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument(
|
||||||
|
'--input',
|
||||||
|
nargs='+',
|
||||||
|
default=['datasets/DF2K/DF2K_HR', 'datasets/DF2K/DF2K_multiscale'],
|
||||||
|
help='Input folder, can be a list')
|
||||||
|
parser.add_argument(
|
||||||
|
'--root',
|
||||||
|
nargs='+',
|
||||||
|
default=['datasets/DF2K', 'datasets/DF2K'],
|
||||||
|
help='Folder root, should have the length as input folders')
|
||||||
|
parser.add_argument(
|
||||||
|
'--meta_info',
|
||||||
|
type=str,
|
||||||
|
default='datasets/DF2K/meta_info/meta_info_DF2Kmultiscale.txt',
|
||||||
|
help='txt path for meta info')
|
||||||
|
parser.add_argument('--check', action='store_true', help='Read image to check whether it is ok')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
assert len(args.input) == len(args.root), ('Input folder and folder root should have the same length, but got '
|
||||||
|
f'{len(args.input)} and {len(args.root)}.')
|
||||||
|
os.makedirs(os.path.dirname(args.meta_info), exist_ok=True)
|
||||||
|
|
||||||
|
main(args)
|
||||||
47
scripts/generate_meta_info_pairdata.py
Normal file
47
scripts/generate_meta_info_pairdata.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import argparse
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
txt_file = open(args.meta_info, 'w')
|
||||||
|
img_paths_gt = sorted(glob.glob(os.path.join(args.input[0], '*')))
|
||||||
|
img_paths_lq = sorted(glob.glob(os.path.join(args.input[1], '*')))
|
||||||
|
|
||||||
|
assert len(img_paths_gt) == len(img_paths_lq), ('GT folder and LQ folder should have the same length, but got '
|
||||||
|
f'{len(img_paths_gt)} and {len(img_paths_lq)}.')
|
||||||
|
|
||||||
|
for img_path_gt, img_path_lq in zip(img_paths_gt, img_paths_lq):
|
||||||
|
img_name_gt = os.path.relpath(img_path_gt, args.root[0])
|
||||||
|
img_name_lq = os.path.relpath(img_path_lq, args.root[1])
|
||||||
|
print(f'{img_name_gt}, {img_name_lq}')
|
||||||
|
txt_file.write(f'{img_name_gt}, {img_name_lq}\n')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
"""Generate meta info (txt file) for paired images.
|
||||||
|
"""
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument(
|
||||||
|
'--input',
|
||||||
|
nargs='+',
|
||||||
|
default=['datasets/DF2K/DIV2K_train_HR_sub', 'datasets/DF2K/DIV2K_train_LR_bicubic_X4_sub'],
|
||||||
|
help='Input folder, should be [gt_folder, lq_folder]')
|
||||||
|
parser.add_argument('--root', nargs='+', default=[None, None], help='Folder root, will use the ')
|
||||||
|
parser.add_argument(
|
||||||
|
'--meta_info',
|
||||||
|
type=str,
|
||||||
|
default='datasets/DF2K/meta_info/meta_info_DIV2K_sub_pair.txt',
|
||||||
|
help='txt path for meta info')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
assert len(args.input) == 2, 'Input folder should have two elements: gt folder and lq folder'
|
||||||
|
assert len(args.root) == 2, 'Root path should have two elements: root for gt folder and lq folder'
|
||||||
|
os.makedirs(os.path.dirname(args.meta_info), exist_ok=True)
|
||||||
|
for i in range(2):
|
||||||
|
if args.input[i].endswith('/'):
|
||||||
|
args.input[i] = args.input[i][:-1]
|
||||||
|
if args.root[i] is None:
|
||||||
|
args.root[i] = os.path.dirname(args.input[i])
|
||||||
|
|
||||||
|
main(args)
|
||||||
46
scripts/generate_multiscale_DF2K.py
Normal file
46
scripts/generate_multiscale_DF2K.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import argparse
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
|
||||||
|
# For DF2K, we consider the following three scales,
|
||||||
|
# and the smallest image whose shortest edge is 400
|
||||||
|
scale_list = [0.75, 0.5, 1 / 3]
|
||||||
|
shortest_edge = 400
|
||||||
|
|
||||||
|
path_list = sorted(glob.glob(os.path.join(args.input, '*')))
|
||||||
|
for path in path_list:
|
||||||
|
print(path)
|
||||||
|
basename = os.path.splitext(os.path.basename(path))[0]
|
||||||
|
|
||||||
|
img = Image.open(path)
|
||||||
|
width, height = img.size
|
||||||
|
for idx, scale in enumerate(scale_list):
|
||||||
|
print(f'\t{scale:.2f}')
|
||||||
|
rlt = img.resize((int(width * scale), int(height * scale)), resample=Image.LANCZOS)
|
||||||
|
rlt.save(os.path.join(args.output, f'{basename}T{idx}.png'))
|
||||||
|
|
||||||
|
# save the smallest image which the shortest edge is 400
|
||||||
|
if width < height:
|
||||||
|
ratio = height / width
|
||||||
|
width = shortest_edge
|
||||||
|
height = int(width * ratio)
|
||||||
|
else:
|
||||||
|
ratio = width / height
|
||||||
|
height = shortest_edge
|
||||||
|
width = int(height * ratio)
|
||||||
|
rlt = img.resize((int(width), int(height)), resample=Image.LANCZOS)
|
||||||
|
rlt.save(os.path.join(args.output, f'{basename}T{idx+1}.png'))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--input', type=str, default='datasets/DF2K/DF2K_HR', help='Input folder')
|
||||||
|
parser.add_argument('--output', type=str, default='datasets/DF2K/DF2K_multiscale', help='Output folder')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
os.makedirs(args.output, exist_ok=True)
|
||||||
|
main(args)
|
||||||
@@ -3,7 +3,7 @@ import torch.onnx
|
|||||||
from basicsr.archs.rrdbnet_arch import RRDBNet
|
from basicsr.archs.rrdbnet_arch import RRDBNet
|
||||||
|
|
||||||
# An instance of your model
|
# An instance of your model
|
||||||
model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32)
|
model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=4)
|
||||||
model.load_state_dict(torch.load('experiments/pretrained_models/RealESRGAN_x4plus.pth')['params_ema'])
|
model.load_state_dict(torch.load('experiments/pretrained_models/RealESRGAN_x4plus.pth')['params_ema'])
|
||||||
# set the train mode to false since we will only run the forward pass.
|
# set the train mode to false since we will only run the forward pass.
|
||||||
model.train(False)
|
model.train(False)
|
||||||
|
|||||||
@@ -17,6 +17,6 @@ line_length = 120
|
|||||||
multi_line_output = 0
|
multi_line_output = 0
|
||||||
known_standard_library = pkg_resources,setuptools
|
known_standard_library = pkg_resources,setuptools
|
||||||
known_first_party = realesrgan
|
known_first_party = realesrgan
|
||||||
known_third_party = basicsr,cv2,numpy,torch
|
known_third_party = PIL,basicsr,cv2,numpy,torch,torchvision,tqdm
|
||||||
no_lines_before = STDLIB,LOCALFOLDER
|
no_lines_before = STDLIB,LOCALFOLDER
|
||||||
default_section = THIRDPARTY
|
default_section = THIRDPARTY
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -45,7 +45,7 @@ def get_hash():
|
|||||||
sha = get_git_hash()[:7]
|
sha = get_git_hash()[:7]
|
||||||
elif os.path.exists(version_file):
|
elif os.path.exists(version_file):
|
||||||
try:
|
try:
|
||||||
from facexlib.version import __version__
|
from realesrgan.version import __version__
|
||||||
sha = __version__.split('+')[-1]
|
sha = __version__.split('+')[-1]
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise ImportError('Unable to get git version')
|
raise ImportError('Unable to get git version')
|
||||||
|
|||||||
Reference in New Issue
Block a user