Skip to content

crops

annotation_inside_crop(annotation, crop_corners)

Check whether annotation coordinates lie inside crop coordinates.

Parameters:

Name Type Description Default
annotation Dict

Single annotation entry in COCO format.

required
crop_corners List[int]

Generated from get_crop_corners.

required

Returns:

Name Type Description
bool bool

True if any annotation coordinate lies inside crop.

Source code in pyodi/core/crops.py
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
def annotation_inside_crop(annotation: Dict, crop_corners: List[int]) -> bool:
    """Check whether annotation coordinates lie inside crop coordinates.

    Args:
        annotation (Dict): Single annotation entry in COCO format.
        crop_corners (List[int]): Generated from `get_crop_corners`.

    Returns:
        bool: True if any annotation coordinate lies inside crop.
    """
    left, top, width, height = annotation["bbox"]

    right = left + width
    bottom = top + height

    if left > crop_corners[2]:
        return False
    if top > crop_corners[3]:
        return False
    if right < crop_corners[0]:
        return False
    if bottom < crop_corners[1]:
        return False

    return True

filter_annotation_by_area(annotation, new_annotation, min_area_threshold)

Check whether cropped annotation area is smaller than minimum area size.

Parameters:

Name Type Description Default
annotation Dict

Single annotation entry in COCO format.

required
new_annotation Dict

Single annotation entry in COCO format.

required
min_area_threshold float

Minimum area threshold ratio.

required

Returns:

Type Description
bool

True if annotation area is smaller than the minimum area size.

Source code in pyodi/core/crops.py
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def filter_annotation_by_area(
    annotation: Dict, new_annotation: Dict, min_area_threshold: float
) -> bool:
    """Check whether cropped annotation area is smaller than minimum area size.

    Args:
        annotation: Single annotation entry in COCO format.
        new_annotation: Single annotation entry in COCO format.
        min_area_threshold: Minimum area threshold ratio.

    Returns:
        True if annotation area is smaller than the minimum area size.
    """
    area = annotation["area"]
    new_area = new_annotation["area"]
    min_area = area * min_area_threshold

    if new_area > min_area:
        return False

    return True

get_annotation_in_crop(annotation, crop_corners)

Translate annotation coordinates to crop coordinates.

Parameters:

Name Type Description Default
annotation Dict

Single annotation entry in COCO format.

required
crop_corners List[int]

Generated from get_crop_corners.

required

Returns:

Name Type Description
Dict Dict

Annotation entry with coordinates translated to crop coordinates.

Source code in pyodi/core/crops.py
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
def get_annotation_in_crop(annotation: Dict, crop_corners: List[int]) -> Dict:
    """Translate annotation coordinates to crop coordinates.

    Args:
        annotation (Dict): Single annotation entry in COCO format.
        crop_corners (List[int]): Generated from `get_crop_corners`.

    Returns:
        Dict: Annotation entry with coordinates translated to crop coordinates.
    """
    left, top, width, height = annotation["bbox"]
    right = left + width
    bottom = top + height

    new_left = max(left - crop_corners[0], 0)
    new_top = max(top - crop_corners[1], 0)
    new_right = min(right - crop_corners[0], crop_corners[2] - crop_corners[0])
    new_bottom = min(bottom - crop_corners[1], crop_corners[3] - crop_corners[1])

    new_width = new_right - new_left
    new_height = new_bottom - new_top

    new_bbox = [new_left, new_top, new_width, new_height]
    new_area = new_width * new_height
    new_segmentation = [
        new_left,
        new_top,
        new_left,
        new_top + new_height,
        new_left + new_width,
        new_top + new_height,
        new_left + new_width,
        new_top,
    ]
    return {
        "bbox": new_bbox,
        "area": new_area,
        "segmentation": new_segmentation,
        "iscrowd": annotation["iscrowd"],
        "score": annotation.get("score", 1),
        "category_id": annotation["category_id"],
    }

get_crops_corners(image_pil, crop_height, crop_width, row_overlap=0, col_overlap=0)

Divides image_pil in crops.

The crops corners will be generated using the crop_height, crop_width, row_overlap and col_overlap arguments.

Parameters:

Name Type Description Default
image_pil PIL.Image

Instance of PIL.Image

required
row_overlap int

Default 0.

0
col_overlap int

Default 0.

0

Returns:

Type Description
List[List[int]]

List[List[int]]: List of 4 corner coordinates for each crop of the N crops. [ [crop_0_left, crop_0_top, crop_0_right, crop_0_bottom], ... [crop_N_left, crop_N_top, crop_N_right, crop_N_bottom] ]

Source code in pyodi/core/crops.py
 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
def get_crops_corners(
    image_pil: Image,
    crop_height: int,
    crop_width: int,
    row_overlap: int = 0,
    col_overlap: int = 0,
) -> List[List[int]]:
    """Divides `image_pil` in crops.

    The crops corners will be generated using the `crop_height`, `crop_width`,
    `row_overlap` and `col_overlap` arguments.

    Args:
        image_pil (PIL.Image): Instance of PIL.Image
        crop_height (int)
        crop_width (int)
        row_overlap (int, optional): Default 0.
        col_overlap (int, optional): Default 0.

    Returns:
        List[List[int]]: List of 4 corner coordinates for each crop of the N crops.
            [
                [crop_0_left, crop_0_top, crop_0_right, crop_0_bottom],
                ...
                [crop_N_left, crop_N_top, crop_N_right, crop_N_bottom]
            ]
    """
    crops_corners = []
    row_max = row_min = 0
    width, height = image_pil.size
    while row_max - row_overlap < height:
        col_min = col_max = 0
        row_max = row_min + crop_height
        while col_max - col_overlap < width:
            col_max = col_min + crop_width
            if row_max > height or col_max > width:
                rmax = min(height, row_max)
                cmax = min(width, col_max)
                crops_corners.append(
                    [cmax - crop_width, rmax - crop_height, cmax, rmax]
                )
            else:
                crops_corners.append([col_min, row_min, col_max, row_max])
            col_min = col_max - col_overlap
        row_min = row_max - row_overlap
    return crops_corners