#!/usr/bin/env python # -*- coding: utf-8 -*- r""" @DATE: 2024/9/5 16:45 @File: __init__.py @IDE: pycharm @Description: 创建证件照 """ import numpy as np from typing import Tuple import hivision.creator.utils as U from .context import Context, ContextHandler, Params, Result from .human_matting import extract_human from .face_detector import detect_face_mtcnn from hivision.plugin.beauty.handler import beauty_face from .photo_adjuster import adjust_photo import cv2 import time class IDCreator: """ 证件照创建类,包含完整的证件照流程 """ def __init__(self): # 回调时机 self.before_all: ContextHandler = None """ 在所有处理之前,此时图像已经被 resize 到最大边长为 2000 """ self.after_matting: ContextHandler = None """ 在抠图之后,ctx.matting_image 被赋值 """ self.after_detect: ContextHandler = None """ 在人脸检测之后,ctx.face 被赋值,如果为仅换底,则不会执行此回调 """ self.after_all: ContextHandler = None """ 在所有处理之后,此时 ctx.result 被赋值 """ # 处理者 self.matting_handler: ContextHandler = extract_human self.detection_handler: ContextHandler = detect_face_mtcnn self.beauty_handler: ContextHandler = beauty_face # 上下文 self.ctx = None def __call__( self, image: np.ndarray, size: Tuple[int, int] = (413, 295), change_bg_only: bool = False, crop_only: bool = False, head_measure_ratio: float = 0.2, head_height_ratio: float = 0.45, head_top_range: float = (0.12, 0.1), face: Tuple[int, int, int, int] = None, whitening_strength: int = 0, brightness_strength: int = 0, contrast_strength: int = 0, sharpen_strength: int = 0, saturation_strength: int = 0, face_alignment: bool = False, ) -> Result: """ 证件照处理函数 :param image: 输入图像 :param change_bg_only: 是否只需要抠图 :param crop_only: 是否只需要裁剪 :param size: 输出的图像大小(h,w) :param head_measure_ratio: 人脸面积与全图面积的期望比值 :param head_height_ratio: 人脸中心处在全图高度的比例期望值 :param head_top_range: 头距离顶部的比例(max,min) :param face: 人脸坐标 :param whitening_strength: 美白强度 :param brightness_strength: 亮度强度 :param contrast_strength: 对比度强度 :param sharpen_strength: 锐化强度 :param align_face: 是否需要人脸矫正 :return: 返回处理后的证件照和一系列参数 """ # 0.初始化上下文 params = Params( size=size, change_bg_only=change_bg_only, head_measure_ratio=head_measure_ratio, head_height_ratio=head_height_ratio, head_top_range=head_top_range, crop_only=crop_only, face=face, whitening_strength=whitening_strength, brightness_strength=brightness_strength, contrast_strength=contrast_strength, sharpen_strength=sharpen_strength, saturation_strength=saturation_strength, face_alignment=face_alignment, ) # 总的开始时间 total_start_time = time.time() self.ctx = Context(params) ctx = self.ctx ctx.processing_image = image ctx.processing_image = U.resize_image_esp( ctx.processing_image, 2000 ) # 将输入图片 resize 到最大边长为 2000 ctx.origin_image = ctx.processing_image.copy() self.before_all and self.before_all(ctx) # 1. ------------------人像抠图------------------ # 如果仅裁剪,则不进行抠图 if not ctx.params.crop_only: # 调用抠图工作流 print("[1] Start Human Matting...") start_matting_time = time.time() self.matting_handler(ctx) end_matting_time = time.time() print(f"[1] Human Matting Time: {end_matting_time - start_matting_time:.3f}s") self.after_matting and self.after_matting(ctx) # 如果进行抠图 else: ctx.matting_image = ctx.processing_image # 2. ------------------美颜------------------ print("[2] Start Beauty...") start_beauty_time = time.time() self.beauty_handler(ctx) end_beauty_time = time.time() print(f"[2] Beauty Time: {end_beauty_time - start_beauty_time:.3f}s") # 如果仅换底,则直接返回抠图结果 if ctx.params.change_bg_only: ctx.result = Result( standard=ctx.matting_image, hd=ctx.matting_image, matting=ctx.matting_image, clothing_params=None, typography_params=None, face=None, ) self.after_all and self.after_all(ctx) return ctx.result # 3. ------------------人脸检测------------------ print("[3] Start Face Detection...") start_detection_time = time.time() self.detection_handler(ctx) end_detection_time = time.time() print(f"[3] Face Detection Time: {end_detection_time - start_detection_time:.3f}s") self.after_detect and self.after_detect(ctx) # 3.1 ------------------人脸对齐------------------ if ctx.params.face_alignment and abs(ctx.face["roll_angle"]) > 2: print("[3.1] Start Face Alignment...") start_alignment_time = time.time() from hivision.creator.rotation_adjust import rotate_bound_4channels # 根据角度旋转原图和抠图 b, g, r, a = cv2.split(ctx.matting_image) ctx.origin_image, ctx.matting_image, _, _, _, _ = rotate_bound_4channels( cv2.merge((b, g, r)), a, -1 * ctx.face["roll_angle"], ) # 旋转后再执行一遍人脸检测 self.detection_handler(ctx) self.after_detect and self.after_detect(ctx) end_alignment_time = time.time() print(f"[3.1] Face Alignment Time: {end_alignment_time - start_alignment_time:.3f}s") # 4. ------------------图像调整------------------ print("[4] Start Image Post-Adjustment...") start_adjust_time = time.time() result_image_hd, result_image_standard, clothing_params, typography_params = ( adjust_photo(ctx) ) end_adjust_time = time.time() print(f"[4] Image Post-Adjustment Time: {end_adjust_time - start_adjust_time:.3f}s") # 5. ------------------返回结果------------------ ctx.result = Result( standard=result_image_standard, hd=result_image_hd, matting=ctx.matting_image, clothing_params=clothing_params, typography_params=typography_params, face=ctx.face, ) self.after_all and self.after_all(ctx) # 总的结束时间 total_end_time = time.time() print(f"[Total] Total Time: {total_end_time - total_start_time:.3f}s") return ctx.result