# 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 ```