mirror of
https://github.com/facefusion/facefusion.git
synced 2026-09-15 12:05:27 +02:00
add hrffa face aligner and alphaface_256 face swapper from 3.9.0
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RKsZJc4Fu2WgFd9R2Ayu25
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
62b2819504
commit
574965f65d
@@ -42,6 +42,32 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
|
||||
},
|
||||
'size': (256, 256)
|
||||
},
|
||||
'hrffa':
|
||||
{
|
||||
'__metadata__':
|
||||
{
|
||||
'vendor': 'PINTO0309',
|
||||
'license': 'MIT',
|
||||
'year': 2025
|
||||
},
|
||||
'hashes':
|
||||
{
|
||||
'hrffa':
|
||||
{
|
||||
'url': resolve_download_url('models-3.9.0', 'hrffa.hash'),
|
||||
'path': resolve_relative_path('../.assets/models/hrffa.hash')
|
||||
}
|
||||
},
|
||||
'sources':
|
||||
{
|
||||
'hrffa':
|
||||
{
|
||||
'url': resolve_download_url('models-3.9.0', 'hrffa.onnx'),
|
||||
'path': resolve_relative_path('../.assets/models/hrffa.onnx')
|
||||
}
|
||||
},
|
||||
'size': (256, 256)
|
||||
},
|
||||
'peppa_wutz':
|
||||
{
|
||||
'__metadata__':
|
||||
@@ -119,6 +145,10 @@ def collect_model_downloads() -> Tuple[DownloadSet, DownloadSet]:
|
||||
'fan_68_5': model_set.get('fan_68_5').get('sources').get('fan_68_5')
|
||||
}
|
||||
|
||||
if state_manager.get_item('face_aligner_model') == 'hrffa':
|
||||
model_hash_set['hrffa'] = model_set.get('hrffa').get('hashes').get('hrffa')
|
||||
model_source_set['hrffa'] = model_set.get('hrffa').get('sources').get('hrffa')
|
||||
|
||||
for face_aligner_model in [ '2dfan4', 'peppa_wutz' ]:
|
||||
if state_manager.get_item('face_aligner_model') in [ 'many', face_aligner_model ]:
|
||||
model_hash_set[face_aligner_model] = model_set.get(face_aligner_model).get('hashes').get(face_aligner_model)
|
||||
@@ -134,19 +164,21 @@ def pre_check() -> bool:
|
||||
|
||||
|
||||
def detect_face_landmark(vision_frame : VisionFrame, bounding_box : BoundingBox, face_angle : Angle) -> Tuple[FaceLandmark68, Score]:
|
||||
face_landmark_2dfan4 = None
|
||||
face_landmark_peppa_wutz = None
|
||||
face_landmark_score_2dfan4 = 0.0
|
||||
face_landmark_score_peppa_wutz = 0.0
|
||||
if state_manager.get_item('face_aligner_model') == '2dfan4':
|
||||
return detect_with_2dfan4(vision_frame, bounding_box, face_angle)
|
||||
|
||||
if state_manager.get_item('face_aligner_model') in [ 'many', '2dfan4' ]:
|
||||
face_landmark_2dfan4, face_landmark_score_2dfan4 = detect_with_2dfan4(vision_frame, bounding_box, face_angle)
|
||||
if state_manager.get_item('face_aligner_model') == 'hrffa':
|
||||
return detect_with_hrffa(vision_frame, bounding_box)
|
||||
|
||||
if state_manager.get_item('face_aligner_model') in [ 'many', 'peppa_wutz' ]:
|
||||
face_landmark_peppa_wutz, face_landmark_score_peppa_wutz = detect_with_peppa_wutz(vision_frame, bounding_box, face_angle)
|
||||
if state_manager.get_item('face_aligner_model') == 'peppa_wutz':
|
||||
return detect_with_peppa_wutz(vision_frame, bounding_box, face_angle)
|
||||
|
||||
face_landmark_2dfan4, face_landmark_score_2dfan4 = detect_with_2dfan4(vision_frame, bounding_box, face_angle)
|
||||
face_landmark_peppa_wutz, face_landmark_score_peppa_wutz = detect_with_peppa_wutz(vision_frame, bounding_box, face_angle)
|
||||
|
||||
if face_landmark_score_2dfan4 > face_landmark_score_peppa_wutz - 0.2:
|
||||
return face_landmark_2dfan4, face_landmark_score_2dfan4
|
||||
|
||||
return face_landmark_peppa_wutz, face_landmark_score_peppa_wutz
|
||||
|
||||
|
||||
@@ -169,6 +201,24 @@ def detect_with_2dfan4(temp_vision_frame: VisionFrame, bounding_box: BoundingBox
|
||||
return face_landmark_68, face_landmark_score_68
|
||||
|
||||
|
||||
def detect_with_hrffa(temp_vision_frame : VisionFrame, bounding_box : BoundingBox) -> Tuple[FaceLandmark68, Score]:
|
||||
model_size = create_static_model_set('full').get('hrffa').get('size')
|
||||
scale = model_size[0] / (numpy.subtract(bounding_box[2:], bounding_box[:2]).max().clip(1, None) * 1.7)
|
||||
translation = (model_size[0] - numpy.add(bounding_box[2:], bounding_box[:2]) * scale) * 0.5
|
||||
|
||||
crop_vision_frame, affine_matrix = warp_face_by_translation(temp_vision_frame, translation, scale, model_size)
|
||||
crop_vision_frame = crop_vision_frame[:, :, ::-1].transpose(2, 0, 1).astype(numpy.float32) / 255.0
|
||||
crop_vision_frame = (crop_vision_frame - 0.5) / 0.5
|
||||
crop_vision_frame = numpy.expand_dims(crop_vision_frame, axis = 0)
|
||||
|
||||
face_landmark_68 = forward_with_hrffa(crop_vision_frame)
|
||||
face_landmark_68 = face_landmark_68.reshape(-1, 2) * model_size[0]
|
||||
face_landmark_68 = transform_points(face_landmark_68, cv2.invertAffineTransform(affine_matrix))
|
||||
face_landmark_score_68 = 1.0
|
||||
|
||||
return face_landmark_68, face_landmark_score_68
|
||||
|
||||
|
||||
def detect_with_peppa_wutz(temp_vision_frame : VisionFrame, bounding_box : BoundingBox, face_angle : Angle) -> Tuple[FaceLandmark68, Score]:
|
||||
model_size = create_static_model_set('full').get('peppa_wutz').get('size')
|
||||
scale = 195 / numpy.subtract(bounding_box[2:], bounding_box[:2]).max().clip(1, None)
|
||||
@@ -216,6 +266,18 @@ def forward_with_2dfan4(crop_vision_frame : VisionFrame) -> Tuple[Prediction, Pr
|
||||
return prediction
|
||||
|
||||
|
||||
def forward_with_hrffa(crop_vision_frame : VisionFrame) -> Prediction:
|
||||
face_aligner = get_inference_pool().get('hrffa')
|
||||
|
||||
with conditional_thread_semaphore():
|
||||
prediction = face_aligner.run(None,
|
||||
{
|
||||
'input': crop_vision_frame
|
||||
})[0]
|
||||
|
||||
return prediction
|
||||
|
||||
|
||||
def forward_with_peppa_wutz(crop_vision_frame : VisionFrame) -> Prediction:
|
||||
face_aligner = get_inference_pool().get('peppa_wutz')
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ from facefusion.processors.modules.face_swapper.types import FaceSwapperModel, F
|
||||
|
||||
face_swapper_set : FaceSwapperSet =\
|
||||
{
|
||||
'alphaface_256': [ '256x256', '512x512', '768x768', '1024x1024' ],
|
||||
'blendswap_256': [ '256x256', '384x384', '512x512', '768x768', '1024x1024' ],
|
||||
'ghost_1_256': [ '256x256', '512x512', '768x768', '1024x1024' ],
|
||||
'ghost_2_256': [ '256x256', '512x512', '768x768', '1024x1024' ],
|
||||
|
||||
@@ -33,6 +33,36 @@ from facefusion.vision import read_static_image, read_static_images, read_static
|
||||
def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
|
||||
return\
|
||||
{
|
||||
'alphaface_256':
|
||||
{
|
||||
'__metadata__':
|
||||
{
|
||||
'vendor': 'AlphaFace',
|
||||
'license': 'Non-Commercial',
|
||||
'year': 2026
|
||||
},
|
||||
'hashes':
|
||||
{
|
||||
'face_swapper':
|
||||
{
|
||||
'url': resolve_download_url('models-3.9.0', 'alphaface_256.hash'),
|
||||
'path': resolve_relative_path('../.assets/models/alphaface_256.hash')
|
||||
}
|
||||
},
|
||||
'sources':
|
||||
{
|
||||
'face_swapper':
|
||||
{
|
||||
'url': resolve_download_url('models-3.9.0', 'alphaface_256.onnx'),
|
||||
'path': resolve_relative_path('../.assets/models/alphaface_256.onnx')
|
||||
}
|
||||
},
|
||||
'type': 'alphaface',
|
||||
'template': 'arcface_128',
|
||||
'size': (256, 256),
|
||||
'mean': [ 0.0, 0.0, 0.0 ],
|
||||
'standard_deviation': [ 1.0, 1.0, 1.0 ]
|
||||
},
|
||||
'blendswap_256':
|
||||
{
|
||||
'__metadata__':
|
||||
@@ -713,6 +743,10 @@ def prepare_source_frame(source_face : Face, source_vision_frame : VisionFrame)
|
||||
def prepare_source_embedding(source_face : Face) -> Embedding:
|
||||
model_type = get_model_options().get('type')
|
||||
|
||||
if model_type == 'alphaface':
|
||||
source_embedding = source_face.embedding.reshape((1, -1))
|
||||
return source_embedding
|
||||
|
||||
if model_type == 'ghost':
|
||||
source_embedding = source_face.embedding.reshape(-1, 512)
|
||||
source_embedding, _ = convert_source_embedding(source_embedding)
|
||||
@@ -741,7 +775,7 @@ def balance_source_embedding(source_embedding : Embedding, target_embedding : Em
|
||||
face_swapper_weight = state_manager.get_item('face_swapper_weight')
|
||||
face_swapper_weight = numpy.interp(face_swapper_weight, [ 0, 1 ], [ 0.35, -0.35 ]).astype(numpy.float32)
|
||||
|
||||
if model_type in [ 'hififace', 'hyperswap', 'inswapper', 'simswap' ]:
|
||||
if model_type in [ 'alphaface', 'hififace', 'hyperswap', 'inswapper', 'simswap' ]:
|
||||
target_embedding = target_embedding / numpy.linalg.norm(target_embedding)
|
||||
|
||||
source_embedding = source_embedding.reshape(1, -1)
|
||||
|
||||
@@ -11,7 +11,7 @@ FaceSwapperInputs = TypedDict('FaceSwapperInputs',
|
||||
'temp_vision_mask' : Mask
|
||||
})
|
||||
|
||||
FaceSwapperModel = Literal['blendswap_256', 'ghost_1_256', 'ghost_2_256', 'ghost_3_256', 'hififace_unofficial_256', 'hyperswap_1a_256', 'hyperswap_1b_256', 'hyperswap_1c_256', 'inswapper_128', 'inswapper_128_fp16', 'simswap_256', 'simswap_unofficial_512', 'uniface_256']
|
||||
FaceSwapperModel = Literal['alphaface_256', 'blendswap_256', 'ghost_1_256', 'ghost_2_256', 'ghost_3_256', 'hififace_unofficial_256', 'hyperswap_1a_256', 'hyperswap_1b_256', 'hyperswap_1c_256', 'inswapper_128', 'inswapper_128_fp16', 'simswap_256', 'simswap_unofficial_512', 'uniface_256']
|
||||
|
||||
FaceSwapperWeight : TypeAlias = float
|
||||
|
||||
|
||||
+1
-1
@@ -185,7 +185,7 @@ TableHeader : TypeAlias = str
|
||||
TableContent : TypeAlias = Any
|
||||
|
||||
FaceDetectorModel = Literal['many', 'retinaface', 'scrfd', 'yolo_face', 'yunet']
|
||||
FaceAlignerModel = Literal['many', '2dfan4', 'peppa_wutz']
|
||||
FaceAlignerModel = Literal['many', '2dfan4', 'hrffa', 'peppa_wutz']
|
||||
FaceDetectorSet : TypeAlias = Dict[FaceDetectorModel, List[str]]
|
||||
FaceSelectorMode = Literal['many', 'one', 'reference']
|
||||
FaceSelectorOrder = Literal['left-right', 'right-left', 'top-bottom', 'bottom-top', 'small-large', 'large-small', 'best-worst', 'worst-best']
|
||||
|
||||
Reference in New Issue
Block a user