File size: 3,862 Bytes
97a6728
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import numpy as np


def expand_bbox_to_ratio(bbox, imshape, target_aspect_ratio):
    x0, y0, x1, y1 = [int(_) for _ in bbox]
    h, w = y1 - y0, x1 - x0
    cur_ratio = h / w

    if cur_ratio == target_aspect_ratio:
        return [x0, y0, x1, y1]
    if cur_ratio < target_aspect_ratio:
        target_height = int(w*target_aspect_ratio)
        y0, y1 = expand_axis(y0, y1, target_height, imshape[0])
    else:
        target_width = int(h/target_aspect_ratio)
        x0, x1 = expand_axis(x0, x1, target_width, imshape[1])
    return x0, y0, x1, y1


def expand_axis(start, end, target_width, limit):
    # Can return a bbox outside of limit
    cur_width = end - start
    start = start - (target_width-cur_width)//2
    end = end + (target_width-cur_width)//2
    if end - start != target_width:
        end += 1
    assert end - start == target_width
    if start < 0 and end > limit:
        return start, end
    if start < 0 and end < limit:
        to_shift = min(0 - start, limit - end)
        start += to_shift
        end += to_shift
    if end > limit and start > 0:
        to_shift = min(end - limit, start)
        end -= to_shift
        start -= to_shift
    assert end - start == target_width
    return start, end


def expand_box(bbox, imshape, mask, percentage_background: float):
    assert isinstance(bbox[0], int)
    assert 0 < percentage_background < 1
    # Percentage in S
    mask_pixels = mask.long().sum().cpu()
    total_pixels = (bbox[2] - bbox[0]) * (bbox[3] - bbox[1])
    percentage_mask = mask_pixels / total_pixels
    if (1 - percentage_mask) > percentage_background:
        return bbox
    target_pixels = mask_pixels / (1 - percentage_background)
    x0, y0, x1, y1 = bbox
    H = y1 - y0
    W = x1 - x0
    p = np.sqrt(target_pixels/(H*W))
    target_width = int(np.ceil(p * W))
    target_height = int(np.ceil(p * H))
    x0, x1 = expand_axis(x0, x1, target_width, imshape[1])
    y0, y1 = expand_axis(y0, y1, target_height, imshape[0])
    return [x0, y0, x1, y1]


def expand_axises_by_percentage(bbox_XYXY, imshape, percentage):
    x0, y0, x1, y1 = bbox_XYXY
    H = y1 - y0
    W = x1 - x0
    expansion = int(((H*W)**0.5) * percentage)
    new_width = W + expansion
    new_height = H + expansion
    x0, x1 = expand_axis(x0, x1, min(new_width, imshape[1]), imshape[1])
    y0, y1 = expand_axis(y0, y1, min(new_height, imshape[0]), imshape[0])
    return [x0, y0, x1, y1]


def get_expanded_bbox(
        bbox_XYXY,
        imshape,
        mask,
        percentage_background: float,
        axis_minimum_expansion: float,
        target_aspect_ratio: float):
    bbox_XYXY = bbox_XYXY.long().cpu().numpy().tolist()
    # Expand each axis of the bounding box by a minimum percentage
    bbox_XYXY = expand_axises_by_percentage(bbox_XYXY, imshape, axis_minimum_expansion)
    # Find the minimum bbox with the aspect ratio. Can be outside of imshape
    bbox_XYXY = expand_bbox_to_ratio(bbox_XYXY, imshape, target_aspect_ratio)
    # Expands square box such that X% of the bbox is background
    bbox_XYXY = expand_box(bbox_XYXY, imshape, mask, percentage_background)
    assert isinstance(bbox_XYXY[0], (int, np.int64))
    return bbox_XYXY


def include_box(bbox, minimum_area, aspect_ratio_range, min_bbox_ratio_inside, imshape):
    def area_inside_ratio(bbox, imshape):
        area = (bbox[2] - bbox[0]) * (bbox[3] - bbox[1])
        area_inside = (min(bbox[2], imshape[1]) - max(0, bbox[0])) * (min(imshape[0], bbox[3]) - max(0, bbox[1]))
        return area_inside / area
    ratio = (bbox[3] - bbox[1]) / (bbox[2] - bbox[0])
    area = (bbox[3] - bbox[1]) * (bbox[2] - bbox[0])
    if area_inside_ratio(bbox, imshape) < min_bbox_ratio_inside:
        return False
    if ratio <= aspect_ratio_range[0] or ratio >= aspect_ratio_range[1] or area < minimum_area:
        return False
    return True