Compare commits

..
7 Commits
Author SHA1 Message Date
57fcb86b82 3.6.0 (#1062)
* mark as next

* add fran model

* add support for corridor key (#1060)

* introduce despill color

* simplify the apply dispill color

* finalize naming for both fill and despill

* follow vision_frame convension

* patch fran model

* adjust fran urls

* Feat/dynamic env setup (#1061)

* dynamic environment setup

* dynamic environment setup

* fix fran model

* prevent directml using incompatible corridor_key model

* fix environment setup for windows

* switch to corridor_key_1024 and corridor_key_2048

* switch to corridor_key_1024 and corridor_key_2048

* mark it as 3.6.0

* rename environment to conda

* rename environment to conda

* fix testing for face analyser

* some background remove cosmetics

* some background remove cosmetics

* some background remove cosmetics

* update preview

---------

Co-authored-by: harisreedhar <h4harisreedhar.s.s@gmail.com>
2026-03-16 15:08:43 +01:00
henryruhs 2cc05d4fba update licenses 2026-03-09 21:24:53 +01:00
Henry RuhsandGitHub a498f3d618 Patch 3.5.4 (#1055)
* remove insecure flag from curl

* eleminate repating definitons

* limit processors and ui layouts by choices

* follow couple of v4 standards

* use more secure mkstemp

* dynamic cache path for execution providers

* fix benchmarker, prevent path traveling via job-id

* fix order in execution provider choices

* resort by prioroty

* introduce support for QNN

* close file description for Windows to stop crying

* prevent ConnectionResetError under windows

* needed for nested .caches directory as onnxruntime does not create it

* different approach to silent asyncio

* update dependencies

* simplify the name to just inference providers

* switch to trt_builder_optimization_level 4
2026-03-08 11:00:45 +01:00
c7976ec9d4 Fix list literal spacing to use [ x, y ] style (#1044)
Enforce consistent space inside square brackets for all list literals
across source and test files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-18 09:18:03 +01:00
Henry RuhsandGitHub 8801668562 3.5.3
* honor webcam resolution to avoid stripe mismatch, update dependencies

* avoid version conflicts

* enforce prores video extraction to 8 bit

* make the installer more robust on execution switch

* make the installer more robust on execution switch

* improve the installer env handling

* different approach to handle env
2026-02-11 09:35:08 +01:00
Henry RuhsandGitHub a7f3de3dbc Rename local(s) to locale(s) (#1008) 2025-12-17 18:37:51 +01:00
Henry RuhsandGitHub 666c15f9da Patch 3.5.2 (#1002)
* Remove old files

* Fix some spacing

* Introduce retry to download

* More testing

* Better installer scripting (#994)

* Better installer scripting

* Add migraphx installer support

* Add migraphx installer support

* Ignore issue

* Ignore issue

* Make --force-install optional
2025-12-13 08:37:15 +01:00
77 changed files with 814 additions and 495 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

+2 -1
View File
@@ -67,7 +67,8 @@ processors =
age_modifier_model =
age_modifier_direction =
background_remover_model =
background_remover_color =
background_remover_fill_color =
background_remover_despill_color =
deep_swapper_model =
deep_swapper_morph =
expression_restorer_model =
+2 -1
View File
@@ -4,7 +4,8 @@ import os
os.environ['OMP_NUM_THREADS'] = '1'
from facefusion import core
from facefusion import conda, core
if __name__ == '__main__':
conda.setup()
core.cli()
+78 -92
View File
@@ -7,6 +7,84 @@ from facefusion.types import ApplyStateItem, Args
from facefusion.vision import detect_video_fps
def apply_args(args : Args, apply_state_item : ApplyStateItem) -> None:
apply_state_item('command', args.get('command'))
apply_state_item('temp_path', args.get('temp_path'))
apply_state_item('jobs_path', args.get('jobs_path'))
apply_state_item('source_paths', args.get('source_paths'))
apply_state_item('target_path', args.get('target_path'))
apply_state_item('output_path', args.get('output_path'))
apply_state_item('source_pattern', args.get('source_pattern'))
apply_state_item('target_pattern', args.get('target_pattern'))
apply_state_item('output_pattern', args.get('output_pattern'))
apply_state_item('face_detector_model', args.get('face_detector_model'))
apply_state_item('face_detector_size', args.get('face_detector_size'))
apply_state_item('face_detector_margin', normalize_space(args.get('face_detector_margin')))
apply_state_item('face_detector_angles', args.get('face_detector_angles'))
apply_state_item('face_detector_score', args.get('face_detector_score'))
apply_state_item('face_landmarker_model', args.get('face_landmarker_model'))
apply_state_item('face_landmarker_score', args.get('face_landmarker_score'))
apply_state_item('face_selector_mode', args.get('face_selector_mode'))
apply_state_item('face_selector_order', args.get('face_selector_order'))
apply_state_item('face_selector_age_start', args.get('face_selector_age_start'))
apply_state_item('face_selector_age_end', args.get('face_selector_age_end'))
apply_state_item('face_selector_gender', args.get('face_selector_gender'))
apply_state_item('face_selector_race', args.get('face_selector_race'))
apply_state_item('reference_face_position', args.get('reference_face_position'))
apply_state_item('reference_face_distance', args.get('reference_face_distance'))
apply_state_item('reference_frame_number', args.get('reference_frame_number'))
apply_state_item('face_occluder_model', args.get('face_occluder_model'))
apply_state_item('face_parser_model', args.get('face_parser_model'))
apply_state_item('face_mask_types', args.get('face_mask_types'))
apply_state_item('face_mask_areas', args.get('face_mask_areas'))
apply_state_item('face_mask_regions', args.get('face_mask_regions'))
apply_state_item('face_mask_blur', args.get('face_mask_blur'))
apply_state_item('face_mask_padding', normalize_space(args.get('face_mask_padding')))
apply_state_item('voice_extractor_model', args.get('voice_extractor_model'))
apply_state_item('trim_frame_start', args.get('trim_frame_start'))
apply_state_item('trim_frame_end', args.get('trim_frame_end'))
apply_state_item('temp_frame_format', args.get('temp_frame_format'))
apply_state_item('keep_temp', args.get('keep_temp'))
apply_state_item('output_image_quality', args.get('output_image_quality'))
apply_state_item('output_image_scale', args.get('output_image_scale'))
apply_state_item('output_audio_encoder', args.get('output_audio_encoder'))
apply_state_item('output_audio_quality', args.get('output_audio_quality'))
apply_state_item('output_audio_volume', args.get('output_audio_volume'))
apply_state_item('output_video_encoder', args.get('output_video_encoder'))
apply_state_item('output_video_preset', args.get('output_video_preset'))
apply_state_item('output_video_quality', args.get('output_video_quality'))
apply_state_item('output_video_scale', args.get('output_video_scale'))
if args.get('output_video_fps') or is_video(args.get('target_path')):
output_video_fps = normalize_fps(args.get('output_video_fps')) or detect_video_fps(args.get('target_path'))
apply_state_item('output_video_fps', output_video_fps)
available_processors = [ get_file_name(file_path) for file_path in resolve_file_paths('facefusion/processors/modules') ]
apply_state_item('processors', args.get('processors'))
for processor_module in get_processors_modules(available_processors):
processor_module.apply_args(args, apply_state_item)
apply_state_item('open_browser', args.get('open_browser'))
apply_state_item('ui_layouts', args.get('ui_layouts'))
apply_state_item('ui_workflow', args.get('ui_workflow'))
apply_state_item('execution_device_ids', args.get('execution_device_ids'))
apply_state_item('execution_providers', args.get('execution_providers'))
apply_state_item('execution_thread_count', args.get('execution_thread_count'))
apply_state_item('download_providers', args.get('download_providers'))
apply_state_item('download_scope', args.get('download_scope'))
apply_state_item('benchmark_mode', args.get('benchmark_mode'))
apply_state_item('benchmark_resolutions', args.get('benchmark_resolutions'))
apply_state_item('benchmark_cycle_count', args.get('benchmark_cycle_count'))
apply_state_item('video_memory_strategy', args.get('video_memory_strategy'))
apply_state_item('system_memory_limit', args.get('system_memory_limit'))
apply_state_item('log_level', args.get('log_level'))
apply_state_item('halt_on_error', args.get('halt_on_error'))
apply_state_item('job_id', args.get('job_id'))
apply_state_item('job_status', args.get('job_status'))
apply_state_item('step_index', args.get('step_index'))
def reduce_step_args(args : Args) -> Args:
step_args =\
{
@@ -37,95 +115,3 @@ def collect_job_args() -> Args:
key: state_manager.get_item(key) for key in job_store.get_job_keys() #type:ignore[arg-type]
}
return job_args
def apply_args(args : Args, apply_state_item : ApplyStateItem) -> None:
# general
apply_state_item('command', args.get('command'))
# paths
apply_state_item('temp_path', args.get('temp_path'))
apply_state_item('jobs_path', args.get('jobs_path'))
apply_state_item('source_paths', args.get('source_paths'))
apply_state_item('target_path', args.get('target_path'))
apply_state_item('output_path', args.get('output_path'))
# patterns
apply_state_item('source_pattern', args.get('source_pattern'))
apply_state_item('target_pattern', args.get('target_pattern'))
apply_state_item('output_pattern', args.get('output_pattern'))
# face detector
apply_state_item('face_detector_model', args.get('face_detector_model'))
apply_state_item('face_detector_size', args.get('face_detector_size'))
apply_state_item('face_detector_margin', normalize_space(args.get('face_detector_margin')))
apply_state_item('face_detector_angles', args.get('face_detector_angles'))
apply_state_item('face_detector_score', args.get('face_detector_score'))
# face landmarker
apply_state_item('face_landmarker_model', args.get('face_landmarker_model'))
apply_state_item('face_landmarker_score', args.get('face_landmarker_score'))
# face selector
apply_state_item('face_selector_mode', args.get('face_selector_mode'))
apply_state_item('face_selector_order', args.get('face_selector_order'))
apply_state_item('face_selector_age_start', args.get('face_selector_age_start'))
apply_state_item('face_selector_age_end', args.get('face_selector_age_end'))
apply_state_item('face_selector_gender', args.get('face_selector_gender'))
apply_state_item('face_selector_race', args.get('face_selector_race'))
apply_state_item('reference_face_position', args.get('reference_face_position'))
apply_state_item('reference_face_distance', args.get('reference_face_distance'))
apply_state_item('reference_frame_number', args.get('reference_frame_number'))
# face masker
apply_state_item('face_occluder_model', args.get('face_occluder_model'))
apply_state_item('face_parser_model', args.get('face_parser_model'))
apply_state_item('face_mask_types', args.get('face_mask_types'))
apply_state_item('face_mask_areas', args.get('face_mask_areas'))
apply_state_item('face_mask_regions', args.get('face_mask_regions'))
apply_state_item('face_mask_blur', args.get('face_mask_blur'))
apply_state_item('face_mask_padding', normalize_space(args.get('face_mask_padding')))
# voice extractor
apply_state_item('voice_extractor_model', args.get('voice_extractor_model'))
# frame extraction
apply_state_item('trim_frame_start', args.get('trim_frame_start'))
apply_state_item('trim_frame_end', args.get('trim_frame_end'))
apply_state_item('temp_frame_format', args.get('temp_frame_format'))
apply_state_item('keep_temp', args.get('keep_temp'))
# output creation
apply_state_item('output_image_quality', args.get('output_image_quality'))
apply_state_item('output_image_scale', args.get('output_image_scale'))
apply_state_item('output_audio_encoder', args.get('output_audio_encoder'))
apply_state_item('output_audio_quality', args.get('output_audio_quality'))
apply_state_item('output_audio_volume', args.get('output_audio_volume'))
apply_state_item('output_video_encoder', args.get('output_video_encoder'))
apply_state_item('output_video_preset', args.get('output_video_preset'))
apply_state_item('output_video_quality', args.get('output_video_quality'))
apply_state_item('output_video_scale', args.get('output_video_scale'))
if args.get('output_video_fps') or is_video(args.get('target_path')):
output_video_fps = normalize_fps(args.get('output_video_fps')) or detect_video_fps(args.get('target_path'))
apply_state_item('output_video_fps', output_video_fps)
# processors
available_processors = [ get_file_name(file_path) for file_path in resolve_file_paths('facefusion/processors/modules') ]
apply_state_item('processors', args.get('processors'))
for processor_module in get_processors_modules(available_processors):
processor_module.apply_args(args, apply_state_item)
# uis
apply_state_item('open_browser', args.get('open_browser'))
apply_state_item('ui_layouts', args.get('ui_layouts'))
apply_state_item('ui_workflow', args.get('ui_workflow'))
# execution
apply_state_item('execution_device_ids', args.get('execution_device_ids'))
apply_state_item('execution_providers', args.get('execution_providers'))
apply_state_item('execution_thread_count', args.get('execution_thread_count'))
# download
apply_state_item('download_providers', args.get('download_providers'))
apply_state_item('download_scope', args.get('download_scope'))
# benchmark
apply_state_item('benchmark_mode', args.get('benchmark_mode'))
apply_state_item('benchmark_resolutions', args.get('benchmark_resolutions'))
apply_state_item('benchmark_cycle_count', args.get('benchmark_cycle_count'))
# memory
apply_state_item('video_memory_strategy', args.get('video_memory_strategy'))
apply_state_item('system_memory_limit', args.get('system_memory_limit'))
# misc
apply_state_item('log_level', args.get('log_level'))
apply_state_item('halt_on_error', args.get('halt_on_error'))
# jobs
apply_state_item('job_id', args.get('job_id'))
apply_state_item('job_status', args.get('job_status'))
apply_state_item('step_index', args.get('step_index'))
+1 -1
View File
@@ -89,7 +89,7 @@ def cycle(cycle_count : int) -> BenchmarkCycleSet:
def suggest_output_path(target_path : str) -> str:
target_file_extension = get_file_extension(target_path)
return os.path.join(tempfile.gettempdir(), hashlib.sha1().hexdigest()[:8] + target_file_extension)
return os.path.join(tempfile.gettempdir(), hashlib.sha1(target_path.encode()).hexdigest() + target_file_extension)
def render() -> None:
+2 -2
View File
@@ -43,9 +43,9 @@ def detect_local_camera_ids(id_start : int, id_end : int) -> List[int]:
local_camera_ids = []
for camera_id in range(id_start, id_end):
cv2.setLogLevel(0)
cv2.utils.logging.setLogLevel(0)
camera_capture = get_local_camera_capture(camera_id)
cv2.setLogLevel(3)
cv2.utils.logging.setLogLevel(3)
if camera_capture and camera_capture.isOpened():
local_camera_ids.append(camera_id)
+34 -33
View File
@@ -1,5 +1,5 @@
import logging
from typing import List, Sequence
from typing import List, Sequence, get_args
from facefusion.common_helper import create_float_range, create_int_range
from facefusion.types import Angle, AudioEncoder, AudioFormat, AudioTypeSet, BenchmarkMode, BenchmarkResolution, BenchmarkSet, DownloadProvider, DownloadProviderSet, DownloadScope, EncoderSet, ExecutionProvider, ExecutionProviderSet, FaceDetectorModel, FaceDetectorSet, FaceLandmarkerModel, FaceMaskArea, FaceMaskAreaSet, FaceMaskRegion, FaceMaskRegionSet, FaceMaskType, FaceOccluderModel, FaceParserModel, FaceSelectorMode, FaceSelectorOrder, Gender, ImageFormat, ImageTypeSet, JobStatus, LogLevel, LogLevelSet, Race, Score, TempFrameFormat, UiWorkflow, VideoEncoder, VideoFormat, VideoMemoryStrategy, VideoPreset, VideoTypeSet, VoiceExtractorModel
@@ -12,15 +12,15 @@ face_detector_set : FaceDetectorSet =\
'yolo_face': [ '640x640' ],
'yunet': [ '640x640' ]
}
face_detector_models : List[FaceDetectorModel] = list(face_detector_set.keys())
face_landmarker_models : List[FaceLandmarkerModel] = [ 'many', '2dfan4', 'peppa_wutz' ]
face_selector_modes : List[FaceSelectorMode] = [ 'many', 'one', 'reference' ]
face_selector_orders : List[FaceSelectorOrder] = [ 'left-right', 'right-left', 'top-bottom', 'bottom-top', 'small-large', 'large-small', 'best-worst', 'worst-best' ]
face_selector_genders : List[Gender] = [ 'female', 'male' ]
face_selector_races : List[Race] = [ 'white', 'black', 'latino', 'asian', 'indian', 'arabic' ]
face_occluder_models : List[FaceOccluderModel] = [ 'many', 'xseg_1', 'xseg_2', 'xseg_3' ]
face_parser_models : List[FaceParserModel] = [ 'bisenet_resnet_18', 'bisenet_resnet_34' ]
face_mask_types : List[FaceMaskType] = [ 'box', 'occlusion', 'area', 'region' ]
face_detector_models : List[FaceDetectorModel] = list(get_args(FaceDetectorModel))
face_landmarker_models : List[FaceLandmarkerModel] = list(get_args(FaceLandmarkerModel))
face_selector_modes : List[FaceSelectorMode] = list(get_args(FaceSelectorMode))
face_selector_orders : List[FaceSelectorOrder] = list(get_args(FaceSelectorOrder))
face_selector_genders : List[Gender] = list(get_args(Gender))
face_selector_races : List[Race] = list(get_args(Race))
face_occluder_models : List[FaceOccluderModel] = list(get_args(FaceOccluderModel))
face_parser_models : List[FaceParserModel] = list(get_args(FaceParserModel))
face_mask_types : List[FaceMaskType] = list(get_args(FaceMaskType))
face_mask_area_set : FaceMaskAreaSet =\
{
'upper-face': [ 0, 1, 2, 31, 32, 33, 34, 35, 14, 15, 16, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17 ],
@@ -40,10 +40,10 @@ face_mask_region_set : FaceMaskRegionSet =\
'upper-lip': 12,
'lower-lip': 13
}
face_mask_areas : List[FaceMaskArea] = list(face_mask_area_set.keys())
face_mask_regions : List[FaceMaskRegion] = list(face_mask_region_set.keys())
face_mask_areas : List[FaceMaskArea] = list(get_args(FaceMaskArea))
face_mask_regions : List[FaceMaskRegion] = list(get_args(FaceMaskRegion))
voice_extractor_models : List[VoiceExtractorModel] = [ 'kim_vocal_1', 'kim_vocal_2', 'uvr_mdxnet' ]
voice_extractor_models : List[VoiceExtractorModel] = list(get_args(VoiceExtractorModel))
audio_type_set : AudioTypeSet =\
{
@@ -74,21 +74,21 @@ video_type_set : VideoTypeSet =\
'webm': 'video/webm',
'wmv': 'video/x-ms-wmv'
}
audio_formats : List[AudioFormat] = list(audio_type_set.keys())
image_formats : List[ImageFormat] = list(image_type_set.keys())
video_formats : List[VideoFormat] = list(video_type_set.keys())
temp_frame_formats : List[TempFrameFormat] = [ 'bmp', 'jpeg', 'png', 'tiff' ]
audio_formats : List[AudioFormat] = list(get_args(AudioFormat))
image_formats : List[ImageFormat] = list(get_args(ImageFormat))
video_formats : List[VideoFormat] = list(get_args(VideoFormat))
temp_frame_formats : List[TempFrameFormat] = list(get_args(TempFrameFormat))
output_audio_encoders : List[AudioEncoder] = list(get_args(AudioEncoder))
output_video_encoders : List[VideoEncoder] = list(get_args(VideoEncoder))
output_encoder_set : EncoderSet =\
{
'audio': [ 'flac', 'aac', 'libmp3lame', 'libopus', 'libvorbis', 'pcm_s16le', 'pcm_s32le' ],
'video': [ 'libx264', 'libx264rgb', 'libx265', 'libvpx-vp9', 'h264_nvenc', 'hevc_nvenc', 'h264_amf', 'hevc_amf', 'h264_qsv', 'hevc_qsv', 'h264_videotoolbox', 'hevc_videotoolbox', 'rawvideo' ]
'audio': output_audio_encoders,
'video': output_video_encoders
}
output_audio_encoders : List[AudioEncoder] = output_encoder_set.get('audio')
output_video_encoders : List[VideoEncoder] = output_encoder_set.get('video')
output_video_presets : List[VideoPreset] = [ 'ultrafast', 'superfast', 'veryfast', 'faster', 'fast', 'medium', 'slow', 'slower', 'veryslow' ]
output_video_presets : List[VideoPreset] = list(get_args(VideoPreset))
benchmark_modes : List[BenchmarkMode] = [ 'warm', 'cold' ]
benchmark_modes : List[BenchmarkMode] = list(get_args(BenchmarkMode))
benchmark_set : BenchmarkSet =\
{
'240p': '.assets/examples/target-240p.mp4',
@@ -99,20 +99,21 @@ benchmark_set : BenchmarkSet =\
'1440p': '.assets/examples/target-1440p.mp4',
'2160p': '.assets/examples/target-2160p.mp4'
}
benchmark_resolutions : List[BenchmarkResolution] = list(benchmark_set.keys())
benchmark_resolutions : List[BenchmarkResolution] = list(get_args(BenchmarkResolution))
execution_provider_set : ExecutionProviderSet =\
{
'cuda': 'CUDAExecutionProvider',
'tensorrt': 'TensorrtExecutionProvider',
'directml': 'DmlExecutionProvider',
'rocm': 'ROCMExecutionProvider',
'migraphx': 'MIGraphXExecutionProvider',
'openvino': 'OpenVINOExecutionProvider',
'coreml': 'CoreMLExecutionProvider',
'openvino': 'OpenVINOExecutionProvider',
'qnn': 'QNNExecutionProvider',
'directml': 'DmlExecutionProvider',
'cpu': 'CPUExecutionProvider'
}
execution_providers : List[ExecutionProvider] = list(execution_provider_set.keys())
execution_providers : List[ExecutionProvider] = list(get_args(ExecutionProvider))
download_provider_set : DownloadProviderSet =\
{
'github':
@@ -133,10 +134,10 @@ download_provider_set : DownloadProviderSet =\
'path': '/facefusion/{base_name}/resolve/main/{file_name}'
}
}
download_providers : List[DownloadProvider] = list(download_provider_set.keys())
download_scopes : List[DownloadScope] = [ 'lite', 'full' ]
download_providers : List[DownloadProvider] = list(get_args(DownloadProvider))
download_scopes : List[DownloadScope] = list(get_args(DownloadScope))
video_memory_strategies : List[VideoMemoryStrategy] = [ 'strict', 'moderate', 'tolerant' ]
video_memory_strategies : List[VideoMemoryStrategy] = list(get_args(VideoMemoryStrategy))
log_level_set : LogLevelSet =\
{
@@ -145,10 +146,10 @@ log_level_set : LogLevelSet =\
'info': logging.INFO,
'debug': logging.DEBUG
}
log_levels : List[LogLevel] = list(log_level_set.keys())
log_levels : List[LogLevel] = list(get_args(LogLevel))
ui_workflows : List[UiWorkflow] = [ 'instant_runner', 'job_runner', 'job_manager' ]
job_statuses : List[JobStatus] = [ 'drafted', 'queued', 'completed', 'failed' ]
ui_workflows : List[UiWorkflow] = list(get_args(UiWorkflow))
job_statuses : List[JobStatus] = list(get_args(JobStatus))
benchmark_cycle_count_range : Sequence[int] = create_int_range(1, 10, 1)
execution_thread_count_range : Sequence[int] = create_int_range(1, 32, 1)
+41
View File
@@ -0,0 +1,41 @@
import os
import sys
from typing import List
from facefusion.common_helper import is_linux, is_windows
def setup() -> None:
conda_prefix = os.getenv('CONDA_PREFIX')
conda_ready = os.getenv('CONDA_READY')
if conda_prefix and not conda_ready:
if is_linux():
python_id = 'python' + str(sys.version_info.major) + '.' + str(sys.version_info.minor)
library_paths : List[str] =\
[
os.path.join(conda_prefix, 'lib'),
os.path.join(conda_prefix, 'lib', python_id, 'site-packages', 'tensorrt_libs')
]
library_paths = list(filter(os.path.exists, library_paths))
if library_paths:
if os.getenv('LD_LIBRARY_PATH'):
library_paths.append(os.getenv('LD_LIBRARY_PATH'))
os.environ['LD_LIBRARY_PATH'] = os.pathsep.join(library_paths)
os.environ['CONDA_READY'] = '1'
os.execv(sys.executable, [ sys.executable ] + sys.argv)
if is_windows():
library_paths =\
[
os.path.join(conda_prefix, 'Lib'),
os.path.join(conda_prefix, 'Lib', 'site-packages', 'tensorrt_libs')
]
library_paths = list(filter(os.path.exists, library_paths))
if library_paths:
if os.getenv('PATH'):
library_paths.append(os.getenv('PATH'))
os.environ['PATH'] = os.pathsep.join(library_paths)
os.environ['CONDA_READY'] = '1'
+6 -2
View File
@@ -9,14 +9,14 @@ from facefusion.types import Command
def run(commands : List[Command]) -> List[Command]:
user_agent = metadata.get('name') + '/' + metadata.get('version')
return [ shutil.which('curl'), '--user-agent', user_agent, '--insecure', '--location', '--silent' ] + commands
return [ shutil.which('curl'), '--user-agent', user_agent, '--location', '--silent' ] + commands
def chain(*commands : List[Command]) -> List[Command]:
return list(itertools.chain(*commands))
def head(url : str) -> List[Command]:
def ping(url : str) -> List[Command]:
return [ '-I', url ]
@@ -26,3 +26,7 @@ def download(url : str, download_file_path : str) -> List[Command]:
def set_timeout(timeout : int) -> List[Command]:
return [ '--connect-timeout', str(timeout) ]
def set_retry(retry : int) -> List[Command]:
return [ '--retry', str(retry) ]
+4 -3
View File
@@ -29,7 +29,8 @@ def conditional_download(download_directory_path : str, urls : List[str]) -> Non
with tqdm(total = download_size, initial = initial_size, desc = translator.get('downloading'), unit = 'B', unit_scale = True, unit_divisor = 1024, ascii = ' =', disable = state_manager.get_item('log_level') in [ 'warn', 'error' ]) as progress:
commands = curl_builder.chain(
curl_builder.download(url, download_file_path),
curl_builder.set_timeout(5)
curl_builder.set_timeout(5),
curl_builder.set_retry(5)
)
open_curl(commands)
current_size = initial_size
@@ -44,7 +45,7 @@ def conditional_download(download_directory_path : str, urls : List[str]) -> Non
@lru_cache(maxsize = 64)
def get_static_download_size(url : str) -> int:
commands = curl_builder.chain(
curl_builder.head(url),
curl_builder.ping(url),
curl_builder.set_timeout(5)
)
process = open_curl(commands)
@@ -62,7 +63,7 @@ def get_static_download_size(url : str) -> int:
@lru_cache(maxsize = 64)
def ping_static_url(url : str) -> bool:
commands = curl_builder.chain(
curl_builder.head(url),
curl_builder.ping(url),
curl_builder.set_timeout(5)
)
process = open_curl(commands)
+61 -27
View File
@@ -1,15 +1,17 @@
import os
import shutil
import subprocess
import xml.etree.ElementTree as ElementTree
from functools import lru_cache
from typing import List, Optional
from onnxruntime import get_available_providers, set_default_logger_severity
import onnxruntime
import facefusion.choices
from facefusion.types import ExecutionDevice, ExecutionProvider, InferenceSessionProvider, ValueAndUnit
from facefusion.filesystem import create_directory, is_directory
from facefusion.types import ExecutionDevice, ExecutionProvider, InferenceOptionSet, InferenceProvider, ValueAndUnit
set_default_logger_severity(3)
onnxruntime.set_default_logger_severity(3)
def has_execution_provider(execution_provider : ExecutionProvider) -> bool:
@@ -17,7 +19,7 @@ def has_execution_provider(execution_provider : ExecutionProvider) -> bool:
def get_available_execution_providers() -> List[ExecutionProvider]:
inference_session_providers = get_available_providers()
inference_session_providers = onnxruntime.get_available_providers()
available_execution_providers : List[ExecutionProvider] = []
for execution_provider, execution_provider_value in facefusion.choices.execution_provider_set.items():
@@ -28,54 +30,86 @@ def get_available_execution_providers() -> List[ExecutionProvider]:
return available_execution_providers
def create_inference_session_providers(execution_device_id : int, execution_providers : List[ExecutionProvider]) -> List[InferenceSessionProvider]:
inference_session_providers : List[InferenceSessionProvider] = []
def create_inference_providers(execution_device_id : int, execution_providers : List[ExecutionProvider]) -> List[InferenceProvider]:
inference_providers : List[InferenceProvider] = []
cache_path = resolve_cache_path()
for execution_provider in execution_providers:
if execution_provider == 'cuda':
inference_session_providers.append((facefusion.choices.execution_provider_set.get(execution_provider),
inference_providers.append((facefusion.choices.execution_provider_set.get(execution_provider),
{
'device_id': execution_device_id,
'cudnn_conv_algo_search': resolve_cudnn_conv_algo_search()
}))
if execution_provider == 'tensorrt':
inference_session_providers.append((facefusion.choices.execution_provider_set.get(execution_provider),
inference_option_set : InferenceOptionSet =\
{
'device_id': execution_device_id,
'trt_engine_cache_enable': True,
'trt_engine_cache_path': '.caches',
'trt_timing_cache_enable': True,
'trt_timing_cache_path': '.caches',
'trt_builder_optimization_level': 5
}))
'device_id': execution_device_id
}
if is_directory(cache_path) or create_directory(cache_path):
inference_option_set.update(
{
'trt_engine_cache_enable': True,
'trt_engine_cache_path': cache_path,
'trt_timing_cache_enable': True,
'trt_timing_cache_path': cache_path,
'trt_builder_optimization_level': 4
})
inference_providers.append((facefusion.choices.execution_provider_set.get(execution_provider), inference_option_set))
if execution_provider in [ 'directml', 'rocm' ]:
inference_session_providers.append((facefusion.choices.execution_provider_set.get(execution_provider),
inference_providers.append((facefusion.choices.execution_provider_set.get(execution_provider),
{
'device_id': execution_device_id
}))
if execution_provider == 'migraphx':
inference_session_providers.append((facefusion.choices.execution_provider_set.get(execution_provider),
inference_option_set =\
{
'device_id': execution_device_id,
'migraphx_model_cache_dir': '.caches'
}))
'device_id': execution_device_id
}
if is_directory(cache_path) or create_directory(cache_path):
inference_option_set.update(
{
'migraphx_model_cache_dir': cache_path
})
inference_providers.append((facefusion.choices.execution_provider_set.get(execution_provider), inference_option_set))
if execution_provider == 'coreml':
inference_option_set =\
{
'SpecializationStrategy': 'FastPrediction'
}
if is_directory(cache_path) or create_directory(cache_path):
inference_option_set.update(
{
'ModelCacheDirectory': cache_path
})
inference_providers.append((facefusion.choices.execution_provider_set.get(execution_provider), inference_option_set))
if execution_provider == 'openvino':
inference_session_providers.append((facefusion.choices.execution_provider_set.get(execution_provider),
inference_providers.append((facefusion.choices.execution_provider_set.get(execution_provider),
{
'device_type': resolve_openvino_device_type(execution_device_id),
'precision': 'FP32'
}))
if execution_provider == 'coreml':
inference_session_providers.append((facefusion.choices.execution_provider_set.get(execution_provider),
if execution_provider == 'qnn':
inference_providers.append((facefusion.choices.execution_provider_set.get(execution_provider),
{
'SpecializationStrategy': 'FastPrediction',
'ModelCacheDirectory': '.caches'
'device_id': execution_device_id,
'backend_type': 'htp'
}))
if 'cpu' in execution_providers:
inference_session_providers.append(facefusion.choices.execution_provider_set.get('cpu'))
inference_providers.append(facefusion.choices.execution_provider_set.get('cpu'))
return inference_session_providers
return inference_providers
def resolve_cache_path() -> str:
return os.path.join('.caches', onnxruntime.get_version_string())
def resolve_cudnn_conv_algo_search() -> str:
+1 -1
View File
@@ -20,7 +20,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'__metadata__':
{
'vendor': 'dchen236',
'license': 'Non-Commercial',
'license': 'CC-BY-4.0',
'year': 2021
},
'hashes':
+5 -5
View File
@@ -381,11 +381,11 @@ def detect_with_yunet(vision_frame : VisionFrame, face_detector_size : str) -> T
face_scores.extend(face_scores_raw[keep_indices])
face_landmarks_5_raw = numpy.concatenate(
[
face_landmarks_5_raw[:, [0, 1]] * feature_stride + anchors,
face_landmarks_5_raw[:, [2, 3]] * feature_stride + anchors,
face_landmarks_5_raw[:, [4, 5]] * feature_stride + anchors,
face_landmarks_5_raw[:, [6, 7]] * feature_stride + anchors,
face_landmarks_5_raw[:, [8, 9]] * feature_stride + anchors
face_landmarks_5_raw[:, [ 0, 1 ]] * feature_stride + anchors,
face_landmarks_5_raw[:, [ 2, 3 ]] * feature_stride + anchors,
face_landmarks_5_raw[:, [ 4, 5 ]] * feature_stride + anchors,
face_landmarks_5_raw[:, [ 6, 7 ]] * feature_stride + anchors,
face_landmarks_5_raw[:, [ 8, 9 ]] * feature_stride + anchors
], axis = -1).reshape(-1, 5, 2)
for face_landmark_raw_5 in face_landmarks_5_raw[keep_indices]:
+2 -2
View File
@@ -81,7 +81,7 @@ def warp_face_by_face_landmark_5(temp_vision_frame : VisionFrame, face_landmark_
def warp_face_by_bounding_box(temp_vision_frame : VisionFrame, bounding_box : BoundingBox, crop_size : Size) -> Tuple[VisionFrame, Matrix]:
source_points = numpy.array([ [ bounding_box[0], bounding_box[1] ], [bounding_box[2], bounding_box[1] ], [ bounding_box[0], bounding_box[3] ] ]).astype(numpy.float32)
source_points = numpy.array([ [ bounding_box[0], bounding_box[1] ], [ bounding_box[2], bounding_box[1] ], [ bounding_box[0], bounding_box[3] ] ]).astype(numpy.float32)
target_points = numpy.array([ [ 0, 0 ], [ crop_size[0], 0 ], [ 0, crop_size[1] ] ]).astype(numpy.float32)
affine_matrix = cv2.getAffineTransform(source_points, target_points)
if bounding_box[2] - bounding_box[0] > crop_size[0] or bounding_box[3] - bounding_box[1] > crop_size[1]:
@@ -247,7 +247,7 @@ def get_nms_threshold(face_detector_model : FaceDetectorModel, face_detector_ang
def merge_matrix(temp_matrices : List[Matrix]) -> Matrix:
matrix = numpy.vstack([temp_matrices[0], [0, 0, 1]])
matrix = numpy.vstack([ temp_matrices[0], [ 0, 0, 1 ] ])
for temp_matrix in temp_matrices[1:]:
temp_matrix = numpy.vstack([ temp_matrix, [ 0, 0, 1 ] ])
+1 -1
View File
@@ -233,7 +233,7 @@ def create_area_mask(crop_vision_frame : VisionFrame, face_landmark_68 : FaceLan
convex_hull = cv2.convexHull(face_landmark_68[landmark_points].astype(numpy.int32))
area_mask = numpy.zeros(crop_size).astype(numpy.float32)
cv2.fillConvexPoly(area_mask, convex_hull, 1.0) # type: ignore[call-overload]
cv2.fillConvexPoly(area_mask, convex_hull, 1.0) #type:ignore[call-overload]
area_mask = (cv2.GaussianBlur(area_mask.clip(0, 1), (0, 0), 5).clip(0.5, 1) - 0.5) * 2
return area_mask
+3 -1
View File
@@ -114,6 +114,7 @@ def extract_frames(target_path : str, temp_video_resolution : Resolution, temp_v
ffmpeg_builder.set_input(target_path),
ffmpeg_builder.set_media_resolution(pack_resolution(temp_video_resolution)),
ffmpeg_builder.set_frame_quality(0),
ffmpeg_builder.enforce_pixel_format('rgb24'),
ffmpeg_builder.select_frame_range(trim_frame_start, trim_frame_end, temp_video_fps),
ffmpeg_builder.prevent_frame_drop(),
ffmpeg_builder.set_output(temp_frames_pattern)
@@ -243,7 +244,8 @@ def merge_video(target_path : str, temp_video_fps : Fps, output_video_resolution
def concat_video(output_path : str, temp_output_paths : List[str]) -> bool:
concat_video_path = tempfile.mktemp()
file_descriptor, concat_video_path = tempfile.mkstemp()
os.close(file_descriptor)
with open(concat_video_path, 'w') as concat_video_file:
for temp_output_path in temp_output_paths:
+5 -1
View File
@@ -48,7 +48,7 @@ def set_input(input_path : str) -> List[Command]:
def set_input_fps(input_fps : Fps) -> List[Command]:
return [ '-r', str(input_fps)]
return [ '-r', str(input_fps) ]
def set_output(output_path : str) -> List[Command]:
@@ -79,6 +79,10 @@ def unsafe_concat() -> List[Command]:
return [ '-f', 'concat', '-safe', '0' ]
def enforce_pixel_format(pixel_format : str) -> List[Command]:
return [ '-pix_fmt', pixel_format ]
def set_pixel_format(video_encoder : VideoEncoder) -> List[Command]:
if video_encoder == 'rawvideo':
return [ '-pix_fmt', 'rgb24' ]
+3 -3
View File
@@ -8,7 +8,7 @@ from onnxruntime import InferenceSession
from facefusion import logger, process_manager, state_manager, translator
from facefusion.app_context import detect_app_context
from facefusion.common_helper import is_windows
from facefusion.execution import create_inference_session_providers, has_execution_provider
from facefusion.execution import create_inference_providers, has_execution_provider
from facefusion.exit_helper import fatal_exit
from facefusion.filesystem import get_file_name, is_file
from facefusion.time_helper import calculate_end_time
@@ -72,8 +72,8 @@ def create_inference_session(model_path : str, execution_device_id : int, execut
start_time = time()
try:
inference_session_providers = create_inference_session_providers(execution_device_id, execution_providers)
inference_session = InferenceSession(model_path, providers = inference_session_providers)
inference_providers = create_inference_providers(execution_device_id, execution_providers)
inference_session = InferenceSession(model_path, providers = inference_providers)
logger.debug(translator.get('loading_model_succeeded').format(model_name = model_file_name, seconds = calculate_end_time(start_time)), __name__)
return inference_session
+23 -49
View File
@@ -10,30 +10,34 @@ from types import FrameType
from facefusion import metadata
from facefusion.common_helper import is_linux, is_windows
LOCALS =\
LOCALES =\
{
'install_dependency': 'install the {dependency} package',
'force_reinstall': 'force reinstall of packages',
'skip_conda': 'skip the conda environment check',
'conda_not_activated': 'conda is not activated'
}
ONNXRUNTIME_SET =\
{
'default': ('onnxruntime', '1.23.2')
'default': ('onnxruntime', '1.24.1')
}
if is_windows() or is_linux():
ONNXRUNTIME_SET['cuda'] = ('onnxruntime-gpu', '1.23.2')
ONNXRUNTIME_SET['openvino'] = ('onnxruntime-openvino', '1.23.0')
ONNXRUNTIME_SET['cuda'] = ('onnxruntime-gpu', '1.24.3')
ONNXRUNTIME_SET['openvino'] = ('onnxruntime-openvino', '1.24.1')
if is_windows():
ONNXRUNTIME_SET['directml'] = ('onnxruntime-directml', '1.23.0')
ONNXRUNTIME_SET['directml'] = ('onnxruntime-directml', '1.24.3')
ONNXRUNTIME_SET['qnn'] = ('onnxruntime-qnn', '1.24.3')
if is_linux():
ONNXRUNTIME_SET['rocm'] = ('onnxruntime-rocm', '1.21.0')
ONNXRUNTIME_SET['migraphx'] = ('onnxruntime-migraphx', '1.24.2')
ONNXRUNTIME_SET['rocm'] = ('onnxruntime-rocm', '1.22.2.post1')
def cli() -> None:
signal.signal(signal.SIGINT, signal_exit)
program = ArgumentParser(formatter_class = partial(HelpFormatter, max_help_position = 50))
program.add_argument('--onnxruntime', help = LOCALS.get('install_dependency').format(dependency = 'onnxruntime'), choices = ONNXRUNTIME_SET.keys(), required = True)
program.add_argument('--skip-conda', help = LOCALS.get('skip_conda'), action = 'store_true')
program.add_argument('--onnxruntime', help = LOCALES.get('install_dependency').format(dependency = 'onnxruntime'), choices = ONNXRUNTIME_SET.keys(), required = True)
program.add_argument('--force-reinstall', help = LOCALES.get('force_reinstall'), action = 'store_true')
program.add_argument('--skip-conda', help = LOCALES.get('skip_conda'), action = 'store_true')
program.add_argument('-v', '--version', version = metadata.get('name') + ' ' + metadata.get('version'), action = 'version')
run(program)
@@ -45,56 +49,26 @@ def signal_exit(signum : int, frame : FrameType) -> None:
def run(program : ArgumentParser) -> None:
args = program.parse_args()
has_conda = 'CONDA_PREFIX' in os.environ
onnxruntime_name, onnxruntime_version = ONNXRUNTIME_SET.get(args.onnxruntime)
if not args.skip_conda and not has_conda:
sys.stdout.write(LOCALS.get('conda_not_activated') + os.linesep)
sys.stdout.write(LOCALES.get('conda_not_activated') + os.linesep)
sys.exit(1)
commands = [ shutil.which('pip'), 'install' ]
if args.force_reinstall:
commands.append('--force-reinstall')
with open('requirements.txt') as file:
for line in file.readlines():
__line__ = line.strip()
if not __line__.startswith('onnxruntime'):
subprocess.call([ shutil.which('pip'), 'install', line, '--force-reinstall' ])
commands.append(__line__)
if args.onnxruntime == 'rocm':
python_id = 'cp' + str(sys.version_info.major) + str(sys.version_info.minor)
onnxruntime_name, onnxruntime_version = ONNXRUNTIME_SET.get(args.onnxruntime)
commands.append(onnxruntime_name + '==' + onnxruntime_version)
if python_id in [ 'cp310', 'cp312' ]:
wheel_name = 'onnxruntime_rocm-' + onnxruntime_version + '-' + python_id + '-' + python_id + '-linux_x86_64.whl'
wheel_url = 'https://repo.radeon.com/rocm/manylinux/rocm-rel-6.4/' + wheel_name
subprocess.call([ shutil.which('pip'), 'install', wheel_url, '--force-reinstall' ])
else:
subprocess.call([ shutil.which('pip'), 'install', onnxruntime_name + '==' + onnxruntime_version, '--force-reinstall' ])
if args.onnxruntime == 'cuda' and has_conda:
library_paths = []
if is_linux():
if os.getenv('LD_LIBRARY_PATH'):
library_paths = os.getenv('LD_LIBRARY_PATH').split(os.pathsep)
python_id = 'python' + str(sys.version_info.major) + '.' + str(sys.version_info.minor)
library_paths.extend(
[
os.path.join(os.getenv('CONDA_PREFIX'), 'lib'),
os.path.join(os.getenv('CONDA_PREFIX'), 'lib', python_id, 'site-packages', 'tensorrt_libs')
])
library_paths = list(dict.fromkeys([ library_path for library_path in library_paths if os.path.exists(library_path) ]))
subprocess.call([ shutil.which('conda'), 'env', 'config', 'vars', 'set', 'LD_LIBRARY_PATH=' + os.pathsep.join(library_paths) ])
if is_windows():
if os.getenv('PATH'):
library_paths = os.getenv('PATH').split(os.pathsep)
library_paths.extend(
[
os.path.join(os.getenv('CONDA_PREFIX'), 'Lib'),
os.path.join(os.getenv('CONDA_PREFIX'), 'Lib', 'site-packages', 'tensorrt_libs')
])
library_paths = list(dict.fromkeys([ library_path for library_path in library_paths if os.path.exists(library_path) ]))
subprocess.call([ shutil.which('conda'), 'env', 'config', 'vars', 'set', 'PATH=' + os.pathsep.join(library_paths) ])
subprocess.call([ shutil.which('pip'), 'uninstall', 'onnxruntime', onnxruntime_name, '-y', '-q' ])
subprocess.call(commands)
@@ -1,6 +1,6 @@
from facefusion.types import Locals
from facefusion.types import Locales
LOCALS : Locals =\
LOCALES : Locales =\
{
'en':
{
@@ -189,7 +189,7 @@ LOCALS : Locals =\
},
'about':
{
'fund': 'fund training server',
'fund': 'fund ai workstation',
'subscribe': 'become a member',
'join': 'join our community'
},
+1 -1
View File
@@ -4,7 +4,7 @@ METADATA =\
{
'name': 'FaceFusion',
'description': 'Industry leading face manipulation platform',
'version': '3.5.1',
'version': '3.6.0',
'license': 'OpenRAIL-AS',
'author': 'Henry Ruhs',
'url': 'https://facefusion.io'
+2 -2
View File
@@ -19,9 +19,9 @@ def normalize_space(spaces : Optional[List[int]]) -> Optional[Padding]:
if spaces and len(spaces) == 1:
return tuple([spaces[0]] * 4) #type:ignore[return-value]
if spaces and len(spaces) == 2:
return tuple([spaces[0], spaces[1], spaces[0], spaces[1]]) #type:ignore[return-value]
return tuple([ spaces[0], spaces[1], spaces[0], spaces[1] ]) #type:ignore[return-value]
if spaces and len(spaces) == 3:
return tuple([spaces[0], spaces[1], spaces[2], spaces[1]]) #type:ignore[return-value]
return tuple([ spaces[0], spaces[1], spaces[2], spaces[1] ]) #type:ignore[return-value]
if spaces and len(spaces) == 4:
return tuple(spaces) #type:ignore[return-value]
return None
-27
View File
@@ -1,27 +0,0 @@
from facefusion.processors.modules.age_modifier.choices import age_modifier_direction_range, age_modifier_models # noqa: F401
from facefusion.processors.modules.background_remover.choices import background_remover_color_range, background_remover_models # noqa: F401
from facefusion.processors.modules.deep_swapper.choices import deep_swapper_models, deep_swapper_morph_range # noqa: F401
from facefusion.processors.modules.expression_restorer.choices import expression_restorer_areas, expression_restorer_factor_range, expression_restorer_models # noqa: F401
from facefusion.processors.modules.face_debugger.choices import face_debugger_items # noqa: F401
from facefusion.processors.modules.face_editor.choices import ( # noqa: F401
face_editor_eye_gaze_horizontal_range,
face_editor_eye_gaze_vertical_range,
face_editor_eye_open_ratio_range,
face_editor_eyebrow_direction_range,
face_editor_head_pitch_range,
face_editor_head_roll_range,
face_editor_head_yaw_range,
face_editor_lip_open_ratio_range,
face_editor_models,
face_editor_mouth_grim_range,
face_editor_mouth_position_horizontal_range,
face_editor_mouth_position_vertical_range,
face_editor_mouth_pout_range,
face_editor_mouth_purse_range,
face_editor_mouth_smile_range,
)
from facefusion.processors.modules.face_enhancer.choices import face_enhancer_blend_range, face_enhancer_models, face_enhancer_weight_range # noqa: F401
from facefusion.processors.modules.face_swapper.choices import face_swapper_models, face_swapper_set, face_swapper_weight_range # noqa: F401
from facefusion.processors.modules.frame_colorizer.choices import frame_colorizer_blend_range, frame_colorizer_models, frame_colorizer_sizes # noqa: F401
from facefusion.processors.modules.frame_enhancer.choices import frame_enhancer_blend_range, frame_enhancer_models # noqa: F401
from facefusion.processors.modules.lip_syncer.choices import lip_syncer_models, lip_syncer_weight_range # noqa: F401
@@ -1,8 +1,8 @@
from typing import List, Sequence
from typing import List, Sequence, get_args
from facefusion.common_helper import create_int_range
from facefusion.processors.modules.age_modifier.types import AgeModifierModel
age_modifier_models : List[AgeModifierModel] = [ 'styleganex_age' ]
age_modifier_models : List[AgeModifierModel] = list(get_args(AgeModifierModel))
age_modifier_direction_range : Sequence[int] = create_int_range(-100, 100, 1)
@@ -29,6 +29,41 @@ from facefusion.vision import match_frame_color, read_static_image, read_static_
def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
return\
{
'fran':
{
'__metadata__':
{
'vendor': 'ry-lu',
'license': 'mit',
'year': 2024
},
'hashes':
{
'age_modifier':
{
'url': resolve_download_url('models-3.6.0', 'fran.hash'),
'path': resolve_relative_path('../.assets/models/fran.hash')
}
},
'sources':
{
'age_modifier':
{
'url': resolve_download_url('models-3.6.0', 'fran.onnx'),
'path': resolve_relative_path('../.assets/models/fran.onnx')
}
},
'templates':
{
'target': 'ffhq_512',
},
'sizes':
{
'target': (1024, 1024),
},
'mean': [ 0.0, 0.0, 0.0 ],
'standard_deviation': [ 1.0, 1.0, 1.0 ]
},
'styleganex_age':
{
'__metadata__':
@@ -62,7 +97,9 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
{
'target': (256, 256),
'target_with_background': (384, 384)
}
},
'mean': [ 0.5, 0.5, 0.5 ],
'standard_deviation': [ 0.5, 0.5, 0.5 ]
}
}
@@ -87,7 +124,7 @@ def get_model_options() -> ModelOptions:
def register_args(program : ArgumentParser) -> None:
group_processors = find_argument_group(program, 'processors')
if group_processors:
group_processors.add_argument('--age-modifier-model', help = translator.get('help.model', __package__), default = config.get_str_value('processors', 'age_modifier_model', 'styleganex_age'), choices = age_modifier_choices.age_modifier_models)
group_processors.add_argument('--age-modifier-model', help = translator.get('help.model', __package__), default = config.get_str_value('processors', 'age_modifier_model', 'fran'), choices = age_modifier_choices.age_modifier_models)
group_processors.add_argument('--age-modifier-direction', help = translator.get('help.direction', __package__), type = int, default = config.get_int_value('processors', 'age_modifier_direction', '0'), choices = age_modifier_choices.age_modifier_direction_range, metavar = create_int_metavar(age_modifier_choices.age_modifier_direction_range))
facefusion.jobs.job_store.register_step_keys([ 'age_modifier_model', 'age_modifier_direction' ])
@@ -137,32 +174,57 @@ def modify_age(target_face : Face, temp_vision_frame : VisionFrame) -> VisionFra
model_sizes = get_model_options().get('sizes')
face_landmark_5 = target_face.landmark_set.get('5/68').copy()
crop_vision_frame, affine_matrix = warp_face_by_face_landmark_5(temp_vision_frame, face_landmark_5, model_templates.get('target'), model_sizes.get('target'))
extend_face_landmark_5 = scale_face_landmark_5(face_landmark_5, 0.875)
extend_vision_frame, extend_affine_matrix = warp_face_by_face_landmark_5(temp_vision_frame, extend_face_landmark_5, model_templates.get('target_with_background'), model_sizes.get('target_with_background'))
extend_vision_frame_raw = extend_vision_frame.copy()
box_mask = create_box_mask(extend_vision_frame, state_manager.get_item('face_mask_blur'), (0, 0, 0, 0))
crop_masks =\
[
box_mask
]
if 'occlusion' in state_manager.get_item('face_mask_types'):
occlusion_mask = create_occlusion_mask(crop_vision_frame)
temp_matrix = merge_matrix([ extend_affine_matrix, cv2.invertAffineTransform(affine_matrix) ])
occlusion_mask = cv2.warpAffine(occlusion_mask, temp_matrix, model_sizes.get('target_with_background'))
crop_masks.append(occlusion_mask)
if state_manager.get_item('age_modifier_model') == 'fran':
box_mask = create_box_mask(crop_vision_frame, state_manager.get_item('face_mask_blur'), (0, 0, 0, 0))
crop_masks =\
[
box_mask
]
crop_vision_frame = prepare_vision_frame(crop_vision_frame)
extend_vision_frame = prepare_vision_frame(extend_vision_frame)
age_modifier_direction = numpy.array(numpy.interp(state_manager.get_item('age_modifier_direction'), [ -100, 100 ], [ 2.5, -2.5 ])).astype(numpy.float32)
extend_vision_frame = forward(crop_vision_frame, extend_vision_frame, age_modifier_direction)
extend_vision_frame = normalize_extend_frame(extend_vision_frame)
extend_vision_frame = match_frame_color(extend_vision_frame_raw, extend_vision_frame)
extend_affine_matrix *= (model_sizes.get('target')[0] * 4) / model_sizes.get('target_with_background')[0]
crop_mask = numpy.minimum.reduce(crop_masks).clip(0, 1)
crop_mask = cv2.resize(crop_mask, (model_sizes.get('target')[0] * 4, model_sizes.get('target')[1] * 4))
paste_vision_frame = paste_back(temp_vision_frame, extend_vision_frame, crop_mask, extend_affine_matrix)
return paste_vision_frame
if 'occlusion' in state_manager.get_item('face_mask_types'):
occlusion_mask = create_occlusion_mask(crop_vision_frame)
crop_masks.append(occlusion_mask)
crop_vision_frame = prepare_vision_frame(crop_vision_frame)
target_age = numpy.mean(target_face.age)
age_modifier_direction = numpy.array([ target_age, target_age + state_manager.get_item('age_modifier_direction') ], dtype = numpy.float32) / 100
age_modifier_direction = age_modifier_direction.clip(0, 1)
crop_vision_frame = forward(crop_vision_frame, crop_vision_frame, age_modifier_direction)
crop_vision_frame = normalize_vision_frame(crop_vision_frame)
crop_mask = numpy.minimum.reduce(crop_masks).clip(0, 1)
paste_vision_frame = paste_back(temp_vision_frame, crop_vision_frame, crop_mask, affine_matrix)
return paste_vision_frame
if state_manager.get_item('age_modifier_model') == 'styleganex_age':
extend_face_landmark_5 = scale_face_landmark_5(face_landmark_5, 0.875)
extend_vision_frame, extend_affine_matrix = warp_face_by_face_landmark_5(temp_vision_frame, extend_face_landmark_5, model_templates.get('target_with_background'), model_sizes.get('target_with_background'))
extend_vision_frame_raw = extend_vision_frame.copy()
box_mask = create_box_mask(extend_vision_frame, state_manager.get_item('face_mask_blur'), (0, 0, 0, 0))
crop_masks =\
[
box_mask
]
if 'occlusion' in state_manager.get_item('face_mask_types'):
occlusion_mask = create_occlusion_mask(crop_vision_frame)
temp_matrix = merge_matrix([ extend_affine_matrix, cv2.invertAffineTransform(affine_matrix) ])
occlusion_mask = cv2.warpAffine(occlusion_mask, temp_matrix, model_sizes.get('target_with_background'))
crop_masks.append(occlusion_mask)
crop_vision_frame = prepare_vision_frame(crop_vision_frame)
extend_vision_frame = prepare_vision_frame(extend_vision_frame)
age_modifier_direction = numpy.array(numpy.interp(state_manager.get_item('age_modifier_direction'), [ -100, 100 ], [ 2.5, -2.5 ])).astype(numpy.float32)
extend_vision_frame = forward(crop_vision_frame, extend_vision_frame, age_modifier_direction)
extend_vision_frame = normalize_extend_frame(extend_vision_frame)
extend_vision_frame = match_frame_color(extend_vision_frame_raw, extend_vision_frame)
extend_affine_matrix *= (model_sizes.get('target')[0] * 4) / model_sizes.get('target_with_background')[0]
crop_mask = numpy.minimum.reduce(crop_masks).clip(0, 1)
crop_mask = cv2.resize(crop_mask, (model_sizes.get('target')[0] * 4, model_sizes.get('target')[1] * 4))
paste_vision_frame = paste_back(temp_vision_frame, extend_vision_frame, crop_mask, extend_affine_matrix)
return paste_vision_frame
return temp_vision_frame
def forward(crop_vision_frame : VisionFrame, extend_vision_frame : VisionFrame, age_modifier_direction : AgeModifierDirection) -> VisionFrame:
@@ -187,12 +249,24 @@ def forward(crop_vision_frame : VisionFrame, extend_vision_frame : VisionFrame,
def prepare_vision_frame(vision_frame : VisionFrame) -> VisionFrame:
model_mean = get_model_options().get('mean')
model_standard_deviation = get_model_options().get('standard_deviation')
vision_frame = vision_frame[:, :, ::-1] / 255.0
vision_frame = (vision_frame - 0.5) / 0.5
vision_frame = (vision_frame - model_mean) / model_standard_deviation
vision_frame = numpy.expand_dims(vision_frame.transpose(2, 0, 1), axis = 0).astype(numpy.float32)
return vision_frame
def normalize_vision_frame(vision_frame : VisionFrame) -> VisionFrame:
model_mean = get_model_options().get('mean')
model_standard_deviation = get_model_options().get('standard_deviation')
vision_frame = vision_frame.transpose(1, 2, 0)
vision_frame = vision_frame * model_standard_deviation + model_mean
vision_frame = vision_frame.clip(0, 1)
vision_frame = vision_frame[:, :, ::-1] * 255
return vision_frame
def normalize_extend_frame(extend_vision_frame : VisionFrame) -> VisionFrame:
model_sizes = get_model_options().get('sizes')
extend_vision_frame = numpy.clip(extend_vision_frame, -1, 1)
@@ -1,6 +1,6 @@
from facefusion.types import Locals
from facefusion.types import Locales
LOCALS : Locals =\
LOCALES : Locales =\
{
'en':
{
@@ -12,6 +12,6 @@ AgeModifierInputs = TypedDict('AgeModifierInputs',
'temp_vision_mask' : Mask
})
AgeModifierModel = Literal['styleganex_age']
AgeModifierModel = Literal['fran', 'styleganex_age']
AgeModifierDirection : TypeAlias = NDArray[Any]
@@ -1,8 +1,8 @@
from typing import List, Sequence
from typing import List, Sequence, get_args
from facefusion.common_helper import create_int_range
from facefusion.processors.modules.background_remover.types import BackgroundRemoverModel
background_remover_models : List[BackgroundRemoverModel] = [ 'ben_2', 'birefnet_general', 'birefnet_portrait', 'isnet_general', 'modnet', 'ormbg', 'rmbg_1.4', 'rmbg_2.0', 'silueta', 'u2net_cloth', 'u2net_general', 'u2net_human', 'u2netp' ]
background_remover_models : List[BackgroundRemoverModel] = list(get_args(BackgroundRemoverModel))
background_remover_color_range : Sequence[int] = create_int_range(0, 255, 1)
@@ -8,7 +8,7 @@ import numpy
import facefusion.jobs.job_manager
import facefusion.jobs.job_store
from facefusion import config, content_analyser, inference_manager, logger, state_manager, translator, video_manager
from facefusion.common_helper import is_macos
from facefusion.common_helper import is_macos, is_windows
from facefusion.download import conditional_download_hashes, conditional_download_sources, resolve_download_url
from facefusion.execution import has_execution_provider
from facefusion.filesystem import in_directory, is_image, is_video, resolve_relative_path, same_file_extension
@@ -51,6 +51,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'path': resolve_relative_path('../.assets/models/ben_2.onnx')
}
},
'type': 'ben',
'size': (1024, 1024),
'mean': [ 0.0, 0.0, 0.0 ],
'standard_deviation': [ 1.0, 1.0, 1.0 ]
@@ -79,6 +80,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'path': resolve_relative_path('../.assets/models/birefnet_general.onnx')
}
},
'type': 'birefnet',
'size': (1024, 1024),
'mean': [ 0.0, 0.0, 0.0 ],
'standard_deviation': [ 1.0, 1.0, 1.0 ]
@@ -107,10 +109,69 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'path': resolve_relative_path('../.assets/models/birefnet_portrait.onnx')
}
},
'type': 'birefnet',
'size': (1024, 1024),
'mean': [ 0.0, 0.0, 0.0 ],
'standard_deviation': [ 1.0, 1.0, 1.0 ]
},
'corridor_key_1024':
{
'__metadata__':
{
'vendor': 'nikopueringer',
'license': 'Non-Commercial',
'year': 2025
},
'hashes':
{
'background_remover':
{
'url': resolve_download_url('models-3.6.0', 'corridor_key_1024.hash'),
'path': resolve_relative_path('../.assets/models/corridor_key_1024.hash')
}
},
'sources':
{
'background_remover':
{
'url': resolve_download_url('models-3.6.0', 'corridor_key_1024.onnx'),
'path': resolve_relative_path('../.assets/models/corridor_key_1024.onnx')
}
},
'type': 'corridor_key',
'size': (1024, 1024),
'mean': [ 0.485, 0.456, 0.406 ],
'standard_deviation': [ 0.229, 0.224, 0.225 ]
},
'corridor_key_2048':
{
'__metadata__':
{
'vendor': 'nikopueringer',
'license': 'Non-Commercial',
'year': 2025
},
'hashes':
{
'background_remover':
{
'url': resolve_download_url('models-3.6.0', 'corridor_key_2048.hash'),
'path': resolve_relative_path('../.assets/models/corridor_key_2048.hash')
}
},
'sources':
{
'background_remover':
{
'url': resolve_download_url('models-3.6.0', 'corridor_key_2048.onnx'),
'path': resolve_relative_path('../.assets/models/corridor_key_2048.onnx')
}
},
'type': 'corridor_key',
'size': (2048, 2048),
'mean': [ 0.485, 0.456, 0.406 ],
'standard_deviation': [ 0.229, 0.224, 0.225 ]
},
'isnet_general':
{
'__metadata__':
@@ -135,6 +196,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'path': resolve_relative_path('../.assets/models/isnet_general.onnx')
}
},
'type': 'isnet',
'size': (1024, 1024),
'mean': [ 0.5, 0.5, 0.5 ],
'standard_deviation': [ 1.0, 1.0, 1.0 ]
@@ -163,6 +225,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'path': resolve_relative_path('../.assets/models/modnet.onnx')
}
},
'type': 'modnet',
'size': (512, 512),
'mean': [ 0.5, 0.5, 0.5 ],
'standard_deviation': [ 0.5, 0.5, 0.5 ]
@@ -191,6 +254,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'path': resolve_relative_path('../.assets/models/ormbg.onnx')
}
},
'type': 'ormbg',
'size': (1024, 1024),
'mean': [ 0.0, 0.0, 0.0 ],
'standard_deviation': [ 1.0, 1.0, 1.0 ]
@@ -219,6 +283,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'path': resolve_relative_path('../.assets/models/rmbg_1.4.onnx')
}
},
'type': 'rmbg',
'size': (1024, 1024),
'mean': [ 0.5, 0.5, 0.5 ],
'standard_deviation': [ 1.0, 1.0, 1.0 ]
@@ -247,6 +312,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'path': resolve_relative_path('../.assets/models/rmbg_2.0.onnx')
}
},
'type': 'rmbg',
'size': (1024, 1024),
'mean': [ 0.485, 0.456, 0.406 ],
'standard_deviation': [ 0.229, 0.224, 0.225 ]
@@ -275,6 +341,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'path': resolve_relative_path('../.assets/models/silueta.onnx')
}
},
'type': 'silueta',
'size': (320, 320),
'mean': [ 0.485, 0.456, 0.406 ],
'standard_deviation': [ 0.229, 0.224, 0.225 ]
@@ -303,6 +370,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'path': resolve_relative_path('../.assets/models/u2net_cloth.onnx')
}
},
'type': 'u2net_cloth',
'size': (768, 768),
'mean': [ 0.485, 0.456, 0.406 ],
'standard_deviation': [ 0.229, 0.224, 0.225 ]
@@ -331,6 +399,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'path': resolve_relative_path('../.assets/models/u2net_general.onnx')
}
},
'type': 'u2net',
'size': (320, 320),
'mean': [ 0.485, 0.456, 0.406 ],
'standard_deviation': [ 0.229, 0.224, 0.225 ]
@@ -359,6 +428,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'path': resolve_relative_path('../.assets/models/u2net_human.onnx')
}
},
'type': 'u2net',
'size': (320, 320),
'mean': [ 0.485, 0.456, 0.406 ],
'standard_deviation': [ 0.229, 0.224, 0.225 ]
@@ -387,6 +457,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'path': resolve_relative_path('../.assets/models/u2netp.onnx')
}
},
'type': 'u2netp',
'size': (320, 320),
'mean': [ 0.485, 0.456, 0.406 ],
'standard_deviation': [ 0.229, 0.224, 0.225 ]
@@ -407,7 +478,9 @@ def clear_inference_pool() -> None:
def resolve_execution_providers() -> List[ExecutionProvider]:
if is_macos() and has_execution_provider('coreml'):
model_type = get_model_options().get('type')
if is_macos() and has_execution_provider('coreml') or is_windows() and has_execution_provider('directml') and model_type == 'corridor_key':
return [ 'cpu' ]
return state_manager.get_item('execution_providers')
@@ -420,14 +493,16 @@ def get_model_options() -> ModelOptions:
def register_args(program : ArgumentParser) -> None:
group_processors = find_argument_group(program, 'processors')
if group_processors:
group_processors.add_argument('--background-remover-model', help = translator.get('help.model', __package__), default = config.get_str_value('processors', 'background_remover_model', 'rmbg_2.0'), choices = background_remover_choices.background_remover_models)
group_processors.add_argument('--background-remover-color', help = translator.get('help.color', __package__), type = partial(sanitize_int_range, int_range = background_remover_choices.background_remover_color_range), default = config.get_int_list('processors', 'background_remover_color', '0 0 0 0'), nargs ='+')
facefusion.jobs.job_store.register_step_keys([ 'background_remover_model', 'background_remover_color' ])
group_processors.add_argument('--background-remover-model', help = translator.get('help.model', __package__), default = config.get_str_value('processors', 'background_remover_model', 'modnet'), choices = background_remover_choices.background_remover_models)
group_processors.add_argument('--background-remover-fill-color', help = translator.get('help.fill_color', __package__), type = partial(sanitize_int_range, int_range = background_remover_choices.background_remover_color_range), default = config.get_int_list('processors', 'background_remover_fill_color', '0 0 0 0'), nargs = '+')
group_processors.add_argument('--background-remover-despill-color', help = translator.get('help.despill_color', __package__), type = partial(sanitize_int_range, int_range = background_remover_choices.background_remover_color_range), default = config.get_int_list('processors', 'background_remover_despill_color', '0 0 0 0'), nargs = '+')
facefusion.jobs.job_store.register_step_keys([ 'background_remover_model', 'background_remover_fill_color', 'background_remover_despill_color' ])
def apply_args(args : Args, apply_state_item : ApplyStateItem) -> None:
apply_state_item('background_remover_model', args.get('background_remover_model'))
apply_state_item('background_remover_color', normalize_color(args.get('background_remover_color')))
apply_state_item('background_remover_fill_color', normalize_color(args.get('background_remover_fill_color')))
apply_state_item('background_remover_despill_color', normalize_color(args.get('background_remover_despill_color')))
def pre_check() -> bool:
@@ -461,16 +536,26 @@ def post_process() -> None:
def remove_background(temp_vision_frame : VisionFrame) -> Tuple[VisionFrame, Mask]:
temp_vision_mask = forward(prepare_temp_frame(temp_vision_frame))
temp_vision_mask = normalize_vision_mask(temp_vision_mask)
temp_vision_mask = cv2.resize(temp_vision_mask, temp_vision_frame.shape[:2][::-1])
temp_vision_frame = apply_background_color(temp_vision_frame, temp_vision_mask)
return temp_vision_frame, temp_vision_mask
model_type = get_model_options().get('type')
if model_type == 'corridor_key':
remove_vision_mask, remove_vision_frame = forward_corridor_key(prepare_temp_frame(temp_vision_frame))
remove_vision_frame = numpy.squeeze(remove_vision_frame).transpose(1, 2, 0)
remove_vision_frame = numpy.clip(remove_vision_frame * 255, 0, 255).astype(numpy.uint8)
temp_vision_frame = cv2.resize(remove_vision_frame[:, :, ::-1], temp_vision_frame.shape[:2][::-1])
else:
remove_vision_mask = forward(prepare_temp_frame(temp_vision_frame))
remove_vision_mask = normalize_vision_mask(remove_vision_mask)
remove_vision_mask = cv2.resize(remove_vision_mask, temp_vision_frame.shape[:2][::-1])
temp_vision_frame = apply_despill_color(temp_vision_frame)
temp_vision_frame = apply_fill_color(temp_vision_frame, remove_vision_mask)
return temp_vision_frame, remove_vision_mask
def forward(temp_vision_frame : VisionFrame) -> VisionFrame:
background_remover = get_inference_pool().get('background_remover')
model_name = state_manager.get_item('background_remover_model')
model_type = get_model_options().get('type')
with thread_semaphore():
remove_vision_frame = background_remover.run(None,
@@ -478,20 +563,42 @@ def forward(temp_vision_frame : VisionFrame) -> VisionFrame:
'input': temp_vision_frame
})[0]
if model_name == 'u2net_cloth':
if model_type == 'u2net_cloth':
remove_vision_frame = numpy.argmax(remove_vision_frame, axis = 1)
return remove_vision_frame
def forward_corridor_key(temp_vision_frame : VisionFrame) -> Tuple[Mask, VisionFrame]:
background_remover = get_inference_pool().get('background_remover')
with thread_semaphore():
remove_vision_mask, remove_vision_frame = background_remover.run(None,
{
'input': temp_vision_frame
})
return remove_vision_mask, remove_vision_frame
def prepare_temp_frame(temp_vision_frame : VisionFrame) -> VisionFrame:
model_type = get_model_options().get('type')
model_size = get_model_options().get('size')
model_mean = get_model_options().get('mean')
model_standard_deviation = get_model_options().get('standard_deviation')
if model_type == 'corridor_key':
coarse_color = temp_vision_frame[:, :, ::-1].astype(numpy.float32) / 255.0
coarse_bias = coarse_color[:, :, 1] - numpy.maximum(coarse_color[:, :, 0], coarse_color[:, :, 2])
coarse_vision_mask = cv2.resize(1.0 - numpy.clip(coarse_bias * 2.0, 0, 1), model_size)[:, :, numpy.newaxis]
temp_vision_frame = cv2.resize(temp_vision_frame, model_size)
temp_vision_frame = temp_vision_frame[:, :, ::-1] / 255.0
temp_vision_frame = (temp_vision_frame - model_mean) / model_standard_deviation
if model_type == 'corridor_key':
temp_vision_frame = numpy.concatenate([ temp_vision_frame, coarse_vision_mask ], axis = 2)
temp_vision_frame = temp_vision_frame.transpose(2, 0, 1)
temp_vision_frame = numpy.expand_dims(temp_vision_frame, axis = 0).astype(numpy.float32)
return temp_vision_frame
@@ -503,16 +610,32 @@ def normalize_vision_mask(temp_vision_mask : Mask) -> Mask:
return temp_vision_mask
def apply_background_color(temp_vision_frame : VisionFrame, temp_vision_mask : Mask) -> VisionFrame:
background_remover_color = state_manager.get_item('background_remover_color')
def apply_fill_color(temp_vision_frame : VisionFrame, temp_vision_mask : Mask) -> VisionFrame:
background_remover_fill_color = state_manager.get_item('background_remover_fill_color')
temp_vision_mask = temp_vision_mask.astype(numpy.float32) / 255
temp_vision_mask = numpy.expand_dims(temp_vision_mask, axis = 2)
temp_vision_mask = (1 - temp_vision_mask) * background_remover_color[-1] / 255
color_frame = numpy.zeros_like(temp_vision_frame)
color_frame[:, :, 0] = background_remover_color[2]
color_frame[:, :, 1] = background_remover_color[1]
color_frame[:, :, 2] = background_remover_color[0]
temp_vision_frame = temp_vision_frame * (1 - temp_vision_mask) + color_frame * temp_vision_mask
temp_vision_mask = (1 - temp_vision_mask) * background_remover_fill_color[-1] / 255
fill_vision_frame = numpy.zeros_like(temp_vision_frame)
fill_vision_frame[:, :, 0] = background_remover_fill_color[2]
fill_vision_frame[:, :, 1] = background_remover_fill_color[1]
fill_vision_frame[:, :, 2] = background_remover_fill_color[0]
temp_vision_frame = temp_vision_frame * (1 - temp_vision_mask) + fill_vision_frame * temp_vision_mask
temp_vision_frame = temp_vision_frame.astype(numpy.uint8)
return temp_vision_frame
def apply_despill_color(temp_vision_frame : VisionFrame) -> VisionFrame:
background_remover_despill_color = state_manager.get_item('background_remover_despill_color')
temp_vision_frame = temp_vision_frame.astype(numpy.float32)
color_alpha = background_remover_despill_color[3] / 255.0
despill_vision_frame = numpy.zeros_like(temp_vision_frame)
despill_vision_frame[:, :, 0] = background_remover_despill_color[2]
despill_vision_frame[:, :, 1] = background_remover_despill_color[1]
despill_vision_frame[:, :, 2] = background_remover_despill_color[0]
color_weight = despill_vision_frame / numpy.maximum(numpy.max(background_remover_despill_color[:3]), 1)
color_limit = numpy.roll(temp_vision_frame, 1, 2) + numpy.roll(temp_vision_frame, -1, 2)
limit_vision_frame = numpy.minimum(temp_vision_frame, color_limit * 0.5)
temp_vision_frame = temp_vision_frame + (limit_vision_frame - temp_vision_frame) * color_alpha * color_weight
temp_vision_frame = temp_vision_frame.astype(numpy.uint8)
return temp_vision_frame
@@ -0,0 +1,26 @@
from facefusion.types import Locales
LOCALES : Locales =\
{
'en':
{
'help':
{
'model': 'choose the model responsible for removing the background',
'fill_color': 'apply red, green, blue and alpha values to the background',
'despill_color': 'remove red, green, blue and alpha values from the foreground'
},
'uis':
{
'model_dropdown': 'BACKGROUND REMOVER MODEL',
'fill_color_red_number': 'FILL COLOR RED',
'fill_color_green_number': 'FILL COLOR GREEN',
'fill_color_blue_number': 'FILL COLOR BLUE',
'fill_color_alpha_number': 'FILL COLOR ALPHA',
'despill_color_red_number': 'DESPILL COLOR RED',
'despill_color_green_number': 'DESPILL COLOR GREEN',
'despill_color_blue_number': 'DESPILL COLOR BLUE',
'despill_color_alpha_number': 'DESPILL COLOR ALPHA'
}
}
}
@@ -1,21 +0,0 @@
from facefusion.types import Locals
LOCALS : Locals =\
{
'en':
{
'help':
{
'model': 'choose the model responsible for removing the background',
'color': 'apply red, green blue and alpha values to the background'
},
'uis':
{
'model_dropdown': 'BACKGROUND REMOVER MODEL',
'color_red_number': 'BACKGROUND COLOR RED',
'color_green_number': 'BACKGROUND COLOR GREEN',
'color_blue_number': 'BACKGROUND COLOR BLUE',
'color_alpha_number': 'BACKGROUND COLOR ALPHA'
}
}
}
@@ -9,4 +9,4 @@ BackgroundRemoverInputs = TypedDict('BackgroundRemoverInputs',
'temp_vision_mask' : Mask
})
BackgroundRemoverModel = Literal['ben_2', 'birefnet_general', 'birefnet_portrait', 'isnet_general', 'modnet', 'ormbg', 'rmbg_1.4', 'rmbg_2.0', 'silueta', 'u2net_cloth', 'u2net_general', 'u2net_human', 'u2netp']
BackgroundRemoverModel = Literal['ben_2', 'birefnet_general', 'birefnet_portrait', 'corridor_key_1024', 'corridor_key_2048', 'isnet_general', 'modnet', 'ormbg', 'rmbg_1.4', 'rmbg_2.0', 'silueta', 'u2net_cloth', 'u2net_general', 'u2net_human', 'u2netp']
@@ -1,6 +1,6 @@
from facefusion.types import Locals
from facefusion.types import Locales
LOCALS : Locals =\
LOCALES : Locales =\
{
'en':
{
@@ -1,10 +1,10 @@
from typing import List, Sequence
from typing import List, Sequence, get_args
from facefusion.common_helper import create_int_range
from facefusion.processors.modules.expression_restorer.types import ExpressionRestorerArea, ExpressionRestorerModel
expression_restorer_models : List[ExpressionRestorerModel] = [ 'live_portrait' ]
expression_restorer_models : List[ExpressionRestorerModel] = list(get_args(ExpressionRestorerModel))
expression_restorer_areas : List[ExpressionRestorerArea] = [ 'upper-face', 'lower-face' ]
expression_restorer_areas : List[ExpressionRestorerArea] = list(get_args(ExpressionRestorerArea))
expression_restorer_factor_range : Sequence[int] = create_int_range(0, 100, 1)
@@ -101,7 +101,7 @@ def register_args(program : ArgumentParser) -> None:
if group_processors:
group_processors.add_argument('--expression-restorer-model', help = translator.get('help.model', __package__), default = config.get_str_value('processors', 'expression_restorer_model', 'live_portrait'), choices = expression_restorer_choices.expression_restorer_models)
group_processors.add_argument('--expression-restorer-factor', help = translator.get('help.factor', __package__), type = int, default = config.get_int_value('processors', 'expression_restorer_factor', '80'), choices = expression_restorer_choices.expression_restorer_factor_range, metavar = create_int_metavar(expression_restorer_choices.expression_restorer_factor_range))
group_processors.add_argument('--expression-restorer-areas', help = translator.get('help.areas', __package__).format(choices = ', '.join(expression_restorer_choices.expression_restorer_areas)), default = config.get_str_list('processors', 'expression_restorer_areas', ' '.join(expression_restorer_choices.expression_restorer_areas)), choices = expression_restorer_choices.expression_restorer_areas, nargs ='+', metavar ='EXPRESSION_RESTORER_AREAS')
group_processors.add_argument('--expression-restorer-areas', help = translator.get('help.areas', __package__).format(choices = ', '.join(expression_restorer_choices.expression_restorer_areas)), default = config.get_str_list('processors', 'expression_restorer_areas', ' '.join(expression_restorer_choices.expression_restorer_areas)), choices = expression_restorer_choices.expression_restorer_areas, nargs = '+', metavar = 'EXPRESSION_RESTORER_AREAS')
facefusion.jobs.job_store.register_step_keys([ 'expression_restorer_model', 'expression_restorer_factor', 'expression_restorer_areas' ])
@@ -192,12 +192,12 @@ def restrict_expression_areas(temp_expression : LivePortraitExpression, target_e
expression_restorer_areas = state_manager.get_item('expression_restorer_areas')
if 'upper-face' not in expression_restorer_areas:
target_expression[:, [1, 2, 6, 10, 11, 12, 13, 15, 16]] = temp_expression[:, [1, 2, 6, 10, 11, 12, 13, 15, 16]]
target_expression[:, [ 1, 2, 6, 10, 11, 12, 13, 15, 16 ]] = temp_expression[:, [ 1, 2, 6, 10, 11, 12, 13, 15, 16 ]]
if 'lower-face' not in expression_restorer_areas:
target_expression[:, [3, 7, 14, 17, 18, 19, 20]] = temp_expression[:, [3, 7, 14, 17, 18, 19, 20]]
target_expression[:, [ 3, 7, 14, 17, 18, 19, 20 ]] = temp_expression[:, [ 3, 7, 14, 17, 18, 19, 20 ]]
target_expression[:, [0, 4, 5, 8, 9]] = temp_expression[:, [0, 4, 5, 8, 9]]
target_expression[:, [ 0, 4, 5, 8, 9 ]] = temp_expression[:, [ 0, 4, 5, 8, 9 ]]
return target_expression
@@ -1,6 +1,6 @@
from facefusion.types import Locals
from facefusion.types import Locales
LOCALS : Locals =\
LOCALES : Locales =\
{
'en':
{
@@ -1,5 +1,5 @@
from typing import List
from typing import List, get_args
from facefusion.processors.modules.face_debugger.types import FaceDebuggerItem
face_debugger_items : List[FaceDebuggerItem] = [ 'bounding-box', 'face-landmark-5', 'face-landmark-5/68', 'face-landmark-68', 'face-landmark-68/5', 'face-mask' ]
face_debugger_items : List[FaceDebuggerItem] = list(get_args(FaceDebuggerItem))
@@ -1,6 +1,6 @@
from facefusion.types import Locals
from facefusion.types import Locales
LOCALS : Locals =\
LOCALES : Locales =\
{
'en':
{
@@ -1,9 +1,9 @@
from typing import List, Sequence
from typing import List, Sequence, get_args
from facefusion.common_helper import create_float_range
from facefusion.processors.modules.face_editor.types import FaceEditorModel
face_editor_models : List[FaceEditorModel] = [ 'live_portrait' ]
face_editor_models : List[FaceEditorModel] = list(get_args(FaceEditorModel))
face_editor_eyebrow_direction_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
face_editor_eye_gaze_horizontal_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
@@ -1,6 +1,6 @@
from facefusion.types import Locals
from facefusion.types import Locales
LOCALS : Locals =\
LOCALES : Locales =\
{
'en':
{
@@ -1,9 +1,9 @@
from typing import List, Sequence
from typing import List, Sequence, get_args
from facefusion.common_helper import create_float_range, create_int_range
from facefusion.processors.modules.face_enhancer.types import FaceEnhancerModel
face_enhancer_models : List[FaceEnhancerModel] = [ 'codeformer', 'gfpgan_1.2', 'gfpgan_1.3', 'gfpgan_1.4', 'gpen_bfr_256', 'gpen_bfr_512', 'gpen_bfr_1024', 'gpen_bfr_2048', 'restoreformer_plus_plus' ]
face_enhancer_models : List[FaceEnhancerModel] = list(get_args(FaceEnhancerModel))
face_enhancer_blend_range : Sequence[int] = create_int_range(0, 100, 1)
@@ -1,6 +1,6 @@
from facefusion.types import Locals
from facefusion.types import Locales
LOCALS : Locals =\
LOCALES : Locales =\
{
'en':
{
@@ -1,8 +1,9 @@
from typing import List, Sequence
from typing import List, Sequence, get_args
from facefusion.common_helper import create_float_range
from facefusion.processors.modules.face_swapper.types import FaceSwapperModel, FaceSwapperSet, FaceSwapperWeight
face_swapper_set : FaceSwapperSet =\
{
'blendswap_256': [ '256x256', '384x384', '512x512', '768x768', '1024x1024' ],
@@ -20,6 +21,6 @@ face_swapper_set : FaceSwapperSet =\
'uniface_256': [ '256x256', '512x512', '768x768', '1024x1024' ]
}
face_swapper_models : List[FaceSwapperModel] = list(face_swapper_set.keys())
face_swapper_models : List[FaceSwapperModel] = list(get_args(FaceSwapperModel))
face_swapper_weight_range : Sequence[FaceSwapperWeight] = create_float_range(0.0, 1.0, 0.05)
@@ -540,8 +540,8 @@ def pre_process(mode : ProcessMode) -> bool:
return False
source_image_paths = filter_image_paths(state_manager.get_item('source_paths'))
source_frames = read_static_images(source_image_paths)
source_faces = get_many_faces(source_frames)
source_vision_frames = read_static_images(source_image_paths)
source_faces = get_many_faces(source_vision_frames)
if not get_one_face(source_faces):
logger.error(translator.get('no_source_face_detected') + translator.get('exclamation_mark'), __name__)
@@ -1,6 +1,6 @@
from facefusion.types import Locals
from facefusion.types import Locales
LOCALS : Locals =\
LOCALES : Locales =\
{
'en':
{
@@ -1,9 +1,9 @@
from typing import List, Sequence
from typing import List, Sequence, get_args
from facefusion.common_helper import create_int_range
from facefusion.processors.modules.frame_colorizer.types import FrameColorizerModel
frame_colorizer_models : List[FrameColorizerModel] = [ 'ddcolor', 'ddcolor_artistic', 'deoldify', 'deoldify_artistic', 'deoldify_stable' ]
frame_colorizer_models : List[FrameColorizerModel] = list(get_args(FrameColorizerModel))
frame_colorizer_sizes : List[str] = [ '192x192', '256x256', '384x384', '512x512' ]
@@ -1,6 +1,6 @@
from facefusion.types import Locals
from facefusion.types import Locales
LOCALS : Locals =\
LOCALES : Locales =\
{
'en':
{
@@ -1,8 +1,8 @@
from typing import List, Sequence
from typing import List, Sequence, get_args
from facefusion.common_helper import create_int_range
from facefusion.processors.modules.frame_enhancer.types import FrameEnhancerModel
frame_enhancer_models : List[FrameEnhancerModel] = [ 'clear_reality_x4', 'face_dat_x4', 'lsdir_x4', 'nomos8k_sc_x4', 'real_esrgan_x2', 'real_esrgan_x2_fp16', 'real_esrgan_x4', 'real_esrgan_x4_fp16', 'real_esrgan_x8', 'real_esrgan_x8_fp16', 'real_hatgan_x4', 'real_web_photo_x4', 'realistic_rescaler_x4', 'remacri_x4', 'siax_x4', 'span_kendata_x4', 'swin2_sr_x4', 'tghq_face_x8', 'ultra_sharp_x4', 'ultra_sharp_2_x4' ]
frame_enhancer_models : List[FrameEnhancerModel] = list(get_args(FrameEnhancerModel))
frame_enhancer_blend_range : Sequence[int] = create_int_range(0, 100, 1)
@@ -56,7 +56,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'__metadata__':
{
'vendor': 'Helaman',
'license': 'Non-Commercial',
'license': 'CC-BY-4.0',
'year': 2023
},
'hashes':
@@ -83,7 +83,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'__metadata__':
{
'vendor': 'Phhofm',
'license': 'Non-Commercial',
'license': 'CC-BY-4.0',
'year': 2023
},
'hashes':
@@ -299,7 +299,7 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
'__metadata__':
{
'vendor': 'Helaman',
'license': 'Non-Commercial',
'license': 'CC-BY-4.0',
'year': 2024
},
'hashes':
@@ -1,6 +1,6 @@
from facefusion.types import Locals
from facefusion.types import Locales
LOCALS : Locals =\
LOCALES : Locales =\
{
'en':
{
@@ -1,8 +1,8 @@
from typing import List, Sequence
from typing import List, Sequence, get_args
from facefusion.common_helper import create_float_range
from facefusion.processors.modules.lip_syncer.types import LipSyncerModel
lip_syncer_models : List[LipSyncerModel] = [ 'edtalk_256', 'wav2lip_96', 'wav2lip_gan_96' ]
lip_syncer_models : List[LipSyncerModel] = list(get_args(LipSyncerModel))
lip_syncer_weight_range : Sequence[float] = create_float_range(0.0, 1.0, 0.05)
@@ -1,6 +1,6 @@
from facefusion.types import Locals
from facefusion.types import Locales
LOCALS : Locals =\
LOCALES : Locales =\
{
'en':
{
+4 -8
View File
@@ -10,7 +10,7 @@ from facefusion.ffmpeg import get_available_encoder_set
from facefusion.filesystem import get_file_name, resolve_file_paths
from facefusion.jobs import job_store
from facefusion.processors.core import get_processors_modules
from facefusion.sanitizer import sanitize_int_range
from facefusion.sanitizer import sanitize_int_range, sanitize_job_id
def create_help_formatter_small(prog : str) -> HelpFormatter:
@@ -188,7 +188,7 @@ def create_processors_program() -> ArgumentParser:
program = ArgumentParser(add_help = False)
available_processors = [ get_file_name(file_path) for file_path in resolve_file_paths('facefusion/processors/modules') ]
group_processors = program.add_argument_group('processors')
group_processors.add_argument('--processors', help = translator.get('help.processors').format(choices = ', '.join(available_processors)), default = config.get_str_list('processors', 'processors', 'face_swapper'), nargs = '+')
group_processors.add_argument('--processors', help = translator.get('help.processors').format(choices = ', '.join(available_processors)), default = config.get_str_list('processors', 'processors', 'face_swapper'), choices = available_processors, nargs = '+', metavar = 'PROCESSORS')
job_store.register_step_keys([ 'processors' ])
for processor_module in get_processors_modules(available_processors):
processor_module.register_args(program)
@@ -200,7 +200,7 @@ def create_uis_program() -> ArgumentParser:
available_ui_layouts = [ get_file_name(file_path) for file_path in resolve_file_paths('facefusion/uis/layouts') ]
group_uis = program.add_argument_group('uis')
group_uis.add_argument('--open-browser', help = translator.get('help.open_browser'), action = 'store_true', default = config.get_bool_value('uis', 'open_browser'))
group_uis.add_argument('--ui-layouts', help = translator.get('help.ui_layouts').format(choices = ', '.join(available_ui_layouts)), default = config.get_str_list('uis', 'ui_layouts', 'default'), nargs = '+')
group_uis.add_argument('--ui-layouts', help = translator.get('help.ui_layouts').format(choices = ', '.join(available_ui_layouts)), default = config.get_str_list('uis', 'ui_layouts', 'default'), choices = available_ui_layouts, nargs = '+', metavar = 'UI_LAYOUTS')
group_uis.add_argument('--ui-workflow', help = translator.get('help.ui_workflow'), default = config.get_str_value('uis', 'ui_workflow', 'instant_runner'), choices = facefusion.choices.ui_workflows)
return program
@@ -268,8 +268,7 @@ def create_halt_on_error_program() -> ArgumentParser:
def create_job_id_program() -> ArgumentParser:
program = ArgumentParser(add_help = False)
program.add_argument('job_id', help = translator.get('help.job_id'))
job_store.register_job_keys([ 'job_id' ])
program.add_argument('job_id', help = translator.get('help.job_id'), type = sanitize_job_id)
return program
@@ -298,13 +297,11 @@ def create_program() -> ArgumentParser:
program._positionals.title = 'commands'
program.add_argument('-v', '--version', version = metadata.get('name') + ' ' + metadata.get('version'), action = 'version')
sub_program = program.add_subparsers(dest = 'command')
# general
sub_program.add_parser('run', help = translator.get('help.run'), parents = [ create_config_path_program(), create_temp_path_program(), create_jobs_path_program(), create_source_paths_program(), create_target_path_program(), create_output_path_program(), collect_step_program(), create_uis_program(), create_benchmark_program(), collect_job_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('headless-run', help = translator.get('help.headless_run'), parents = [ create_config_path_program(), create_temp_path_program(), create_jobs_path_program(), create_source_paths_program(), create_target_path_program(), create_output_path_program(), collect_step_program(), collect_job_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('batch-run', help = translator.get('help.batch_run'), parents = [ create_config_path_program(), create_temp_path_program(), create_jobs_path_program(), create_source_pattern_program(), create_target_pattern_program(), create_output_pattern_program(), collect_step_program(), collect_job_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('force-download', help = translator.get('help.force_download'), parents = [ create_download_providers_program(), create_download_scope_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('benchmark', help = translator.get('help.benchmark'), parents = [ create_temp_path_program(), collect_step_program(), create_benchmark_program(), collect_job_program() ], formatter_class = create_help_formatter_large)
# job manager
sub_program.add_parser('job-list', help = translator.get('help.job_list'), parents = [ create_job_status_program(), create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-create', help = translator.get('help.job_create'), parents = [ create_job_id_program(), create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-submit', help = translator.get('help.job_submit'), parents = [ create_job_id_program(), create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
@@ -315,7 +312,6 @@ def create_program() -> ArgumentParser:
sub_program.add_parser('job-remix-step', help = translator.get('help.job_remix_step'), parents = [ create_job_id_program(), create_step_index_program(), create_config_path_program(), create_jobs_path_program(), create_source_paths_program(), create_output_path_program(), collect_step_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-insert-step', help = translator.get('help.job_insert_step'), parents = [ create_job_id_program(), create_step_index_program(), create_config_path_program(), create_jobs_path_program(), create_source_paths_program(), create_target_path_program(), create_output_path_program(), collect_step_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-remove-step', help = translator.get('help.job_remove_step'), parents = [ create_job_id_program(), create_step_index_program(), create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
# job runner
sub_program.add_parser('job-run', help = translator.get('help.job_run'), parents = [ create_job_id_program(), create_config_path_program(), create_temp_path_program(), create_jobs_path_program(), collect_job_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-run-all', help = translator.get('help.job_run_all'), parents = [ create_config_path_program(), create_temp_path_program(), create_jobs_path_program(), collect_job_program(), create_halt_on_error_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-retry', help = translator.get('help.job_retry'), parents = [ create_job_id_program(), create_config_path_program(), create_temp_path_program(), create_jobs_path_program(), collect_job_program() ], formatter_class = create_help_formatter_large)
+9
View File
@@ -1,6 +1,15 @@
import hashlib
from typing import Sequence
def sanitize_job_id(job_id : str) -> str:
__job_id__ = job_id.replace('-', '')
if __job_id__.isalnum():
return job_id
return hashlib.sha1(job_id.encode()).hexdigest()
def sanitize_int_range(value : int, int_range : Sequence[int]) -> int:
if value in int_range:
return value
+6 -6
View File
@@ -26,17 +26,17 @@ def multi_process_capture(camera_capture : cv2.VideoCapture, camera_fps : Fps) -
futures = []
while camera_capture and camera_capture.isOpened():
_, capture_frame = camera_capture.read()
if analyse_stream(capture_frame, camera_fps):
_, capture_vision_frame = camera_capture.read()
if analyse_stream(capture_vision_frame, camera_fps):
camera_capture.release()
if numpy.any(capture_frame):
future = executor.submit(process_stream_frame, capture_frame)
if numpy.any(capture_vision_frame):
future = executor.submit(process_stream_frame, capture_vision_frame)
futures.append(future)
for future_done in [ future for future in futures if future.done() ]:
capture_frame = future_done.result()
capture_deque.append(capture_frame)
capture_vision_frame = future_done.result()
capture_deque.append(capture_vision_frame)
futures.remove(future_done)
while capture_deque:
+8 -8
View File
@@ -1,29 +1,29 @@
import importlib
from typing import Optional
from facefusion.types import Language, LocalPoolSet, Locals
from facefusion.types import Language, LocalePoolSet, Locales
LOCAL_POOL_SET : LocalPoolSet = {}
LOCALE_POOL_SET : LocalePoolSet = {}
CURRENT_LANGUAGE : Language = 'en'
def __autoload__(module_name : str) -> None:
try:
__locals__ = importlib.import_module(module_name + '.locals')
load(__locals__.LOCALS, module_name)
__locales__ = importlib.import_module(module_name + '.locales')
load(__locales__.LOCALES, module_name)
except ImportError:
pass
def load(__locals__ : Locals, module_name : str) -> None:
LOCAL_POOL_SET[module_name] = __locals__
def load(__locales__ : Locales, module_name : str) -> None:
LOCALE_POOL_SET[module_name] = __locales__
def get(notation : str, module_name : str = 'facefusion') -> Optional[str]:
if module_name not in LOCAL_POOL_SET:
if module_name not in LOCALE_POOL_SET:
__autoload__(module_name)
current = LOCAL_POOL_SET.get(module_name).get(CURRENT_LANGUAGE)
current = LOCALE_POOL_SET.get(module_name).get(CURRENT_LANGUAGE)
for fragment in notation.split('.'):
if fragment in current:
+6 -5
View File
@@ -51,8 +51,8 @@ FaceStore = TypedDict('FaceStore',
})
Language = Literal['en']
Locals : TypeAlias = Dict[Language, Dict[str, Any]]
LocalPoolSet : TypeAlias = Dict[str, Locals]
Locales : TypeAlias = Dict[Language, Dict[str, Any]]
LocalePoolSet : TypeAlias = Dict[str, Locales]
VideoCaptureSet : TypeAlias = Dict[str, cv2.VideoCapture]
VideoWriterSet : TypeAlias = Dict[str, cv2.VideoWriter]
@@ -167,10 +167,11 @@ ModelOptions : TypeAlias = Dict[str, Any]
ModelSet : TypeAlias = Dict[str, ModelOptions]
ModelInitializer : TypeAlias = NDArray[Any]
ExecutionProvider = Literal['cpu', 'coreml', 'cuda', 'directml', 'openvino', 'migraphx', 'rocm', 'tensorrt']
ExecutionProviderValue = Literal['CPUExecutionProvider', 'CoreMLExecutionProvider', 'CUDAExecutionProvider', 'DmlExecutionProvider', 'OpenVINOExecutionProvider', 'MIGraphXExecutionProvider', 'ROCMExecutionProvider', 'TensorrtExecutionProvider']
ExecutionProvider = Literal['cuda', 'tensorrt', 'rocm', 'migraphx', 'coreml', 'openvino', 'qnn', 'directml', 'cpu']
ExecutionProviderValue = Literal['CPUExecutionProvider', 'CoreMLExecutionProvider', 'CUDAExecutionProvider', 'DmlExecutionProvider', 'OpenVINOExecutionProvider', 'MIGraphXExecutionProvider', 'QNNExecutionProvider', 'ROCMExecutionProvider', 'TensorrtExecutionProvider']
ExecutionProviderSet : TypeAlias = Dict[ExecutionProvider, ExecutionProviderValue]
InferenceSessionProvider : TypeAlias = Any
InferenceProvider : TypeAlias = Any
InferenceOptionSet : TypeAlias = Dict[str, Any]
ValueAndUnit = TypedDict('ValueAndUnit',
{
'value' : int,
+1 -1
View File
@@ -14,7 +14,7 @@ preview_resolutions : List[str] = [ '512x512', '768x768', '1024x1024' ]
webcam_modes : List[WebcamMode] = [ 'inline', 'udp', 'v4l2' ]
webcam_resolutions : List[str] = [ '320x240', '640x480', '800x600', '1024x768', '1280x720', '1280x960', '1920x1080' ]
background_remover_colors : Dict[str, Color] =\
background_remover_fill_colors : Dict[str, Color] =\
{
'red' : (255, 0, 0, 255),
'green' : (0, 255, 0, 255),
@@ -11,82 +11,132 @@ from facefusion.sanitizer import sanitize_int_range
from facefusion.uis.core import get_ui_component, register_ui_component
BACKGROUND_REMOVER_MODEL_DROPDOWN : Optional[gradio.Dropdown] = None
BACKGROUND_REMOVER_COLOR_WRAPPER : Optional[gradio.Group] = None
BACKGROUND_REMOVER_COLOR_RED_NUMBER : Optional[gradio.Number] = None
BACKGROUND_REMOVER_COLOR_GREEN_NUMBER : Optional[gradio.Number] = None
BACKGROUND_REMOVER_COLOR_BLUE_NUMBER : Optional[gradio.Number] = None
BACKGROUND_REMOVER_COLOR_ALPHA_NUMBER : Optional[gradio.Number] = None
BACKGROUND_REMOVER_FILL_COLOR_WRAPPER : Optional[gradio.Group] = None
BACKGROUND_REMOVER_FILL_COLOR_RED_NUMBER : Optional[gradio.Number] = None
BACKGROUND_REMOVER_FILL_COLOR_GREEN_NUMBER : Optional[gradio.Number] = None
BACKGROUND_REMOVER_FILL_COLOR_BLUE_NUMBER : Optional[gradio.Number] = None
BACKGROUND_REMOVER_FILL_COLOR_ALPHA_NUMBER : Optional[gradio.Number] = None
BACKGROUND_REMOVER_DESPILL_COLOR_WRAPPER : Optional[gradio.Group] = None
BACKGROUND_REMOVER_DESPILL_COLOR_RED_NUMBER : Optional[gradio.Number] = None
BACKGROUND_REMOVER_DESPILL_COLOR_GREEN_NUMBER : Optional[gradio.Number] = None
BACKGROUND_REMOVER_DESPILL_COLOR_BLUE_NUMBER : Optional[gradio.Number] = None
BACKGROUND_REMOVER_DESPILL_COLOR_ALPHA_NUMBER : Optional[gradio.Number] = None
def render() -> None:
global BACKGROUND_REMOVER_MODEL_DROPDOWN
global BACKGROUND_REMOVER_COLOR_WRAPPER
global BACKGROUND_REMOVER_COLOR_RED_NUMBER
global BACKGROUND_REMOVER_COLOR_GREEN_NUMBER
global BACKGROUND_REMOVER_COLOR_BLUE_NUMBER
global BACKGROUND_REMOVER_COLOR_ALPHA_NUMBER
global BACKGROUND_REMOVER_FILL_COLOR_WRAPPER
global BACKGROUND_REMOVER_FILL_COLOR_RED_NUMBER
global BACKGROUND_REMOVER_FILL_COLOR_GREEN_NUMBER
global BACKGROUND_REMOVER_FILL_COLOR_BLUE_NUMBER
global BACKGROUND_REMOVER_FILL_COLOR_ALPHA_NUMBER
global BACKGROUND_REMOVER_DESPILL_COLOR_WRAPPER
global BACKGROUND_REMOVER_DESPILL_COLOR_RED_NUMBER
global BACKGROUND_REMOVER_DESPILL_COLOR_GREEN_NUMBER
global BACKGROUND_REMOVER_DESPILL_COLOR_BLUE_NUMBER
global BACKGROUND_REMOVER_DESPILL_COLOR_ALPHA_NUMBER
has_background_remover = 'background_remover' in state_manager.get_item('processors')
background_remover_color = state_manager.get_item('background_remover_color')
background_remover_fill_color = state_manager.get_item('background_remover_fill_color')
background_remover_despill_color = state_manager.get_item('background_remover_despill_color')
BACKGROUND_REMOVER_MODEL_DROPDOWN = gradio.Dropdown(
label = translator.get('uis.model_dropdown', 'facefusion.processors.modules.background_remover'),
choices = background_remover_choices.background_remover_models,
value = state_manager.get_item('background_remover_model'),
visible = has_background_remover
)
with gradio.Group(visible = has_background_remover) as BACKGROUND_REMOVER_COLOR_WRAPPER:
with gradio.Group(visible = has_background_remover) as BACKGROUND_REMOVER_FILL_COLOR_WRAPPER:
with gradio.Row():
BACKGROUND_REMOVER_COLOR_RED_NUMBER = gradio.Number(
label = translator.get('uis.color_red_number', 'facefusion.processors.modules.background_remover'),
value = background_remover_color[0],
BACKGROUND_REMOVER_FILL_COLOR_RED_NUMBER = gradio.Number(
label = translator.get('uis.fill_color_red_number', 'facefusion.processors.modules.background_remover'),
value = background_remover_fill_color[0],
minimum = background_remover_choices.background_remover_color_range[0],
maximum = background_remover_choices.background_remover_color_range[-1],
step = calculate_int_step(background_remover_choices.background_remover_color_range)
)
BACKGROUND_REMOVER_COLOR_GREEN_NUMBER = gradio.Number(
label = translator.get('uis.color_green_number', 'facefusion.processors.modules.background_remover'),
value = background_remover_color[1],
BACKGROUND_REMOVER_FILL_COLOR_GREEN_NUMBER = gradio.Number(
label = translator.get('uis.fill_color_green_number', 'facefusion.processors.modules.background_remover'),
value = background_remover_fill_color[1],
minimum = background_remover_choices.background_remover_color_range[0],
maximum = background_remover_choices.background_remover_color_range[-1],
step = calculate_int_step(background_remover_choices.background_remover_color_range)
)
with gradio.Row():
BACKGROUND_REMOVER_COLOR_BLUE_NUMBER = gradio.Number(
label = translator.get('uis.color_blue_number', 'facefusion.processors.modules.background_remover'),
value = background_remover_color[2],
BACKGROUND_REMOVER_FILL_COLOR_BLUE_NUMBER = gradio.Number(
label = translator.get('uis.fill_color_blue_number', 'facefusion.processors.modules.background_remover'),
value = background_remover_fill_color[2],
minimum = background_remover_choices.background_remover_color_range[0],
maximum = background_remover_choices.background_remover_color_range[-1],
step = calculate_int_step(background_remover_choices.background_remover_color_range)
)
BACKGROUND_REMOVER_COLOR_ALPHA_NUMBER = gradio.Number(
label = translator.get('uis.color_alpha_number', 'facefusion.processors.modules.background_remover'),
value = background_remover_color[3],
BACKGROUND_REMOVER_FILL_COLOR_ALPHA_NUMBER = gradio.Number(
label = translator.get('uis.fill_color_alpha_number', 'facefusion.processors.modules.background_remover'),
value = background_remover_fill_color[3],
minimum = background_remover_choices.background_remover_color_range[0],
maximum = background_remover_choices.background_remover_color_range[-1],
step = calculate_int_step(background_remover_choices.background_remover_color_range)
)
with gradio.Group(visible = has_background_remover) as BACKGROUND_REMOVER_DESPILL_COLOR_WRAPPER:
with gradio.Row():
BACKGROUND_REMOVER_DESPILL_COLOR_RED_NUMBER = gradio.Number(
label = translator.get('uis.despill_color_red_number', 'facefusion.processors.modules.background_remover'),
value = background_remover_despill_color[0],
minimum = background_remover_choices.background_remover_color_range[0],
maximum = background_remover_choices.background_remover_color_range[-1],
step = calculate_int_step(background_remover_choices.background_remover_color_range)
)
BACKGROUND_REMOVER_DESPILL_COLOR_GREEN_NUMBER = gradio.Number(
label = translator.get('uis.despill_color_green_number', 'facefusion.processors.modules.background_remover'),
value = background_remover_despill_color[1],
minimum = background_remover_choices.background_remover_color_range[0],
maximum = background_remover_choices.background_remover_color_range[-1],
step = calculate_int_step(background_remover_choices.background_remover_color_range)
)
with gradio.Row():
BACKGROUND_REMOVER_DESPILL_COLOR_BLUE_NUMBER = gradio.Number(
label = translator.get('uis.despill_color_blue_number', 'facefusion.processors.modules.background_remover'),
value = background_remover_despill_color[2],
minimum = background_remover_choices.background_remover_color_range[0],
maximum = background_remover_choices.background_remover_color_range[-1],
step = calculate_int_step(background_remover_choices.background_remover_color_range)
)
BACKGROUND_REMOVER_DESPILL_COLOR_ALPHA_NUMBER = gradio.Number(
label = translator.get('uis.despill_color_alpha_number', 'facefusion.processors.modules.background_remover'),
value = background_remover_despill_color[3],
minimum = background_remover_choices.background_remover_color_range[0],
maximum = background_remover_choices.background_remover_color_range[-1],
step = calculate_int_step(background_remover_choices.background_remover_color_range)
)
register_ui_component('background_remover_model_dropdown', BACKGROUND_REMOVER_MODEL_DROPDOWN)
register_ui_component('background_remover_color_red_number', BACKGROUND_REMOVER_COLOR_RED_NUMBER)
register_ui_component('background_remover_color_green_number', BACKGROUND_REMOVER_COLOR_GREEN_NUMBER)
register_ui_component('background_remover_color_blue_number', BACKGROUND_REMOVER_COLOR_BLUE_NUMBER)
register_ui_component('background_remover_color_alpha_number', BACKGROUND_REMOVER_COLOR_ALPHA_NUMBER)
register_ui_component('background_remover_fill_color_red_number', BACKGROUND_REMOVER_FILL_COLOR_RED_NUMBER)
register_ui_component('background_remover_fill_color_green_number', BACKGROUND_REMOVER_FILL_COLOR_GREEN_NUMBER)
register_ui_component('background_remover_fill_color_blue_number', BACKGROUND_REMOVER_FILL_COLOR_BLUE_NUMBER)
register_ui_component('background_remover_fill_color_alpha_number', BACKGROUND_REMOVER_FILL_COLOR_ALPHA_NUMBER)
register_ui_component('background_remover_despill_color_red_number', BACKGROUND_REMOVER_DESPILL_COLOR_RED_NUMBER)
register_ui_component('background_remover_despill_color_green_number', BACKGROUND_REMOVER_DESPILL_COLOR_GREEN_NUMBER)
register_ui_component('background_remover_despill_color_blue_number', BACKGROUND_REMOVER_DESPILL_COLOR_BLUE_NUMBER)
register_ui_component('background_remover_despill_color_alpha_number', BACKGROUND_REMOVER_DESPILL_COLOR_ALPHA_NUMBER)
def listen() -> None:
BACKGROUND_REMOVER_MODEL_DROPDOWN.change(update_background_remover_model, inputs = BACKGROUND_REMOVER_MODEL_DROPDOWN, outputs = BACKGROUND_REMOVER_MODEL_DROPDOWN)
background_remover_color_inputs = [ BACKGROUND_REMOVER_COLOR_RED_NUMBER, BACKGROUND_REMOVER_COLOR_GREEN_NUMBER, BACKGROUND_REMOVER_COLOR_BLUE_NUMBER, BACKGROUND_REMOVER_COLOR_ALPHA_NUMBER ]
background_remover_fill_color_inputs = [ BACKGROUND_REMOVER_FILL_COLOR_RED_NUMBER, BACKGROUND_REMOVER_FILL_COLOR_GREEN_NUMBER, BACKGROUND_REMOVER_FILL_COLOR_BLUE_NUMBER, BACKGROUND_REMOVER_FILL_COLOR_ALPHA_NUMBER ]
background_remover_despill_color_inputs = [ BACKGROUND_REMOVER_DESPILL_COLOR_RED_NUMBER, BACKGROUND_REMOVER_DESPILL_COLOR_GREEN_NUMBER, BACKGROUND_REMOVER_DESPILL_COLOR_BLUE_NUMBER, BACKGROUND_REMOVER_DESPILL_COLOR_ALPHA_NUMBER ]
for background_remover_color_input in background_remover_color_inputs:
background_remover_color_input.change(update_background_remover_color, inputs = background_remover_color_inputs)
for background_remover_fill_color_input in background_remover_fill_color_inputs:
background_remover_fill_color_input.change(update_background_remover_fill_color, inputs = background_remover_fill_color_inputs)
for background_remover_despill_color_input in background_remover_despill_color_inputs:
background_remover_despill_color_input.change(update_background_remover_despill_color, inputs = background_remover_despill_color_inputs)
processors_checkbox_group = get_ui_component('processors_checkbox_group')
if processors_checkbox_group:
processors_checkbox_group.change(remote_update, inputs = processors_checkbox_group, outputs = [BACKGROUND_REMOVER_MODEL_DROPDOWN, BACKGROUND_REMOVER_COLOR_WRAPPER])
processors_checkbox_group.change(remote_update, inputs = processors_checkbox_group, outputs = [ BACKGROUND_REMOVER_MODEL_DROPDOWN, BACKGROUND_REMOVER_FILL_COLOR_WRAPPER, BACKGROUND_REMOVER_DESPILL_COLOR_WRAPPER ])
def remote_update(processors : List[str]) -> Tuple[gradio.Dropdown, gradio.Group]:
def remote_update(processors : List[str]) -> Tuple[gradio.Dropdown, gradio.Group, gradio.Group]:
has_background_remover = 'background_remover' in processors
return gradio.Dropdown(visible = has_background_remover), gradio.Group(visible = has_background_remover)
return gradio.Dropdown(visible = has_background_remover), gradio.Group(visible = has_background_remover), gradio.Group(visible = has_background_remover)
def update_background_remover_model(background_remover_model : BackgroundRemoverModel) -> gradio.Dropdown:
@@ -99,9 +149,17 @@ def update_background_remover_model(background_remover_model : BackgroundRemover
return gradio.Dropdown()
def update_background_remover_color(red : int, green : int, blue : int, alpha : int) -> None:
def update_background_remover_fill_color(red : int, green : int, blue : int, alpha : int) -> None:
red = sanitize_int_range(red, background_remover_choices.background_remover_color_range)
green = sanitize_int_range(green, background_remover_choices.background_remover_color_range)
blue = sanitize_int_range(blue, background_remover_choices.background_remover_color_range)
alpha = sanitize_int_range(alpha, background_remover_choices.background_remover_color_range)
state_manager.set_item('background_remover_color', (red, green, blue, alpha))
state_manager.set_item('background_remover_fill_color', (red, green, blue, alpha))
def update_background_remover_despill_color(red : int, green : int, blue : int, alpha : int) -> None:
red = sanitize_int_range(red, background_remover_choices.background_remover_color_range)
green = sanitize_int_range(green, background_remover_choices.background_remover_color_range)
blue = sanitize_int_range(blue, background_remover_choices.background_remover_color_range)
alpha = sanitize_int_range(alpha, background_remover_choices.background_remover_color_range)
state_manager.set_item('background_remover_despill_color', (red, green, blue, alpha))
+1 -1
View File
@@ -132,7 +132,7 @@ def listen() -> None:
'target_video'
]):
for method in [ 'change', 'clear' ]:
getattr(ui_component, method)(remote_update, outputs = [OUTPUT_IMAGE_QUALITY_SLIDER, OUTPUT_IMAGE_SCALE_SLIDER, OUTPUT_AUDIO_ENCODER_DROPDOWN, OUTPUT_AUDIO_QUALITY_SLIDER, OUTPUT_AUDIO_VOLUME_SLIDER, OUTPUT_VIDEO_ENCODER_DROPDOWN, OUTPUT_VIDEO_PRESET_DROPDOWN, OUTPUT_VIDEO_QUALITY_SLIDER, OUTPUT_VIDEO_SCALE_SLIDER, OUTPUT_VIDEO_FPS_SLIDER])
getattr(ui_component, method)(remote_update, outputs = [ OUTPUT_IMAGE_QUALITY_SLIDER, OUTPUT_IMAGE_SCALE_SLIDER, OUTPUT_AUDIO_ENCODER_DROPDOWN, OUTPUT_AUDIO_QUALITY_SLIDER, OUTPUT_AUDIO_VOLUME_SLIDER, OUTPUT_VIDEO_ENCODER_DROPDOWN, OUTPUT_VIDEO_PRESET_DROPDOWN, OUTPUT_VIDEO_QUALITY_SLIDER, OUTPUT_VIDEO_SCALE_SLIDER, OUTPUT_VIDEO_FPS_SLIDER ])
def remote_update() -> Tuple[gradio.Slider, gradio.Slider, gradio.Dropdown, gradio.Slider, gradio.Slider, gradio.Dropdown, gradio.Dropdown, gradio.Slider, gradio.Slider, gradio.Slider]:
+9 -5
View File
@@ -90,10 +90,14 @@ def listen() -> None:
for ui_component in get_ui_components(
[
'background_remover_color_red_number',
'background_remover_color_green_number',
'background_remover_color_blue_number',
'background_remover_color_alpha_number',
'background_remover_fill_color_red_number',
'background_remover_fill_color_green_number',
'background_remover_fill_color_blue_number',
'background_remover_fill_color_alpha_number',
'background_remover_despill_color_red_number',
'background_remover_despill_color_green_number',
'background_remover_despill_color_blue_number',
'background_remover_despill_color_alpha_number',
'face_debugger_items_checkbox_group',
'frame_colorizer_size_dropdown',
'face_mask_types_checkbox_group',
@@ -296,7 +300,7 @@ def extract_crop_frame(vision_frame : VisionFrame, face : Face) -> Optional[Visi
def prepare_output_frame(target_vision_frame : VisionFrame, temp_vision_frame : VisionFrame, temp_vision_mask : Mask) -> VisionFrame:
temp_vision_mask = temp_vision_mask.clip(state_manager.get_item('background_remover_color')[-1], 255)
temp_vision_mask = temp_vision_mask.clip(state_manager.get_item('background_remover_fill_color')[-1], 255)
temp_vision_frame = merge_vision_mask(temp_vision_frame, temp_vision_mask)
temp_vision_frame = cv2.resize(temp_vision_frame, target_vision_frame.shape[1::-1])
return temp_vision_frame
+8 -7
View File
@@ -10,7 +10,7 @@ from facefusion.streamer import multi_process_capture, open_stream
from facefusion.types import Fps, VisionFrame, WebcamMode
from facefusion.uis.core import get_ui_component
from facefusion.uis.types import File
from facefusion.vision import unpack_resolution
from facefusion.vision import fit_cover_frame, unpack_resolution
SOURCE_FILE : Optional[gradio.File] = None
WEBCAM_IMAGE : Optional[gradio.Image] = None
@@ -90,7 +90,7 @@ def start(webcam_device_id : int, webcam_mode : WebcamMode, webcam_resolution :
stream = None
if webcam_mode in [ 'udp', 'v4l2' ]:
stream = open_stream(webcam_mode, webcam_resolution, webcam_fps) # type:ignore[arg-type]
stream = open_stream(webcam_mode, webcam_resolution, webcam_fps) #type:ignore[arg-type]
webcam_width, webcam_height = unpack_resolution(webcam_resolution)
if camera_capture and camera_capture.isOpened():
@@ -98,14 +98,15 @@ def start(webcam_device_id : int, webcam_mode : WebcamMode, webcam_resolution :
camera_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, webcam_height)
camera_capture.set(cv2.CAP_PROP_FPS, webcam_fps)
for capture_frame in multi_process_capture(camera_capture, webcam_fps):
capture_frame = cv2.cvtColor(capture_frame, cv2.COLOR_BGR2RGB)
for capture_vision_frame in multi_process_capture(camera_capture, webcam_fps):
capture_vision_frame = cv2.cvtColor(capture_vision_frame, cv2.COLOR_BGR2RGB)
capture_vision_frame = fit_cover_frame(capture_vision_frame, (webcam_width, webcam_height))
if webcam_mode == 'inline':
yield capture_frame
else:
yield capture_vision_frame
if webcam_mode in [ 'udp', 'v4l2' ]:
try:
stream.stdin.write(capture_frame.tobytes())
stream.stdin.write(capture_vision_frame.tobytes())
except Exception:
pass
+2
View File
@@ -1,4 +1,5 @@
import importlib
import logging
import os
import warnings
from types import ModuleType
@@ -72,6 +73,7 @@ def init() -> None:
os.environ['GRADIO_ANALYTICS_ENABLED'] = '0'
os.environ['GRADIO_TEMP_DIR'] = os.path.join(state_manager.get_item('temp_path'), 'gradio')
logging.getLogger('asyncio').setLevel(logging.CRITICAL)
warnings.filterwarnings('ignore', category = UserWarning, module = 'gradio')
gradio.processing_utils._check_allowed = uis_overrides.mock
gradio.processing_utils.convert_video_to_playable_mp4 = uis_overrides.convert_video_to_playable_mp4
+8 -4
View File
@@ -6,10 +6,14 @@ ComponentName = Literal\
'age_modifier_direction_slider',
'age_modifier_model_dropdown',
'background_remover_model_dropdown',
'background_remover_color_red_number',
'background_remover_color_green_number',
'background_remover_color_blue_number',
'background_remover_color_alpha_number',
'background_remover_fill_color_red_number',
'background_remover_fill_color_green_number',
'background_remover_fill_color_blue_number',
'background_remover_fill_color_alpha_number',
'background_remover_despill_color_red_number',
'background_remover_despill_color_green_number',
'background_remover_despill_color_blue_number',
'background_remover_despill_color_alpha_number',
'deep_swapper_model_dropdown',
'deep_swapper_morph_slider',
'expression_restorer_factor_slider',
+2 -2
View File
@@ -69,8 +69,8 @@ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
{
'__metadata__':
{
'vendor': 'Unknown',
'license': 'Non-Commercial',
'vendor': 'Anjok07',
'license': 'MIT',
'year': 2023
},
'hashes':
+1 -1
View File
@@ -24,7 +24,7 @@ def process(start_time : float) -> ErrorCode:
process_manager.start()
for task in tasks:
error_code = task() # type:ignore[operator]
error_code = task() #type:ignore[operator]
if error_code > 0:
process_manager.end()
+1 -1
View File
@@ -31,7 +31,7 @@ def process(start_time : float) -> ErrorCode:
process_manager.start()
for task in tasks:
error_code = task() # type:ignore[operator]
error_code = task() #type:ignore[operator]
if error_code > 0:
process_manager.end()
+6 -7
View File
@@ -1,9 +1,8 @@
gradio-rangeslider==0.0.8
gradio==5.44.1
numpy==2.3.4
onnx==1.19.1
onnxruntime==1.23.2
opencv-python==4.12.0.88
psutil==7.1.2
tqdm==4.67.1
scipy==1.16.3
numpy==2.2.1
onnx==1.20.1
onnxruntime==1.24.3
opencv-python==4.13.0.92
tqdm==4.67.3
scipy==1.17.1
+1 -1
View File
@@ -15,7 +15,7 @@ def before_all() -> None:
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
])
subprocess.run(['ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg')])
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
@pytest.fixture(scope = 'function', autouse = True)
+2 -2
View File
@@ -20,8 +20,8 @@ def test_create_float_range() -> None:
def test_calc_int_step() -> None:
assert calculate_int_step([0, 1]) == 1
assert calculate_int_step([ 0, 1 ]) == 1
def test_calc_float_step() -> None:
assert calculate_float_step([0.1, 0.2]) == 0.1
assert calculate_float_step([ 0.1, 0.2 ]) == 0.1
+6 -3
View File
@@ -1,14 +1,17 @@
from shutil import which
from facefusion import metadata
from facefusion.curl_builder import chain, head, run
from facefusion.curl_builder import chain, ping, run, set_timeout
def test_run() -> None:
user_agent = metadata.get('name') + '/' + metadata.get('version')
assert run([]) == [ which('curl'), '--user-agent', user_agent, '--insecure', '--location', '--silent' ]
assert run([]) == [ which('curl'), '--user-agent', user_agent, '--location', '--silent' ]
def test_chain() -> None:
assert chain(head(metadata.get('url'))) == [ '-I', metadata.get('url') ]
assert chain(
ping(metadata.get('url')),
set_timeout(5)
) == [ '-I', metadata.get('url'), '--connect-timeout', '5' ]
+4 -4
View File
@@ -1,4 +1,4 @@
from facefusion.execution import create_inference_session_providers, get_available_execution_providers, has_execution_provider
from facefusion.execution import create_inference_providers, get_available_execution_providers, has_execution_provider
def test_has_execution_provider() -> None:
@@ -10,8 +10,8 @@ def test_get_available_execution_providers() -> None:
assert 'cpu' in get_available_execution_providers()
def test_create_inference_session_providers() -> None:
inference_session_providers =\
def test_create_inference_providers() -> None:
inference_providers =\
[
('CUDAExecutionProvider',
{
@@ -21,4 +21,4 @@ def test_create_inference_session_providers() -> None:
'CPUExecutionProvider'
]
assert create_inference_session_providers(1, [ 'cpu', 'cuda' ]) == inference_session_providers
assert create_inference_providers(1, [ 'cpu', 'cuda' ]) == inference_providers
+4 -2
View File
@@ -5,6 +5,7 @@ import pytest
from facefusion import face_classifier, face_detector, face_landmarker, face_recognizer, state_manager
from facefusion.download import conditional_download
from facefusion.face_analyser import get_many_faces
from facefusion.face_store import clear_static_faces
from facefusion.vision import read_static_image
from .helper import get_test_example_file, get_test_examples_directory
@@ -37,6 +38,7 @@ def before_each() -> None:
face_detector.clear_inference_pool()
face_landmarker.clear_inference_pool()
face_recognizer.clear_inference_pool()
clear_static_faces()
def test_get_one_face_with_retinaface() -> None:
@@ -62,7 +64,7 @@ def test_get_one_face_with_retinaface() -> None:
def test_get_one_face_with_scrfd() -> None:
state_manager.init_item('face_detector_model', 'scrfd')
state_manager.init_item('face_detector_size', '640x640')
state_manager.init_item('face_detector_size', '320x320')
state_manager.init_item('face_detector_margin', (0, 0, 0, 0))
face_detector.pre_check()
@@ -82,7 +84,7 @@ def test_get_one_face_with_scrfd() -> None:
def test_get_one_face_with_yoloface() -> None:
state_manager.init_item('face_detector_model', 'yoloface')
state_manager.init_item('face_detector_model', 'yolo_face')
state_manager.init_item('face_detector_size', '640x640')
state_manager.init_item('face_detector_margin', (0, 0, 0, 0))
face_detector.pre_check()
+5 -2
View File
@@ -1,10 +1,12 @@
import os
import tempfile
from facefusion.json import read_json, write_json
def test_read_json() -> None:
_, json_path = tempfile.mkstemp(suffix = '.json')
file_descriptor, json_path = tempfile.mkstemp(suffix = '.json')
os.close(file_descriptor)
assert not read_json(json_path)
@@ -14,6 +16,7 @@ def test_read_json() -> None:
def test_write_json() -> None:
_, json_path = tempfile.mkstemp(suffix = '.json')
file_descriptor, json_path = tempfile.mkstemp(suffix = '.json')
os.close(file_descriptor)
assert write_json(json_path, {})
+18 -6
View File
@@ -1,8 +1,6 @@
from argparse import ArgumentParser
import pytest
from facefusion.program_helper import find_argument_group, validate_actions
from facefusion.program_helper import find_argument_group, validate_actions, validate_args
def test_find_argument_group() -> None:
@@ -12,12 +10,26 @@ def test_find_argument_group() -> None:
assert find_argument_group(program, 'test-1')
assert find_argument_group(program, 'test-2')
assert find_argument_group(program, 'invalid') is None
assert find_argument_group(program, 'test-3') is None
@pytest.mark.skip()
def test_validate_args() -> None:
pass
program = ArgumentParser()
program.add_argument('--test-1', default = 'test_1', choices = [ 'test_1', 'test_2' ])
assert validate_args(program) is True
subparsers = program.add_subparsers()
sub_program = subparsers.add_parser('sub-command')
sub_program.add_argument('--test-2', default = 'test_2', choices = [ 'test_1', 'test_2' ])
assert validate_args(program) is True
for action in sub_program._actions:
if action.dest == 'test_2':
action.default = 'test_3'
assert validate_args(program) is False
def test_validate_actions() -> None:
+1 -1
View File
@@ -3,6 +3,6 @@ from facefusion.sanitizer import sanitize_int_range
def test_sanitize_int_range() -> None:
assert sanitize_int_range(0, [ 0, 1, 2 ]) == 0
assert sanitize_int_range(2, [0, 1, 2]) == 2
assert sanitize_int_range(2, [ 0, 1, 2 ]) == 2
assert sanitize_int_range(-1, [ 0, 1 ]) == 0
assert sanitize_int_range(3, [ 0, 1 ]) == 0
+3 -3
View File
@@ -1,11 +1,11 @@
from facefusion import translator
from facefusion.locals import LOCALS
from facefusion.locales import LOCALES
def test_load() -> None:
translator.load(LOCALS, __name__)
translator.load(LOCALES, __name__)
assert __name__ in translator.LOCAL_POOL_SET
assert __name__ in translator.LOCALE_POOL_SET
def test_get() -> None: