* Operating system specific installer options

* Update dependencies

* Sorting before NMS according to the standard

* Minor typing fix

* Change the wording

* Update preview.py (#222)

Added a release listener to the preview frame slider, this will update the frame preview with the latest frame

* Combine preview slider listener

* Remove change listener

* Introduce multi source (#223)

* Implement multi source

* Adjust face enhancer and face debugger to multi source

* Implement multi source to UI

* Implement multi source to UI part2

* Implement multi source to UI part3

* Implement multi source to UI part4

* Some cleanup

* Add face occluder (#225) (#226)

* Add face occluder (#225)

* add face-occluder (commandline only)

* review 1

* Update face_masker.py

* Update face_masker.py

* Add gui & fix typing

* Minor naming cleanup

* Minor naming cleanup part2

---------

Co-authored-by: Harisreedhar <46858047+harisreedhar@users.noreply.github.com>

* Update usage information

* Fix averaged normed_embedding

* Remove blur from face occluder, enable accelerators

* Switch to RANSAC with 100 threshold

* Update face_enhancer.py (#229)

* Update face_debugger.py (#230)

* Split utilities (#232)

* Split utilities

* Split utilities part2

* Split utilities part3

* Split utilities part4

* Some cleanup

* Implement log level support (#233)

* Implement log level support

* Fix testing

* Implement debug logger

* Implement debug logger

* Fix alignment offset (#235)

* Update face_helper.py

* fix 2

* Enforce virtual environment via installer

* Enforce virtual environment via installer

* Enforce virtual environment via installer

* Enforce virtual environment via installer

* Feat/multi process reference faces (#239)

* Multi processing aware reference faces

* First clean up and joining of files

* Finalize the face store

* Reduce similar face detection to one set, use __name__ for scopes in logger

* Rename to face_occluder

* Introduce ModelSet type

* Improve webcam error handling

* Prevent null pointer on is_image() and is_video()

* Prevent null pointer on is_image() and is_video()

* Fix find similar faces

* Fix find similar faces

* Fix process_images for face enhancer

* Bunch of minor improvements

* onnxruntime for ROCM under linux

* Improve mask related naming

* Fix falsy import

* Fix typo

* Feat/face parser refactoring (#247)

* Face parser update (#244)

* face-parser

* Update face_masker.py

* update debugger

* Update globals.py

* Update face_masker.py

* Refactor code to split occlusion from region

* fix (#246)

* fix

* fix debugger resolution

* flip input to horizontal

* Clean up UI

* Reduce the regions to inside face only

* Reduce the regions to inside face only

---------

Co-authored-by: Harisreedhar <46858047+harisreedhar@users.noreply.github.com>

* Fix enhancer, remove useless dest in add_argument()

* Prevent unselect of the face_mask_regions via UI

* Prepare next release

* Shorten arguments that have choices and nargs

* Add missing clear to face debugger

---------

Co-authored-by: Mathias <github@feroc.de>
Co-authored-by: Harisreedhar <46858047+harisreedhar@users.noreply.github.com>
This commit is contained in:
Henry Ruhs
2023-12-20 00:00:32 +01:00
committed by GitHub
parent e70430703b
commit 3a5fe2a602
58 changed files with 1287 additions and 861 deletions

View File

@@ -7,11 +7,12 @@ import gradio
import facefusion.globals
from facefusion import wording
from facefusion.face_analyser import get_face_analyser
from facefusion.face_cache import clear_faces_cache
from facefusion.face_store import clear_static_faces
from facefusion.processors.frame.core import get_frame_processors_modules
from facefusion.vision import count_video_frame_total
from facefusion.core import limit_resources, conditional_process
from facefusion.utilities import normalize_output_path, clear_temp
from facefusion.normalizer import normalize_output_path
from facefusion.filesystem import clear_temp
from facefusion.uis.core import get_ui_component
BENCHMARK_RESULTS_DATAFRAME : Optional[gradio.Dataframe] = None
@@ -75,7 +76,7 @@ def listen() -> None:
def start(benchmark_runs : List[str], benchmark_cycles : int) -> Generator[List[Any], None, None]:
facefusion.globals.source_path = '.assets/examples/source.jpg'
facefusion.globals.source_paths = [ '.assets/examples/source.jpg' ]
target_paths = [ BENCHMARKS[benchmark_run] for benchmark_run in benchmark_runs if benchmark_run in BENCHMARKS ]
benchmark_results = []
if target_paths:
@@ -94,7 +95,7 @@ def pre_process() -> None:
def post_process() -> None:
clear_faces_cache()
clear_static_faces()
def benchmark(target_path : str, benchmark_cycles : int) -> List[Any]:
@@ -102,7 +103,7 @@ def benchmark(target_path : str, benchmark_cycles : int) -> List[Any]:
total_fps = 0.0
for i in range(benchmark_cycles):
facefusion.globals.target_path = target_path
facefusion.globals.output_path = normalize_output_path(facefusion.globals.source_path, facefusion.globals.target_path, tempfile.gettempdir())
facefusion.globals.output_path = normalize_output_path(facefusion.globals.source_paths, facefusion.globals.target_path, tempfile.gettempdir())
video_frame_total = count_video_frame_total(facefusion.globals.target_path)
start_time = time.perf_counter()
conditional_process()

View File

@@ -6,7 +6,7 @@ import facefusion.globals
from facefusion import wording
from facefusion.face_analyser import clear_face_analyser
from facefusion.processors.frame.core import clear_frame_processors_modules
from facefusion.utilities import encode_execution_providers, decode_execution_providers
from facefusion.execution_helper import encode_execution_providers, decode_execution_providers
EXECUTION_PROVIDERS_CHECKBOX_GROUP : Optional[gradio.CheckboxGroup] = None

View File

@@ -53,7 +53,7 @@ def render() -> None:
FACE_DETECTOR_SCORE_SLIDER = gradio.Slider(
label = wording.get('face_detector_score_slider_label'),
value = facefusion.globals.face_detector_score,
step =facefusion.choices.face_detector_score_range[1] - facefusion.choices.face_detector_score_range[0],
step = facefusion.choices.face_detector_score_range[1] - facefusion.choices.face_detector_score_range[0],
minimum = facefusion.choices.face_detector_score_range[0],
maximum = facefusion.choices.face_detector_score_range[-1]
)

View File

@@ -1,33 +1,49 @@
from typing import Optional
from typing import Optional, Tuple, List
import gradio
import facefusion.globals
import facefusion.choices
from facefusion import wording
from facefusion.typing import FaceMaskType, FaceMaskRegion
from facefusion.uis.core import register_ui_component
FACE_MASK_TYPES_CHECKBOX_GROUP : Optional[gradio.CheckboxGroup] = None
FACE_MASK_BLUR_SLIDER : Optional[gradio.Slider] = None
FACE_MASK_BOX_GROUP : Optional[gradio.Group] = None
FACE_MASK_REGION_GROUP : Optional[gradio.Group] = None
FACE_MASK_PADDING_TOP_SLIDER : Optional[gradio.Slider] = None
FACE_MASK_PADDING_RIGHT_SLIDER : Optional[gradio.Slider] = None
FACE_MASK_PADDING_BOTTOM_SLIDER : Optional[gradio.Slider] = None
FACE_MASK_PADDING_LEFT_SLIDER : Optional[gradio.Slider] = None
FACE_MASK_REGION_CHECKBOX_GROUP : Optional[gradio.CheckboxGroup] = None
def render() -> None:
global FACE_MASK_TYPES_CHECKBOX_GROUP
global FACE_MASK_BLUR_SLIDER
global FACE_MASK_BOX_GROUP
global FACE_MASK_REGION_GROUP
global FACE_MASK_PADDING_TOP_SLIDER
global FACE_MASK_PADDING_RIGHT_SLIDER
global FACE_MASK_PADDING_BOTTOM_SLIDER
global FACE_MASK_PADDING_LEFT_SLIDER
global FACE_MASK_REGION_CHECKBOX_GROUP
FACE_MASK_BLUR_SLIDER = gradio.Slider(
label = wording.get('face_mask_blur_slider_label'),
step = facefusion.choices.face_mask_blur_range[1] - facefusion.choices.face_mask_blur_range[0],
minimum = facefusion.choices.face_mask_blur_range[0],
maximum = facefusion.choices.face_mask_blur_range[-1],
value = facefusion.globals.face_mask_blur
has_box_mask = 'box' in facefusion.globals.face_mask_types
has_region_mask = 'region' in facefusion.globals.face_mask_types
FACE_MASK_TYPES_CHECKBOX_GROUP = gradio.CheckboxGroup(
label = wording.get('face_mask_types_checkbox_group_label'),
choices = facefusion.choices.face_mask_types,
value = facefusion.globals.face_mask_types
)
with gradio.Group():
with gradio.Group(visible = has_box_mask) as FACE_MASK_BOX_GROUP:
FACE_MASK_BLUR_SLIDER = gradio.Slider(
label = wording.get('face_mask_blur_slider_label'),
step = facefusion.choices.face_mask_blur_range[1] - facefusion.choices.face_mask_blur_range[0],
minimum = facefusion.choices.face_mask_blur_range[0],
maximum = facefusion.choices.face_mask_blur_range[-1],
value = facefusion.globals.face_mask_blur
)
with gradio.Row():
FACE_MASK_PADDING_TOP_SLIDER = gradio.Slider(
label = wording.get('face_mask_padding_top_slider_label'),
@@ -58,23 +74,50 @@ def render() -> None:
maximum = facefusion.choices.face_mask_padding_range[-1],
value = facefusion.globals.face_mask_padding[3]
)
with gradio.Row():
FACE_MASK_REGION_CHECKBOX_GROUP = gradio.CheckboxGroup(
label = wording.get('face_mask_region_checkbox_group_label'),
choices = facefusion.choices.face_mask_regions,
value = facefusion.globals.face_mask_regions,
visible = has_region_mask
)
register_ui_component('face_mask_types_checkbox_group', FACE_MASK_TYPES_CHECKBOX_GROUP)
register_ui_component('face_mask_blur_slider', FACE_MASK_BLUR_SLIDER)
register_ui_component('face_mask_padding_top_slider', FACE_MASK_PADDING_TOP_SLIDER)
register_ui_component('face_mask_padding_right_slider', FACE_MASK_PADDING_RIGHT_SLIDER)
register_ui_component('face_mask_padding_bottom_slider', FACE_MASK_PADDING_BOTTOM_SLIDER)
register_ui_component('face_mask_padding_left_slider', FACE_MASK_PADDING_LEFT_SLIDER)
register_ui_component('face_mask_region_checkbox_group', FACE_MASK_REGION_CHECKBOX_GROUP)
def listen() -> None:
FACE_MASK_TYPES_CHECKBOX_GROUP.change(update_face_mask_type, inputs = FACE_MASK_TYPES_CHECKBOX_GROUP, outputs = [ FACE_MASK_TYPES_CHECKBOX_GROUP, FACE_MASK_BOX_GROUP, FACE_MASK_REGION_CHECKBOX_GROUP ])
FACE_MASK_BLUR_SLIDER.change(update_face_mask_blur, inputs = FACE_MASK_BLUR_SLIDER)
FACE_MASK_REGION_CHECKBOX_GROUP.change(update_face_mask_regions, inputs = FACE_MASK_REGION_CHECKBOX_GROUP, outputs = FACE_MASK_REGION_CHECKBOX_GROUP)
face_mask_padding_sliders = [ FACE_MASK_PADDING_TOP_SLIDER, FACE_MASK_PADDING_RIGHT_SLIDER, FACE_MASK_PADDING_BOTTOM_SLIDER, FACE_MASK_PADDING_LEFT_SLIDER ]
for face_mask_padding_slider in face_mask_padding_sliders:
face_mask_padding_slider.change(update_face_mask_padding, inputs = face_mask_padding_sliders)
def update_face_mask_type(face_mask_types : List[FaceMaskType]) -> Tuple[gradio.CheckboxGroup, gradio.Group, gradio.CheckboxGroup]:
if not face_mask_types:
face_mask_types = facefusion.choices.face_mask_types
facefusion.globals.face_mask_types = face_mask_types
has_box_mask = 'box' in face_mask_types
has_region_mask = 'region' in face_mask_types
return gradio.CheckboxGroup(value = face_mask_types), gradio.Group(visible = has_box_mask), gradio.CheckboxGroup(visible = has_region_mask)
def update_face_mask_blur(face_mask_blur : float) -> None:
facefusion.globals.face_mask_blur = face_mask_blur
def update_face_mask_padding(face_mask_padding_top : int, face_mask_padding_right : int, face_mask_padding_bottom : int, face_mask_padding_left : int) -> None:
facefusion.globals.face_mask_padding = (face_mask_padding_top, face_mask_padding_right, face_mask_padding_bottom, face_mask_padding_left)
def update_face_mask_regions(face_mask_regions : List[FaceMaskRegion]) -> gradio.CheckboxGroup:
if not face_mask_regions:
face_mask_regions = facefusion.choices.face_mask_regions
facefusion.globals.face_mask_regions = face_mask_regions
return gradio.CheckboxGroup(value = face_mask_regions)

View File

@@ -5,12 +5,11 @@ import gradio
import facefusion.globals
import facefusion.choices
from facefusion import wording
from facefusion.face_cache import clear_faces_cache
from facefusion.face_store import clear_static_faces, clear_reference_faces
from facefusion.vision import get_video_frame, read_static_image, normalize_frame_color
from facefusion.face_analyser import get_many_faces
from facefusion.face_reference import clear_face_reference
from facefusion.typing import Frame, FaceSelectorMode
from facefusion.utilities import is_image, is_video
from facefusion.filesystem import is_image, is_video
from facefusion.uis.core import get_ui_component, register_ui_component
from facefusion.uis.typing import ComponentName
@@ -111,8 +110,8 @@ def update_face_selector_mode(face_selector_mode : FaceSelectorMode) -> Tuple[gr
def clear_and_update_reference_face_position(event : gradio.SelectData) -> gradio.Gallery:
clear_face_reference()
clear_faces_cache()
clear_reference_faces()
clear_static_faces()
update_reference_face_position(event.index)
return update_reference_position_gallery()
@@ -130,8 +129,8 @@ def update_reference_frame_number(reference_frame_number : int) -> None:
def clear_and_update_reference_position_gallery() -> gradio.Gallery:
clear_face_reference()
clear_faces_cache()
clear_reference_faces()
clear_static_faces()
return update_reference_position_gallery()

View File

@@ -4,7 +4,7 @@ import gradio
import facefusion.globals
from facefusion import wording
from facefusion.processors.frame.core import load_frame_processor_module, clear_frame_processors_modules
from facefusion.utilities import list_module_names
from facefusion.filesystem import list_module_names
from facefusion.uis.core import register_ui_component
FRAME_PROCESSORS_CHECKBOX_GROUP : Optional[gradio.CheckboxGroup] = None

View File

@@ -5,7 +5,8 @@ import facefusion.globals
from facefusion import wording
from facefusion.core import limit_resources, conditional_process
from facefusion.uis.core import get_ui_component
from facefusion.utilities import is_image, is_video, normalize_output_path, clear_temp
from facefusion.normalizer import normalize_output_path
from facefusion.filesystem import is_image, is_video, clear_temp
OUTPUT_IMAGE : Optional[gradio.Image] = None
OUTPUT_VIDEO : Optional[gradio.Video] = None
@@ -45,7 +46,7 @@ def listen() -> None:
def start(output_path : str) -> Tuple[gradio.Image, gradio.Video]:
facefusion.globals.output_path = normalize_output_path(facefusion.globals.source_path, facefusion.globals.target_path, output_path)
facefusion.globals.output_path = normalize_output_path(facefusion.globals.source_paths, facefusion.globals.target_path, output_path)
limit_resources()
conditional_process()
if is_image(facefusion.globals.output_path):

View File

@@ -6,7 +6,7 @@ import facefusion.globals
import facefusion.choices
from facefusion import wording
from facefusion.typing import OutputVideoEncoder
from facefusion.utilities import is_image, is_video
from facefusion.filesystem import is_image, is_video
from facefusion.uis.typing import ComponentName
from facefusion.uis.core import get_ui_component, register_ui_component

View File

@@ -4,15 +4,14 @@ import gradio
import facefusion.globals
from facefusion import wording
from facefusion.core import conditional_set_face_reference
from facefusion.face_cache import clear_faces_cache
from facefusion.typing import Frame, Face
from facefusion.vision import get_video_frame, count_video_frame_total, normalize_frame_color, resize_frame_dimension, read_static_image
from facefusion.face_analyser import get_one_face, clear_face_analyser
from facefusion.face_reference import get_face_reference, clear_face_reference
from facefusion.core import conditional_append_reference_faces
from facefusion.face_store import clear_static_faces, get_reference_faces, clear_reference_faces
from facefusion.typing import Frame, Face, FaceSet
from facefusion.vision import get_video_frame, count_video_frame_total, normalize_frame_color, resize_frame_dimension, read_static_image, read_static_images
from facefusion.face_analyser import get_average_face, clear_face_analyser
from facefusion.content_analyser import analyse_frame
from facefusion.processors.frame.core import load_frame_processor_module
from facefusion.utilities import is_video, is_image
from facefusion.filesystem import is_image, is_video
from facefusion.uis.typing import ComponentName
from facefusion.uis.core import get_ui_component, register_ui_component
@@ -37,16 +36,17 @@ def render() -> None:
'maximum': 100,
'visible': False
}
conditional_set_face_reference()
source_face = get_one_face(read_static_image(facefusion.globals.source_path))
reference_face = get_face_reference() if 'reference' in facefusion.globals.face_selector_mode else None
conditional_append_reference_faces()
source_frames = read_static_images(facefusion.globals.source_paths)
source_face = get_average_face(source_frames)
reference_faces = get_reference_faces() if 'reference' in facefusion.globals.face_selector_mode else None
if is_image(facefusion.globals.target_path):
target_frame = read_static_image(facefusion.globals.target_path)
preview_frame = process_preview_frame(source_face, reference_face, target_frame)
preview_frame = process_preview_frame(source_face, reference_faces, target_frame)
preview_image_args['value'] = normalize_frame_color(preview_frame)
if is_video(facefusion.globals.target_path):
temp_frame = get_video_frame(facefusion.globals.target_path, facefusion.globals.reference_frame_number)
preview_frame = process_preview_frame(source_face, reference_face, temp_frame)
preview_frame = process_preview_frame(source_face, reference_faces, temp_frame)
preview_image_args['value'] = normalize_frame_color(preview_frame)
preview_image_args['visible'] = True
preview_frame_slider_args['value'] = facefusion.globals.reference_frame_number
@@ -58,7 +58,7 @@ def render() -> None:
def listen() -> None:
PREVIEW_FRAME_SLIDER.change(update_preview_image, inputs = PREVIEW_FRAME_SLIDER, outputs = PREVIEW_IMAGE)
PREVIEW_FRAME_SLIDER.release(update_preview_image, inputs = PREVIEW_FRAME_SLIDER, outputs = PREVIEW_IMAGE)
multi_one_component_names : List[ComponentName] =\
[
'source_image',
@@ -101,11 +101,13 @@ def listen() -> None:
'frame_enhancer_blend_slider',
'face_selector_mode_dropdown',
'reference_face_distance_slider',
'face_mask_types_checkbox_group',
'face_mask_blur_slider',
'face_mask_padding_top_slider',
'face_mask_padding_bottom_slider',
'face_mask_padding_left_slider',
'face_mask_padding_right_slider'
'face_mask_padding_right_slider',
'face_mask_region_checkbox_group'
]
for component_name in change_one_component_names:
component = get_ui_component(component_name)
@@ -126,15 +128,17 @@ def listen() -> None:
def clear_and_update_preview_image(frame_number : int = 0) -> gradio.Image:
clear_face_analyser()
clear_face_reference()
clear_faces_cache()
clear_reference_faces()
clear_static_faces()
return update_preview_image(frame_number)
def update_preview_image(frame_number : int = 0) -> gradio.Image:
conditional_set_face_reference()
source_face = get_one_face(read_static_image(facefusion.globals.source_path))
reference_face = get_face_reference() if 'reference' in facefusion.globals.face_selector_mode else None
clear_reference_faces()
conditional_append_reference_faces()
source_frames = read_static_images(facefusion.globals.source_paths)
source_face = get_average_face(source_frames)
reference_face = get_reference_faces() if 'reference' in facefusion.globals.face_selector_mode else None
if is_image(facefusion.globals.target_path):
target_frame = read_static_image(facefusion.globals.target_path)
preview_frame = process_preview_frame(source_face, reference_face, target_frame)
@@ -155,7 +159,7 @@ def update_preview_frame_slider() -> gradio.Slider:
return gradio.Slider(value = None, maximum = None, visible = False)
def process_preview_frame(source_face : Face, reference_face : Face, temp_frame : Frame) -> Frame:
def process_preview_frame(source_face : Face, reference_faces : FaceSet, temp_frame : Frame) -> Frame:
temp_frame = resize_frame_dimension(temp_frame, 640, 640)
if analyse_frame(temp_frame):
return cv2.GaussianBlur(temp_frame, (99, 99), 0)
@@ -164,7 +168,7 @@ def process_preview_frame(source_face : Face, reference_face : Face, temp_frame
if frame_processor_module.pre_process('preview'):
temp_frame = frame_processor_module.process_frame(
source_face,
reference_face,
reference_faces,
temp_frame
)
return temp_frame

View File

@@ -1,9 +1,10 @@
from typing import Any, IO, Optional
from typing import Optional, List
import gradio
import facefusion.globals
from facefusion import wording
from facefusion.utilities import is_image
from facefusion.uis.typing import File
from facefusion.filesystem import are_images
from facefusion.uis.core import register_ui_component
SOURCE_FILE : Optional[gradio.File] = None
@@ -14,9 +15,9 @@ def render() -> None:
global SOURCE_FILE
global SOURCE_IMAGE
is_source_image = is_image(facefusion.globals.source_path)
are_source_images = are_images(facefusion.globals.source_paths)
SOURCE_FILE = gradio.File(
file_count = 'single',
file_count = 'multiple',
file_types =
[
'.png',
@@ -24,11 +25,12 @@ def render() -> None:
'.webp'
],
label = wording.get('source_file_label'),
value = facefusion.globals.source_path if is_source_image else None
value = facefusion.globals.source_paths if are_source_images else None
)
source_file_names = [ source_file_value['name'] for source_file_value in SOURCE_FILE.value ] if SOURCE_FILE.value else None
SOURCE_IMAGE = gradio.Image(
value = SOURCE_FILE.value['name'] if is_source_image else None,
visible = is_source_image,
value = source_file_names[0] if are_source_images else None,
visible = are_source_images,
show_label = False
)
register_ui_component('source_image', SOURCE_IMAGE)
@@ -38,9 +40,10 @@ def listen() -> None:
SOURCE_FILE.change(update, inputs = SOURCE_FILE, outputs = SOURCE_IMAGE)
def update(file: IO[Any]) -> gradio.Image:
if file and is_image(file.name):
facefusion.globals.source_path = file.name
return gradio.Image(value = file.name, visible = True)
facefusion.globals.source_path = None
def update(files : List[File]) -> gradio.Image:
file_names = [ file.name for file in files ] if files else None
if are_images(file_names):
facefusion.globals.source_paths = file_names
return gradio.Image(value = file_names[0], visible = True)
facefusion.globals.source_paths = None
return gradio.Image(value = None, visible = False)

View File

@@ -1,11 +1,11 @@
from typing import Any, IO, Tuple, Optional
from typing import Tuple, Optional
import gradio
import facefusion.globals
from facefusion import wording
from facefusion.face_cache import clear_faces_cache
from facefusion.face_reference import clear_face_reference
from facefusion.utilities import is_image, is_video
from facefusion.face_store import clear_static_faces, clear_reference_faces
from facefusion.uis.typing import File
from facefusion.filesystem import is_image, is_video
from facefusion.uis.core import register_ui_component
TARGET_FILE : Optional[gradio.File] = None
@@ -50,9 +50,9 @@ def listen() -> None:
TARGET_FILE.change(update, inputs = TARGET_FILE, outputs = [ TARGET_IMAGE, TARGET_VIDEO ])
def update(file : IO[Any]) -> Tuple[gradio.Image, gradio.Video]:
clear_face_reference()
clear_faces_cache()
def update(file : File) -> Tuple[gradio.Image, gradio.Video]:
clear_reference_faces()
clear_static_faces()
if file and is_image(file.name):
facefusion.globals.target_path = file.name
return gradio.Image(value = file.name, visible = True), gradio.Video(value = None, visible = False)

View File

@@ -5,7 +5,7 @@ import facefusion.globals
import facefusion.choices
from facefusion import wording
from facefusion.typing import TempFrameFormat
from facefusion.utilities import is_video
from facefusion.filesystem import is_video
from facefusion.uis.core import get_ui_component
TEMP_FRAME_FORMAT_DROPDOWN : Optional[gradio.Dropdown] = None

View File

@@ -4,7 +4,7 @@ import gradio
import facefusion.globals
from facefusion import wording
from facefusion.vision import count_video_frame_total
from facefusion.utilities import is_video
from facefusion.filesystem import is_video
from facefusion.uis.core import get_ui_component
TRIM_FRAME_START_SLIDER : Optional[gradio.Slider] = None

View File

@@ -9,13 +9,13 @@ import gradio
from tqdm import tqdm
import facefusion.globals
from facefusion import wording
from facefusion import logger, wording
from facefusion.content_analyser import analyse_stream
from facefusion.typing import Frame, Face
from facefusion.face_analyser import get_one_face
from facefusion.face_analyser import get_average_face
from facefusion.processors.frame.core import get_frame_processors_modules
from facefusion.utilities import open_ffmpeg
from facefusion.vision import normalize_frame_color, read_static_image
from facefusion.ffmpeg import open_ffmpeg
from facefusion.vision import normalize_frame_color, read_static_images
from facefusion.uis.typing import StreamMode, WebcamMode
from facefusion.uis.core import get_ui_component
@@ -79,30 +79,34 @@ def listen() -> None:
getattr(source_image, method)(stop, cancels = start_event)
def start(mode : WebcamMode, resolution : str, fps : float) -> Generator[Frame, None, None]:
def start(webcam_mode : WebcamMode, resolution : str, fps : float) -> Generator[Frame, None, None]:
facefusion.globals.face_selector_mode = 'one'
facefusion.globals.face_analyser_order = 'large-small'
source_face = get_one_face(read_static_image(facefusion.globals.source_path))
source_frames = read_static_images(facefusion.globals.source_paths)
source_face = get_average_face(source_frames)
stream = None
if mode in [ 'udp', 'v4l2' ]:
stream = open_stream(mode, resolution, fps) # type: ignore[arg-type]
if webcam_mode in [ 'udp', 'v4l2' ]:
stream = open_stream(webcam_mode, resolution, fps) # type: ignore[arg-type]
webcam_width, webcam_height = map(int, resolution.split('x'))
webcam_capture = get_webcam_capture()
if webcam_capture and webcam_capture.isOpened():
webcam_capture.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*'MJPG')) # type: ignore[attr-defined]
webcam_capture.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*'MJPG')) # type: ignore[attr-defined]
webcam_capture.set(cv2.CAP_PROP_FRAME_WIDTH, webcam_width)
webcam_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, webcam_height)
webcam_capture.set(cv2.CAP_PROP_FPS, fps)
for capture_frame in multi_process_capture(source_face, webcam_capture, fps):
if mode == 'inline':
if webcam_mode == 'inline':
yield normalize_frame_color(capture_frame)
else:
stream.stdin.write(capture_frame.tobytes())
try:
stream.stdin.write(capture_frame.tobytes())
except Exception:
clear_webcam_capture()
yield None
def multi_process_capture(source_face : Face, webcam_capture : cv2.VideoCapture, fps : float) -> Generator[Frame, None, None]:
with tqdm(desc = wording.get('processing'), unit = 'frame', ascii = ' =') as progress:
with tqdm(desc = wording.get('processing'), unit = 'frame', ascii = ' =', disable = facefusion.globals.log_level in [ 'warn', 'error' ]) as progress:
with ThreadPoolExecutor(max_workers = facefusion.globals.execution_thread_count) as executor:
futures = []
deque_capture_frames : Deque[Frame] = deque()
@@ -137,11 +141,15 @@ def process_stream_frame(source_face : Face, temp_frame : Frame) -> Frame:
return temp_frame
def open_stream(mode : StreamMode, resolution : str, fps : float) -> subprocess.Popen[bytes]:
def open_stream(stream_mode : StreamMode, resolution : str, fps : float) -> subprocess.Popen[bytes]:
commands = [ '-f', 'rawvideo', '-pix_fmt', 'bgr24', '-s', resolution, '-r', str(fps), '-i', '-' ]
if mode == 'udp':
if stream_mode == 'udp':
commands.extend([ '-b:v', '2000k', '-f', 'mpegts', 'udp://localhost:27000?pkt_size=1316' ])
if mode == 'v4l2':
device_name = os.listdir('/sys/devices/virtual/video4linux')[0]
commands.extend([ '-f', 'v4l2', '/dev/' + device_name ])
if stream_mode == 'v4l2':
try:
device_name = os.listdir('/sys/devices/virtual/video4linux')[0]
if device_name:
commands.extend([ '-f', 'v4l2', '/dev/' + device_name ])
except FileNotFoundError:
logger.error(wording.get('stream_not_loaded').format(stream_mode = stream_mode), __name__.upper())
return open_ffmpeg(commands)

View File

@@ -5,9 +5,9 @@ import sys
import gradio
import facefusion.globals
from facefusion import metadata, wording
from facefusion import metadata, logger, wording
from facefusion.uis.typing import Component, ComponentName
from facefusion.utilities import resolve_relative_path
from facefusion.filesystem import resolve_relative_path
UI_COMPONENTS: Dict[ComponentName, Component] = {}
UI_LAYOUT_MODULES : List[ModuleType] = []
@@ -27,7 +27,8 @@ def load_ui_layout_module(ui_layout : str) -> Any:
for method_name in UI_LAYOUT_METHODS:
if not hasattr(ui_layout_module, method_name):
raise NotImplementedError
except ModuleNotFoundError:
except ModuleNotFoundError as exception:
logger.debug(exception.msg, __name__.upper())
sys.exit(wording.get('ui_layout_not_loaded').format(ui_layout = ui_layout))
except NotImplementedError:
sys.exit(wording.get('ui_layout_not_implemented').format(ui_layout = ui_layout))

View File

@@ -1,7 +1,7 @@
import gradio
import facefusion.globals
from facefusion.utilities import conditional_download
from facefusion.download import conditional_download
from facefusion.uis.components import about, frame_processors, frame_processors_options, execution, execution_thread_count, execution_queue_count, limit_resources, benchmark_options, benchmark

View File

@@ -1,6 +1,6 @@
import gradio
from facefusion.uis.components import about, frame_processors, frame_processors_options, execution, execution_thread_count, execution_queue_count, limit_resources, temp_frame, output_options, common_options, source, target, output, preview, trim_frame, face_analyser, face_selector, face_mask
from facefusion.uis.components import about, frame_processors, frame_processors_options, execution, execution_thread_count, execution_queue_count, limit_resources, temp_frame, output_options, common_options, source, target, output, preview, trim_frame, face_analyser, face_selector, face_masker
def pre_check() -> bool:
@@ -47,7 +47,7 @@ def render() -> gradio.Blocks:
with gradio.Blocks():
face_selector.render()
with gradio.Blocks():
face_mask.render()
face_masker.render()
with gradio.Blocks():
face_analyser.render()
return layout
@@ -69,7 +69,7 @@ def listen() -> None:
preview.listen()
trim_frame.listen()
face_selector.listen()
face_mask.listen()
face_masker.listen()
face_analyser.listen()

View File

@@ -1,6 +1,7 @@
from typing import Literal
from typing import Literal, Any, IO
import gradio
File = IO[Any]
Component = gradio.File or gradio.Image or gradio.Video or gradio.Slider
ComponentName = Literal\
[
@@ -17,11 +18,13 @@ ComponentName = Literal\
'face_detector_model_dropdown',
'face_detector_size_dropdown',
'face_detector_score_slider',
'face_mask_types_checkbox_group',
'face_mask_blur_slider',
'face_mask_padding_top_slider',
'face_mask_padding_bottom_slider',
'face_mask_padding_left_slider',
'face_mask_padding_right_slider',
'face_mask_region_checkbox_group',
'frame_processors_checkbox_group',
'face_swapper_model_dropdown',
'face_enhancer_model_dropdown',