Upload 4 files
Browse files- processors/core.py +45 -0
- processors/live_portrait.py +101 -0
- processors/pixel_boost.py +18 -0
- processors/types.py +20 -0
processors/core.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import importlib
|
| 2 |
+
from types import ModuleType
|
| 3 |
+
from typing import Any, List
|
| 4 |
+
|
| 5 |
+
from facefusion import logger, translator
|
| 6 |
+
from facefusion.exit_helper import hard_exit
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
PROCESSORS_METHODS =\
|
| 10 |
+
[
|
| 11 |
+
'get_inference_pool',
|
| 12 |
+
'clear_inference_pool',
|
| 13 |
+
'register_args',
|
| 14 |
+
'apply_args',
|
| 15 |
+
'get_common_modules',
|
| 16 |
+
'pre_check',
|
| 17 |
+
'pre_process',
|
| 18 |
+
'post_process',
|
| 19 |
+
'process_frame'
|
| 20 |
+
]
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def load_processor_module(processor : str) -> Any:
|
| 24 |
+
try:
|
| 25 |
+
processor_module = importlib.import_module('facefusion.processors.modules.' + processor + '.core')
|
| 26 |
+
for method_name in PROCESSORS_METHODS:
|
| 27 |
+
if not hasattr(processor_module, method_name):
|
| 28 |
+
raise NotImplementedError
|
| 29 |
+
except ModuleNotFoundError as exception:
|
| 30 |
+
logger.error(translator.get('processor_not_loaded').format(processor = processor), __name__)
|
| 31 |
+
logger.debug(exception.msg, __name__)
|
| 32 |
+
hard_exit(1)
|
| 33 |
+
except NotImplementedError:
|
| 34 |
+
logger.error(translator.get('processor_not_implemented').format(processor = processor), __name__)
|
| 35 |
+
hard_exit(1)
|
| 36 |
+
return processor_module
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def get_processors_modules(processors : List[str]) -> List[ModuleType]:
|
| 40 |
+
processor_modules = []
|
| 41 |
+
|
| 42 |
+
for processor in processors:
|
| 43 |
+
processor_module = load_processor_module(processor)
|
| 44 |
+
processor_modules.append(processor_module)
|
| 45 |
+
return processor_modules
|
processors/live_portrait.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Tuple
|
| 2 |
+
|
| 3 |
+
import numpy
|
| 4 |
+
import scipy
|
| 5 |
+
|
| 6 |
+
from facefusion.processors.types import LivePortraitExpression, LivePortraitPitch, LivePortraitRoll, LivePortraitRotation, LivePortraitYaw
|
| 7 |
+
|
| 8 |
+
EXPRESSION_MIN = numpy.array(
|
| 9 |
+
[
|
| 10 |
+
[
|
| 11 |
+
[ -2.88067125e-02, -8.12731311e-02, -1.70541159e-03 ],
|
| 12 |
+
[ -4.88598682e-02, -3.32196616e-02, -1.67431499e-04 ],
|
| 13 |
+
[ -6.75425082e-02, -4.28681746e-02, -1.98950816e-04 ],
|
| 14 |
+
[ -7.23103955e-02, -3.28503326e-02, -7.31324719e-04 ],
|
| 15 |
+
[ -3.87073644e-02, -6.01546466e-02, -5.50269964e-04 ],
|
| 16 |
+
[ -6.38048723e-02, -2.23840728e-01, -7.13261834e-04 ],
|
| 17 |
+
[ -3.02710701e-02, -3.93195450e-02, -8.24086510e-06 ],
|
| 18 |
+
[ -2.95799859e-02, -5.39318882e-02, -1.74219604e-04 ],
|
| 19 |
+
[ -2.92359516e-02, -1.53050944e-02, -6.30460854e-05 ],
|
| 20 |
+
[ -5.56493877e-03, -2.34344602e-02, -1.26858242e-04 ],
|
| 21 |
+
[ -4.37593013e-02, -2.77768299e-02, -2.70503685e-02 ],
|
| 22 |
+
[ -1.76926646e-02, -1.91676542e-02, -1.15090821e-04 ],
|
| 23 |
+
[ -8.34268332e-03, -3.99775570e-03, -3.27481248e-05 ],
|
| 24 |
+
[ -3.40162888e-02, -2.81868968e-02, -1.96679524e-04 ],
|
| 25 |
+
[ -2.91855410e-02, -3.97511162e-02, -2.81230678e-05 ],
|
| 26 |
+
[ -1.50395725e-02, -2.49494594e-02, -9.42573533e-05 ],
|
| 27 |
+
[ -1.67938769e-02, -2.00953931e-02, -4.00750607e-04 ],
|
| 28 |
+
[ -1.86435618e-02, -2.48535164e-02, -2.74416432e-02 ],
|
| 29 |
+
[ -4.61211195e-03, -1.21660791e-02, -2.93173041e-04 ],
|
| 30 |
+
[ -4.10017073e-02, -7.43824020e-02, -4.42762971e-02 ],
|
| 31 |
+
[ -1.90370996e-02, -3.74363363e-02, -1.34740388e-02 ]
|
| 32 |
+
]
|
| 33 |
+
]).astype(numpy.float32)
|
| 34 |
+
EXPRESSION_MAX = numpy.array(
|
| 35 |
+
[
|
| 36 |
+
[
|
| 37 |
+
[ 4.46682945e-02, 7.08772913e-02, 4.08344204e-04 ],
|
| 38 |
+
[ 2.14308221e-02, 6.15894832e-02, 4.85319615e-05 ],
|
| 39 |
+
[ 3.02363783e-02, 4.45043296e-02, 1.28298725e-05 ],
|
| 40 |
+
[ 3.05869691e-02, 3.79812494e-02, 6.57040102e-04 ],
|
| 41 |
+
[ 4.45670523e-02, 3.97259220e-02, 7.10966764e-04 ],
|
| 42 |
+
[ 9.43699256e-02, 9.85926315e-02, 2.02551950e-04 ],
|
| 43 |
+
[ 1.61131397e-02, 2.92906128e-02, 3.44733417e-06 ],
|
| 44 |
+
[ 5.23825921e-02, 1.07065082e-01, 6.61510974e-04 ],
|
| 45 |
+
[ 2.85718683e-03, 8.32320191e-03, 2.39314613e-04 ],
|
| 46 |
+
[ 2.57947259e-02, 1.60935968e-02, 2.41853559e-05 ],
|
| 47 |
+
[ 4.90833223e-02, 3.43903080e-02, 3.22353356e-02 ],
|
| 48 |
+
[ 1.44766076e-02, 3.39248963e-02, 1.42291479e-04 ],
|
| 49 |
+
[ 8.75749043e-04, 6.82212645e-03, 2.76097053e-05 ],
|
| 50 |
+
[ 1.86958015e-02, 3.84016186e-02, 7.33085908e-05 ],
|
| 51 |
+
[ 2.01714113e-02, 4.90544215e-02, 2.34028921e-05 ],
|
| 52 |
+
[ 2.46518422e-02, 3.29151377e-02, 3.48571630e-05 ],
|
| 53 |
+
[ 2.22457591e-02, 1.21796541e-02, 1.56396593e-04 ],
|
| 54 |
+
[ 1.72109623e-02, 3.01626958e-02, 1.36556877e-02 ],
|
| 55 |
+
[ 1.83460284e-02, 1.61141958e-02, 2.87440169e-04 ],
|
| 56 |
+
[ 3.57594155e-02, 1.80554688e-01, 2.75554154e-02 ],
|
| 57 |
+
[ 2.17450950e-02, 8.66811201e-02, 3.34241726e-02 ]
|
| 58 |
+
]
|
| 59 |
+
]).astype(numpy.float32)
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def limit_expression(expression : LivePortraitExpression) -> LivePortraitExpression:
|
| 63 |
+
return numpy.clip(expression, EXPRESSION_MIN, EXPRESSION_MAX)
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def limit_angle(target_pitch : LivePortraitPitch, target_yaw : LivePortraitYaw, target_roll : LivePortraitRoll, output_pitch : LivePortraitPitch, output_yaw : LivePortraitYaw, output_roll : LivePortraitRoll) -> Tuple[LivePortraitPitch, LivePortraitYaw, LivePortraitRoll]:
|
| 67 |
+
pitch_min, pitch_max, yaw_min, yaw_max, roll_min, roll_max = calculate_euler_limits(target_pitch, target_yaw, target_roll)
|
| 68 |
+
output_pitch = numpy.clip(output_pitch, pitch_min, pitch_max)
|
| 69 |
+
output_yaw = numpy.clip(output_yaw, yaw_min, yaw_max)
|
| 70 |
+
output_roll = numpy.clip(output_roll, roll_min, roll_max)
|
| 71 |
+
return output_pitch, output_yaw, output_roll
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def calculate_euler_limits(pitch : LivePortraitPitch, yaw : LivePortraitYaw, roll : LivePortraitRoll) -> Tuple[float, float, float, float, float, float]:
|
| 75 |
+
pitch_min = -30.0
|
| 76 |
+
pitch_max = 30.0
|
| 77 |
+
yaw_min = -60.0
|
| 78 |
+
yaw_max = 60.0
|
| 79 |
+
roll_min = -20.0
|
| 80 |
+
roll_max = 20.0
|
| 81 |
+
|
| 82 |
+
if pitch < 0:
|
| 83 |
+
pitch_min = min(pitch, pitch_min)
|
| 84 |
+
else:
|
| 85 |
+
pitch_max = max(pitch, pitch_max)
|
| 86 |
+
if yaw < 0:
|
| 87 |
+
yaw_min = min(yaw, yaw_min)
|
| 88 |
+
else:
|
| 89 |
+
yaw_max = max(yaw, yaw_max)
|
| 90 |
+
if roll < 0:
|
| 91 |
+
roll_min = min(roll, roll_min)
|
| 92 |
+
else:
|
| 93 |
+
roll_max = max(roll, roll_max)
|
| 94 |
+
|
| 95 |
+
return pitch_min, pitch_max, yaw_min, yaw_max, roll_min, roll_max
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def create_rotation(pitch : LivePortraitPitch, yaw : LivePortraitYaw, roll : LivePortraitRoll) -> LivePortraitRotation:
|
| 99 |
+
rotation = scipy.spatial.transform.Rotation.from_euler('xyz', [ pitch, yaw, roll ], degrees = True).as_matrix()
|
| 100 |
+
rotation = rotation.astype(numpy.float32)
|
| 101 |
+
return rotation
|
processors/pixel_boost.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import List
|
| 2 |
+
|
| 3 |
+
import numpy
|
| 4 |
+
from cv2.typing import Size
|
| 5 |
+
|
| 6 |
+
from facefusion.types import VisionFrame
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def implode_pixel_boost(crop_vision_frame : VisionFrame, pixel_boost_total : int, model_size : Size) -> VisionFrame:
|
| 10 |
+
pixel_boost_vision_frame = crop_vision_frame.reshape(model_size[0], pixel_boost_total, model_size[1], pixel_boost_total, 3)
|
| 11 |
+
pixel_boost_vision_frame = pixel_boost_vision_frame.transpose(1, 3, 0, 2, 4).reshape(pixel_boost_total ** 2, model_size[0], model_size[1], 3)
|
| 12 |
+
return pixel_boost_vision_frame
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def explode_pixel_boost(temp_vision_frames : List[VisionFrame], pixel_boost_total : int, model_size : Size, pixel_boost_size : Size) -> VisionFrame:
|
| 16 |
+
crop_vision_frame = numpy.stack(temp_vision_frames).reshape(pixel_boost_total, pixel_boost_total, model_size[0], model_size[1], 3)
|
| 17 |
+
crop_vision_frame = crop_vision_frame.transpose(2, 0, 3, 1, 4).reshape(pixel_boost_size[0], pixel_boost_size[1], 3)
|
| 18 |
+
return crop_vision_frame
|
processors/types.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any, Dict, Tuple, TypeAlias
|
| 2 |
+
|
| 3 |
+
from numpy.typing import NDArray
|
| 4 |
+
|
| 5 |
+
from facefusion.types import AppContext, Mask, VisionFrame
|
| 6 |
+
|
| 7 |
+
LivePortraitPitch : TypeAlias = float
|
| 8 |
+
LivePortraitYaw : TypeAlias = float
|
| 9 |
+
LivePortraitRoll : TypeAlias = float
|
| 10 |
+
LivePortraitExpression : TypeAlias = NDArray[Any]
|
| 11 |
+
LivePortraitFeatureVolume : TypeAlias = NDArray[Any]
|
| 12 |
+
LivePortraitMotionPoints : TypeAlias = NDArray[Any]
|
| 13 |
+
LivePortraitRotation : TypeAlias = NDArray[Any]
|
| 14 |
+
LivePortraitScale : TypeAlias = NDArray[Any]
|
| 15 |
+
LivePortraitTranslation : TypeAlias = NDArray[Any]
|
| 16 |
+
|
| 17 |
+
ProcessorStateKey = str
|
| 18 |
+
ProcessorState : TypeAlias = Dict[ProcessorStateKey, Any]
|
| 19 |
+
ProcessorStateSet : TypeAlias = Dict[AppContext, ProcessorState]
|
| 20 |
+
ProcessorOutputs : TypeAlias = Tuple[VisionFrame, Mask]
|