Spaces:
Runtime error
Runtime error
add colorization and inpainting.
Browse files- README.md +32 -19
- basicsr/utils/logger.py +4 -4
- docs/history_changelog.md +14 -0
- inference_colorization.py +86 -0
- inference_inpainting.py +91 -0
- inputs/gray_faces/067_David_Beckham_00.png +0 -0
- inputs/gray_faces/089_Miley_Cyrus_00.png +0 -0
- inputs/gray_faces/099_Victoria_Beckham_00.png +0 -0
- inputs/gray_faces/111_Alexa_Chung_00.png +0 -0
- inputs/gray_faces/132_Robert_Downey_Jr_00.png +0 -0
- inputs/gray_faces/158_Jimmy_Fallon_00.png +0 -0
- inputs/gray_faces/161_Zac_Efron_00.png +0 -0
- inputs/gray_faces/169_John_Lennon_00.png +0 -0
- inputs/gray_faces/170_Marilyn_Monroe_00.png +0 -0
- inputs/gray_faces/Einstein01.png +0 -0
- inputs/gray_faces/Einstein02.png +0 -0
- inputs/gray_faces/Hepburn01.png +0 -0
- inputs/gray_faces/Hepburn02.png +0 -0
- inputs/masked_faces/00105.png +0 -0
- inputs/masked_faces/00108.png +0 -0
- inputs/masked_faces/00169.png +0 -0
- inputs/masked_faces/00588.png +0 -0
- inputs/masked_faces/00664.png +0 -0
- scripts/crop_align_face.py +31 -18
README.md
CHANGED
@@ -22,22 +22,17 @@ S-Lab, Nanyang Technological University
|
|
22 |
|
23 |
**[<font color=#d1585d>News</font>]**: :whale: *We regret to inform you that the release of our code will be postponed from its earlier plan. Nevertheless, we assure you that it will be made available **by the end of this April**. Thank you for your understanding and patience. Our apologies for any inconvenience this may cause.*
|
24 |
### Update
|
|
|
25 |
- **2023.02.10**: Include `dlib` as a new face detector option, it produces more accurate face identity.
|
26 |
-
- **2022.10.05**: Support video input `--input_path [
|
27 |
- **2022.09.14**: Integrated to :hugs: [Hugging Face](https://huggingface.co/spaces). Try out online demo! [](https://huggingface.co/spaces/sczhou/CodeFormer)
|
28 |
- **2022.09.09**: Integrated to :rocket: [Replicate](https://replicate.com/explore). Try out online demo! [](https://replicate.com/sczhou/codeformer)
|
29 |
-
- **
|
30 |
-
- **2022.08.23**: Some modifications on face detection and fusion for better AI-created face enhancement.
|
31 |
-
- **2022.08.07**: Integrate [Real-ESRGAN](https://github.com/xinntao/Real-ESRGAN) to support background image enhancement.
|
32 |
-
- **2022.07.29**: Integrate new face detectors of `['RetinaFace'(default), 'YOLOv5']`.
|
33 |
-
- **2022.07.17**: Add Colab demo of CodeFormer. <a href="https://colab.research.google.com/drive/1m52PNveE4PBhYrecj34cnpEeiHcC5LTb?usp=sharing"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="google colab logo"></a>
|
34 |
-
- **2022.07.16**: Release inference code for face restoration. :blush:
|
35 |
-
- **2022.06.21**: This repo is created.
|
36 |
|
37 |
### TODO
|
38 |
-
- [ ] Add checkpoint for face inpainting
|
39 |
-
- [ ] Add checkpoint for face colorization
|
40 |
- [ ] Add training code and config files
|
|
|
|
|
41 |
- [x] ~~Add background image enhancement~~
|
42 |
|
43 |
#### :panda_face: Try Enhancing Old Photos / Fixing AI-arts
|
@@ -75,34 +70,41 @@ conda activate codeformer
|
|
75 |
# install python dependencies
|
76 |
pip3 install -r requirements.txt
|
77 |
python basicsr/setup.py develop
|
78 |
-
conda install -c conda-forge dlib (only for
|
79 |
```
|
80 |
<!-- conda install -c conda-forge dlib -->
|
81 |
|
82 |
### Quick Inference
|
83 |
|
84 |
#### Download Pre-trained Models:
|
85 |
-
Download the facelib and dlib pretrained models from [[Google Drive](https://drive.google.com/drive/folders/1b_3qwrzY_kTQh0-SnBoGBgOrJ_PLZSKm?usp=sharing) | [OneDrive](https://entuedu-my.sharepoint.com/:f:/g/personal/s200094_e_ntu_edu_sg/EvDxR7FcAbZMp_MA9ouq7aQB8XTppMb3-T0uGZ_2anI2mg?e=DXsJFo)] to the `weights/facelib` folder. You can manually download the pretrained models OR download by running the following command
|
86 |
```
|
87 |
python scripts/download_pretrained_models.py facelib
|
88 |
python scripts/download_pretrained_models.py dlib (only for dlib face detector)
|
89 |
```
|
90 |
|
91 |
-
Download the CodeFormer pretrained models from [[Google Drive](https://drive.google.com/drive/folders/1CNNByjHDFt0b95q54yMVp6Ifo5iuU6QS?usp=sharing) | [OneDrive](https://entuedu-my.sharepoint.com/:f:/g/personal/s200094_e_ntu_edu_sg/EoKFj4wo8cdIn2-TY2IV6CYBhZ0pIG4kUOeHdPR_A5nlbg?e=AO8UN9)] to the `weights/CodeFormer` folder. You can manually download the pretrained models OR download by running the following command
|
92 |
```
|
93 |
python scripts/download_pretrained_models.py CodeFormer
|
94 |
```
|
95 |
|
96 |
#### Prepare Testing Data:
|
97 |
-
You can put the testing images in the `inputs/TestWhole` folder. If you would like to test on cropped and aligned faces, you can put them in the `inputs/cropped_faces` folder.
|
|
|
|
|
|
|
|
|
98 |
|
99 |
|
100 |
-
#### Testing
|
101 |
[Note] If you want to compare CodeFormer in your paper, please run the following command indicating `--has_aligned` (for cropped and aligned face), as the command for the whole image will involve a process of face-background fusion that may damage hair texture on the boundary, which leads to unfair comparison.
|
102 |
|
|
|
|
|
|
|
103 |
🧑🏻 Face Restoration (cropped and aligned face)
|
104 |
```
|
105 |
-
# For cropped and aligned faces
|
106 |
python inference_codeformer.py -w 0.5 --has_aligned --input_path [image folder]|[image path]
|
107 |
```
|
108 |
|
@@ -121,14 +123,25 @@ conda install -c conda-forge ffmpeg
|
|
121 |
```
|
122 |
```
|
123 |
# For video clips
|
124 |
-
#
|
125 |
python inference_codeformer.py --bg_upsampler realesrgan --face_upsample -w 1.0 --input_path [video path]
|
126 |
```
|
127 |
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
|
129 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
|
131 |
-
The results will be saved in the `results` folder.
|
132 |
|
133 |
### Citation
|
134 |
If our work is useful for your research, please consider citing:
|
|
|
22 |
|
23 |
**[<font color=#d1585d>News</font>]**: :whale: *We regret to inform you that the release of our code will be postponed from its earlier plan. Nevertheless, we assure you that it will be made available **by the end of this April**. Thank you for your understanding and patience. Our apologies for any inconvenience this may cause.*
|
24 |
### Update
|
25 |
+
- **2023.04.09**: Add features of inpainting and colorization for cropped and aligned face images.
|
26 |
- **2023.02.10**: Include `dlib` as a new face detector option, it produces more accurate face identity.
|
27 |
+
- **2022.10.05**: Support video input `--input_path [YOUR_VIDEO.mp4]`. Try it to enhance your videos! :clapper:
|
28 |
- **2022.09.14**: Integrated to :hugs: [Hugging Face](https://huggingface.co/spaces). Try out online demo! [](https://huggingface.co/spaces/sczhou/CodeFormer)
|
29 |
- **2022.09.09**: Integrated to :rocket: [Replicate](https://replicate.com/explore). Try out online demo! [](https://replicate.com/sczhou/codeformer)
|
30 |
+
- [**More**](docs/history_changelog.md)
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
|
32 |
### TODO
|
|
|
|
|
33 |
- [ ] Add training code and config files
|
34 |
+
- [x] Add checkpoint and script for face inpainting
|
35 |
+
- [x] Add checkpoint and script for face colorization
|
36 |
- [x] ~~Add background image enhancement~~
|
37 |
|
38 |
#### :panda_face: Try Enhancing Old Photos / Fixing AI-arts
|
|
|
70 |
# install python dependencies
|
71 |
pip3 install -r requirements.txt
|
72 |
python basicsr/setup.py develop
|
73 |
+
conda install -c conda-forge dlib (only for face detection or cropping with dlib)
|
74 |
```
|
75 |
<!-- conda install -c conda-forge dlib -->
|
76 |
|
77 |
### Quick Inference
|
78 |
|
79 |
#### Download Pre-trained Models:
|
80 |
+
Download the facelib and dlib pretrained models from [[Releases](https://github.com/sczhou/CodeFormer/releases) | [Google Drive](https://drive.google.com/drive/folders/1b_3qwrzY_kTQh0-SnBoGBgOrJ_PLZSKm?usp=sharing) | [OneDrive](https://entuedu-my.sharepoint.com/:f:/g/personal/s200094_e_ntu_edu_sg/EvDxR7FcAbZMp_MA9ouq7aQB8XTppMb3-T0uGZ_2anI2mg?e=DXsJFo)] to the `weights/facelib` folder. You can manually download the pretrained models OR download by running the following command:
|
81 |
```
|
82 |
python scripts/download_pretrained_models.py facelib
|
83 |
python scripts/download_pretrained_models.py dlib (only for dlib face detector)
|
84 |
```
|
85 |
|
86 |
+
Download the CodeFormer pretrained models from [[Releases](https://github.com/sczhou/CodeFormer/releases) | [Google Drive](https://drive.google.com/drive/folders/1CNNByjHDFt0b95q54yMVp6Ifo5iuU6QS?usp=sharing) | [OneDrive](https://entuedu-my.sharepoint.com/:f:/g/personal/s200094_e_ntu_edu_sg/EoKFj4wo8cdIn2-TY2IV6CYBhZ0pIG4kUOeHdPR_A5nlbg?e=AO8UN9)] to the `weights/CodeFormer` folder. You can manually download the pretrained models OR download by running the following command:
|
87 |
```
|
88 |
python scripts/download_pretrained_models.py CodeFormer
|
89 |
```
|
90 |
|
91 |
#### Prepare Testing Data:
|
92 |
+
You can put the testing images in the `inputs/TestWhole` folder. If you would like to test on cropped and aligned faces, you can put them in the `inputs/cropped_faces` folder. You can get the cropped and aligned faces by running the following command:
|
93 |
+
```
|
94 |
+
# you may need to install dlib via: conda install -c conda-forge dlib
|
95 |
+
python scripts/crop_align_face.py -i [input folder] -o [output folder]
|
96 |
+
```
|
97 |
|
98 |
|
99 |
+
#### Testing:
|
100 |
[Note] If you want to compare CodeFormer in your paper, please run the following command indicating `--has_aligned` (for cropped and aligned face), as the command for the whole image will involve a process of face-background fusion that may damage hair texture on the boundary, which leads to unfair comparison.
|
101 |
|
102 |
+
Fidelity weight *w* lays in [0, 1]. Generally, smaller *w* tends to produce a higher-quality result, while larger *w* yields a higher-fidelity result. The results will be saved in the `results` folder.
|
103 |
+
|
104 |
+
|
105 |
🧑🏻 Face Restoration (cropped and aligned face)
|
106 |
```
|
107 |
+
# For cropped and aligned faces (512x512)
|
108 |
python inference_codeformer.py -w 0.5 --has_aligned --input_path [image folder]|[image path]
|
109 |
```
|
110 |
|
|
|
123 |
```
|
124 |
```
|
125 |
# For video clips
|
126 |
+
# Video path should end with '.mp4'|'.mov'|'.avi'
|
127 |
python inference_codeformer.py --bg_upsampler realesrgan --face_upsample -w 1.0 --input_path [video path]
|
128 |
```
|
129 |
|
130 |
+
🌈 Face Colorization (cropped and aligned face)
|
131 |
+
```
|
132 |
+
# For cropped and aligned faces (512x512)
|
133 |
+
# Colorize black and white or faded photo
|
134 |
+
python inference_inpainting.py --input_path [image folder]|[image path]
|
135 |
+
```
|
136 |
|
137 |
+
🎨 Face Inpainting (cropped and aligned face)
|
138 |
+
```
|
139 |
+
# For cropped and aligned faces (512x512)
|
140 |
+
# Inputs could be masked by white brush using a image editing app, e.g., Photoshop
|
141 |
+
# (check out the examples in inputs/masked_faces)
|
142 |
+
python inference_colorization.py --input_path [image folder]|[image path]
|
143 |
+
```
|
144 |
|
|
|
145 |
|
146 |
### Citation
|
147 |
If our work is useful for your research, please consider citing:
|
basicsr/utils/logger.py
CHANGED
@@ -67,10 +67,10 @@ class MessageLogger():
|
|
67 |
message += f'{k}: {v:.4e} '
|
68 |
# tensorboard logger
|
69 |
if self.use_tb_logger:
|
70 |
-
if k.startswith('l_'):
|
71 |
-
|
72 |
-
else:
|
73 |
-
|
74 |
self.logger.info(message)
|
75 |
|
76 |
|
|
|
67 |
message += f'{k}: {v:.4e} '
|
68 |
# tensorboard logger
|
69 |
if self.use_tb_logger:
|
70 |
+
# if k.startswith('l_'):
|
71 |
+
# self.tb_logger.add_scalar(f'losses/{k}', v, current_iter)
|
72 |
+
# else:
|
73 |
+
self.tb_logger.add_scalar(k, v, current_iter)
|
74 |
self.logger.info(message)
|
75 |
|
76 |
|
docs/history_changelog.md
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# History of Changelog
|
2 |
+
|
3 |
+
- **2023.04.09**: Add features of inpainting and colorization for cropped face images.
|
4 |
+
- **2023.02.10**: Include `dlib` as a new face detector option, it produces more accurate face identity.
|
5 |
+
- **2022.10.05**: Support video input `--input_path [YOUR_VIDEO.mp4]`. Try it to enhance your videos! :clapper:
|
6 |
+
- **2022.09.14**: Integrated to :hugs: [Hugging Face](https://huggingface.co/spaces). Try out online demo! [](https://huggingface.co/spaces/sczhou/CodeFormer)
|
7 |
+
- **2022.09.09**: Integrated to :rocket: [Replicate](https://replicate.com/explore). Try out online demo! [](https://replicate.com/sczhou/codeformer)
|
8 |
+
- **2022.09.04**: Add face upsampling `--face_upsample` for high-resolution AI-created face enhancement.
|
9 |
+
- **2022.08.23**: Some modifications on face detection and fusion for better AI-created face enhancement.
|
10 |
+
- **2022.08.07**: Integrate [Real-ESRGAN](https://github.com/xinntao/Real-ESRGAN) to support background image enhancement.
|
11 |
+
- **2022.07.29**: Integrate new face detectors of `['RetinaFace'(default), 'YOLOv5']`.
|
12 |
+
- **2022.07.17**: Add Colab demo of CodeFormer. <a href="https://colab.research.google.com/drive/1m52PNveE4PBhYrecj34cnpEeiHcC5LTb?usp=sharing"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="google colab logo"></a>
|
13 |
+
- **2022.07.16**: Release inference code for face restoration. :blush:
|
14 |
+
- **2022.06.21**: This repo is created.
|
inference_colorization.py
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import cv2
|
3 |
+
import argparse
|
4 |
+
import glob
|
5 |
+
import torch
|
6 |
+
from torchvision.transforms.functional import normalize
|
7 |
+
from basicsr.utils import imwrite, img2tensor, tensor2img
|
8 |
+
from basicsr.utils.download_util import load_file_from_url
|
9 |
+
from basicsr.utils.misc import get_device
|
10 |
+
from basicsr.utils.registry import ARCH_REGISTRY
|
11 |
+
|
12 |
+
pretrain_model_url = 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/codeformer_colorization.pth'
|
13 |
+
|
14 |
+
if __name__ == '__main__':
|
15 |
+
# device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
16 |
+
device = get_device()
|
17 |
+
parser = argparse.ArgumentParser()
|
18 |
+
|
19 |
+
parser.add_argument('-i', '--input_path', type=str, default='./inputs/gray_faces',
|
20 |
+
help='Input image or folder. Default: inputs/gray_faces')
|
21 |
+
parser.add_argument('-o', '--output_path', type=str, default=None,
|
22 |
+
help='Output folder. Default: results/<input_name>')
|
23 |
+
parser.add_argument('--suffix', type=str, default=None,
|
24 |
+
help='Suffix of the restored faces. Default: None')
|
25 |
+
args = parser.parse_args()
|
26 |
+
|
27 |
+
# ------------------------ input & output ------------------------
|
28 |
+
print('[NOTE] The input face images should be aligned and cropped to a resolution of 512x512.')
|
29 |
+
if args.input_path.endswith(('jpg', 'jpeg', 'png', 'JPG', 'JPEG', 'PNG')): # input single img path
|
30 |
+
input_img_list = [args.input_path]
|
31 |
+
result_root = f'results/test_colorization_img'
|
32 |
+
else: # input img folder
|
33 |
+
if args.input_path.endswith('/'): # solve when path ends with /
|
34 |
+
args.input_path = args.input_path[:-1]
|
35 |
+
# scan all the jpg and png images
|
36 |
+
input_img_list = sorted(glob.glob(os.path.join(args.input_path, '*.[jpJP][pnPN]*[gG]')))
|
37 |
+
result_root = f'results/{os.path.basename(args.input_path)}'
|
38 |
+
|
39 |
+
if not args.output_path is None: # set output path
|
40 |
+
result_root = args.output_path
|
41 |
+
|
42 |
+
test_img_num = len(input_img_list)
|
43 |
+
|
44 |
+
# ------------------ set up CodeFormer restorer -------------------
|
45 |
+
net = ARCH_REGISTRY.get('CodeFormer')(dim_embd=512, codebook_size=1024, n_head=8, n_layers=9,
|
46 |
+
connect_list=['32', '64', '128']).to(device)
|
47 |
+
|
48 |
+
# ckpt_path = 'weights/CodeFormer/codeformer.pth'
|
49 |
+
ckpt_path = load_file_from_url(url=pretrain_model_url,
|
50 |
+
model_dir='weights/CodeFormer', progress=True, file_name=None)
|
51 |
+
checkpoint = torch.load(ckpt_path)['params_ema']
|
52 |
+
net.load_state_dict(checkpoint)
|
53 |
+
net.eval()
|
54 |
+
|
55 |
+
# -------------------- start to processing ---------------------
|
56 |
+
for i, img_path in enumerate(input_img_list):
|
57 |
+
img_name = os.path.basename(img_path)
|
58 |
+
basename, ext = os.path.splitext(img_name)
|
59 |
+
print(f'[{i+1}/{test_img_num}] Processing: {img_name}')
|
60 |
+
input_face = cv2.imread(img_path)
|
61 |
+
assert input_face.shape[:2] == (512, 512), 'Input resolution must be 512x512 for colorization.'
|
62 |
+
# input_face = cv2.resize(input_face, (512, 512), interpolation=cv2.INTER_LINEAR)
|
63 |
+
input_face = img2tensor(input_face / 255., bgr2rgb=True, float32=True)
|
64 |
+
normalize(input_face, (0.5, 0.5, 0.5), (0.5, 0.5, 0.5), inplace=True)
|
65 |
+
input_face = input_face.unsqueeze(0).to(device)
|
66 |
+
try:
|
67 |
+
with torch.no_grad():
|
68 |
+
# w is fixed to 0 since we didn't train the Stage III for colorization
|
69 |
+
output_face = net(input_face, w=0, adain=True)[0]
|
70 |
+
save_face = tensor2img(output_face, rgb2bgr=True, min_max=(-1, 1))
|
71 |
+
del output_face
|
72 |
+
torch.cuda.empty_cache()
|
73 |
+
except Exception as error:
|
74 |
+
print(f'\tFailed inference for CodeFormer: {error}')
|
75 |
+
save_face = tensor2img(input_face, rgb2bgr=True, min_max=(-1, 1))
|
76 |
+
|
77 |
+
save_face = save_face.astype('uint8')
|
78 |
+
|
79 |
+
# save face
|
80 |
+
if args.suffix is not None:
|
81 |
+
basename = f'{basename}_{args.suffix}'
|
82 |
+
save_restore_path = os.path.join(result_root, f'{basename}.png')
|
83 |
+
imwrite(save_face, save_restore_path)
|
84 |
+
|
85 |
+
print(f'\nAll results are saved in {result_root}')
|
86 |
+
|
inference_inpainting.py
ADDED
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import cv2
|
3 |
+
import argparse
|
4 |
+
import glob
|
5 |
+
import torch
|
6 |
+
from torchvision.transforms.functional import normalize
|
7 |
+
from basicsr.utils import imwrite, img2tensor, tensor2img
|
8 |
+
from basicsr.utils.download_util import load_file_from_url
|
9 |
+
from basicsr.utils.misc import get_device
|
10 |
+
from basicsr.utils.registry import ARCH_REGISTRY
|
11 |
+
|
12 |
+
pretrain_model_url = 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/codeformer_inpainting.pth'
|
13 |
+
|
14 |
+
if __name__ == '__main__':
|
15 |
+
# device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
16 |
+
device = get_device()
|
17 |
+
parser = argparse.ArgumentParser()
|
18 |
+
|
19 |
+
parser.add_argument('-i', '--input_path', type=str, default='./inputs/masked_faces',
|
20 |
+
help='Input image or folder. Default: inputs/masked_faces')
|
21 |
+
parser.add_argument('-o', '--output_path', type=str, default=None,
|
22 |
+
help='Output folder. Default: results/<input_name>')
|
23 |
+
parser.add_argument('--suffix', type=str, default=None,
|
24 |
+
help='Suffix of the restored faces. Default: None')
|
25 |
+
args = parser.parse_args()
|
26 |
+
|
27 |
+
# ------------------------ input & output ------------------------
|
28 |
+
print('[NOTE] The input face images should be aligned and cropped to a resolution of 512x512.')
|
29 |
+
if args.input_path.endswith(('jpg', 'jpeg', 'png', 'JPG', 'JPEG', 'PNG')): # input single img path
|
30 |
+
input_img_list = [args.input_path]
|
31 |
+
result_root = f'results/test_inpainting_img'
|
32 |
+
else: # input img folder
|
33 |
+
if args.input_path.endswith('/'): # solve when path ends with /
|
34 |
+
args.input_path = args.input_path[:-1]
|
35 |
+
# scan all the jpg and png images
|
36 |
+
input_img_list = sorted(glob.glob(os.path.join(args.input_path, '*.[jpJP][pnPN]*[gG]')))
|
37 |
+
result_root = f'results/{os.path.basename(args.input_path)}'
|
38 |
+
|
39 |
+
if not args.output_path is None: # set output path
|
40 |
+
result_root = args.output_path
|
41 |
+
|
42 |
+
test_img_num = len(input_img_list)
|
43 |
+
|
44 |
+
# ------------------ set up CodeFormer restorer -------------------
|
45 |
+
net = ARCH_REGISTRY.get('CodeFormer')(dim_embd=512, codebook_size=512, n_head=8, n_layers=9,
|
46 |
+
connect_list=['32', '64', '128']).to(device)
|
47 |
+
|
48 |
+
# ckpt_path = 'weights/CodeFormer/codeformer.pth'
|
49 |
+
ckpt_path = load_file_from_url(url=pretrain_model_url,
|
50 |
+
model_dir='weights/CodeFormer', progress=True, file_name=None)
|
51 |
+
checkpoint = torch.load(ckpt_path)['params_ema']
|
52 |
+
net.load_state_dict(checkpoint)
|
53 |
+
net.eval()
|
54 |
+
|
55 |
+
# -------------------- start to processing ---------------------
|
56 |
+
for i, img_path in enumerate(input_img_list):
|
57 |
+
img_name = os.path.basename(img_path)
|
58 |
+
basename, ext = os.path.splitext(img_name)
|
59 |
+
print(f'[{i+1}/{test_img_num}] Processing: {img_name}')
|
60 |
+
input_face = cv2.imread(img_path)
|
61 |
+
assert input_face.shape[:2] == (512, 512), 'Input resolution must be 512x512 for inpainting.'
|
62 |
+
# input_face = cv2.resize(input_face, (512, 512), interpolation=cv2.INTER_LINEAR)
|
63 |
+
input_face = img2tensor(input_face / 255., bgr2rgb=True, float32=True)
|
64 |
+
normalize(input_face, (0.5, 0.5, 0.5), (0.5, 0.5, 0.5), inplace=True)
|
65 |
+
input_face = input_face.unsqueeze(0).to(device)
|
66 |
+
try:
|
67 |
+
with torch.no_grad():
|
68 |
+
mask = torch.zeros(512, 512)
|
69 |
+
m_ind = torch.sum(input_face[0], dim=0)
|
70 |
+
mask[m_ind==3] = 1.0
|
71 |
+
mask = mask.view(1, 1, 512, 512).to(device)
|
72 |
+
# w is fixed to 1, adain=False for inpainting
|
73 |
+
output_face = net(input_face, w=1, adain=False)[0]
|
74 |
+
output_face = (1-mask)*input_face + mask*output_face
|
75 |
+
save_face = tensor2img(output_face, rgb2bgr=True, min_max=(-1, 1))
|
76 |
+
del output_face
|
77 |
+
torch.cuda.empty_cache()
|
78 |
+
except Exception as error:
|
79 |
+
print(f'\tFailed inference for CodeFormer: {error}')
|
80 |
+
save_face = tensor2img(input_face, rgb2bgr=True, min_max=(-1, 1))
|
81 |
+
|
82 |
+
save_face = save_face.astype('uint8')
|
83 |
+
|
84 |
+
# save face
|
85 |
+
if args.suffix is not None:
|
86 |
+
basename = f'{basename}_{args.suffix}'
|
87 |
+
save_restore_path = os.path.join(result_root, f'{basename}.png')
|
88 |
+
imwrite(save_face, save_restore_path)
|
89 |
+
|
90 |
+
print(f'\nAll results are saved in {result_root}')
|
91 |
+
|
inputs/gray_faces/067_David_Beckham_00.png
ADDED
![]() |
inputs/gray_faces/089_Miley_Cyrus_00.png
ADDED
![]() |
inputs/gray_faces/099_Victoria_Beckham_00.png
ADDED
![]() |
inputs/gray_faces/111_Alexa_Chung_00.png
ADDED
![]() |
inputs/gray_faces/132_Robert_Downey_Jr_00.png
ADDED
![]() |
inputs/gray_faces/158_Jimmy_Fallon_00.png
ADDED
![]() |
inputs/gray_faces/161_Zac_Efron_00.png
ADDED
![]() |
inputs/gray_faces/169_John_Lennon_00.png
ADDED
![]() |
inputs/gray_faces/170_Marilyn_Monroe_00.png
ADDED
![]() |
inputs/gray_faces/Einstein01.png
ADDED
![]() |
inputs/gray_faces/Einstein02.png
ADDED
![]() |
inputs/gray_faces/Hepburn01.png
ADDED
![]() |
inputs/gray_faces/Hepburn02.png
ADDED
![]() |
inputs/masked_faces/00105.png
ADDED
![]() |
inputs/masked_faces/00108.png
ADDED
![]() |
inputs/masked_faces/00169.png
ADDED
![]() |
inputs/masked_faces/00588.png
ADDED
![]() |
inputs/masked_faces/00664.png
ADDED
![]() |
scripts/crop_align_face.py
CHANGED
@@ -13,19 +13,25 @@ requirements:
|
|
13 |
# http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
|
14 |
"""
|
15 |
|
16 |
-
import
|
17 |
-
import dlib
|
18 |
import glob
|
19 |
import numpy as np
|
20 |
-
import os
|
21 |
import PIL
|
22 |
import PIL.Image
|
23 |
import scipy
|
24 |
import scipy.ndimage
|
25 |
-
import sys
|
26 |
import argparse
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
|
28 |
# download model from: http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
|
|
|
|
|
|
|
29 |
predictor = dlib.shape_predictor('weights/dlib/shape_predictor_68_face_landmarks-fbdc2cb8.dat')
|
30 |
|
31 |
|
@@ -39,9 +45,9 @@ def get_landmark(filepath, only_keep_largest=True):
|
|
39 |
dets = detector(img, 1)
|
40 |
|
41 |
# Shangchen modified
|
42 |
-
print("
|
43 |
if only_keep_largest:
|
44 |
-
print('
|
45 |
face_areas = []
|
46 |
for k, d in enumerate(dets):
|
47 |
face_area = (d.right() - d.left()) * (d.bottom() - d.top())
|
@@ -50,16 +56,16 @@ def get_landmark(filepath, only_keep_largest=True):
|
|
50 |
largest_idx = face_areas.index(max(face_areas))
|
51 |
d = dets[largest_idx]
|
52 |
shape = predictor(img, d)
|
53 |
-
print("Part 0: {}, Part 1: {} ...".format(
|
54 |
-
|
55 |
else:
|
56 |
for k, d in enumerate(dets):
|
57 |
-
print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
|
58 |
-
|
59 |
# Get the landmarks/parts for the face in box d.
|
60 |
shape = predictor(img, d)
|
61 |
-
print("Part 0: {}, Part 1: {} ...".format(
|
62 |
-
|
63 |
|
64 |
t = list(shape.parts())
|
65 |
a = []
|
@@ -171,7 +177,7 @@ def align_face(filepath, out_path):
|
|
171 |
img = img.resize((output_size, output_size), PIL.Image.ANTIALIAS)
|
172 |
|
173 |
# Save aligned image.
|
174 |
-
print('saveing: ', out_path)
|
175 |
img.save(out_path)
|
176 |
|
177 |
return img, np.max(quad[:, 0]) - np.min(quad[:, 0])
|
@@ -179,14 +185,21 @@ def align_face(filepath, out_path):
|
|
179 |
|
180 |
if __name__ == '__main__':
|
181 |
parser = argparse.ArgumentParser()
|
182 |
-
parser.add_argument('--in_dir', type=str, default='./inputs/whole_imgs')
|
183 |
-
parser.add_argument('--out_dir', type=str, default='./inputs/cropped_faces')
|
184 |
args = parser.parse_args()
|
185 |
|
186 |
-
|
187 |
-
|
|
|
|
|
|
|
|
|
|
|
188 |
|
189 |
-
for in_path in img_list:
|
|
|
|
|
190 |
out_path = os.path.join(args.out_dir, in_path.split("/")[-1])
|
191 |
out_path = out_path.replace('.jpg', '.png')
|
192 |
size_ = align_face(in_path, out_path)
|
|
|
13 |
# http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
|
14 |
"""
|
15 |
|
16 |
+
import os
|
|
|
17 |
import glob
|
18 |
import numpy as np
|
|
|
19 |
import PIL
|
20 |
import PIL.Image
|
21 |
import scipy
|
22 |
import scipy.ndimage
|
|
|
23 |
import argparse
|
24 |
+
from basicsr.utils.download_util import load_file_from_url
|
25 |
+
|
26 |
+
try:
|
27 |
+
import dlib
|
28 |
+
except ImportError:
|
29 |
+
print('Please install dlib by running:' 'conda install -c conda-forge dlib')
|
30 |
|
31 |
# download model from: http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
|
32 |
+
shape_predictor_url = 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/shape_predictor_68_face_landmarks-fbdc2cb8.dat'
|
33 |
+
ckpt_path = load_file_from_url(url=shape_predictor_url,
|
34 |
+
model_dir='weights/dlib', progress=True, file_name=None)
|
35 |
predictor = dlib.shape_predictor('weights/dlib/shape_predictor_68_face_landmarks-fbdc2cb8.dat')
|
36 |
|
37 |
|
|
|
45 |
dets = detector(img, 1)
|
46 |
|
47 |
# Shangchen modified
|
48 |
+
print("\tNumber of faces detected: {}".format(len(dets)))
|
49 |
if only_keep_largest:
|
50 |
+
print('\tOnly keep the largest.')
|
51 |
face_areas = []
|
52 |
for k, d in enumerate(dets):
|
53 |
face_area = (d.right() - d.left()) * (d.bottom() - d.top())
|
|
|
56 |
largest_idx = face_areas.index(max(face_areas))
|
57 |
d = dets[largest_idx]
|
58 |
shape = predictor(img, d)
|
59 |
+
# print("Part 0: {}, Part 1: {} ...".format(
|
60 |
+
# shape.part(0), shape.part(1)))
|
61 |
else:
|
62 |
for k, d in enumerate(dets):
|
63 |
+
# print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
|
64 |
+
# k, d.left(), d.top(), d.right(), d.bottom()))
|
65 |
# Get the landmarks/parts for the face in box d.
|
66 |
shape = predictor(img, d)
|
67 |
+
# print("Part 0: {}, Part 1: {} ...".format(
|
68 |
+
# shape.part(0), shape.part(1)))
|
69 |
|
70 |
t = list(shape.parts())
|
71 |
a = []
|
|
|
177 |
img = img.resize((output_size, output_size), PIL.Image.ANTIALIAS)
|
178 |
|
179 |
# Save aligned image.
|
180 |
+
# print('saveing: ', out_path)
|
181 |
img.save(out_path)
|
182 |
|
183 |
return img, np.max(quad[:, 0]) - np.min(quad[:, 0])
|
|
|
185 |
|
186 |
if __name__ == '__main__':
|
187 |
parser = argparse.ArgumentParser()
|
188 |
+
parser.add_argument('-i', '--in_dir', type=str, default='./inputs/whole_imgs')
|
189 |
+
parser.add_argument('-o', '--out_dir', type=str, default='./inputs/cropped_faces')
|
190 |
args = parser.parse_args()
|
191 |
|
192 |
+
if args.out_dir.endswith('/'): # solve when path ends with /
|
193 |
+
args.out_dir = args.out_dir[:-1]
|
194 |
+
dir_name = os.path.abspath(args.out_dir)
|
195 |
+
os.makedirs(dir_name, exist_ok=True)
|
196 |
+
|
197 |
+
img_list = sorted(glob.glob(os.path.join(args.in_dir, '*.[jpJP][pnPN]*[gG]')))
|
198 |
+
test_img_num = len(img_list)
|
199 |
|
200 |
+
for i, in_path in enumerate(img_list):
|
201 |
+
img_name = os.path.basename(in_path)
|
202 |
+
print(f'[{i+1}/{test_img_num}] Processing: {img_name}')
|
203 |
out_path = os.path.join(args.out_dir, in_path.split("/")[-1])
|
204 |
out_path = out_path.replace('.jpg', '.png')
|
205 |
size_ = align_face(in_path, out_path)
|