def load_sample(fp: str,
                name: str,
                img_type: str = '.jpg',
                an_type: str = 'labelme') -> Sample:
    image = Image.open(os.path.join(fp, name + img_type))
    annotation = load_annotation(os.path.join(fp, name), an_type, 'airport')
    return Sample(image, annotation)
def mirror_image(sample: Sample) -> Sample:
    """
    左右镜像
    :param sample:
    :return:
    """
    image = sample.image
    annotation = sample.annotation
    return Sample(image.transpose(Image.FLIP_LEFT_RIGHT),
                  transform_annotation(annotation, 'mirror'))
def rotate_image(sample: Sample) -> Sample:
    """
    逆时针旋转90度
    :param sample:
    :return:
    """
    # TODO: bug,旋转y轴坐标向下偏移
    image = sample.image
    annotation = sample.annotation
    rotate = Image.ROTATE_90
    return Sample(image.transpose(rotate),
                  transform_annotation(annotation, 'rotate'))
def resize_image(sample: Sample, percent: float) -> Sample:
    """
    百分比重采样
    :param sample:
    :param percent:
    :return:
    """
    image = sample.image
    annotation = sample.annotation
    if percent > 1 or percent <= 0:
        raise ValueError('percent must in the range: (0,1]')
    image_width, image_height = image.size
    new_size = (floor(image_width * percent), floor(image_height * percent))
    return Sample(
        image.resize(new_size),
        transform_annotation(annotation, 'resize', new_size=new_size))
def square_clip(sample: Sample) -> Sample:
    image = sample.image
    image_width, image_height = image.size
    if image_width == image_height:
        return sample
    annotation = sample.annotation
    x, y = floor(image_width / 2), floor(image_height / 2)
    new_size = min(image_width, image_height)
    x0, y0 = x - floor(new_size / 2), y - floor(new_size / 2)
    if x0 < 0:
        x0 = 0
    if y0 < 0:
        y0 = 0
    clip_box = (x0, y0, x0 + new_size, y0 + new_size)
    return Sample(
        image.crop(clip_box),
        transform_annotation(annotation, 'clip', clip_img_box=clip_box))
def rotate_image2(sample: Sample, angle=90) -> Sample:
    """
    逆时针旋转
    :param sample:
    :param angle: 旋转角度
    :return:
    """
    image = sample.image
    w, h = image.size
    annotation = sample.annotation
    if angle > 90 or angle < 0:
        raise ValueError('angle must in range [0, 90]')
    new_image = image.rotate(angle, expand=True)
    nw, nh = new_image.size
    return Sample(
        new_image,
        transform_annotation(annotation,
                             'rotate2',
                             a=angle,
                             w=w,
                             h=h,
                             nw=nw,
                             nh=nh))
def zoom_clip_image(sample: Sample,
                    ratio: float,
                    random_shift=False) -> Sample:
    """
    zoom, then clip by ratio
    :param sample:
    :param ratio:
    :param random_shift:
    :return:
    """
    if ratio > 1:
        ratio = 1
    if ratio < 0:
        raise ValueError('ratio must be greater than 0')

    image = sample.image
    annotation = sample.annotation

    labels = annotation.labels
    object_extents = None
    for label in labels:
        if label.auxiliary:
            object_extents = label.get_extents()
    if object_extents is None:
        raise ValueError('can not find auxiliary label')

    img_width, img_height = image.size
    ob_width = abs(object_extents.x_max - object_extents.x_min)
    ob_height = abs(object_extents.y_max - object_extents.y_min)

    if ratio == 1:
        # 如果目标占满整个子图片,则裁剪成机场范围
        clip_img_box = (object_extents.x_min, object_extents.y_min,
                        object_extents.x_max, object_extents.y_max)
        return Sample(
            image.crop(clip_img_box),
            transform_annotation(annotation, 'clip',
                                 clip_img_box=clip_img_box))

    x_mid = object_extents.x_min + floor(ob_width / 2)
    y_mid = object_extents.y_min + floor(ob_height / 2)

    size = min(img_width, img_height)

    if max(ob_width / ratio, ob_height / ratio) < size:
        # 符合条件说明大小合适,选择合适的范围即可
        size = max(ob_width / ratio, ob_height / ratio)
        c_xmin = x_mid - floor(size / 2)
        c_ymin = y_mid - floor(size / 2)
        c_xmax = x_mid + floor(size / 2)
        c_ymax = y_mid + floor(size / 2)

        if random_shift is True:
            shift_x = random.randint(-floor(ob_width / 2), floor(ob_width / 2))
            shift_y = random.randint(-floor(ob_height / 2),
                                     floor(ob_height / 2))
            c_xmin = c_xmin + shift_x
            c_ymin = c_ymin + shift_y
            c_xmax = c_xmax + shift_x
            c_ymax = c_ymax + shift_y

        if c_xmin < 0:
            c_xmin = 0
            c_xmax = 2 * floor(size / 2)
        if c_ymin < 0:
            c_ymin = 0
            c_ymax = 2 * floor(size / 2)
        if c_xmax > img_width - 1:
            c_xmax = img_width - 1
            c_xmin = c_xmax - 2 * floor(size / 2)
        if c_ymax > img_height - 1:
            c_ymax = img_height - 1
            c_ymin = c_ymax - 2 * floor(size / 2)

        clip_box = (c_xmin, c_ymin, c_xmax, c_ymax)
        return Sample(
            image.crop(clip_box),
            transform_annotation(annotation, 'clip', clip_img_box=clip_box))

    return zoom_clip_image(sample, ratio + 0.05, random_shift)