File size: 3,360 Bytes
a249588
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import numpy as np

def find_min_padding_exact(bbox, kpts, aspect_ratio=3/4, bbox_format='xywh'):
    '''Find the minimum padding to make keypoint inside bbox'''
    assert bbox_format.lower() in ['xywh', 'xyxy'], f"Invalid bbox format {bbox_format}. Only 'xyxy' or 'xywh' are supported."

    if kpts.size % 2 == 0:
        kpts = kpts.reshape(-1, 2)
        vis = np.ones(kpts.shape[0])
    elif kpts.size % 3 == 0:
        kpts = kpts.reshape(-1, 3)
        vis = kpts[:, 2].flatten()
        kpts = kpts[:, :2]
    else:
        raise ValueError('Keypoints should have 2 or 3 values each')

    if bbox_format.lower() == 'xyxy':
        bbox = np.array([
            bbox[0],
            bbox[1],
            bbox[2] - bbox[0],
            bbox[3] - bbox[1],
        ])

    if aspect_ratio is not None:
        # Fix the aspect ratio of the bounding box
        bbox = fix_bbox_aspect_ratio(bbox, aspect_ratio=aspect_ratio, padding=1.0, bbox_format='xywh')
    
    x0, y0, w, h = np.hsplit(bbox, [1, 2, 3])

    x1 = x0 + w
    y1 = y0 + h
    x_bbox_distances = np.max(np.stack([
        np.clip(x0 - kpts[:, 0], a_min=0, a_max=None),
        np.clip(kpts[:, 0] - x1, a_min=0, a_max=None),
    ]), axis=0)
    y_bbox_distances = np.max(np.stack([
        np.clip(y0 - kpts[:, 1], a_min=0, a_max=None),
        np.clip(kpts[:, 1] - y1, a_min=0, a_max=None),
    ]), axis=0)

    padding_x = 2 * x_bbox_distances / w
    padding_y = 2 * y_bbox_distances / h
    padding = 1 + np.maximum(padding_x, padding_y)
    padding = np.array(padding).flatten()

    padding[vis <= 0] = -1.0
    
    return padding

def fix_bbox_aspect_ratio(bbox, aspect_ratio=3/4, padding=1.25, bbox_format='xywh'):
    assert bbox_format.lower() in ['xywh', 'xyxy'], f"Invalid bbox format {bbox_format}. Only 'xyxy' or 'xywh' are supported."

    in_shape = bbox.shape
    bbox = bbox.reshape((-1, 4))

    if bbox_format.lower() == 'xywh':
        bbox_xyxy = np.array([
            bbox[:, 0],
            bbox[:, 1],
            bbox[:, 0] + bbox[:, 2],
            bbox[:, 1] + bbox[:, 3],
        ]).T
    else:
        bbox_xyxy = np.array(bbox)
    
    centers = bbox_xyxy[:, :2] + (bbox_xyxy[:, 2:] - bbox_xyxy[:, :2]) / 2
    widths = bbox_xyxy[:, 2] - bbox_xyxy[:, 0]
    heights = bbox_xyxy[:, 3] - bbox_xyxy[:, 1]
    
    new_widths = widths.copy().astype(np.float32)
    new_heights = heights.copy().astype(np.float32)

    for i in range(bbox_xyxy.shape[0]):
        if widths[i] == 0:
            widths[i] =+ 1
        if heights[i] == 0:
            heights[i] =+ 1

        if widths[i] / heights[i] > aspect_ratio:
            new_heights[i] = widths[i] / aspect_ratio
        else:
            new_widths[i] = heights[i] * aspect_ratio
    new_widths *= padding
    new_heights *= padding

    new_bbox_xyxy = np.array([
        centers[:, 0] - new_widths / 2,
        centers[:, 1] - new_heights / 2,
        centers[:, 0] + new_widths / 2,
        centers[:, 1] + new_heights / 2,
    ]).T

    if bbox_format.lower() == 'xywh':
        new_bbox = np.array([
            new_bbox_xyxy[:, 0],
            new_bbox_xyxy[:, 1],
            new_bbox_xyxy[:, 2] - new_bbox_xyxy[:, 0],
            new_bbox_xyxy[:, 3] - new_bbox_xyxy[:, 1],
        ]).T
    else:
        new_bbox = new_bbox_xyxy


    new_bbox = new_bbox.reshape(in_shape)

    return new_bbox