import numpy as np import cv2 def extract_frames(filename, num_frames, model, image_size=(380, 380)): cap = cv2.VideoCapture(filename) if not cap.isOpened(): return [], [] frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) frame_idxs = np.linspace(0, frame_count - 1, min(num_frames, frame_count), dtype=int) croppedfaces, idx_list = [], [] for idx in frame_idxs: ret = cap.set(cv2.CAP_PROP_POS_FRAMES, idx) if not ret: continue ret, frame = cap.read() if not ret: continue frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) faces = extract_face(frame, model, image_size) if faces: croppedfaces.extend(faces) idx_list.extend([idx] * len(faces)) cap.release() return croppedfaces, idx_list def extract_face(frame, model, image_size=(380, 380)): faces = model.predict_jsons(frame) if len(faces[0]['bbox']) == 0: scale_factor = 0.5 small_frame = cv2.resize(frame, None, fx=scale_factor, fy=scale_factor) faces = model.predict_jsons(small_frame) if len(faces[0]['bbox']) == 0: return [] for face in faces: face['bbox'] = [coord/scale_factor for coord in face['bbox']] croppedfaces = [] for face_idx in range(len(faces)): x0, y0, x1, y1 = faces[face_idx]['bbox'] bbox = np.array([[x0, y0], [x1, y1]]) face = crop_face(frame, None, bbox, False, crop_by_bbox=True, only_img=True, phase='test') croppedfaces.append(cv2.resize(face, dsize=image_size).transpose((2, 0, 1))) return croppedfaces def crop_face(img, landmark=None, bbox=None, margin=False, crop_by_bbox=True, abs_coord=False, only_img=False, phase='test'): assert phase in ['train', 'val', 'test'] assert landmark is not None or bbox is not None H, W = len(img), len(img[0]) if crop_by_bbox: x0, y0 = bbox[0] x1, y1 = bbox[1] w = x1 - x0 h = y1 - y0 w0_margin = w/4 w1_margin = w/4 h0_margin = h/4 h1_margin = h/4 else: x0, y0 = landmark[:68,0].min(), landmark[:68,1].min() x1, y1 = landmark[:68,0].max(), landmark[:68,1].max() w = x1 - x0 h = y1 - y0 w0_margin = w/8 w1_margin = w/8 h0_margin = h/2 h1_margin = h/5 if margin: w0_margin *= 4 w1_margin *= 4 h0_margin *= 2 h1_margin *= 2 elif phase == 'train': rand_factor = np.random.rand(4) * 0.6 + 0.2 w0_margin *= rand_factor[0] w1_margin *= rand_factor[1] h0_margin *= rand_factor[2] h1_margin *= rand_factor[3] else: w0_margin *= 0.5 w1_margin *= 0.5 h0_margin *= 0.5 h1_margin *= 0.5 y0_new = max(0, int(y0-h0_margin)) y1_new = min(H, int(y1+h1_margin)+1) x0_new = max(0, int(x0-w0_margin)) x1_new = min(W, int(x1+w1_margin)+1) img_cropped = img[y0_new:y1_new, x0_new:x1_new] if only_img: return img_cropped if landmark is not None: landmark_cropped = np.zeros_like(landmark) for i, (p,q) in enumerate(landmark): landmark_cropped[i] = [p-x0_new, q-y0_new] else: landmark_cropped = None if bbox is not None: bbox_cropped = np.zeros_like(bbox) for i, (p,q) in enumerate(bbox): bbox_cropped[i] = [p-x0_new, q-y0_new] else: bbox_cropped = None if abs_coord: return img_cropped, landmark_cropped, bbox_cropped, (y0-y0_new, x0-x0_new, y1_new-y1, x1_new-x1), y0_new, y1_new, x0_new, x1_new else: return img_cropped, landmark_cropped, bbox_cropped, (y0-y0_new, x0-x0_new, y1_new-y1, x1_new-x1)