| | import os |
| | import cv2 |
| | import numpy as np |
| | from tqdm import tqdm |
| | from utils import scale_bbox_from_center |
| |
|
| | detect_conditions = [ |
| | "best detection", |
| | "left most", |
| | "right most", |
| | "top most", |
| | "bottom most", |
| | "middle", |
| | "biggest", |
| | "smallest", |
| | ] |
| |
|
| | swap_options_list = [ |
| | "All Face", |
| | "Specific Face", |
| | "Age less than", |
| | "Age greater than", |
| | "All Male", |
| | "All Female", |
| | "Left Most", |
| | "Right Most", |
| | "Top Most", |
| | "Bottom Most", |
| | "Middle", |
| | "Biggest", |
| | "Smallest", |
| | ] |
| |
|
| | def get_single_face(faces, method="best detection"): |
| | total_faces = len(faces) |
| | if total_faces == 1: |
| | return faces[0] |
| |
|
| | print(f"{total_faces} face detected. Using {method} face.") |
| | if method == "best detection": |
| | return sorted(faces, key=lambda face: face["det_score"])[-1] |
| | elif method == "left most": |
| | return sorted(faces, key=lambda face: face["bbox"][0])[0] |
| | elif method == "right most": |
| | return sorted(faces, key=lambda face: face["bbox"][0])[-1] |
| | elif method == "top most": |
| | return sorted(faces, key=lambda face: face["bbox"][1])[0] |
| | elif method == "bottom most": |
| | return sorted(faces, key=lambda face: face["bbox"][1])[-1] |
| | elif method == "middle": |
| | return sorted(faces, key=lambda face: ( |
| | (face["bbox"][0] + face["bbox"][2]) / 2 - 0.5) ** 2 + |
| | ((face["bbox"][1] + face["bbox"][3]) / 2 - 0.5) ** 2)[len(faces) // 2] |
| | elif method == "biggest": |
| | return sorted(faces, key=lambda face: (face["bbox"][2] - face["bbox"][0]) * (face["bbox"][3] - face["bbox"][1]))[-1] |
| | elif method == "smallest": |
| | return sorted(faces, key=lambda face: (face["bbox"][2] - face["bbox"][0]) * (face["bbox"][3] - face["bbox"][1]))[0] |
| |
|
| |
|
| | def analyse_face(image, model, return_single_face=True, detect_condition="best detection", scale=1.0): |
| | faces = model.get(image) |
| | if scale != 1: |
| | for i, face in enumerate(faces): |
| | landmark = face['kps'] |
| | center = np.mean(landmark, axis=0) |
| | landmark = center + (landmark - center) * scale |
| | faces[i]['kps'] = landmark |
| |
|
| | if not return_single_face: |
| | return faces |
| |
|
| | return get_single_face(faces, method=detect_condition) |
| |
|
| |
|
| | def cosine_distance(a, b): |
| | a /= np.linalg.norm(a) |
| | b /= np.linalg.norm(b) |
| | return 1 - np.dot(a, b) |
| |
|
| |
|
| | def get_analysed_data(face_analyser, image_sequence, source_data, swap_condition="All face", detect_condition="left most", scale=1.0): |
| | if swap_condition != "Specific Face": |
| | source_path, age = source_data |
| | source_image = cv2.imread(source_path) |
| | analysed_source = analyse_face(source_image, face_analyser, return_single_face=True, detect_condition=detect_condition, scale=scale) |
| | else: |
| | analysed_source_specifics = [] |
| | source_specifics, threshold = source_data |
| | for source, specific in zip(*source_specifics): |
| | if source is None or specific is None: |
| | continue |
| | analysed_source = analyse_face(source, face_analyser, return_single_face=True, detect_condition=detect_condition, scale=scale) |
| | analysed_specific = analyse_face(specific, face_analyser, return_single_face=True, detect_condition=detect_condition, scale=scale) |
| | analysed_source_specifics.append([analysed_source, analysed_specific]) |
| |
|
| | analysed_target_list = [] |
| | analysed_source_list = [] |
| | whole_frame_eql_list = [] |
| | num_faces_per_frame = [] |
| |
|
| | total_frames = len(image_sequence) |
| | curr_idx = 0 |
| | for curr_idx, frame_path in tqdm(enumerate(image_sequence), total=total_frames, desc="Analysing face data"): |
| | frame = cv2.imread(frame_path) |
| | analysed_faces = analyse_face(frame, face_analyser, return_single_face=False, detect_condition=detect_condition, scale=scale) |
| |
|
| | n_faces = 0 |
| | for analysed_face in analysed_faces: |
| | if swap_condition == "All Face": |
| | analysed_target_list.append(analysed_face) |
| | analysed_source_list.append(analysed_source) |
| | whole_frame_eql_list.append(frame_path) |
| | n_faces += 1 |
| | elif swap_condition == "Age less than" and analysed_face["age"] < age: |
| | analysed_target_list.append(analysed_face) |
| | analysed_source_list.append(analysed_source) |
| | whole_frame_eql_list.append(frame_path) |
| | n_faces += 1 |
| | elif swap_condition == "Age greater than" and analysed_face["age"] > age: |
| | analysed_target_list.append(analysed_face) |
| | analysed_source_list.append(analysed_source) |
| | whole_frame_eql_list.append(frame_path) |
| | n_faces += 1 |
| | elif swap_condition == "All Male" and analysed_face["gender"] == 1: |
| | analysed_target_list.append(analysed_face) |
| | analysed_source_list.append(analysed_source) |
| | whole_frame_eql_list.append(frame_path) |
| | n_faces += 1 |
| | elif swap_condition == "All Female" and analysed_face["gender"] == 0: |
| | analysed_target_list.append(analysed_face) |
| | analysed_source_list.append(analysed_source) |
| | whole_frame_eql_list.append(frame_path) |
| | n_faces += 1 |
| | elif swap_condition == "Specific Face": |
| | for analysed_source, analysed_specific in analysed_source_specifics: |
| | distance = cosine_distance(analysed_specific["embedding"], analysed_face["embedding"]) |
| | if distance < threshold: |
| | analysed_target_list.append(analysed_face) |
| | analysed_source_list.append(analysed_source) |
| | whole_frame_eql_list.append(frame_path) |
| | n_faces += 1 |
| |
|
| | if swap_condition == "Left Most": |
| | analysed_face = get_single_face(analysed_faces, method="left most") |
| | analysed_target_list.append(analysed_face) |
| | analysed_source_list.append(analysed_source) |
| | whole_frame_eql_list.append(frame_path) |
| | n_faces += 1 |
| |
|
| | elif swap_condition == "Right Most": |
| | analysed_face = get_single_face(analysed_faces, method="right most") |
| | analysed_target_list.append(analysed_face) |
| | analysed_source_list.append(analysed_source) |
| | whole_frame_eql_list.append(frame_path) |
| | n_faces += 1 |
| |
|
| | elif swap_condition == "Top Most": |
| | analysed_face = get_single_face(analysed_faces, method="top most") |
| | analysed_target_list.append(analysed_face) |
| | analysed_source_list.append(analysed_source) |
| | whole_frame_eql_list.append(frame_path) |
| | n_faces += 1 |
| |
|
| | elif swap_condition == "Bottom Most": |
| | analysed_face = get_single_face(analysed_faces, method="bottom most") |
| | analysed_target_list.append(analysed_face) |
| | analysed_source_list.append(analysed_source) |
| | whole_frame_eql_list.append(frame_path) |
| | n_faces += 1 |
| |
|
| | elif swap_condition == "Middle": |
| | analysed_face = get_single_face(analysed_faces, method="middle") |
| | analysed_target_list.append(analysed_face) |
| | analysed_source_list.append(analysed_source) |
| | whole_frame_eql_list.append(frame_path) |
| | n_faces += 1 |
| |
|
| | elif swap_condition == "Biggest": |
| | analysed_face = get_single_face(analysed_faces, method="biggest") |
| | analysed_target_list.append(analysed_face) |
| | analysed_source_list.append(analysed_source) |
| | whole_frame_eql_list.append(frame_path) |
| | n_faces += 1 |
| |
|
| | elif swap_condition == "Smallest": |
| | analysed_face = get_single_face(analysed_faces, method="smallest") |
| | analysed_target_list.append(analysed_face) |
| | analysed_source_list.append(analysed_source) |
| | whole_frame_eql_list.append(frame_path) |
| | n_faces += 1 |
| |
|
| | num_faces_per_frame.append(n_faces) |
| |
|
| | return analysed_target_list, analysed_source_list, whole_frame_eql_list, num_faces_per_frame |
| |
|