File size: 4,978 Bytes
67a9b5d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import numbers
import warnings

import khandy
import numpy as np


def crop(image, x_min, y_min, x_max, y_max, border_value=0):
    """Crop the given image at specified rectangular area.
    
    See Also:
        translate_image
        
    References:
        PIL.Image.crop
        tf.image.resize_image_with_crop_or_pad
    """
    assert khandy.is_numpy_image(image)
    assert isinstance(x_min, numbers.Integral) and isinstance(y_min, numbers.Integral)
    assert isinstance(x_max, numbers.Integral) and isinstance(y_max, numbers.Integral)
    assert (x_min <= x_max) and (y_min <= y_max)
    
    src_height, src_width = image.shape[:2]
    dst_height, dst_width = y_max - y_min + 1, x_max - x_min + 1
    channels = 1 if image.ndim == 2 else image.shape[2]
    
    if isinstance(border_value, (tuple, list)):
        assert len(border_value) == channels, \
            'Expected the num of elements in tuple equals the channels ' \
            'of input image. Found {} vs {}'.format(
                len(border_value), channels)
    else:
        border_value = (border_value,) * channels
    dst_image = khandy.create_solid_color_image(
        dst_width, dst_height, border_value, dtype=image.dtype)

    src_x_begin = max(x_min, 0)
    src_x_end   = min(x_max + 1, src_width)
    dst_x_begin = src_x_begin - x_min
    dst_x_end   = src_x_end - x_min

    src_y_begin = max(y_min, 0)
    src_y_end   = min(y_max + 1, src_height)
    dst_y_begin = src_y_begin - y_min
    dst_y_end   = src_y_end - y_min
    
    if (src_x_begin >= src_x_end) or (src_y_begin >= src_y_end):
        return dst_image
    dst_image[dst_y_begin: dst_y_end, dst_x_begin: dst_x_end, ...] = \
        image[src_y_begin: src_y_end, src_x_begin: src_x_end, ...]
    return dst_image
    

def crop_or_pad(image, x_min, y_min, x_max, y_max, border_value=0):
    warnings.warn('crop_or_pad will be deprecated, use crop instead!')
    return crop(image, x_min, y_min, x_max, y_max, border_value)


def crop_coords(boxes, image_width, image_height):
    """
    References:
        `mmcv.impad`
        `pad` in https://github.com/kpzhang93/MTCNN_face_detection_alignment
        `MtcnnDetector.pad` in https://github.com/AITTSMD/MTCNN-Tensorflow
    """
    x_mins = boxes[:, 0]
    y_mins = boxes[:, 1]
    x_maxs = boxes[:, 2]
    y_maxs = boxes[:, 3]
    dst_widths = x_maxs - x_mins + 1
    dst_heights = y_maxs - y_mins + 1
    
    src_x_begin = np.maximum(x_mins, 0)
    src_x_end   = np.minimum(x_maxs + 1, image_width)
    dst_x_begin = src_x_begin - x_mins
    dst_x_end   = src_x_end - x_mins
    
    src_y_begin = np.maximum(y_mins, 0)
    src_y_end   = np.minimum(y_maxs + 1, image_height)
    dst_y_begin = src_y_begin - y_mins
    dst_y_end   = src_y_end - y_mins

    coords = np.stack([dst_y_begin, dst_y_end, dst_x_begin, dst_x_end, 
                       src_y_begin, src_y_end, src_x_begin, src_x_end, 
                       dst_heights, dst_widths], axis=0)
    return coords
    

def crop_or_pad_coords(boxes, image_width, image_height):
    warnings.warn('crop_or_pad_coords will be deprecated, use crop_coords instead!')
    return crop_coords(boxes, image_width, image_height)


def center_crop(image, dst_width, dst_height, strict=True):
    """
    strict: 
        when True, raise error if src size is less than dst size. 
        when False, remain unchanged if src size is less than dst size, otherwise center crop.
    """
    assert khandy.is_numpy_image(image)
    assert isinstance(dst_width, numbers.Integral) and isinstance(dst_height, numbers.Integral)
    src_height, src_width = image.shape[:2]
    if strict:
        assert (src_height >= dst_height) and (src_width >= dst_width)

    crop_top = max((src_height - dst_height) // 2, 0)
    crop_left = max((src_width - dst_width) // 2, 0)
    cropped = image[crop_top: dst_height + crop_top, 
                    crop_left: dst_width + crop_left, ...]
    return cropped


def center_pad(image, dst_width, dst_height, strict=True):
    """
    strict: 
        when True, raise error if src size is greater than dst size. 
        when False, remain unchanged if src size is greater than dst size, otherwise center pad.
    """
    assert khandy.is_numpy_image(image)
    assert isinstance(dst_width, numbers.Integral) and isinstance(dst_height, numbers.Integral)
    
    src_height, src_width = image.shape[:2]
    if strict:
        assert (src_height <= dst_height) and (src_width <= dst_width)
    
    padding_x = max(dst_width - src_width, 0)
    padding_y = max(dst_height - src_height, 0)
    padding_top = padding_y // 2
    padding_left = padding_x // 2
    if image.ndim == 2:
        padding = ((padding_top, padding_y - padding_top), 
                   (padding_left, padding_x - padding_left))
    else:
        padding = ((padding_top, padding_y - padding_top), 
                   (padding_left, padding_x - padding_left), (0, 0))
    return np.pad(image, padding, 'constant')