Spaces:
Sleeping
Sleeping
import sys, os | |
__dir__ = os.path.dirname(os.path.abspath(__file__)) | |
sys.path.append(__dir__) | |
sys.path.append(os.path.abspath(os.path.join(__dir__, '..'))) | |
import torch | |
import cv2 | |
import numpy as np | |
from face_detection.data import cfg_mnet, cfg_re50 | |
from face_detection.layers.functions.prior_box import PriorBox | |
from face_detection.utils.nms.py_cpu_nms import py_cpu_nms | |
from face_detection.models.retinaface import RetinaFace | |
from face_detection.utils.box_utils import decode | |
from face_detection.helper import remove_prefix, check_keys, get_boundingbox | |
class FaceDetection: | |
def __init__(self, batch_size=16, device=None, gpu_id=0, weights='./weights/Resnet50_Final.pth'): | |
torch.backends.cudnn.benchmark = True | |
if device: | |
self.device = device | |
elif torch.cuda.is_available() and gpu_id != -1: | |
self.device = 'cuda:{}'.format(gpu_id) | |
else: | |
self.device = 'cpu' | |
self.device = torch.device(self.device) | |
self.batch_size = batch_size | |
self.load_model(weights, self.device, load_to_cpu=True if str(self.device)=='cpu' else False) | |
self.model.eval() | |
def load_model(self, pretrained_path, device, load_to_cpu=False): | |
print('Loading pretrained model from {}'.format(pretrained_path)) | |
if load_to_cpu: | |
pretrained_dict = torch.load( | |
pretrained_path, map_location=lambda storage, loc: storage) | |
else: | |
pretrained_dict = torch.load( | |
pretrained_path, map_location=lambda storage, loc: storage.cuda(device)) | |
if "state_dict" in pretrained_dict.keys(): | |
pretrained_dict = remove_prefix( | |
pretrained_dict['state_dict'], 'module.') | |
else: | |
pretrained_dict = remove_prefix(pretrained_dict, 'module.') | |
self.model = RetinaFace(cfg=cfg_re50, phase='test') | |
check_keys(self.model, pretrained_dict) | |
self.model.load_state_dict(pretrained_dict, strict=False) | |
self.model.to(device) | |
def detect(self, images, model, device, resize=1, confidence_threshold=0.997): | |
""" | |
"And now I am become death, destroyer of worlds" | |
-The author who wrote this | |
""" | |
result = [] | |
img_list = [] | |
for img in images: | |
img = torch.tensor(img) - torch.tensor([104, 117, 123]) | |
img_list.append(img) | |
im_height, im_width, _ = img_list[0].shape | |
scale = torch.Tensor([im_width, im_height, im_width, im_height]) | |
img_x = torch.stack(img_list, dim=0).permute([0, 3, 1, 2]) | |
scale = scale.to(device) | |
# forward times | |
f_times = img_x.shape[0] // self.batch_size | |
if img_x.shape[0] % self.batch_size != 0: | |
f_times += 1 | |
locs_list = list() | |
confs_list = list() | |
with torch.no_grad(): | |
for _ in range(f_times): | |
if _ != f_times - 1: | |
batch_img_x = img_x[_ * self.batch_size:(_ + 1) * self.batch_size] | |
else: | |
batch_img_x = img_x[_ * self.batch_size:] # last batch | |
batch_img_x = batch_img_x.to(device).float() | |
l, c, _ = model(batch_img_x) | |
locs_list.append(l) | |
confs_list.append(c) | |
locs = torch.cat(locs_list, dim=0) | |
confs = torch.cat(confs_list, dim=0) | |
priorbox = PriorBox(cfg_re50, image_size=(im_height, im_width)) | |
priors = priorbox.forward() | |
priors = priors.to(device) | |
prior_data = priors.data | |
img_cpu = img_x.permute([0, 2, 3, 1]).cpu().numpy() | |
i = 0 | |
for img, loc, conf in zip(img_cpu, locs, confs): | |
boxes = decode(loc.data, prior_data, cfg_re50['variance']) | |
boxes = boxes * scale / resize | |
boxes = boxes.cpu().numpy() | |
scores = conf.data.cpu().numpy()[:, 1] | |
# ignore low scores | |
inds = np.where(scores > confidence_threshold)[0] | |
boxes = boxes[inds] | |
scores = scores[inds] | |
# keep top-K before NMS | |
order = scores.argsort()[::-1][:] # top_k | |
boxes = boxes[order] | |
scores = scores[order] | |
# do NMS | |
dets = np.hstack((boxes, scores[:, np.newaxis])).astype( | |
np.float32, copy=False) | |
keep = py_cpu_nms(dets, 0.4) # nms threshold | |
dets = dets[keep, :] | |
# keep top-K faster NMS | |
dets = dets[:, :] # keep top k | |
if len(dets) == 0: | |
continue | |
face_images = [] | |
face_bbox = [] | |
for det in dets: | |
det = list(map(int, det)) | |
x, y, size_bb_x, size_bb_y = get_boundingbox(det, img.shape[1], img.shape[0]) | |
cropped_img = img[y:y + size_bb_y, x:x + size_bb_x, :] + (104, 117, 123) | |
cropped_img = cropped_img.astype(np.uint8) | |
face_images.append(cropped_img) | |
face_bbox.append({ | |
'top':y, | |
'left':x, | |
'width': size_bb_x, | |
'height':size_bb_y, | |
}) | |
i += 1 | |
result.append({'face_images': face_images, | |
'face_bbox': face_bbox}) | |
return result | |
def __call__(self, images, confidence_threshold=0.997, return_heatmap=False): | |
return self.detect(images, confidence_threshold=confidence_threshold, model=self.model, device=self.device) | |
if __name__ == '__main__': | |
img = cv2.imread('sample_files/wefie.jpg') | |
face_detector = FaceDetection() | |
result = face_detector([img]) | |
print(result) |