sczhou commited on
Commit
50489a6
·
1 Parent(s): 9715dfb

add back dlib as a face detector option (#122)

Browse files
.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: *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!*
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! [![Hugging Face](https://img.shields.io/badge/Demo-%F0%9F%A4%97%20Hugging%20Face-blue)](https://huggingface.co/spaces/sczhou/CodeFormer)
27
  - **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
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! [![Hugging Face](https://img.shields.io/badge/Demo-%F0%9F%A4%97%20Hugging%20Face-blue)](https://huggingface.co/spaces/sczhou/CodeFormer)
28
  - **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)
 
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
- if self.template_3points:
 
 
 
 
 
 
 
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.face_det = init_detection_model(det_model, half=False, device=self.device)
 
 
 
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.face_det.detect_faces(input_img)
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("\nInput file is not found.")
 
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