Skip to content

Commit 50489a6

Browse files
committed
add back dlib as a face detector option (#122)
1 parent 9715dfb commit 50489a6

File tree

5 files changed

+79
-11
lines changed

5 files changed

+79
-11
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,5 @@ venv.bak/
123123

124124
# project
125125
results/
126-
dlib/
127126
*_old*
128127

README.md

+5-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ S-Lab, Nanyang Technological University
2020

2121
:star: If CodeFormer is helpful to your images or projects, please help star this repo. Thanks! :hugs:
2222

23-
**[<font color=#d1585d>News</font>]**: :whale: *Due to copyright issues, we have to delay the release of the training code (expected by the end of this year). Please star and stay tuned for our future updates!*
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.*
2424
### Update
25+
- **2023.02.10**: Include `dlib` as a new face detector option, it produces more accurate face identity.
2526
- **2022.10.05**: Support video input `--input_path [YOUR_VIDOE.mp4]`. Try it to enhance your videos! :clapper:
2627
- **2022.09.14**: Integrated to :hugs: [Hugging Face](https://huggingface.co/spaces). Try out online demo! [![Hugging Face](https://img.shields.io/badge/Demo-%F0%9F%A4%97%20Hugging%20Face-blue)](https://huggingface.co/spaces/sczhou/CodeFormer)
2728
- **2022.09.09**: Integrated to :rocket: [Replicate](https://replicate.com/explore). Try out online demo! [![Replicate](https://img.shields.io/badge/Demo-%F0%9F%9A%80%20Replicate-blue)](https://replicate.com/sczhou/codeformer)
@@ -74,15 +75,17 @@ conda activate codeformer
7475
# install python dependencies
7576
pip3 install -r requirements.txt
7677
python basicsr/setup.py develop
78+
conda install -c conda-forge dlib (only for dlib face detector)
7779
```
7880
<!-- conda install -c conda-forge dlib -->
7981

8082
### Quick Inference
8183

8284
#### 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.
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.
8486
```
8587
python scripts/download_pretrained_models.py facelib
88+
python scripts/download_pretrained_models.py dlib (only for dlib face detector)
8689
```
8790

8891
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

+66-5
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@
77
from facelib.detection import init_detection_model
88
from facelib.parsing import init_parsing_model
99
from facelib.utils.misc import img2tensor, imwrite, is_gray, bgr2gray, adain_npy
10+
from basicsr.utils.download_util import load_file_from_url
1011
from basicsr.utils.misc import get_device
1112

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+
}
1217

1318
def get_largest_face(det_faces, h, w):
1419

@@ -65,8 +70,15 @@ def __init__(self,
6570
self.crop_ratio = crop_ratio # (h, w)
6671
assert (self.crop_ratio[0] >= 1 and self.crop_ratio[1] >= 1), 'crop ration only supports >=1'
6772
self.face_size = (int(face_size * self.crop_ratio[1]), int(face_size * self.crop_ratio[0]))
68-
69-
if self.template_3points:
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:
7082
self.face_template = np.array([[192, 240], [319, 240], [257, 371]])
7183
else:
7284
# standard 5 landmarks for FFHQ faces with 512 x 512
@@ -78,7 +90,6 @@ def __init__(self,
7890
# self.face_template = np.array([[193.65928, 242.98541], [318.32558, 243.06108], [255.67984, 328.82894],
7991
# [198.22603, 372.82502], [313.91018, 372.75659]])
8092

81-
8293
self.face_template = self.face_template * (face_size / 512.0)
8394
if self.crop_ratio[0] > 1:
8495
self.face_template[:, 1] += face_size * (self.crop_ratio[0] - 1) / 2
@@ -104,7 +115,10 @@ def __init__(self,
104115
self.device = device
105116

106117
# init face detection model
107-
self.face_det = init_detection_model(det_model, half=False, device=self.device)
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)
108122

109123
# init face parsing model
110124
self.use_parse = use_parse
@@ -135,12 +149,59 @@ def read_image(self, img):
135149
f = 512.0/min(self.input_img.shape[:2])
136150
self.input_img = cv2.resize(self.input_img, (0,0), fx=f, fy=f, interpolation=cv2.INTER_LINEAR)
137151

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+
138196
def get_face_landmarks_5(self,
139197
only_keep_largest=False,
140198
only_center_face=False,
141199
resize=None,
142200
blur_ratio=0.01,
143201
eye_dist_threshold=None):
202+
if self.det_model == 'dlib':
203+
return self.get_face_landmarks_5_dlib(only_keep_largest)
204+
144205
if resize is None:
145206
scale = 1
146207
input_img = self.input_img
@@ -153,7 +214,7 @@ def get_face_landmarks_5(self,
153214
input_img = cv2.resize(self.input_img, (w, h), interpolation=interp)
154215

155216
with torch.no_grad():
156-
bboxes = self.face_det.detect_faces(input_img)
217+
bboxes = self.face_detector.detect_faces(input_img)
157218

158219
if bboxes is None or bboxes.shape[0] == 0:
159220
return 0

inference_codeformer.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def set_realesrgan():
7171
# large det_model: 'YOLOv5l', 'retinaface_resnet50'
7272
# small det_model: 'YOLOv5n', 'retinaface_mobile0.25'
7373
parser.add_argument('--detection_model', type=str, default='retinaface_resnet50',
74-
help='Face detector. Optional: retinaface_resnet50, retinaface_mobile0.25, YOLOv5l, YOLOv5n. \
74+
help='Face detector. Optional: retinaface_resnet50, retinaface_mobile0.25, YOLOv5l, YOLOv5n, dlib. \
7575
Default: retinaface_resnet50')
7676
parser.add_argument('--bg_upsampler', type=str, default='None', help='Background upsampler. Optional: realesrgan')
7777
parser.add_argument('--face_upsample', action='store_true', help='Face upsampler after enhancement. Default: False')
@@ -113,7 +113,8 @@ def set_realesrgan():
113113

114114
test_img_num = len(input_img_list)
115115
if test_img_num == 0:
116-
raise FileNotFoundError("\nInput file is not found.")
116+
raise FileNotFoundError('No input image/video is found...\n'
117+
'\tNote that --input_path for video should end with .mp4|.mov|.avi')
117118

118119
# ------------------ set up background upsampler ------------------
119120
if args.bg_upsampler == 'realesrgan':

scripts/download_pretrained_models.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def download_pretrained_models(method, file_urls):
1919
parser.add_argument(
2020
'method',
2121
type=str,
22-
help=("Options: 'CodeFormer' 'facelib'. Set to 'all' to download all the models."))
22+
help=("Options: 'CodeFormer' 'facelib' 'dlib'. Set to 'all' to download all the models."))
2323
args = parser.parse_args()
2424

2525
file_urls = {
@@ -30,6 +30,10 @@ def download_pretrained_models(method, file_urls):
3030
# 'yolov5l-face.pth': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/yolov5l-face.pth',
3131
'detection_Resnet50_Final.pth': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/detection_Resnet50_Final.pth',
3232
'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'
3337
}
3438
}
3539

0 commit comments

Comments
 (0)