diff --git a/facefusion/processors/live_portrait.py b/facefusion/processors/live_portrait.py index 7da122a2..6cb89226 100644 --- a/facefusion/processors/live_portrait.py +++ b/facefusion/processors/live_portrait.py @@ -1,3 +1,5 @@ +from typing import Tuple + import numpy import scipy @@ -61,6 +63,41 @@ def limit_expression(expression : LivePortraitExpression) -> LivePortraitExpress return numpy.clip(expression, EXPRESSION_MIN, EXPRESSION_MAX) +def limit_euler_angles(target_euler_angles : Tuple[LivePortraitPitch, LivePortraitYaw, LivePortraitRoll], output_euler_angles : Tuple[LivePortraitPitch, LivePortraitYaw, LivePortraitRoll]) -> Tuple[LivePortraitPitch, LivePortraitYaw, LivePortraitRoll]: + pitch, yaw, roll = output_euler_angles + pitch_min, pitch_max, yaw_min, yaw_max, roll_min, roll_max = calc_rotation_limits(target_euler_angles) + pitch = numpy.clip(pitch, pitch_min, pitch_max) + yaw = numpy.clip(yaw, yaw_min, yaw_max) + roll = numpy.clip(roll, roll_min, roll_max) + return pitch, yaw, roll + + +def calc_rotation_limits(euler_angles : Tuple[LivePortraitPitch, LivePortraitYaw, LivePortraitRoll]) -> Tuple[float, float, float, float, float, float]: + pitch, yaw, roll = euler_angles + pitch_min = -30.0 + pitch_max = 30.0 + yaw_min = -60.0 + yaw_max = 60.0 + roll_min = -20.0 + roll_max = 20.0 + + if pitch < 0: + pitch_min = min(pitch, pitch_min) + else: + pitch_max = max(pitch, pitch_max) + + if yaw < 0: + yaw_min = min(yaw, yaw_min) + else: + yaw_max = max(yaw, yaw_max) + + if roll < 0: + roll_min = min(roll, roll_min) + else: + roll_max = max(roll, roll_max) + return pitch_min, pitch_max, yaw_min, yaw_max, roll_min, roll_max + + def create_rotation(pitch : LivePortraitPitch, yaw : LivePortraitYaw, roll : LivePortraitRoll) -> LivePortraitRotation: rotation = scipy.spatial.transform.Rotation.from_euler('xyz', [ pitch, yaw, roll ], degrees = True).as_matrix() rotation = rotation.astype(numpy.float32) diff --git a/facefusion/processors/modules/face_editor.py b/facefusion/processors/modules/face_editor.py index 08e38d3e..b24e36db 100755 --- a/facefusion/processors/modules/face_editor.py +++ b/facefusion/processors/modules/face_editor.py @@ -17,7 +17,7 @@ from facefusion.face_selector import find_similar_faces, sort_and_filter_faces from facefusion.face_store import get_reference_faces from facefusion.filesystem import in_directory, is_image, is_video, resolve_relative_path, same_file_extension from facefusion.processors import choices as processors_choices -from facefusion.processors.live_portrait import create_rotation, limit_expression +from facefusion.processors.live_portrait import create_rotation, limit_euler_angles, limit_expression from facefusion.processors.typing import FaceEditorInputs, LivePortraitExpression, LivePortraitFeatureVolume, LivePortraitMotionPoints, LivePortraitPitch, LivePortraitRoll, LivePortraitRotation, LivePortraitScale, LivePortraitTranslation, LivePortraitYaw from facefusion.program_helper import find_argument_group from facefusion.thread_helper import conditional_thread_semaphore, thread_semaphore @@ -442,10 +442,11 @@ def edit_head_rotation(pitch : LivePortraitPitch, yaw : LivePortraitYaw, roll : face_editor_head_pitch = state_manager.get_item('face_editor_head_pitch') face_editor_head_yaw = state_manager.get_item('face_editor_head_yaw') face_editor_head_roll = state_manager.get_item('face_editor_head_roll') - pitch += float(numpy.interp(face_editor_head_pitch, [ -1, 1 ], [ 30, -30 ])) - yaw += float(numpy.interp(face_editor_head_yaw, [ -1, 1 ], [ 30, -30 ])) - roll += float(numpy.interp(face_editor_head_roll, [ -1, 1 ], [ -30, 30 ])) - rotation = create_rotation(pitch, yaw, roll) + edit_pitch = pitch + float(numpy.interp(face_editor_head_pitch, [ -1, 1 ], [ 20, -20 ])) + edit_yaw = yaw + float(numpy.interp(face_editor_head_yaw, [ -1, 1 ], [ 60, -60 ])) + edit_roll = roll + float(numpy.interp(face_editor_head_roll, [ -1, 1 ], [ -15, 15 ])) + edit_pitch, edit_yaw, edit_roll = limit_euler_angles(( pitch, yaw, roll ), ( edit_pitch, edit_yaw, edit_roll )) + rotation = create_rotation(edit_pitch, edit_yaw, edit_roll) return rotation