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.download import conditional_download
from facefusion.face_store import get_static_faces, set_static_faces from facefusion.face_store import get_static_faces, set_static_faces
from facefusion.execution_helper import apply_execution_provider_options 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.filesystem import resolve_relative_path
from facefusion.typing import VisionFrame, Face, FaceSet, FaceAnalyserOrder, FaceAnalyserAge, FaceAnalyserGender, ModelSet, Bbox, Kps, Score, Embedding from facefusion.typing import VisionFrame, Face, FaceSet, FaceAnalyserOrder, FaceAnalyserAge, FaceAnalyserGender, ModelSet, Bbox, Kps, Score, Embedding
from facefusion.vision import resize_frame_resolution, unpack_resolution 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]: def filter_by_age(faces : List[Face], age : FaceAnalyserAge) -> List[Face]:
filter_faces = [] filter_faces = []
for face in faces: for face in faces:
if face.age < 13 and age == 'child': if categorize_age(face.age) == age:
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':
filter_faces.append(face) filter_faces.append(face)
return filter_faces 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]: def filter_by_gender(faces : List[Face], gender : FaceAnalyserGender) -> List[Face]:
filter_faces = [] filter_faces = []
for face in faces: for face in faces:
if face.gender == 0 and gender == 'female': if categorize_gender(face.gender) == gender:
filter_faces.append(face)
if face.gender == 1 and gender == 'male':
filter_faces.append(face) filter_faces.append(face)
return filter_faces return filter_faces
+17 -1
View File
@@ -4,7 +4,7 @@ from functools import lru_cache
import cv2 import cv2
import numpy 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]] =\ 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) iou = width * height / (areas[index] + areas[remain_indices] - width * height)
indices = indices[numpy.where(iou <= iou_threshold)[0] + 1] indices = indices[numpy.where(iou <= iou_threshold)[0] + 1]
return keep_indices 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.common_helper import create_int_range
from facefusion.processors.frame.typings import FaceDebuggerItem, FaceEnhancerModel, FaceSwapperModel, FrameEnhancerModel 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_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' ] 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' ] 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) face_enhancer_blend_range : List[int] = create_int_range(0, 100, 1)
frame_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.content_analyser import clear_content_analyser
from facefusion.typing import Face, FaceSet, VisionFrame, Update_Process, ProcessMode 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.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.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 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) secondary_color = (0, 255, 0)
bounding_box = target_face.bbox.astype(numpy.int32) bounding_box = target_face.bbox.astype(numpy.int32)
temp_frame = temp_frame.copy() temp_frame = temp_frame.copy()
if 'bbox' in frame_processors_globals.face_debugger_items: 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) 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: 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] 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) 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: 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: if 'kps' in frame_processors_globals.face_debugger_items:
kps = target_face.kps.astype(numpy.int32) kps = target_face.kps.astype(numpy.int32)
for index in range(kps.shape[0]): for index in range(kps.shape[0]):
cv2.circle(temp_frame, (kps[index][0], kps[index][1]), 3, primary_color, -1) cv2.circle(temp_frame, (kps[index][0], kps[index][1]), 3, primary_color, -1)
if 'score' in frame_processors_globals.face_debugger_items: if 'score' in frame_processors_globals.face_debugger_items:
face_score_text = str(round(target_face.score, 2)) face_score_text = str(round(target_face.score, 2))
face_score_position = (bounding_box[0] + 20, bounding_box[1] + 20) top = top + 20
cv2.putText(temp_frame, face_score_text, face_score_position, cv2.FONT_HERSHEY_SIMPLEX, 0.5, secondary_color, 2) 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 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_frames = read_static_images(source_paths)
source_face = get_average_face(source_frames) source_face = get_average_face(source_frames)
reference_faces = get_reference_faces() if 'reference' in facefusion.globals.face_selector_mode else None reference_faces = get_reference_faces() if 'reference' in facefusion.globals.face_selector_mode else None
for temp_frame_path in temp_frame_paths: for temp_frame_path in temp_frame_paths:
temp_frame = read_image(temp_frame_path) temp_frame = read_image(temp_frame_path)
result_frame = process_frame(source_face, reference_faces, temp_frame) result_frame = process_frame(source_face, reference_faces, temp_frame)
+1 -1
View File
@@ -1,6 +1,6 @@
from typing import Literal 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'] 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'] 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'] FrameEnhancerModel = Literal['real_esrgan_x2plus', 'real_esrgan_x4plus', 'real_esrnet_x4plus']