File size: 7,803 Bytes
d5d20be
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
import numpy as np
import cv2
import functools
import time
from hivisionai.hycv.matting_tools import read_modnet_image


def calTime(mark):
    if isinstance(mark, str):
        def decorater(func):
            @functools.wraps(func)
            def wrapper(*args, **kw):
                start_time = time.time()
                return_param = func(*args, **kw)
                print("[Mark-{}] {} 函数花费的时间为 {:.2f}.".format(mark, func.__name__, time.time() - start_time))
                return return_param

            return wrapper

        return decorater
    else:
        func = mark

        @functools.wraps(func)
        def wrapper(*args, **kw):
            start_time = time.time()
            return_param = func(*args, **kw)
            print("{} 函数花费的时间为 {:.2f}.".format(func.__name__, time.time() - start_time))
            return return_param

        return wrapper


def standard_photo_resize(input_image: np.array, size):
    """
    input_image: 输入图像,即高清照
    size: 标准照的尺寸
    """
    resize_ratio = input_image.shape[0] / size[0]
    resize_item = int(round(input_image.shape[0] / size[0]))
    if resize_ratio >= 2:
        for i in range(resize_item - 1):
            if i == 0:
                result_image = cv2.resize(input_image,
                                          (size[1] * (resize_item - i - 1), size[0] * (resize_item - i - 1)),
                                          interpolation=cv2.INTER_AREA)
            else:
                result_image = cv2.resize(result_image,
                                          (size[1] * (resize_item - i - 1), size[0] * (resize_item - i - 1)),
                                          interpolation=cv2.INTER_AREA)
    else:
        result_image = cv2.resize(input_image, (size[1], size[0]), interpolation=cv2.INTER_AREA)

    return result_image


def hollowOutFix(src: np.ndarray) -> np.ndarray:
    b, g, r, a = cv2.split(src)
    src_bgr = cv2.merge((b, g, r))
    # -----------padding---------- #
    add_area = np.zeros((10, a.shape[1]), np.uint8)
    a = np.vstack((add_area, a, add_area))
    add_area = np.zeros((a.shape[0], 10), np.uint8)
    a = np.hstack((add_area, a, add_area))
    # -------------end------------ #
    _, a_threshold = cv2.threshold(a, 127, 255, 0)
    a_erode = cv2.erode(a_threshold, kernel=cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)), iterations=3)
    contours, hierarchy = cv2.findContours(a_erode, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    contours = [x for x in contours]
    # contours = np.squeeze(contours)
    contours.sort(key=lambda c: cv2.contourArea(c), reverse=True)
    a_contour = cv2.drawContours(np.zeros(a.shape, np.uint8), contours[0], -1, 255, 2)
    # a_base = a_contour[1:-1, 1:-1]
    h, w = a.shape[:2]
    mask = np.zeros([h + 2, w + 2], np.uint8)  # mask必须行和列都加2,且必须为uint8单通道阵列
    cv2.floodFill(a_contour, mask=mask, seedPoint=(0, 0), newVal=255)
    a = cv2.add(a, 255 - a_contour)
    return cv2.merge((src_bgr, a[10:-10, 10:-10]))


def resize_image_by_min(input_image, esp=600):
    """
    将图像缩放为最短边至少为600的图像。
    :param input_image: 输入图像(OpenCV矩阵)
    :param esp: 缩放后的最短边长
    :return: 缩放后的图像,缩放倍率
    """
    height, width = input_image.shape[0], input_image.shape[1]
    min_border = min(height, width)
    if min_border < esp:
        if height >= width:
            new_width = esp
            new_height = height * esp // width
        else:
            new_height = esp
            new_width = width * esp // height

        return cv2.resize(input_image, (new_width, new_height), interpolation=cv2.INTER_AREA), new_height / height

    else:
        return input_image, 1


def rotate_bound(image, angle):
    """
    一个旋转函数,输入一张图片和一个旋转角,可以实现不损失图像信息的旋转。
    """
    # grab the dimensions of the image and then determine the
    # center
    (h, w) = image.shape[:2]
    (cX, cY) = (w / 2, h / 2)

    # grab the rotation matrix (applying the negative of the
    # angle to rotate clockwise), then grab the sine and cosine
    # (i.e., the rotation components of the matrix)
    M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])

    # compute the new bounding dimensions of the image
    nW = int((h * sin) + (w * cos))
    nH = int((h * cos) + (w * sin))

    # adjust the rotation matrix to take into account translation
    M[0, 2] += (nW / 2) - cX
    M[1, 2] += (nH / 2) - cY

    # perform the actual rotation and return the image
    return cv2.warpAffine(image, M, (nW, nH)), cos, sin


def rotate_bound_4channels(image, a, angle):
    """
    一个旋转函数,输入一张图片和一个旋转角,可以实现不损失图像信息的旋转。
    """
    input_image, cos, sin = rotate_bound(image, angle)
    new_a, _, _ = rotate_bound(a, angle)  # 对做matte旋转,以便之后merge
    b, g, r = cv2.split(input_image)
    result_image = cv2.merge((b, g, r, new_a))  # 得到抠图结果图的无损旋转结果

    # perform the actual rotation and return the image
    return input_image, result_image, cos, sin


def draw_picture_dots(image, dots, pen_size=10, pen_color=(0, 0, 255)):
    """
    给一张照片上绘制点。
    image: Opencv图像矩阵
    dots: 一堆点,形如[(100,100),(150,100)]
    pen_size: 画笔的大小
    pen_color: 画笔的颜色
    """
    if isinstance(dots, dict):
        dots = [v for u, v in dots.items()]
    image = image.copy()
    dots = list(dots)
    for dot in dots:
        # print("dot: ", dot)
        x = dot[0]
        y = dot[1]
        cv2.circle(image, (int(x), int(y)), pen_size, pen_color, -1)
    return image


def get_modnet_matting(input_image, sess, ref_size=512):
    """
    使用modnet模型对图像进行抠图处理。
    :param input_image: 输入图像(opencv矩阵)
    :param sess: onnxruntime推理主体
    :param ref_size: 缩放参数
    :return: 抠图后的图像
    """
    input_name = sess.get_inputs()[0].name
    output_name = sess.get_outputs()[0].name

    im, width, length = read_modnet_image(input_image=input_image, ref_size=ref_size)

    matte = sess.run([output_name], {input_name: im})
    matte = (matte[0] * 255).astype('uint8')
    matte = np.squeeze(matte)
    mask = cv2.resize(matte, (width, length), interpolation=cv2.INTER_AREA)
    b, g, r = cv2.split(np.uint8(input_image))

    output_image = cv2.merge((b, g, r, mask))

    return output_image


def detect_distance(value, crop_heigh, max=0.06, min=0.04):
    """
    检测人头顶与照片顶部的距离是否在适当范围内。
    输入:与顶部的差值
    输出:(status, move_value)
    status=0 不动
    status=1 人脸应向上移动(裁剪框向下移动)
    status-2 人脸应向下移动(裁剪框向上移动)
    ---------------------------------------
    value:头顶与照片顶部的距离
    crop_heigh: 裁剪框的高度
    max: 距离的最大值
    min: 距离的最小值
    ---------------------------------------
    """
    value = value / crop_heigh  # 头顶往上的像素占图像的比例
    if min <= value <= max:
        return 0, 0
    elif value > max:
        # 头顶往上的像素比例高于max
        move_value = value - max
        move_value = int(move_value * crop_heigh)
        # print("上移{}".format(move_value))
        return 1, move_value
    else:
        # 头顶往上的像素比例低于min
        move_value = min - value
        move_value = int(move_value * crop_heigh)
        # print("下移{}".format(move_value))
        return -1, move_value