5.2 KiB
5.2 KiB
Documentation
- Class name: BuildFaceModel
- Category: 🌌 ReActor
- Output node: True
- Repo Ref: https://github.com/Gourieff/comfyui-reactor-node.git
该节点旨在从一组输入图像中合成面部模型,利用先进的计算机视觉技术来检测、分析和融合面部特征。它旨在创建输入面部的合表示,可用于各种应用,如识别、认证或可视化。该节点强调整合图像处理和机器学习技术,以实现高级面部合成。
Input types
Required
- images
- 'image'参数对于面部模型构建过程至关重要。它作为主要输入,提供面部检测和特征提取所需的视觉数据。图像的质量和数量直接影响合成面部模型的准确性和细节。
- Comfy dtype: COMBO[string]
- Python dtype: List[Image.Image]
- face_model_name
- 'face_model_name'参数对于识别和组织输出的面部模型至关重要。它作为每个模型的唯一标识符,便于后续检索和管理合成的面部数据。
- Comfy dtype: string
- Python dtype: str
- compute_method
- 'compute_method'参数决定了用于将多个面部特征融合到单个复合模型中的技术。它影响面部模型的最终表示,不同的方法可能导致不同程度的细节和准确性。
- Comfy dtype: COMBO[string]
- Python dtype: str
Optional
- save_mode
- 'save_mode'参数决定合成的面部模型是否保存到输出目录。它允许用户控制节点的输出,决定是否保留生成的模型以供将来使用,还是在处理后简单地丢弃它们。
- Comfy dtype: COMBO[boolean]
- Python dtype: bool
Output types
- face_model_name
- 输出'face_model_name'代表合成面部模型的唯一标识符。它是用户在后续流程或应用中引用和使用生成模型的关键信息。
- Comfy dtype: string
- Python dtype: str
Usage tips
- Infra type: CPU
Source code
class BuildFaceModel:
def __init__(self):
self.output_dir = FACE_MODELS_PATH
@classmethod
def INPUT_TYPES(s):
return {'required': {'images': ('IMAGE',), 'save_mode': ('BOOLEAN', {'default': True, 'label_off': 'OFF', 'label_on': 'ON'}), 'face_model_name': ('STRING', {'default': 'default'}), 'compute_method': (['Mean', 'Median', 'Mode'], {'default': 'Mean'})}}
RETURN_TYPES = ()
FUNCTION = 'blend_faces'
OUTPUT_NODE = True
CATEGORY = '🌌 ReActor'
def build_face_model(self, image: Image.Image, det_size=(640, 640)):
if image is None:
error_msg = 'Please load an Image'
logger.error(error_msg)
return error_msg
image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
face_model = analyze_faces(image, det_size)
if len(face_model) == 0:
det_size_half = half_det_size(det_size)
face_model = analyze_faces(image, det_size_half)
if face_model is not None and len(face_model) > 0:
return face_model[0]
else:
no_face_msg = 'No face found, please try another image'
logger.error(no_face_msg)
return no_face_msg
def blend_faces(self, images, save_mode, face_model_name, compute_method):
if save_mode and images is not None:
faces = []
embeddings = []
images_list: List[Image.Image] = batch_tensor_to_pil(images)
apply_logging_patch(1)
n = len(images_list)
import logging
logging.StreamHandler.terminator = ' '
for (i, image) in enumerate(images_list):
logger.status(f'Building Face Model {i + 1} of {n}...')
face = self.build_face_model(image)
print(f'{int((i + 1) / n * 100)}%')
if isinstance(face, str):
continue
faces.append(face)
embeddings.append(face.embedding)
logging.StreamHandler.terminator = '\n'
if len(faces) > 0:
compute_method_name = 'Mean' if compute_method == 0 else 'Median' if compute_method == 1 else 'Mode'
logger.status(f'Blending with Compute Method {compute_method_name}...')
blended_embedding = np.mean(embeddings, axis=0) if compute_method == 'Mean' else np.median(embeddings, axis=0) if compute_method == 'Median' else stats.mode(embeddings, axis=0)[0].astype(np.float32)
blended_face = Face(bbox=faces[0].bbox, kps=faces[0].kps, det_score=faces[0].det_score, landmark_3d_68=faces[0].landmark_3d_68, pose=faces[0].pose, landmark_2d_106=faces[0].landmark_2d_106, embedding=blended_embedding, gender=faces[0].gender, age=faces[0].age)
if blended_face is not None:
face_model_path = os.path.join(FACE_MODELS_PATH, face_model_name + '.safetensors')
save_face_model(blended_face, face_model_path)
logger.status('--Done!--')
return face_model_name
else:
no_face_msg = 'Something went wrong, please try another set of images'
logger.error(no_face_msg)
return face_model_name
logger.status('--Done!--')
if images is None:
logger.error('Please provide `images`')
return face_model_name