| import cv2
|
| import numpy as np
|
| from skimage import transform as trans
|
|
|
|
|
|
|
| def get_keypts(face):
|
|
|
|
|
| if len(face['keypoints']) == 0:
|
| return []
|
|
|
| leye = np.array(face['keypoints']['left_eye'], dtype=np.int).reshape(-1, 2)
|
| reye = np.array(face['keypoints']['right_eye'],
|
| dtype=np.int).reshape(-1, 2)
|
| nose = np.array(face['keypoints']['nose'], dtype=np.int).reshape(-1, 2)
|
| lmouth = np.array(face['keypoints']['mouth_left'],
|
| dtype=np.int).reshape(-1, 2)
|
| rmouth = np.array(face['keypoints']['mouth_right'],
|
| dtype=np.int).reshape(-1, 2)
|
|
|
| pts = np.concatenate([leye, reye, nose, lmouth, rmouth], axis=0)
|
|
|
| return pts
|
|
|
|
|
| def img_align_crop(img, landmark=None, outsize=None, scale=1.3, mask=None):
|
| """ align and crop the face according to the given bbox and landmarks
|
| landmark: 5 key points
|
| """
|
|
|
| M = None
|
|
|
| target_size = [112, 112]
|
|
|
| dst = np.array([
|
| [30.2946, 51.6963],
|
| [65.5318, 51.5014],
|
| [48.0252, 71.7366],
|
| [33.5493, 92.3655],
|
| [62.7299, 92.2041]], dtype=np.float32)
|
|
|
| if target_size[1] == 112:
|
| dst[:, 0] += 8.0
|
|
|
| dst[:, 0] = dst[:, 0] * outsize[0] / target_size[0]
|
| dst[:, 1] = dst[:, 1] * outsize[1] / target_size[1]
|
|
|
| target_size = outsize
|
|
|
| margin_rate = scale - 1
|
| x_margin = target_size[0] * margin_rate / 2.
|
| y_margin = target_size[1] * margin_rate / 2.
|
|
|
|
|
| dst[:, 0] += x_margin
|
| dst[:, 1] += y_margin
|
|
|
|
|
| dst[:, 0] *= target_size[0] / (target_size[0] + 2 * x_margin)
|
| dst[:, 1] *= target_size[1] / (target_size[1] + 2 * y_margin)
|
|
|
| src = landmark.astype(np.float32)
|
|
|
|
|
| tform = trans.SimilarityTransform()
|
| tform.estimate(src, dst)
|
| M = tform.params[0:2, :]
|
|
|
|
|
|
|
|
|
| img = cv2.warpAffine(img, M, (target_size[1], target_size[0]))
|
|
|
| if outsize is not None:
|
| img = cv2.resize(img, (outsize[1], outsize[0]))
|
|
|
| if mask is not None:
|
| mask = cv2.warpAffine(mask, M, (target_size[1], target_size[0]))
|
| mask = cv2.resize(mask, (outsize[1], outsize[0]))
|
| return img, mask
|
| else:
|
| return img
|
|
|
|
|
|
|
|
|
|
|
| def expand_bbox(bbox, width, height, scale=1.3, minsize=None):
|
| """
|
| Expand original boundingbox by scale.
|
| :param bbx: original boundingbox
|
| :param width: frame width
|
| :param height: frame height
|
| :param scale: bounding box size multiplier to get a bigger face region
|
| :param minsize: set minimum bounding box size
|
| :return: expanded bbox
|
| """
|
| x, y, w, h = bbox
|
|
|
|
|
| cx = int(x + w / 2)
|
| cy = int(y + h / 2)
|
|
|
|
|
| new_size = max(int(w * scale), int(h * scale))
|
| new_x = max(0, int(cx - new_size / 2))
|
| new_y = max(0, int(cy - new_size / 2))
|
|
|
|
|
| new_size = min(width - new_x, new_size)
|
| new_size = min(height - new_size, new_size)
|
|
|
| return new_x, new_y, new_size, new_size
|
|
|
|
|
| def extract_face_MTCNN(face_detector, image, expand_scale=1.3, res=256):
|
|
|
| height, width = image.shape[:2]
|
|
|
|
|
| rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
|
|
|
|
| faces = face_detector.detect_faces(rgb)
|
| if len(faces):
|
|
|
| face = None
|
| bbox = None
|
| max_region = 0
|
| for ff in faces:
|
| if max_region == 0:
|
| face = ff
|
| bbox = face['box']
|
| max_region = bbox[2]*bbox[3]
|
| else:
|
| bb = ff['box']
|
| region = bb[2]*bb[3]
|
| if region > max_rigion:
|
| max_rigion = region
|
| face = ff
|
| bbox = face['box']
|
| print(max_region)
|
|
|
|
|
|
|
|
|
|
|
|
|
| x, y, w, h = expand_bbox(bbox, width, height, scale=expand_scale)
|
| cropped_face = rgb[y:y+h, x:x+w]
|
|
|
| cropped_face = cv2.resize(
|
| cropped_face, (res, res), interpolation=cv2.INTER_CUBIC)
|
| cropped_face = cv2.cvtColor(cropped_face, cv2.COLOR_RGB2BGR)
|
| return cropped_face
|
|
|
| return None
|
|
|
|
|
| def extract_aligned_face_MTCNN(face_detector, image, expand_scale=1.3, res=256, mask=None):
|
|
|
| height, width = image.shape[:2]
|
|
|
|
|
| rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
|
|
|
|
| faces = face_detector.detect_faces(rgb)
|
| if len(faces):
|
|
|
| face = None
|
| bbox = None
|
| max_region = 0
|
| for i, ff in enumerate(faces):
|
| if max_region == 0:
|
| face = ff
|
| bbox = face['box']
|
| max_region = bbox[2]*bbox[3]
|
| else:
|
| bb = ff['box']
|
| region = bb[2]*bb[3]
|
| if region > max_region:
|
| max_region = region
|
| face = ff
|
| bbox = face['box']
|
|
|
|
|
|
|
| landmarks = get_keypts(face)
|
|
|
|
|
|
|
| if mask is not None:
|
| cropped_face, cropped_mask = img_align_crop(rgb, landmarks, outsize=[
|
| res, res], scale=expand_scale, mask=mask)
|
| cropped_face = cv2.cvtColor(cropped_face, cv2.COLOR_RGB2BGR)
|
| cropped_mask = cv2.cvtColor(cropped_mask, cv2.COLOR_RGB2GRAY)
|
| return cropped_face, cropped_mask
|
| else:
|
| cropped_face = img_align_crop(rgb, landmarks, outsize=[
|
| res, res], scale=expand_scale)
|
| cropped_face = cv2.cvtColor(cropped_face, cv2.COLOR_RGB2BGR)
|
| return cropped_face
|
|
|
| return None
|
|
|
|
|
| def extract_face_DLIB(face_detector, image, expand_scale=1.3, res=256):
|
|
|
| height, width = image.shape[:2]
|
|
|
|
|
| gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
|
|
|
|
| faces = face_detector(gray, 1)
|
| if len(faces):
|
|
|
| face = faces[0]
|
|
|
| x1 = face.left()
|
| y1 = face.top()
|
| x2 = face.right()
|
| y2 = face.bottom()
|
| bbox = (x1, y1, x2-x1, y2-y1)
|
|
|
|
|
|
|
| x, y, w, h = expand_bbox(bbox, width, height, scale=expand_scale)
|
| cropped_face = image[y:y+h, x:x+w]
|
|
|
| cropped_face = cv2.resize(
|
| cropped_face, (res, res), interpolation=cv2.INTER_CUBIC)
|
|
|
| return cropped_face
|
|
|
| return None
|
|
|