File size: 3,889 Bytes
9e14838
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import os

os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"

from .ct.detection.utils import grab_all_frames, get_valid_faces, sample_chunks
from .ct.operations import multiple_tracking
import numpy as np
from .ct.face_alignment import LandmarkPredictor
from .ct.detection import FaceDetector
import cv2
from .utils import flatten,partition


detector = FaceDetector(0)
predictor = LandmarkPredictor(0)


def get_five(ldm68):
    groups = [range(36, 42), range(42, 48), [30], [48], [54]]
    points = []
    for group in groups:
        points.append(ldm68[group].mean(0))
    return np.array(points)


def get_bbox(mask):
    try:
        y, x = np.nonzero(mask[..., 0])
        return x.min() - 1, y.min() - 1, x.max() + 1, y.max() + 1
    except:
        return None


def get_bigger_box(image, box, scale=0.5):
    height, width = image.shape[:2]
    box = np.rint(box).astype(np.int)
    new_box = box.reshape(2, 2)
    size = new_box[1] - new_box[0]
    diff = scale * size
    diff = diff[None, :] * np.array([-1, 1])[:, None]
    new_box = new_box + diff
    new_box[:, 0] = np.clip(new_box[:, 0], 0, width - 1)
    new_box[:, 1] = np.clip(new_box[:, 1], 0, height - 1)
    new_box = np.rint(new_box).astype(np.int)
    return new_box.reshape(-1)


def process_bigger_clips(clips, dete_res, clip_size, step, scale=0.5):
    assert len(clips) % clip_size == 0
    detect_results = sample_chunks(dete_res, clip_size, step)
    clips = sample_chunks(clips, clip_size, step)
    new_clips = []
    for i, (frame_clip, record_clip) in enumerate(zip(clips, detect_results)):
        tracks = multiple_tracking(record_clip)
        for j, track in enumerate(tracks):
            new_images = []
            for (box, ldm, _), frame in zip(track, frame_clip):
                big_box = get_bigger_box(frame, box, scale)
                x1, y1, x2, y2 = big_box
                top_left = big_box[:2][None, :]
                new_ldm5 = ldm - top_left
                box = np.rint(box).astype(np.int)
                new_box = (box.reshape(2, 2) - top_left).reshape(-1)
                feed = LandmarkPredictor.prepare_feed(frame, box)
                ldm68 = predictor(feed) - top_left
                new_images.append(
                    (frame[y1:y2, x1:x2], big_box, new_box, new_ldm5, ldm68)
                )
            new_clips.append(new_images)
    return new_clips


def post(detected_faces):
    return [[face[:4], None, face[-1]] for face in detected_faces]


def check(detect_res):
    return min([len(faces) for faces in detect_res]) != 0


def detect_all(file, sfd_only=False, return_frames=False, max_size=None):
    frames = grab_all_frames(file, max_size=max_size, cvt=True)
    if not sfd_only:
        detect_res = flatten(
            [detector.detect(item) for item in partition(frames, 50)]
        )
        detect_res = get_valid_faces(detect_res, thres=0.5)
    else:
        raise NotImplementedError

    all_68 = get_lm68(frames, detect_res)
    if not return_frames:
        return detect_res, all_68
    else:
        return detect_res, all_68, frames


def get_lm68(frames, detect_res):
    assert len(frames) == len(detect_res)
    frame_count = len(frames)
    all_68 = []
    for i in range(frame_count):
        frame = frames[i]
        faces = detect_res[i]
        if len(faces) == 0:
            res_68 = []
        else:
            feeds = []
            for face in faces:
                assert len(face) == 3
                box = face[0]
                feed = LandmarkPredictor.prepare_feed(frame, box)
                feeds.append(feed)
            res_68 = predictor(feeds)
            assert len(res_68) == len(faces)
            for face, l_68 in zip(faces, res_68):
                if face[1] is None:
                    face[1] = get_five(l_68)
        all_68.append(res_68)

    assert len(all_68) == len(detect_res)
    return all_68