189 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			189 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Python
		
	
| import os
 | |
| import shutil
 | |
| from typing import Any
 | |
| import insightface
 | |
| 
 | |
| import cv2
 | |
| import numpy as np
 | |
| import modules.globals
 | |
| from tqdm import tqdm
 | |
| from modules.typing import Frame
 | |
| from modules.cluster_analysis import find_cluster_centroids, find_closest_centroid
 | |
| from modules.utilities import get_temp_directory_path, create_temp, extract_frames, clean_temp, get_temp_frame_paths
 | |
| from pathlib import Path
 | |
| 
 | |
| FACE_ANALYSER = None
 | |
| 
 | |
| 
 | |
| def get_face_analyser() -> Any:
 | |
|     global FACE_ANALYSER
 | |
| 
 | |
|     if FACE_ANALYSER is None:
 | |
|         FACE_ANALYSER = insightface.app.FaceAnalysis(name='buffalo_l', providers=modules.globals.execution_providers)
 | |
|         FACE_ANALYSER.prepare(ctx_id=0, det_size=(640, 640))
 | |
|     return FACE_ANALYSER
 | |
| 
 | |
| 
 | |
| def get_one_face(frame: Frame) -> Any:
 | |
|     face = get_face_analyser().get(frame)
 | |
|     try:
 | |
|         return min(face, key=lambda x: x.bbox[0])
 | |
|     except ValueError:
 | |
|         return None
 | |
| 
 | |
| 
 | |
| def get_many_faces(frame: Frame) -> Any:
 | |
|     try:
 | |
|         return get_face_analyser().get(frame)
 | |
|     except IndexError:
 | |
|         return None
 | |
| 
 | |
| def has_valid_map() -> bool:
 | |
|     for map in modules.globals.souce_target_map:
 | |
|         if "source" in map and "target" in map:
 | |
|             return True
 | |
|     return False
 | |
| 
 | |
| def default_source_face() -> Any:
 | |
|     for map in modules.globals.souce_target_map:
 | |
|         if "source" in map:
 | |
|             return map['source']['face']
 | |
|     return None
 | |
| 
 | |
| def simplify_maps() -> Any:
 | |
|     centroids = []
 | |
|     faces = []
 | |
|     for map in modules.globals.souce_target_map:
 | |
|         if "source" in map and "target" in map:
 | |
|             centroids.append(map['target']['face'].normed_embedding)
 | |
|             faces.append(map['source']['face'])
 | |
| 
 | |
|     modules.globals.simple_map = {'source_faces': faces, 'target_embeddings': centroids}
 | |
|     return None
 | |
| 
 | |
| def add_blank_map() -> Any:
 | |
|     try:
 | |
|         max_id = -1
 | |
|         if len(modules.globals.souce_target_map) > 0:
 | |
|             max_id = max(modules.globals.souce_target_map, key=lambda x: x['id'])['id']
 | |
| 
 | |
|         modules.globals.souce_target_map.append({
 | |
|                 'id' : max_id + 1
 | |
|                 })
 | |
|     except ValueError:
 | |
|         return None
 | |
|     
 | |
| def get_unique_faces_from_target_image() -> Any:
 | |
|     try:
 | |
|         modules.globals.souce_target_map = []
 | |
|         target_frame = cv2.imread(modules.globals.target_path)
 | |
|         many_faces = get_many_faces(target_frame)
 | |
|         i = 0
 | |
| 
 | |
|         for face in many_faces:
 | |
|             x_min, y_min, x_max, y_max = face['bbox']
 | |
|             modules.globals.souce_target_map.append({
 | |
|                 'id' : i, 
 | |
|                 'target' : {
 | |
|                             'cv2' : target_frame[int(y_min):int(y_max), int(x_min):int(x_max)],
 | |
|                             'face' : face
 | |
|                             }
 | |
|                 })
 | |
|             i = i + 1
 | |
|     except ValueError:
 | |
|         return None
 | |
|     
 | |
|     
 | |
| def get_unique_faces_from_target_video() -> Any:
 | |
|     try:
 | |
|         modules.globals.souce_target_map = []
 | |
|         frame_face_embeddings = []
 | |
|         face_embeddings = []
 | |
|     
 | |
|         print('Creating temp resources...')
 | |
|         clean_temp(modules.globals.target_path)
 | |
|         create_temp(modules.globals.target_path)
 | |
|         print('Extracting frames...')
 | |
|         extract_frames(modules.globals.target_path)
 | |
| 
 | |
|         temp_frame_paths = get_temp_frame_paths(modules.globals.target_path)
 | |
| 
 | |
|         i = 0
 | |
|         for temp_frame_path in tqdm(temp_frame_paths, desc="Extracting face embeddings from frames"):
 | |
|             temp_frame = cv2.imread(temp_frame_path)
 | |
|             many_faces = get_many_faces(temp_frame)
 | |
| 
 | |
|             for face in many_faces:
 | |
|                 face_embeddings.append(face.normed_embedding)
 | |
|             
 | |
|             frame_face_embeddings.append({'frame': i, 'faces': many_faces, 'location': temp_frame_path})
 | |
|             i += 1
 | |
| 
 | |
|         centroids = find_cluster_centroids(face_embeddings)
 | |
| 
 | |
|         for frame in frame_face_embeddings:
 | |
|             for face in frame['faces']:
 | |
|                 closest_centroid_index, _ = find_closest_centroid(centroids, face.normed_embedding)
 | |
|                 face['target_centroid'] = closest_centroid_index
 | |
| 
 | |
|         for i in range(len(centroids)):
 | |
|             modules.globals.souce_target_map.append({
 | |
|                 'id' : i
 | |
|             })
 | |
| 
 | |
|             temp = []
 | |
|             for frame in tqdm(frame_face_embeddings, desc=f"Mapping frame embeddings to centroids-{i}"):
 | |
|                 temp.append({'frame': frame['frame'], 'faces': [face for face in frame['faces'] if face['target_centroid'] == i], 'location': frame['location']})
 | |
| 
 | |
|             modules.globals.souce_target_map[i]['target_faces_in_frame'] = temp
 | |
| 
 | |
|         # dump_faces(centroids, frame_face_embeddings)
 | |
|         default_target_face()
 | |
|     except ValueError:
 | |
|         return None
 | |
|     
 | |
| 
 | |
| def default_target_face():
 | |
|     for map in modules.globals.souce_target_map:
 | |
|         best_face = None
 | |
|         best_frame = None
 | |
|         for frame in map['target_faces_in_frame']:
 | |
|             if len(frame['faces']) > 0:
 | |
|                 best_face = frame['faces'][0]
 | |
|                 best_frame = frame
 | |
|                 break
 | |
| 
 | |
|         for frame in map['target_faces_in_frame']:
 | |
|             for face in frame['faces']:
 | |
|                 if face['det_score'] > best_face['det_score']:
 | |
|                     best_face = face
 | |
|                     best_frame = frame
 | |
| 
 | |
|         x_min, y_min, x_max, y_max = best_face['bbox']
 | |
| 
 | |
|         target_frame = cv2.imread(best_frame['location'])
 | |
|         map['target'] = {
 | |
|                         'cv2' : target_frame[int(y_min):int(y_max), int(x_min):int(x_max)],
 | |
|                         'face' : best_face
 | |
|                         }
 | |
| 
 | |
| 
 | |
| def dump_faces(centroids: Any, frame_face_embeddings: list):
 | |
|     temp_directory_path = get_temp_directory_path(modules.globals.target_path)
 | |
| 
 | |
|     for i in range(len(centroids)):
 | |
|         if os.path.exists(temp_directory_path + f"/{i}") and os.path.isdir(temp_directory_path + f"/{i}"):
 | |
|             shutil.rmtree(temp_directory_path + f"/{i}")
 | |
|         Path(temp_directory_path + f"/{i}").mkdir(parents=True, exist_ok=True)
 | |
| 
 | |
|         for frame in tqdm(frame_face_embeddings, desc=f"Copying faces to temp/./{i}"):
 | |
|             temp_frame = cv2.imread(frame['location'])
 | |
| 
 | |
|             j = 0
 | |
|             for face in frame['faces']:
 | |
|                 if face['target_centroid'] == i:
 | |
|                     x_min, y_min, x_max, y_max = face['bbox']
 | |
| 
 | |
|                     if temp_frame[int(y_min):int(y_max), int(x_min):int(x_max)].size > 0:
 | |
|                         cv2.imwrite(temp_directory_path + f"/{i}/{frame['frame']}_{j}.png", temp_frame[int(y_min):int(y_max), int(x_min):int(x_max)])
 | |
|                 j += 1 |