Spaces:
Runtime error
Runtime error
add back dlib as a face detector option (#122)
Browse files- .gitignore +0 -1
- README.md +5 -2
- facelib/utils/face_restoration_helper.py +66 -5
- inference_codeformer.py +3 -2
- scripts/download_pretrained_models.py +5 -1
.gitignore
CHANGED
@@ -123,6 +123,5 @@ venv.bak/
|
|
123 |
|
124 |
# project
|
125 |
results/
|
126 |
-
dlib/
|
127 |
*_old*
|
128 |
|
|
|
123 |
|
124 |
# project
|
125 |
results/
|
|
|
126 |
*_old*
|
127 |
|
README.md
CHANGED
@@ -20,8 +20,9 @@ S-Lab, Nanyang Technological University
|
|
20 |
|
21 |
:star: If CodeFormer is helpful to your images or projects, please help star this repo. Thanks! :hugs:
|
22 |
|
23 |
-
**[<font color=#d1585d>News</font>]**: :whale: *
|
24 |
### Update
|
|
|
25 |
- **2022.10.05**: Support video input `--input_path [YOUR_VIDOE.mp4]`. Try it to enhance your videos! :clapper:
|
26 |
- **2022.09.14**: Integrated to :hugs: [Hugging Face](https://huggingface.co/spaces). Try out online demo! [](https://huggingface.co/spaces/sczhou/CodeFormer)
|
27 |
- **2022.09.09**: Integrated to :rocket: [Replicate](https://replicate.com/explore). Try out online demo! [](https://replicate.com/sczhou/codeformer)
|
@@ -74,15 +75,17 @@ conda activate codeformer
|
|
74 |
# install python dependencies
|
75 |
pip3 install -r requirements.txt
|
76 |
python basicsr/setup.py develop
|
|
|
77 |
```
|
78 |
<!-- conda install -c conda-forge dlib -->
|
79 |
|
80 |
### Quick Inference
|
81 |
|
82 |
#### Download Pre-trained Models:
|
83 |
-
Download the facelib 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.
|
84 |
```
|
85 |
python scripts/download_pretrained_models.py facelib
|
|
|
86 |
```
|
87 |
|
88 |
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.
|
|
|
20 |
|
21 |
:star: If CodeFormer is helpful to your images or projects, please help star this repo. Thanks! :hugs:
|
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 [YOUR_VIDOE.mp4]`. Try it to enhance your videos! :clapper:
|
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)
|
|
|
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 dlib face detector)
|
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.
|
facelib/utils/face_restoration_helper.py
CHANGED
@@ -7,8 +7,13 @@ from torchvision.transforms.functional import normalize
|
|
7 |
from facelib.detection import init_detection_model
|
8 |
from facelib.parsing import init_parsing_model
|
9 |
from facelib.utils.misc import img2tensor, imwrite, is_gray, bgr2gray, adain_npy
|
|
|
10 |
from basicsr.utils.misc import get_device
|
11 |
|
|
|
|
|
|
|
|
|
12 |
|
13 |
def get_largest_face(det_faces, h, w):
|
14 |
|
@@ -65,8 +70,15 @@ class FaceRestoreHelper(object):
|
|
65 |
self.crop_ratio = crop_ratio # (h, w)
|
66 |
assert (self.crop_ratio[0] >= 1 and self.crop_ratio[1] >= 1), 'crop ration only supports >=1'
|
67 |
self.face_size = (int(face_size * self.crop_ratio[1]), int(face_size * self.crop_ratio[0]))
|
68 |
-
|
69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
self.face_template = np.array([[192, 240], [319, 240], [257, 371]])
|
71 |
else:
|
72 |
# standard 5 landmarks for FFHQ faces with 512 x 512
|
@@ -78,7 +90,6 @@ class FaceRestoreHelper(object):
|
|
78 |
# self.face_template = np.array([[193.65928, 242.98541], [318.32558, 243.06108], [255.67984, 328.82894],
|
79 |
# [198.22603, 372.82502], [313.91018, 372.75659]])
|
80 |
|
81 |
-
|
82 |
self.face_template = self.face_template * (face_size / 512.0)
|
83 |
if self.crop_ratio[0] > 1:
|
84 |
self.face_template[:, 1] += face_size * (self.crop_ratio[0] - 1) / 2
|
@@ -104,7 +115,10 @@ class FaceRestoreHelper(object):
|
|
104 |
self.device = device
|
105 |
|
106 |
# init face detection model
|
107 |
-
self.
|
|
|
|
|
|
|
108 |
|
109 |
# init face parsing model
|
110 |
self.use_parse = use_parse
|
@@ -135,12 +149,59 @@ class FaceRestoreHelper(object):
|
|
135 |
f = 512.0/min(self.input_img.shape[:2])
|
136 |
self.input_img = cv2.resize(self.input_img, (0,0), fx=f, fy=f, interpolation=cv2.INTER_LINEAR)
|
137 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
def get_face_landmarks_5(self,
|
139 |
only_keep_largest=False,
|
140 |
only_center_face=False,
|
141 |
resize=None,
|
142 |
blur_ratio=0.01,
|
143 |
eye_dist_threshold=None):
|
|
|
|
|
|
|
144 |
if resize is None:
|
145 |
scale = 1
|
146 |
input_img = self.input_img
|
@@ -153,7 +214,7 @@ class FaceRestoreHelper(object):
|
|
153 |
input_img = cv2.resize(self.input_img, (w, h), interpolation=interp)
|
154 |
|
155 |
with torch.no_grad():
|
156 |
-
bboxes = self.
|
157 |
|
158 |
if bboxes is None or bboxes.shape[0] == 0:
|
159 |
return 0
|
|
|
7 |
from facelib.detection import init_detection_model
|
8 |
from facelib.parsing import init_parsing_model
|
9 |
from facelib.utils.misc import img2tensor, imwrite, is_gray, bgr2gray, adain_npy
|
10 |
+
from basicsr.utils.download_util import load_file_from_url
|
11 |
from basicsr.utils.misc import get_device
|
12 |
|
13 |
+
dlib_model_url = {
|
14 |
+
'face_detector': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/mmod_human_face_detector-4cb19393.dat',
|
15 |
+
'shape_predictor_5': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/shape_predictor_5_face_landmarks-c4b1e980.dat'
|
16 |
+
}
|
17 |
|
18 |
def get_largest_face(det_faces, h, w):
|
19 |
|
|
|
70 |
self.crop_ratio = crop_ratio # (h, w)
|
71 |
assert (self.crop_ratio[0] >= 1 and self.crop_ratio[1] >= 1), 'crop ration only supports >=1'
|
72 |
self.face_size = (int(face_size * self.crop_ratio[1]), int(face_size * self.crop_ratio[0]))
|
73 |
+
self.det_model = det_model
|
74 |
+
|
75 |
+
if self.det_model == 'dlib':
|
76 |
+
# standard 5 landmarks for FFHQ faces with 1024 x 1024
|
77 |
+
self.face_template = np.array([[686.77227723, 488.62376238], [586.77227723, 493.59405941],
|
78 |
+
[337.91089109, 488.38613861], [437.95049505, 493.51485149],
|
79 |
+
[513.58415842, 678.5049505]])
|
80 |
+
self.face_template = self.face_template / (1024 // face_size)
|
81 |
+
elif self.template_3points:
|
82 |
self.face_template = np.array([[192, 240], [319, 240], [257, 371]])
|
83 |
else:
|
84 |
# standard 5 landmarks for FFHQ faces with 512 x 512
|
|
|
90 |
# self.face_template = np.array([[193.65928, 242.98541], [318.32558, 243.06108], [255.67984, 328.82894],
|
91 |
# [198.22603, 372.82502], [313.91018, 372.75659]])
|
92 |
|
|
|
93 |
self.face_template = self.face_template * (face_size / 512.0)
|
94 |
if self.crop_ratio[0] > 1:
|
95 |
self.face_template[:, 1] += face_size * (self.crop_ratio[0] - 1) / 2
|
|
|
115 |
self.device = device
|
116 |
|
117 |
# init face detection model
|
118 |
+
if self.det_model == 'dlib':
|
119 |
+
self.face_detector, self.shape_predictor_5 = self.init_dlib(dlib_model_url['face_detector'], dlib_model_url['shape_predictor_5'])
|
120 |
+
else:
|
121 |
+
self.face_detector = init_detection_model(det_model, half=False, device=self.device)
|
122 |
|
123 |
# init face parsing model
|
124 |
self.use_parse = use_parse
|
|
|
149 |
f = 512.0/min(self.input_img.shape[:2])
|
150 |
self.input_img = cv2.resize(self.input_img, (0,0), fx=f, fy=f, interpolation=cv2.INTER_LINEAR)
|
151 |
|
152 |
+
def init_dlib(self, detection_path, landmark5_path):
|
153 |
+
"""Initialize the dlib detectors and predictors."""
|
154 |
+
try:
|
155 |
+
import dlib
|
156 |
+
except ImportError:
|
157 |
+
print('Please install dlib by running:' 'conda install -c conda-forge dlib')
|
158 |
+
detection_path = load_file_from_url(url=detection_path, model_dir='weights/dlib', progress=True, file_name=None)
|
159 |
+
landmark5_path = load_file_from_url(url=landmark5_path, model_dir='weights/dlib', progress=True, file_name=None)
|
160 |
+
face_detector = dlib.cnn_face_detection_model_v1(detection_path)
|
161 |
+
shape_predictor_5 = dlib.shape_predictor(landmark5_path)
|
162 |
+
return face_detector, shape_predictor_5
|
163 |
+
|
164 |
+
def get_face_landmarks_5_dlib(self,
|
165 |
+
only_keep_largest=False,
|
166 |
+
scale=1):
|
167 |
+
det_faces = self.face_detector(self.input_img, scale)
|
168 |
+
|
169 |
+
if len(det_faces) == 0:
|
170 |
+
print('No face detected. Try to increase upsample_num_times.')
|
171 |
+
return 0
|
172 |
+
else:
|
173 |
+
if only_keep_largest:
|
174 |
+
print('Detect several faces and only keep the largest.')
|
175 |
+
face_areas = []
|
176 |
+
for i in range(len(det_faces)):
|
177 |
+
face_area = (det_faces[i].rect.right() - det_faces[i].rect.left()) * (
|
178 |
+
det_faces[i].rect.bottom() - det_faces[i].rect.top())
|
179 |
+
face_areas.append(face_area)
|
180 |
+
largest_idx = face_areas.index(max(face_areas))
|
181 |
+
self.det_faces = [det_faces[largest_idx]]
|
182 |
+
else:
|
183 |
+
self.det_faces = det_faces
|
184 |
+
|
185 |
+
if len(self.det_faces) == 0:
|
186 |
+
return 0
|
187 |
+
|
188 |
+
for face in self.det_faces:
|
189 |
+
shape = self.shape_predictor_5(self.input_img, face.rect)
|
190 |
+
landmark = np.array([[part.x, part.y] for part in shape.parts()])
|
191 |
+
self.all_landmarks_5.append(landmark)
|
192 |
+
|
193 |
+
return len(self.all_landmarks_5)
|
194 |
+
|
195 |
+
|
196 |
def get_face_landmarks_5(self,
|
197 |
only_keep_largest=False,
|
198 |
only_center_face=False,
|
199 |
resize=None,
|
200 |
blur_ratio=0.01,
|
201 |
eye_dist_threshold=None):
|
202 |
+
if self.det_model == 'dlib':
|
203 |
+
return self.get_face_landmarks_5_dlib(only_keep_largest)
|
204 |
+
|
205 |
if resize is None:
|
206 |
scale = 1
|
207 |
input_img = self.input_img
|
|
|
214 |
input_img = cv2.resize(self.input_img, (w, h), interpolation=interp)
|
215 |
|
216 |
with torch.no_grad():
|
217 |
+
bboxes = self.face_detector.detect_faces(input_img)
|
218 |
|
219 |
if bboxes is None or bboxes.shape[0] == 0:
|
220 |
return 0
|
inference_codeformer.py
CHANGED
@@ -71,7 +71,7 @@ if __name__ == '__main__':
|
|
71 |
# large det_model: 'YOLOv5l', 'retinaface_resnet50'
|
72 |
# small det_model: 'YOLOv5n', 'retinaface_mobile0.25'
|
73 |
parser.add_argument('--detection_model', type=str, default='retinaface_resnet50',
|
74 |
-
help='Face detector. Optional: retinaface_resnet50, retinaface_mobile0.25, YOLOv5l, YOLOv5n. \
|
75 |
Default: retinaface_resnet50')
|
76 |
parser.add_argument('--bg_upsampler', type=str, default='None', help='Background upsampler. Optional: realesrgan')
|
77 |
parser.add_argument('--face_upsample', action='store_true', help='Face upsampler after enhancement. Default: False')
|
@@ -113,7 +113,8 @@ if __name__ == '__main__':
|
|
113 |
|
114 |
test_img_num = len(input_img_list)
|
115 |
if test_img_num == 0:
|
116 |
-
raise FileNotFoundError(
|
|
|
117 |
|
118 |
# ------------------ set up background upsampler ------------------
|
119 |
if args.bg_upsampler == 'realesrgan':
|
|
|
71 |
# large det_model: 'YOLOv5l', 'retinaface_resnet50'
|
72 |
# small det_model: 'YOLOv5n', 'retinaface_mobile0.25'
|
73 |
parser.add_argument('--detection_model', type=str, default='retinaface_resnet50',
|
74 |
+
help='Face detector. Optional: retinaface_resnet50, retinaface_mobile0.25, YOLOv5l, YOLOv5n, dlib. \
|
75 |
Default: retinaface_resnet50')
|
76 |
parser.add_argument('--bg_upsampler', type=str, default='None', help='Background upsampler. Optional: realesrgan')
|
77 |
parser.add_argument('--face_upsample', action='store_true', help='Face upsampler after enhancement. Default: False')
|
|
|
113 |
|
114 |
test_img_num = len(input_img_list)
|
115 |
if test_img_num == 0:
|
116 |
+
raise FileNotFoundError('No input image/video is found...\n'
|
117 |
+
'\tNote that --input_path for video should end with .mp4|.mov|.avi')
|
118 |
|
119 |
# ------------------ set up background upsampler ------------------
|
120 |
if args.bg_upsampler == 'realesrgan':
|
scripts/download_pretrained_models.py
CHANGED
@@ -19,7 +19,7 @@ if __name__ == '__main__':
|
|
19 |
parser.add_argument(
|
20 |
'method',
|
21 |
type=str,
|
22 |
-
help=("Options: 'CodeFormer' 'facelib'. Set to 'all' to download all the models."))
|
23 |
args = parser.parse_args()
|
24 |
|
25 |
file_urls = {
|
@@ -30,6 +30,10 @@ if __name__ == '__main__':
|
|
30 |
# 'yolov5l-face.pth': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/yolov5l-face.pth',
|
31 |
'detection_Resnet50_Final.pth': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/detection_Resnet50_Final.pth',
|
32 |
'parsing_parsenet.pth': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/parsing_parsenet.pth'
|
|
|
|
|
|
|
|
|
33 |
}
|
34 |
}
|
35 |
|
|
|
19 |
parser.add_argument(
|
20 |
'method',
|
21 |
type=str,
|
22 |
+
help=("Options: 'CodeFormer' 'facelib' 'dlib'. Set to 'all' to download all the models."))
|
23 |
args = parser.parse_args()
|
24 |
|
25 |
file_urls = {
|
|
|
30 |
# 'yolov5l-face.pth': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/yolov5l-face.pth',
|
31 |
'detection_Resnet50_Final.pth': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/detection_Resnet50_Final.pth',
|
32 |
'parsing_parsenet.pth': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/parsing_parsenet.pth'
|
33 |
+
},
|
34 |
+
'dlib': {
|
35 |
+
'mmod_human_face_detector-4cb19393.dat': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/mmod_human_face_detector-4cb19393.dat',
|
36 |
+
'shape_predictor_5_face_landmarks-c4b1e980.dat': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/shape_predictor_5_face_landmarks-c4b1e980.dat'
|
37 |
}
|
38 |
}
|
39 |
|