|
|
|
|
|
|
|
|
|
|
|
import numpy as np |
|
import cv2 |
|
from cv2box.utils.math import Normalize |
|
from cv2box import CVImage |
|
|
|
from .scrfd_insightface import SCRFD |
|
from face_detect.face_align_utils import norm_crop, apply_roi_func |
|
|
|
|
|
SCRFD_MODEL_PATH = '../pretrain_models/' |
|
|
|
class FaceDetect5Landmarks: |
|
def __init__(self, mode='scrfd_500m', tracking=False): |
|
self.mode = mode |
|
self.tracking = tracking |
|
self.dis_list = [] |
|
self.last_bboxes_ = [] |
|
assert self.mode in ['scrfd', 'scrfd_500m', 'mtcnn'] |
|
self.bboxes = self.kpss = self.image = None |
|
if 'scrfd' in self.mode: |
|
if self.mode == 'scrfd_500m': |
|
scrfd_model_path = SCRFD_MODEL_PATH + 'scrfd_500m_bnkps_shape640x640.onnx' |
|
else: |
|
scrfd_model_path = SCRFD_MODEL_PATH + 'scrfd_10g_bnkps.onnx' |
|
self.det_model_scrfd = SCRFD(scrfd_model_path) |
|
self.det_model_scrfd.prepare(ctx_id=0, input_size=(640, 640)) |
|
|
|
|
|
def get_bboxes(self, image, nms_thresh=0.5, max_num=0, min_bbox_size=None): |
|
""" |
|
Args: |
|
image: RGB image path or Numpy array load by cv2 |
|
nms_thresh: |
|
max_num: |
|
min_bbox_size: |
|
Returns: |
|
""" |
|
self.image = CVImage(image).rgb() |
|
|
|
if self.tracking: |
|
if len(self.last_bboxes_) == 0: |
|
self.bboxes, self.kpss = self.det_model_scrfd.detect(image, thresh=nms_thresh, max_num=1, |
|
metric='default') |
|
self.last_bboxes_ = self.bboxes |
|
|
|
else: |
|
self.bboxes, self.kpss = self.det_model_scrfd.detect(image, thresh=nms_thresh, max_num=0, |
|
metric='default') |
|
self.bboxes, self.kpss = self.tracking_filter() |
|
else: |
|
if 'scrfd' in self.mode: |
|
self.bboxes, self.kpss = self.det_model_scrfd.detect(self.image, thresh=nms_thresh, |
|
max_num=max_num, |
|
metric='default') |
|
|
|
return self.bboxes, self.kpss |
|
|
|
def tracking_filter(self): |
|
for i in range(len(self.bboxes)): |
|
self.dis_list.append(np.linalg.norm(Normalize(self.bboxes[i]).np_norm() - Normalize(self.last_bboxes_[0]).np_norm())) |
|
if not self.dis_list: |
|
return [], [] |
|
best_index = np.argmin(np.array(self.dis_list)) |
|
self.dis_list = [] |
|
self.last_bboxes_ = [self.bboxes[best_index]] |
|
return self.last_bboxes_, [self.kpss[best_index]] |
|
|
|
def bboxes_filter(self, min_bbox_size): |
|
min_area = np.power(min_bbox_size, 2) |
|
area_list = (self.bboxes[:, 2] - self.bboxes[:, 0]) * (self.bboxes[:, 3] - self.bboxes[:, 1]) |
|
min_index = np.where(area_list < min_area) |
|
self.bboxes = np.delete(self.bboxes, min_index, axis=0) |
|
self.kpss = np.delete(self.kpss, min_index, axis=0) |
|
|
|
def get_single_face(self, crop_size, mode='mtcnn_512', apply_roi=False): |
|
""" |
|
Args: |
|
crop_size: |
|
mode: default mtcnn_512 arcface_512 arcface default_95 |
|
Returns: cv2 image |
|
""" |
|
assert mode in ['default', 'mtcnn_512', 'mtcnn_256', 'arcface_512', 'arcface', 'default_95'] |
|
if self.bboxes.shape[0] == 0: |
|
return None, None |
|
det_score = self.bboxes[..., 4] |
|
if self.tracking: |
|
best_index = np.argmax(np.array(self.dis_list)) |
|
kpss = None |
|
if self.kpss is not None: |
|
kpss = self.kpss[best_index] |
|
else: |
|
best_index = np.argmax(det_score) |
|
kpss = None |
|
if self.kpss is not None: |
|
kpss = self.kpss[best_index] |
|
if apply_roi: |
|
roi, roi_box, roi_kpss = apply_roi_func(self.image, self.bboxes[best_index], kpss) |
|
align_img, mat_rev = norm_crop(roi, roi_kpss, crop_size, mode=mode) |
|
align_img = cv2.cvtColor(align_img, cv2.COLOR_RGB2BGR) |
|
return align_img, mat_rev, roi_box |
|
else: |
|
align_img, M = norm_crop(self.image, kpss, crop_size, mode=mode) |
|
align_img = cv2.cvtColor(align_img, cv2.COLOR_RGB2BGR) |
|
return align_img, M |
|
|
|
def get_multi_face(self, crop_size, mode='mtcnn_512'): |
|
""" |
|
Args: |
|
crop_size: |
|
mode: default mtcnn_512 arcface_512 arcface |
|
Returns: |
|
""" |
|
if self.bboxes.shape[0] == 0: |
|
return None |
|
align_img_list = [] |
|
M_list = [] |
|
for i in range(self.bboxes.shape[0]): |
|
kps = None |
|
if self.kpss is not None: |
|
kps = self.kpss[i] |
|
align_img, M = norm_crop(self.image, kps, crop_size, mode=mode) |
|
align_img_list.append(align_img) |
|
M_list.append(M) |
|
return align_img_list, M_list |
|
|
|
def draw_face(self): |
|
for i_ in range(self.bboxes.shape[0]): |
|
bbox = self.bboxes[i_] |
|
x1, y1, x2, y2, score = bbox.astype(int) |
|
cv2.rectangle(self.image, (x1, y1), (x2, y2), (255, 0, 0), 2) |
|
if self.kpss is not None: |
|
kps = self.kpss[i_] |
|
for kp in kps: |
|
kp = kp.astype(int) |
|
cv2.circle(self.image, tuple(kp), 1, (0, 0, 255), 2) |
|
CVImage(self.image, image_format='cv2').show() |
|
|