mirror of
https://github.com/facefusion/facefusion.git
synced 2026-09-27 09:41:47 +02:00
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:
@@ -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
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
@@ -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,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']
|
||||||
|
|||||||
Reference in New Issue
Block a user