andro1241 commited on
Commit
5029349
·
verified ·
1 Parent(s): d23e761

Upload 4 files

Browse files
processors/modules/face_editor/choices.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List, Sequence, get_args
2
+
3
+ from facefusion.common_helper import create_float_range
4
+ from facefusion.processors.modules.face_editor.types import FaceEditorModel
5
+
6
+ face_editor_models : List[FaceEditorModel] = list(get_args(FaceEditorModel))
7
+
8
+ face_editor_eyebrow_direction_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
9
+ face_editor_eye_gaze_horizontal_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
10
+ face_editor_eye_gaze_vertical_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
11
+ face_editor_eye_open_ratio_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
12
+ face_editor_lip_open_ratio_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
13
+ face_editor_mouth_grim_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
14
+ face_editor_mouth_pout_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
15
+ face_editor_mouth_purse_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
16
+ face_editor_mouth_smile_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
17
+ face_editor_mouth_position_horizontal_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
18
+ face_editor_mouth_position_vertical_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
19
+ face_editor_head_pitch_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
20
+ face_editor_head_yaw_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
21
+ face_editor_head_roll_range : Sequence[float] = create_float_range(-1.0, 1.0, 0.05)
processors/modules/face_editor/core.py ADDED
@@ -0,0 +1,509 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from argparse import ArgumentParser
2
+ from functools import lru_cache
3
+ from types import ModuleType
4
+ from typing import List, Tuple
5
+
6
+ import cv2
7
+ import numpy
8
+
9
+ import facefusion.jobs.job_manager
10
+ import facefusion.jobs.job_store
11
+ from facefusion import config, content_analyser, face_classifier, face_detector, face_landmarker, face_masker, face_recognizer, inference_manager, logger, state_manager, translator, video_manager
12
+ from facefusion.common_helper import create_float_metavar, get_middle
13
+ from facefusion.download import conditional_download_hashes, conditional_download_sources, resolve_download_url
14
+ from facefusion.face_creator import scale_face
15
+ from facefusion.face_helper import paste_back, scale_face_landmark_5, warp_face_by_face_landmark_5
16
+ from facefusion.face_masker import create_box_mask
17
+ from facefusion.face_selector import select_faces
18
+ from facefusion.filesystem import in_directory, is_image, is_video, resolve_relative_path, same_file_extension
19
+ from facefusion.processors.live_portrait import create_rotation, limit_angle, limit_expression
20
+ from facefusion.processors.modules.face_editor import choices as face_editor_choices
21
+ from facefusion.processors.modules.face_editor.types import FaceEditorInputs
22
+ from facefusion.processors.types import LivePortraitExpression, LivePortraitFeatureVolume, LivePortraitMotionPoints, LivePortraitPitch, LivePortraitRoll, LivePortraitRotation, LivePortraitScale, LivePortraitTranslation, LivePortraitYaw, ProcessorOutputs
23
+ from facefusion.program_helper import find_argument_group
24
+ from facefusion.thread_helper import conditional_thread_semaphore, thread_semaphore
25
+ from facefusion.types import ApplyStateItem, Args, DownloadScope, Face, FaceLandmark68, InferencePool, ModelOptions, ModelSet, ProcessMode, VisionFrame
26
+ from facefusion.vision import read_static_image, read_static_video_frame
27
+
28
+
29
+ @lru_cache()
30
+ def create_static_model_set(download_scope : DownloadScope) -> ModelSet:
31
+ return\
32
+ {
33
+ 'live_portrait':
34
+ {
35
+ '__metadata__':
36
+ {
37
+ 'vendor': 'KwaiVGI',
38
+ 'license': 'MIT',
39
+ 'year': 2024
40
+ },
41
+ 'hashes':
42
+ {
43
+ 'feature_extractor':
44
+ {
45
+ 'url': resolve_download_url('models-3.0.0', 'live_portrait_feature_extractor.hash'),
46
+ 'path': resolve_relative_path('../.assets/models/live_portrait_feature_extractor.hash')
47
+ },
48
+ 'motion_extractor':
49
+ {
50
+ 'url': resolve_download_url('models-3.0.0', 'live_portrait_motion_extractor.hash'),
51
+ 'path': resolve_relative_path('../.assets/models/live_portrait_motion_extractor.hash')
52
+ },
53
+ 'eye_retargeter':
54
+ {
55
+ 'url': resolve_download_url('models-3.0.0', 'live_portrait_eye_retargeter.hash'),
56
+ 'path': resolve_relative_path('../.assets/models/live_portrait_eye_retargeter.hash')
57
+ },
58
+ 'lip_retargeter':
59
+ {
60
+ 'url': resolve_download_url('models-3.0.0', 'live_portrait_lip_retargeter.hash'),
61
+ 'path': resolve_relative_path('../.assets/models/live_portrait_lip_retargeter.hash')
62
+ },
63
+ 'stitcher':
64
+ {
65
+ 'url': resolve_download_url('models-3.0.0', 'live_portrait_stitcher.hash'),
66
+ 'path': resolve_relative_path('../.assets/models/live_portrait_stitcher.hash')
67
+ },
68
+ 'generator':
69
+ {
70
+ 'url': resolve_download_url('models-3.0.0', 'live_portrait_generator.hash'),
71
+ 'path': resolve_relative_path('../.assets/models/live_portrait_generator.hash')
72
+ }
73
+ },
74
+ 'sources':
75
+ {
76
+ 'feature_extractor':
77
+ {
78
+ 'url': resolve_download_url('models-3.0.0', 'live_portrait_feature_extractor.onnx'),
79
+ 'path': resolve_relative_path('../.assets/models/live_portrait_feature_extractor.onnx')
80
+ },
81
+ 'motion_extractor':
82
+ {
83
+ 'url': resolve_download_url('models-3.0.0', 'live_portrait_motion_extractor.onnx'),
84
+ 'path': resolve_relative_path('../.assets/models/live_portrait_motion_extractor.onnx')
85
+ },
86
+ 'eye_retargeter':
87
+ {
88
+ 'url': resolve_download_url('models-3.0.0', 'live_portrait_eye_retargeter.onnx'),
89
+ 'path': resolve_relative_path('../.assets/models/live_portrait_eye_retargeter.onnx')
90
+ },
91
+ 'lip_retargeter':
92
+ {
93
+ 'url': resolve_download_url('models-3.0.0', 'live_portrait_lip_retargeter.onnx'),
94
+ 'path': resolve_relative_path('../.assets/models/live_portrait_lip_retargeter.onnx')
95
+ },
96
+ 'stitcher':
97
+ {
98
+ 'url': resolve_download_url('models-3.0.0', 'live_portrait_stitcher.onnx'),
99
+ 'path': resolve_relative_path('../.assets/models/live_portrait_stitcher.onnx')
100
+ },
101
+ 'generator':
102
+ {
103
+ 'url': resolve_download_url('models-3.0.0', 'live_portrait_generator.onnx'),
104
+ 'path': resolve_relative_path('../.assets/models/live_portrait_generator.onnx')
105
+ }
106
+ },
107
+ 'template': 'ffhq_512',
108
+ 'size': (512, 512)
109
+ }
110
+ }
111
+
112
+
113
+ def get_inference_pool() -> InferencePool:
114
+ model_names = [ state_manager.get_item('face_editor_model') ]
115
+ model_source_set = get_model_options().get('sources')
116
+
117
+ return inference_manager.get_inference_pool(__name__, model_names, model_source_set)
118
+
119
+
120
+ def clear_inference_pool() -> None:
121
+ model_names = [ state_manager.get_item('face_editor_model') ]
122
+ inference_manager.clear_inference_pool(__name__, model_names)
123
+
124
+
125
+ def get_model_options() -> ModelOptions:
126
+ model_name = state_manager.get_item('face_editor_model')
127
+ return create_static_model_set('full').get(model_name)
128
+
129
+
130
+ def register_args(program : ArgumentParser) -> None:
131
+ group_processors = find_argument_group(program, 'processors')
132
+ if group_processors:
133
+ group_processors.add_argument('--face-editor-model', help = translator.get('help.model', __package__), default = config.get_str_value('processors', 'face_editor_model', 'live_portrait'), choices = face_editor_choices.face_editor_models)
134
+ group_processors.add_argument('--face-editor-eyebrow-direction', help = translator.get('help.eyebrow_direction', __package__), type = float, default = config.get_float_value('processors', 'face_editor_eyebrow_direction', '0'), choices = face_editor_choices.face_editor_eyebrow_direction_range, metavar = create_float_metavar(face_editor_choices.face_editor_eyebrow_direction_range))
135
+ group_processors.add_argument('--face-editor-eye-gaze-horizontal', help = translator.get('help.eye_gaze_horizontal', __package__), type = float, default = config.get_float_value('processors', 'face_editor_eye_gaze_horizontal', '0'), choices = face_editor_choices.face_editor_eye_gaze_horizontal_range, metavar = create_float_metavar(face_editor_choices.face_editor_eye_gaze_horizontal_range))
136
+ group_processors.add_argument('--face-editor-eye-gaze-vertical', help = translator.get('help.eye_gaze_vertical', __package__), type = float, default = config.get_float_value('processors', 'face_editor_eye_gaze_vertical', '0'), choices = face_editor_choices.face_editor_eye_gaze_vertical_range, metavar = create_float_metavar(face_editor_choices.face_editor_eye_gaze_vertical_range))
137
+ group_processors.add_argument('--face-editor-eye-open-ratio', help = translator.get('help.eye_open_ratio', __package__), type = float, default = config.get_float_value('processors', 'face_editor_eye_open_ratio', '0'), choices = face_editor_choices.face_editor_eye_open_ratio_range, metavar = create_float_metavar(face_editor_choices.face_editor_eye_open_ratio_range))
138
+ group_processors.add_argument('--face-editor-lip-open-ratio', help = translator.get('help.lip_open_ratio', __package__), type = float, default = config.get_float_value('processors', 'face_editor_lip_open_ratio', '0'), choices = face_editor_choices.face_editor_lip_open_ratio_range, metavar = create_float_metavar(face_editor_choices.face_editor_lip_open_ratio_range))
139
+ group_processors.add_argument('--face-editor-mouth-grim', help = translator.get('help.mouth_grim', __package__), type = float, default = config.get_float_value('processors', 'face_editor_mouth_grim', '0'), choices = face_editor_choices.face_editor_mouth_grim_range, metavar = create_float_metavar(face_editor_choices.face_editor_mouth_grim_range))
140
+ group_processors.add_argument('--face-editor-mouth-pout', help = translator.get('help.mouth_pout', __package__), type = float, default = config.get_float_value('processors', 'face_editor_mouth_pout', '0'), choices = face_editor_choices.face_editor_mouth_pout_range, metavar = create_float_metavar(face_editor_choices.face_editor_mouth_pout_range))
141
+ group_processors.add_argument('--face-editor-mouth-purse', help = translator.get('help.mouth_purse', __package__), type = float, default = config.get_float_value('processors', 'face_editor_mouth_purse', '0'), choices = face_editor_choices.face_editor_mouth_purse_range, metavar = create_float_metavar(face_editor_choices.face_editor_mouth_purse_range))
142
+ group_processors.add_argument('--face-editor-mouth-smile', help = translator.get('help.mouth_smile', __package__), type = float, default = config.get_float_value('processors', 'face_editor_mouth_smile', '0'), choices = face_editor_choices.face_editor_mouth_smile_range, metavar = create_float_metavar(face_editor_choices.face_editor_mouth_smile_range))
143
+ group_processors.add_argument('--face-editor-mouth-position-horizontal', help = translator.get('help.mouth_position_horizontal', __package__), type = float, default = config.get_float_value('processors', 'face_editor_mouth_position_horizontal', '0'), choices = face_editor_choices.face_editor_mouth_position_horizontal_range, metavar = create_float_metavar(face_editor_choices.face_editor_mouth_position_horizontal_range))
144
+ group_processors.add_argument('--face-editor-mouth-position-vertical', help = translator.get('help.mouth_position_vertical', __package__), type = float, default = config.get_float_value('processors', 'face_editor_mouth_position_vertical', '0'), choices = face_editor_choices.face_editor_mouth_position_vertical_range, metavar = create_float_metavar(face_editor_choices.face_editor_mouth_position_vertical_range))
145
+ group_processors.add_argument('--face-editor-head-pitch', help = translator.get('help.head_pitch', __package__), type = float, default = config.get_float_value('processors', 'face_editor_head_pitch', '0'), choices = face_editor_choices.face_editor_head_pitch_range, metavar = create_float_metavar(face_editor_choices.face_editor_head_pitch_range))
146
+ group_processors.add_argument('--face-editor-head-yaw', help = translator.get('help.head_yaw', __package__), type = float, default = config.get_float_value('processors', 'face_editor_head_yaw', '0'), choices = face_editor_choices.face_editor_head_yaw_range, metavar = create_float_metavar(face_editor_choices.face_editor_head_yaw_range))
147
+ group_processors.add_argument('--face-editor-head-roll', help = translator.get('help.head_roll', __package__), type = float, default = config.get_float_value('processors', 'face_editor_head_roll', '0'), choices = face_editor_choices.face_editor_head_roll_range, metavar = create_float_metavar(face_editor_choices.face_editor_head_roll_range))
148
+ facefusion.jobs.job_store.register_step_keys([ 'face_editor_model', 'face_editor_eyebrow_direction', 'face_editor_eye_gaze_horizontal', 'face_editor_eye_gaze_vertical', 'face_editor_eye_open_ratio', 'face_editor_lip_open_ratio', 'face_editor_mouth_grim', 'face_editor_mouth_pout', 'face_editor_mouth_purse', 'face_editor_mouth_smile', 'face_editor_mouth_position_horizontal', 'face_editor_mouth_position_vertical', 'face_editor_head_pitch', 'face_editor_head_yaw', 'face_editor_head_roll' ])
149
+
150
+
151
+ def apply_args(args : Args, apply_state_item : ApplyStateItem) -> None:
152
+ apply_state_item('face_editor_model', args.get('face_editor_model'))
153
+ apply_state_item('face_editor_eyebrow_direction', args.get('face_editor_eyebrow_direction'))
154
+ apply_state_item('face_editor_eye_gaze_horizontal', args.get('face_editor_eye_gaze_horizontal'))
155
+ apply_state_item('face_editor_eye_gaze_vertical', args.get('face_editor_eye_gaze_vertical'))
156
+ apply_state_item('face_editor_eye_open_ratio', args.get('face_editor_eye_open_ratio'))
157
+ apply_state_item('face_editor_lip_open_ratio', args.get('face_editor_lip_open_ratio'))
158
+ apply_state_item('face_editor_mouth_grim', args.get('face_editor_mouth_grim'))
159
+ apply_state_item('face_editor_mouth_pout', args.get('face_editor_mouth_pout'))
160
+ apply_state_item('face_editor_mouth_purse', args.get('face_editor_mouth_purse'))
161
+ apply_state_item('face_editor_mouth_smile', args.get('face_editor_mouth_smile'))
162
+ apply_state_item('face_editor_mouth_position_horizontal', args.get('face_editor_mouth_position_horizontal'))
163
+ apply_state_item('face_editor_mouth_position_vertical', args.get('face_editor_mouth_position_vertical'))
164
+ apply_state_item('face_editor_head_pitch', args.get('face_editor_head_pitch'))
165
+ apply_state_item('face_editor_head_yaw', args.get('face_editor_head_yaw'))
166
+ apply_state_item('face_editor_head_roll', args.get('face_editor_head_roll'))
167
+
168
+
169
+ def get_common_modules() -> List[ModuleType]:
170
+ return [ content_analyser, face_classifier, face_detector, face_landmarker, face_masker, face_recognizer ]
171
+
172
+
173
+ def pre_check() -> bool:
174
+ model_hash_set = get_model_options().get('hashes')
175
+ model_source_set = get_model_options().get('sources')
176
+
177
+ for common_module in get_common_modules():
178
+ if not common_module.pre_check():
179
+ return False
180
+
181
+ return conditional_download_hashes(model_hash_set) and conditional_download_sources(model_source_set)
182
+
183
+
184
+ def pre_process(mode : ProcessMode) -> bool:
185
+ if mode in [ 'output', 'preview' ] and not is_image(state_manager.get_item('target_path')) and not is_video(state_manager.get_item('target_path')):
186
+ logger.error(translator.get('choose_image_or_video_target') + translator.get('exclamation_mark'), __name__)
187
+ return False
188
+ if mode == 'output' and not in_directory(state_manager.get_item('output_path')):
189
+ logger.error(translator.get('specify_image_or_video_output') + translator.get('exclamation_mark'), __name__)
190
+ return False
191
+ if mode == 'output' and not same_file_extension(state_manager.get_item('target_path'), state_manager.get_item('output_path')):
192
+ logger.error(translator.get('match_target_and_output_extension') + translator.get('exclamation_mark'), __name__)
193
+ return False
194
+ return True
195
+
196
+
197
+ def post_process() -> None:
198
+ read_static_image.cache_clear()
199
+ read_static_video_frame.cache_clear()
200
+ video_manager.clear_video_pool()
201
+
202
+ if state_manager.get_item('video_memory_strategy') in [ 'strict', 'moderate' ]:
203
+ clear_inference_pool()
204
+
205
+ if state_manager.get_item('video_memory_strategy') == 'strict':
206
+ for common_module in get_common_modules():
207
+ common_module.clear_inference_pool()
208
+
209
+
210
+ def edit_face(target_face : Face, temp_vision_frame : VisionFrame) -> VisionFrame:
211
+ model_template = get_model_options().get('template')
212
+ model_size = get_model_options().get('size')
213
+ face_landmark_5 = scale_face_landmark_5(target_face.landmark_set.get('5/68'), 1.5)
214
+ crop_vision_frame, affine_matrix = warp_face_by_face_landmark_5(temp_vision_frame, face_landmark_5, model_template, model_size)
215
+ box_mask = create_box_mask(crop_vision_frame, state_manager.get_item('face_mask_blur'), (0, 0, 0, 0))
216
+ crop_vision_frame = prepare_crop_frame(crop_vision_frame)
217
+ crop_vision_frame = apply_edit(crop_vision_frame, target_face.landmark_set.get('68'))
218
+ crop_vision_frame = normalize_crop_frame(crop_vision_frame)
219
+ paste_vision_frame = paste_back(temp_vision_frame, crop_vision_frame, box_mask, affine_matrix)
220
+ return paste_vision_frame
221
+
222
+
223
+ def apply_edit(crop_vision_frame : VisionFrame, face_landmark_68 : FaceLandmark68) -> VisionFrame:
224
+ feature_volume = forward_extract_feature(crop_vision_frame)
225
+ pitch, yaw, roll, scale, translation, expression, motion_points = forward_extract_motion(crop_vision_frame)
226
+ rotation = create_rotation(pitch, yaw, roll)
227
+ motion_points_target = scale * (motion_points @ rotation.T + expression) + translation
228
+ expression = edit_eye_gaze(expression)
229
+ expression = edit_mouth_grim(expression)
230
+ expression = edit_mouth_position(expression)
231
+ expression = edit_mouth_pout(expression)
232
+ expression = edit_mouth_purse(expression)
233
+ expression = edit_mouth_smile(expression)
234
+ expression = edit_eyebrow_direction(expression)
235
+ expression = limit_expression(expression)
236
+ rotation = edit_head_rotation(pitch, yaw, roll)
237
+ motion_points_source = motion_points @ rotation.T
238
+ motion_points_source += expression
239
+ motion_points_source *= scale
240
+ motion_points_source += translation
241
+ motion_points_source += edit_eye_open(motion_points_target, face_landmark_68)
242
+ motion_points_source += edit_lip_open(motion_points_target, face_landmark_68)
243
+ motion_points_source = forward_stitch_motion_points(motion_points_source, motion_points_target)
244
+ crop_vision_frame = forward_generate_frame(feature_volume, motion_points_source, motion_points_target)
245
+ return crop_vision_frame
246
+
247
+
248
+ def forward_extract_feature(crop_vision_frame : VisionFrame) -> LivePortraitFeatureVolume:
249
+ feature_extractor = get_inference_pool().get('feature_extractor')
250
+
251
+ with conditional_thread_semaphore():
252
+ feature_volume = feature_extractor.run(None,
253
+ {
254
+ 'input': crop_vision_frame
255
+ })[0]
256
+
257
+ return feature_volume
258
+
259
+
260
+ def forward_extract_motion(crop_vision_frame : VisionFrame) -> Tuple[LivePortraitPitch, LivePortraitYaw, LivePortraitRoll, LivePortraitScale, LivePortraitTranslation, LivePortraitExpression, LivePortraitMotionPoints]:
261
+ motion_extractor = get_inference_pool().get('motion_extractor')
262
+
263
+ with conditional_thread_semaphore():
264
+ pitch, yaw, roll, scale, translation, expression, motion_points = motion_extractor.run(None,
265
+ {
266
+ 'input': crop_vision_frame
267
+ })
268
+
269
+ return pitch, yaw, roll, scale, translation, expression, motion_points
270
+
271
+
272
+ def forward_retarget_eye(eye_motion_points : LivePortraitMotionPoints) -> LivePortraitMotionPoints:
273
+ eye_retargeter = get_inference_pool().get('eye_retargeter')
274
+
275
+ with conditional_thread_semaphore():
276
+ eye_motion_points = eye_retargeter.run(None,
277
+ {
278
+ 'input': eye_motion_points
279
+ })[0]
280
+
281
+ return eye_motion_points
282
+
283
+
284
+ def forward_retarget_lip(lip_motion_points : LivePortraitMotionPoints) -> LivePortraitMotionPoints:
285
+ lip_retargeter = get_inference_pool().get('lip_retargeter')
286
+
287
+ with conditional_thread_semaphore():
288
+ lip_motion_points = lip_retargeter.run(None,
289
+ {
290
+ 'input': lip_motion_points
291
+ })[0]
292
+
293
+ return lip_motion_points
294
+
295
+
296
+ def forward_stitch_motion_points(source_motion_points : LivePortraitMotionPoints, target_motion_points : LivePortraitMotionPoints) -> LivePortraitMotionPoints:
297
+ stitcher = get_inference_pool().get('stitcher')
298
+
299
+ with thread_semaphore():
300
+ motion_points = stitcher.run(None,
301
+ {
302
+ 'source': source_motion_points,
303
+ 'target': target_motion_points
304
+ })[0]
305
+
306
+ return motion_points
307
+
308
+
309
+ def forward_generate_frame(feature_volume : LivePortraitFeatureVolume, source_motion_points : LivePortraitMotionPoints, target_motion_points : LivePortraitMotionPoints) -> VisionFrame:
310
+ generator = get_inference_pool().get('generator')
311
+
312
+ with thread_semaphore():
313
+ crop_vision_frame = generator.run(None,
314
+ {
315
+ 'feature_volume': feature_volume,
316
+ 'source': source_motion_points,
317
+ 'target': target_motion_points
318
+ })[0][0]
319
+
320
+ return crop_vision_frame
321
+
322
+
323
+ def edit_eyebrow_direction(expression : LivePortraitExpression) -> LivePortraitExpression:
324
+ face_editor_eyebrow = state_manager.get_item('face_editor_eyebrow_direction')
325
+
326
+ if face_editor_eyebrow > 0:
327
+ expression[0, 1, 1] += numpy.interp(face_editor_eyebrow, [ -1, 1 ], [ -0.015, 0.015 ])
328
+ expression[0, 2, 1] -= numpy.interp(face_editor_eyebrow, [ -1, 1 ], [ -0.020, 0.020 ])
329
+ else:
330
+ expression[0, 1, 0] -= numpy.interp(face_editor_eyebrow, [ -1, 1 ], [ -0.015, 0.015 ])
331
+ expression[0, 2, 0] += numpy.interp(face_editor_eyebrow, [ -1, 1 ], [ -0.020, 0.020 ])
332
+ expression[0, 1, 1] += numpy.interp(face_editor_eyebrow, [ -1, 1 ], [ -0.005, 0.005 ])
333
+ expression[0, 2, 1] -= numpy.interp(face_editor_eyebrow, [ -1, 1 ], [ -0.005, 0.005 ])
334
+ return expression
335
+
336
+
337
+ def edit_eye_gaze(expression : LivePortraitExpression) -> LivePortraitExpression:
338
+ face_editor_eye_gaze_horizontal = state_manager.get_item('face_editor_eye_gaze_horizontal')
339
+ face_editor_eye_gaze_vertical = state_manager.get_item('face_editor_eye_gaze_vertical')
340
+
341
+ if face_editor_eye_gaze_horizontal > 0:
342
+ expression[0, 11, 0] += numpy.interp(face_editor_eye_gaze_horizontal, [ -1, 1 ], [ -0.015, 0.015 ])
343
+ expression[0, 15, 0] += numpy.interp(face_editor_eye_gaze_horizontal, [ -1, 1 ], [ -0.020, 0.020 ])
344
+ else:
345
+ expression[0, 11, 0] += numpy.interp(face_editor_eye_gaze_horizontal, [ -1, 1 ], [ -0.020, 0.020 ])
346
+ expression[0, 15, 0] += numpy.interp(face_editor_eye_gaze_horizontal, [ -1, 1 ], [ -0.015, 0.015 ])
347
+ expression[0, 1, 1] += numpy.interp(face_editor_eye_gaze_vertical, [ -1, 1 ], [ -0.0025, 0.0025 ])
348
+ expression[0, 2, 1] -= numpy.interp(face_editor_eye_gaze_vertical, [ -1, 1 ], [ -0.0025, 0.0025 ])
349
+ expression[0, 11, 1] -= numpy.interp(face_editor_eye_gaze_vertical, [ -1, 1 ], [ -0.010, 0.010 ])
350
+ expression[0, 13, 1] -= numpy.interp(face_editor_eye_gaze_vertical, [ -1, 1 ], [ -0.005, 0.005 ])
351
+ expression[0, 15, 1] -= numpy.interp(face_editor_eye_gaze_vertical, [ -1, 1 ], [ -0.010, 0.010 ])
352
+ expression[0, 16, 1] -= numpy.interp(face_editor_eye_gaze_vertical, [ -1, 1 ], [ -0.005, 0.005 ])
353
+ return expression
354
+
355
+
356
+ def edit_eye_open(motion_points : LivePortraitMotionPoints, face_landmark_68 : FaceLandmark68) -> LivePortraitMotionPoints:
357
+ face_editor_eye_open_ratio = state_manager.get_item('face_editor_eye_open_ratio')
358
+ left_eye_ratio = calculate_distance_ratio(face_landmark_68, 37, 40, 39, 36)
359
+ right_eye_ratio = calculate_distance_ratio(face_landmark_68, 43, 46, 45, 42)
360
+
361
+ if face_editor_eye_open_ratio < 0:
362
+ eye_motion_points = numpy.concatenate([ motion_points.ravel(), [ left_eye_ratio, right_eye_ratio, 0.0 ] ])
363
+ else:
364
+ eye_motion_points = numpy.concatenate([ motion_points.ravel(), [ left_eye_ratio, right_eye_ratio, 0.6 ] ])
365
+ eye_motion_points = eye_motion_points.reshape(1, -1).astype(numpy.float32)
366
+ eye_motion_points = forward_retarget_eye(eye_motion_points) * numpy.abs(face_editor_eye_open_ratio)
367
+ eye_motion_points = eye_motion_points.reshape(-1, 21, 3)
368
+ return eye_motion_points
369
+
370
+
371
+ def edit_lip_open(motion_points : LivePortraitMotionPoints, face_landmark_68 : FaceLandmark68) -> LivePortraitMotionPoints:
372
+ face_editor_lip_open_ratio = state_manager.get_item('face_editor_lip_open_ratio')
373
+ lip_ratio = calculate_distance_ratio(face_landmark_68, 62, 66, 54, 48)
374
+
375
+ if face_editor_lip_open_ratio < 0:
376
+ lip_motion_points = numpy.concatenate([ motion_points.ravel(), [ lip_ratio, 0.0 ] ])
377
+ else:
378
+ lip_motion_points = numpy.concatenate([ motion_points.ravel(), [ lip_ratio, 1.0 ] ])
379
+ lip_motion_points = lip_motion_points.reshape(1, -1).astype(numpy.float32)
380
+ lip_motion_points = forward_retarget_lip(lip_motion_points) * numpy.abs(face_editor_lip_open_ratio)
381
+ lip_motion_points = lip_motion_points.reshape(-1, 21, 3)
382
+ return lip_motion_points
383
+
384
+
385
+ def edit_mouth_grim(expression : LivePortraitExpression) -> LivePortraitExpression:
386
+ face_editor_mouth_grim = state_manager.get_item('face_editor_mouth_grim')
387
+ if face_editor_mouth_grim > 0:
388
+ expression[0, 17, 2] -= numpy.interp(face_editor_mouth_grim, [ -1, 1 ], [ -0.005, 0.005 ])
389
+ expression[0, 19, 2] += numpy.interp(face_editor_mouth_grim, [ -1, 1 ], [ -0.01, 0.01 ])
390
+ expression[0, 20, 1] -= numpy.interp(face_editor_mouth_grim, [ -1, 1 ], [ -0.06, 0.06 ])
391
+ expression[0, 20, 2] -= numpy.interp(face_editor_mouth_grim, [ -1, 1 ], [ -0.03, 0.03 ])
392
+ else:
393
+ expression[0, 19, 1] -= numpy.interp(face_editor_mouth_grim, [ -1, 1 ], [ -0.05, 0.05 ])
394
+ expression[0, 19, 2] -= numpy.interp(face_editor_mouth_grim, [ -1, 1 ], [ -0.02, 0.02 ])
395
+ expression[0, 20, 2] -= numpy.interp(face_editor_mouth_grim, [ -1, 1 ], [ -0.03, 0.03 ])
396
+ return expression
397
+
398
+
399
+ def edit_mouth_position(expression : LivePortraitExpression) -> LivePortraitExpression:
400
+ face_editor_mouth_position_horizontal = state_manager.get_item('face_editor_mouth_position_horizontal')
401
+ face_editor_mouth_position_vertical = state_manager.get_item('face_editor_mouth_position_vertical')
402
+ expression[0, 19, 0] += numpy.interp(face_editor_mouth_position_horizontal, [ -1, 1 ], [ -0.05, 0.05 ])
403
+ expression[0, 20, 0] += numpy.interp(face_editor_mouth_position_horizontal, [ -1, 1 ], [ -0.04, 0.04 ])
404
+ if face_editor_mouth_position_vertical > 0:
405
+ expression[0, 19, 1] -= numpy.interp(face_editor_mouth_position_vertical, [ -1, 1 ], [ -0.04, 0.04 ])
406
+ expression[0, 20, 1] -= numpy.interp(face_editor_mouth_position_vertical, [ -1, 1 ], [ -0.02, 0.02 ])
407
+ else:
408
+ expression[0, 19, 1] -= numpy.interp(face_editor_mouth_position_vertical, [ -1, 1 ], [ -0.05, 0.05 ])
409
+ expression[0, 20, 1] -= numpy.interp(face_editor_mouth_position_vertical, [ -1, 1 ], [ -0.04, 0.04 ])
410
+ return expression
411
+
412
+
413
+ def edit_mouth_pout(expression : LivePortraitExpression) -> LivePortraitExpression:
414
+ face_editor_mouth_pout = state_manager.get_item('face_editor_mouth_pout')
415
+ if face_editor_mouth_pout > 0:
416
+ expression[0, 19, 1] -= numpy.interp(face_editor_mouth_pout, [ -1, 1 ], [ -0.022, 0.022 ])
417
+ expression[0, 19, 2] += numpy.interp(face_editor_mouth_pout, [ -1, 1 ], [ -0.025, 0.025 ])
418
+ expression[0, 20, 2] -= numpy.interp(face_editor_mouth_pout, [ -1, 1 ], [ -0.002, 0.002 ])
419
+ else:
420
+ expression[0, 19, 1] += numpy.interp(face_editor_mouth_pout, [ -1, 1 ], [ -0.022, 0.022 ])
421
+ expression[0, 19, 2] += numpy.interp(face_editor_mouth_pout, [ -1, 1 ], [ -0.025, 0.025 ])
422
+ expression[0, 20, 2] -= numpy.interp(face_editor_mouth_pout, [ -1, 1 ], [ -0.002, 0.002 ])
423
+ return expression
424
+
425
+
426
+ def edit_mouth_purse(expression : LivePortraitExpression) -> LivePortraitExpression:
427
+ face_editor_mouth_purse = state_manager.get_item('face_editor_mouth_purse')
428
+ if face_editor_mouth_purse > 0:
429
+ expression[0, 19, 1] -= numpy.interp(face_editor_mouth_purse, [ -1, 1 ], [ -0.04, 0.04 ])
430
+ expression[0, 19, 2] -= numpy.interp(face_editor_mouth_purse, [ -1, 1 ], [ -0.02, 0.02 ])
431
+ else:
432
+ expression[0, 14, 1] -= numpy.interp(face_editor_mouth_purse, [ -1, 1 ], [ -0.02, 0.02 ])
433
+ expression[0, 17, 2] += numpy.interp(face_editor_mouth_purse, [ -1, 1 ], [ -0.01, 0.01 ])
434
+ expression[0, 19, 2] -= numpy.interp(face_editor_mouth_purse, [ -1, 1 ], [ -0.015, 0.015 ])
435
+ expression[0, 20, 2] -= numpy.interp(face_editor_mouth_purse, [ -1, 1 ], [ -0.002, 0.002 ])
436
+ return expression
437
+
438
+
439
+ def edit_mouth_smile(expression : LivePortraitExpression) -> LivePortraitExpression:
440
+ face_editor_mouth_smile = state_manager.get_item('face_editor_mouth_smile')
441
+ if face_editor_mouth_smile > 0:
442
+ expression[0, 20, 1] -= numpy.interp(face_editor_mouth_smile, [ -1, 1 ], [ -0.015, 0.015 ])
443
+ expression[0, 14, 1] -= numpy.interp(face_editor_mouth_smile, [ -1, 1 ], [ -0.025, 0.025 ])
444
+ expression[0, 17, 1] += numpy.interp(face_editor_mouth_smile, [ -1, 1 ], [ -0.01, 0.01 ])
445
+ expression[0, 17, 2] += numpy.interp(face_editor_mouth_smile, [ -1, 1 ], [ -0.004, 0.004 ])
446
+ expression[0, 3, 1] -= numpy.interp(face_editor_mouth_smile, [ -1, 1 ], [ -0.0045, 0.0045 ])
447
+ expression[0, 7, 1] -= numpy.interp(face_editor_mouth_smile, [ -1, 1 ], [ -0.0045, 0.0045 ])
448
+ else:
449
+ expression[0, 14, 1] -= numpy.interp(face_editor_mouth_smile, [ -1, 1 ], [ -0.02, 0.02 ])
450
+ expression[0, 17, 1] += numpy.interp(face_editor_mouth_smile, [ -1, 1 ], [ -0.003, 0.003 ])
451
+ expression[0, 19, 1] += numpy.interp(face_editor_mouth_smile, [ -1, 1 ], [ -0.02, 0.02 ])
452
+ expression[0, 19, 2] -= numpy.interp(face_editor_mouth_smile, [ -1, 1 ], [ -0.005, 0.005 ])
453
+ expression[0, 20, 2] += numpy.interp(face_editor_mouth_smile, [ -1, 1 ], [ -0.01, 0.01 ])
454
+ expression[0, 3, 1] += numpy.interp(face_editor_mouth_smile, [ -1, 1 ], [ -0.0045, 0.0045 ])
455
+ expression[0, 7, 1] += numpy.interp(face_editor_mouth_smile, [ -1, 1 ], [ -0.0045, 0.0045 ])
456
+ return expression
457
+
458
+
459
+ def edit_head_rotation(pitch : LivePortraitPitch, yaw : LivePortraitYaw, roll : LivePortraitRoll) -> LivePortraitRotation:
460
+ face_editor_head_pitch = state_manager.get_item('face_editor_head_pitch')
461
+ face_editor_head_yaw = state_manager.get_item('face_editor_head_yaw')
462
+ face_editor_head_roll = state_manager.get_item('face_editor_head_roll')
463
+ edit_pitch = pitch + float(numpy.interp(face_editor_head_pitch, [ -1, 1 ], [ 20, -20 ]))
464
+ edit_yaw = yaw + float(numpy.interp(face_editor_head_yaw, [ -1, 1 ], [ 60, -60 ]))
465
+ edit_roll = roll + float(numpy.interp(face_editor_head_roll, [ -1, 1 ], [ -15, 15 ]))
466
+ edit_pitch, edit_yaw, edit_roll = limit_angle(pitch, yaw, roll, edit_pitch, edit_yaw, edit_roll)
467
+ rotation = create_rotation(edit_pitch, edit_yaw, edit_roll)
468
+ return rotation
469
+
470
+
471
+ def calculate_distance_ratio(face_landmark_68 : FaceLandmark68, top_index : int, bottom_index : int, left_index : int, right_index : int) -> float:
472
+ vertical_direction = face_landmark_68[top_index] - face_landmark_68[bottom_index]
473
+ horizontal_direction = face_landmark_68[left_index] - face_landmark_68[right_index]
474
+ distance_ratio = float(numpy.linalg.norm(vertical_direction) / (numpy.linalg.norm(horizontal_direction) + 1e-6))
475
+ return distance_ratio
476
+
477
+
478
+ def prepare_crop_frame(crop_vision_frame : VisionFrame) -> VisionFrame:
479
+ model_size = get_model_options().get('size')
480
+ prepare_size = (model_size[0] // 2, model_size[1] // 2)
481
+ crop_vision_frame = cv2.resize(crop_vision_frame, prepare_size, interpolation = cv2.INTER_AREA)
482
+ crop_vision_frame = crop_vision_frame[:, :, ::-1] / 255.0
483
+ crop_vision_frame = numpy.expand_dims(crop_vision_frame.transpose(2, 0, 1), axis = 0).astype(numpy.float32)
484
+ return crop_vision_frame
485
+
486
+
487
+ def normalize_crop_frame(crop_vision_frame : VisionFrame) -> VisionFrame:
488
+ crop_vision_frame = crop_vision_frame.transpose(1, 2, 0).clip(0, 1)
489
+ crop_vision_frame = (crop_vision_frame * 255.0)
490
+ crop_vision_frame = crop_vision_frame.astype(numpy.uint8)[:, :, ::-1]
491
+ return crop_vision_frame
492
+
493
+
494
+ def process_frame(inputs : FaceEditorInputs) -> ProcessorOutputs:
495
+ reference_vision_frame = inputs.get('reference_vision_frame')
496
+ source_vision_frames = inputs.get('source_vision_frames')
497
+ target_vision_frames = inputs.get('target_vision_frames')
498
+ temp_vision_frame = inputs.get('temp_vision_frame')
499
+ temp_vision_mask = inputs.get('temp_vision_mask')
500
+
501
+ target_vision_frame = get_middle(target_vision_frames)
502
+ target_faces = select_faces(reference_vision_frame, source_vision_frames, target_vision_frames)
503
+
504
+ if target_faces:
505
+ for target_face in target_faces:
506
+ target_face = scale_face(target_face, target_vision_frame, temp_vision_frame)
507
+ temp_vision_frame = edit_face(target_face, temp_vision_frame)
508
+
509
+ return temp_vision_frame, temp_vision_mask
processors/modules/face_editor/locales.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from facefusion.types import Locales
2
+
3
+ LOCALES : Locales =\
4
+ {
5
+ 'en':
6
+ {
7
+ 'help':
8
+ {
9
+ 'model': 'choose the model responsible for editing the face',
10
+ 'eyebrow_direction': 'specify the eyebrow direction',
11
+ 'eye_gaze_horizontal': 'specify the horizontal eye gaze',
12
+ 'eye_gaze_vertical': 'specify the vertical eye gaze',
13
+ 'eye_open_ratio': 'specify the ratio of eye opening',
14
+ 'lip_open_ratio': 'specify the ratio of lip opening',
15
+ 'mouth_grim': 'specify the mouth grim',
16
+ 'mouth_pout': 'specify the mouth pout',
17
+ 'mouth_purse': 'specify the mouth purse',
18
+ 'mouth_smile': 'specify the mouth smile',
19
+ 'mouth_position_horizontal': 'specify the horizontal mouth position',
20
+ 'mouth_position_vertical': 'specify the vertical mouth position',
21
+ 'head_pitch': 'specify the head pitch',
22
+ 'head_yaw': 'specify the head yaw',
23
+ 'head_roll': 'specify the head roll'
24
+ },
25
+ 'uis':
26
+ {
27
+ 'eyebrow_direction_slider': 'FACE EDITOR EYEBROW DIRECTION',
28
+ 'eye_gaze_horizontal_slider': 'FACE EDITOR EYE GAZE HORIZONTAL',
29
+ 'eye_gaze_vertical_slider': 'FACE EDITOR EYE GAZE VERTICAL',
30
+ 'eye_open_ratio_slider': 'FACE EDITOR EYE OPEN RATIO',
31
+ 'head_pitch_slider': 'FACE EDITOR HEAD PITCH',
32
+ 'head_roll_slider': 'FACE EDITOR HEAD ROLL',
33
+ 'head_yaw_slider': 'FACE EDITOR HEAD YAW',
34
+ 'lip_open_ratio_slider': 'FACE EDITOR LIP OPEN RATIO',
35
+ 'model_dropdown': 'FACE EDITOR MODEL',
36
+ 'mouth_grim_slider': 'FACE EDITOR MOUTH GRIM',
37
+ 'mouth_position_horizontal_slider': 'FACE EDITOR MOUTH POSITION HORIZONTAL',
38
+ 'mouth_position_vertical_slider': 'FACE EDITOR MOUTH POSITION VERTICAL',
39
+ 'mouth_pout_slider': 'FACE EDITOR MOUTH POUT',
40
+ 'mouth_purse_slider': 'FACE EDITOR MOUTH PURSE',
41
+ 'mouth_smile_slider': 'FACE EDITOR MOUTH SMILE'
42
+ }
43
+ }
44
+ }
processors/modules/face_editor/types.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List, Literal, TypedDict
2
+
3
+ from facefusion.types import Mask, VisionFrame
4
+
5
+ FaceEditorInputs = TypedDict('FaceEditorInputs',
6
+ {
7
+ 'reference_vision_frame' : VisionFrame,
8
+ 'source_vision_frames' : List[VisionFrame],
9
+ 'target_vision_frames' : List[VisionFrame],
10
+ 'temp_vision_frame' : VisionFrame,
11
+ 'temp_vision_mask' : Mask
12
+ })
13
+
14
+ FaceEditorModel = Literal['live_portrait']