File size: 6,172 Bytes
ca46a75
 
 
 
 
 
 
 
 
 
 
 
 
 
7173af9
f8cafb8
ca46a75
f8cafb8
ca46a75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1c25fe3
f8cafb8
ca46a75
 
 
 
 
 
 
 
7173af9
ca46a75
 
 
7173af9
 
f8cafb8
 
 
 
9b2289b
ca46a75
 
 
 
7173af9
 
ca46a75
 
 
 
7173af9
 
f8cafb8
 
 
9b2289b
 
ca46a75
 
 
 
 
 
 
 
 
7173af9
 
 
f8cafb8
 
 
 
9b2289b
ca46a75
f8cafb8
ca46a75
 
 
 
 
 
 
 
7173af9
9b2289b
7173af9
 
 
 
 
 
 
9b2289b
f8cafb8
 
7173af9
ca46a75
 
 
 
7173af9
ca46a75
 
7173af9
ca46a75
 
 
7173af9
9b2289b
ca46a75
 
7173af9
9b2289b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ca46a75
 
 
7173af9
9b2289b
ca46a75
 
 
7173af9
ca46a75
 
7173af9
ca46a75
 
9b2289b
ca46a75
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#!/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


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,
        )

        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:
            # 调用抠图工作流
            self.matting_handler(ctx)
            self.after_matting and self.after_matting(ctx)
        else:
            ctx.matting_image = ctx.processing_image

        # 2. ------------------美颜------------------
        self.beauty_handler(ctx)

        # 如果仅换底,则直接返回抠图结果
        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. ------------------人脸检测------------------
        self.detection_handler(ctx)
        self.after_detect and self.after_detect(ctx)

        # 3.1 ------------------人脸对齐------------------
        if ctx.params.face_alignment and abs(ctx.face["roll_angle"]) > 2:
            from hivision.creator.rotation_adjust import rotate_bound_4channels

            print("执行人脸对齐")
            print("旋转角度:", ctx.face["roll_angle"])
            # 根据角度旋转原图和抠图
            ctx.origin_image, ctx.matting_image, _, _, _, _ = rotate_bound_4channels(
                ctx.origin_image,
                cv2.split(ctx.matting_image)[-1],
                -1 * ctx.face["roll_angle"],
            )

            # 旋转后再执行一遍人脸检测
            self.detection_handler(ctx)
            self.after_detect and self.after_detect(ctx)

        # 4. ------------------图像调整------------------
        result_image_hd, result_image_standard, clothing_params, typography_params = (
            adjust_photo(ctx)
        )

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

        return ctx.result