Add age and gender to face debugger items (#353)

* Add age and gender to face debugger items

* Rename like suggested in the code review
This commit is contained in:
Henry Ruhs
2024-01-31 09:16:34 +01:00
committed by GitHub
parent 0b345a7e33
commit d19e5918dd
5 changed files with 37 additions and 18 deletions
+3 -11
View File
@@ -8,7 +8,7 @@ import facefusion.globals
from facefusion.download import conditional_download
from facefusion.face_store import get_static_faces, set_static_faces
from facefusion.execution_helper import apply_execution_provider_options
from facefusion.face_helper import warp_face_by_kps, create_static_anchors, distance_to_kps, distance_to_bbox, apply_nms
from facefusion.face_helper import warp_face_by_kps, create_static_anchors, distance_to_kps, distance_to_bbox, apply_nms, categorize_age, categorize_gender
from facefusion.filesystem import resolve_relative_path
from facefusion.typing import VisionFrame, Face, FaceSet, FaceAnalyserOrder, FaceAnalyserAge, FaceAnalyserGender, ModelSet, Bbox, Kps, Score, Embedding
from facefusion.vision import resize_frame_resolution, unpack_resolution
@@ -389,13 +389,7 @@ def sort_by_order(faces : List[Face], order : FaceAnalyserOrder) -> List[Face]:
def filter_by_age(faces : List[Face], age : FaceAnalyserAge) -> List[Face]:
filter_faces = []
for face in faces:
if face.age < 13 and age == 'child':
filter_faces.append(face)
elif face.age < 19 and age == 'teen':
filter_faces.append(face)
elif face.age < 60 and age == 'adult':
filter_faces.append(face)
elif face.age > 59 and age == 'senior':
if categorize_age(face.age) == age:
filter_faces.append(face)
return filter_faces
@@ -403,8 +397,6 @@ def filter_by_age(faces : List[Face], age : FaceAnalyserAge) -> List[Face]:
def filter_by_gender(faces : List[Face], gender : FaceAnalyserGender) -> List[Face]:
filter_faces = []
for face in faces:
if face.gender == 0 and gender == 'female':
filter_faces.append(face)
if face.gender == 1 and gender == 'male':
if categorize_gender(face.gender) == gender:
filter_faces.append(face)
return filter_faces
+17 -1
View File
@@ -4,7 +4,7 @@ from functools import lru_cache
import cv2
import numpy
from facefusion.typing import Bbox, Kps, VisionFrame, Mask, Matrix, Template
from facefusion.typing import Bbox, Kps, VisionFrame, Mask, Matrix, Template, FaceAnalyserAge, FaceAnalyserGender
TEMPLATES : Dict[Template, numpy.ndarray[Any, Any]] =\
{
@@ -121,3 +121,19 @@ def apply_nms(bbox_list : List[Bbox], iou_threshold : float) -> List[int]:
iou = width * height / (areas[index] + areas[remain_indices] - width * height)
indices = indices[numpy.where(iou <= iou_threshold)[0] + 1]
return keep_indices
def categorize_age(age : int) -> FaceAnalyserAge:
if age < 13:
return 'child'
elif age < 19:
return 'teen'
elif age < 60:
return 'adult'
return 'senior'
def categorize_gender(gender : int) -> FaceAnalyserGender:
if gender == 0:
return 'female'
return 'male'
+1 -2
View File
@@ -3,11 +3,10 @@ from typing import List
from facefusion.common_helper import create_int_range
from facefusion.processors.frame.typings import FaceDebuggerItem, FaceEnhancerModel, FaceSwapperModel, FrameEnhancerModel
face_debugger_items : List[FaceDebuggerItem] = [ 'bbox', 'kps', 'face-mask', 'score' ]
face_debugger_items : List[FaceDebuggerItem] = [ 'bbox', 'kps', 'face-mask', 'score', 'age', 'gender' ]
face_enhancer_models : List[FaceEnhancerModel] = [ 'codeformer', 'gfpgan_1.2', 'gfpgan_1.3', 'gfpgan_1.4', 'gpen_bfr_256', 'gpen_bfr_512', 'restoreformer_plus_plus' ]
face_swapper_models : List[FaceSwapperModel] = [ 'blendswap_256', 'inswapper_128', 'inswapper_128_fp16', 'simswap_256', 'simswap_512_unofficial' ]
frame_enhancer_models : List[FrameEnhancerModel] = [ 'real_esrgan_x2plus', 'real_esrgan_x4plus', 'real_esrnet_x4plus' ]
face_enhancer_blend_range : List[int] = create_int_range(0, 100, 1)
frame_enhancer_blend_range : List[int] = create_int_range(0, 100, 1)
@@ -11,7 +11,7 @@ from facefusion.face_store import get_reference_faces
from facefusion.content_analyser import clear_content_analyser
from facefusion.typing import Face, FaceSet, VisionFrame, Update_Process, ProcessMode
from facefusion.vision import read_image, read_static_image, read_static_images, write_image
from facefusion.face_helper import warp_face_by_kps
from facefusion.face_helper import warp_face_by_kps, categorize_age, categorize_gender
from facefusion.face_masker import create_static_box_mask, create_occlusion_mask, create_region_mask, clear_face_occluder, clear_face_parser
from facefusion.processors.frame import globals as frame_processors_globals, choices as frame_processors_choices
@@ -71,6 +71,7 @@ def debug_face(source_face : Face, target_face : Face, reference_faces : FaceSet
secondary_color = (0, 255, 0)
bounding_box = target_face.bbox.astype(numpy.int32)
temp_frame = temp_frame.copy()
if 'bbox' in frame_processors_globals.face_debugger_items:
cv2.rectangle(temp_frame, (bounding_box[0], bounding_box[1]), (bounding_box[2], bounding_box[3]), secondary_color, 2)
if 'face-mask' in frame_processors_globals.face_debugger_items:
@@ -92,14 +93,24 @@ def debug_face(source_face : Face, target_face : Face, reference_faces : FaceSet
inverse_mask_contours = cv2.findContours(inverse_mask_frame, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)[0]
cv2.drawContours(temp_frame, inverse_mask_contours, -1, primary_color, 2)
if bounding_box[3] - bounding_box[1] > 60 and bounding_box[2] - bounding_box[0] > 60:
top = bounding_box[1]
left = bounding_box[0] + 20
if 'kps' in frame_processors_globals.face_debugger_items:
kps = target_face.kps.astype(numpy.int32)
for index in range(kps.shape[0]):
cv2.circle(temp_frame, (kps[index][0], kps[index][1]), 3, primary_color, -1)
if 'score' in frame_processors_globals.face_debugger_items:
face_score_text = str(round(target_face.score, 2))
face_score_position = (bounding_box[0] + 20, bounding_box[1] + 20)
cv2.putText(temp_frame, face_score_text, face_score_position, cv2.FONT_HERSHEY_SIMPLEX, 0.5, secondary_color, 2)
top = top + 20
cv2.putText(temp_frame, face_score_text, (left, top), cv2.FONT_HERSHEY_SIMPLEX, 0.5, secondary_color, 2)
if 'age' in frame_processors_globals.face_debugger_items:
face_age_text = categorize_age(target_face.age)
top = top + 20
cv2.putText(temp_frame, face_age_text, (left, top), cv2.FONT_HERSHEY_SIMPLEX, 0.5, secondary_color, 2)
if 'gender' in frame_processors_globals.face_debugger_items:
face_gender_text = categorize_gender(target_face.gender)
top = top + 20
cv2.putText(temp_frame, face_gender_text, (left, top), cv2.FONT_HERSHEY_SIMPLEX, 0.5, secondary_color, 2)
return temp_frame
@@ -129,6 +140,7 @@ def process_frames(source_paths : List[str], temp_frame_paths : List[str], updat
source_frames = read_static_images(source_paths)
source_face = get_average_face(source_frames)
reference_faces = get_reference_faces() if 'reference' in facefusion.globals.face_selector_mode else None
for temp_frame_path in temp_frame_paths:
temp_frame = read_image(temp_frame_path)
result_frame = process_frame(source_face, reference_faces, temp_frame)
+1 -1
View File
@@ -1,6 +1,6 @@
from typing import Literal
FaceDebuggerItem = Literal['bbox', 'kps', 'face-mask', 'score']
FaceDebuggerItem = Literal['bbox', 'kps', 'face-mask', 'score', 'age', 'gender']
FaceEnhancerModel = Literal['codeformer', 'gfpgan_1.2', 'gfpgan_1.3', 'gfpgan_1.4', 'gpen_bfr_256', 'gpen_bfr_512', 'restoreformer_plus_plus']
FaceSwapperModel = Literal['blendswap_256', 'inswapper_128', 'inswapper_128_fp16', 'simswap_256', 'simswap_512_unofficial']
FrameEnhancerModel = Literal['real_esrgan_x2plus', 'real_esrgan_x4plus', 'real_esrnet_x4plus']