import numpy as np
import cv2
from PIL import Image, ImageEnhance
import random
def random_distort(img):def random_brightness(img, lower=0.5, upper=1.5):e = np.random.uniform(lower, upper)return ImageEnhance.Brightness(img).enhance(e)def random_contrast(img, lower=0.5, upper=1.5):e = np.random.uniform(lower, upper)return ImageEnhance.Contrast(img).enhance(e)def random_color(img, lower=0.5, upper=1.5):e = np.random.uniform(lower, upper)return ImageEnhance.Color(img).enhance(e)ops = [random_brightness, random_contrast, random_color]np.random.shuffle(ops)img = Image.fromarray(img)img = ops[0](img)img = ops[1](img)img = ops[2](img)img = np.asarray(img)return img
def random_expand(img,gtboxes,max_ratio&#61;4.,fill&#61;None,keep_ratio&#61;True,thresh&#61;0.5):if random.random() > thresh:return img, gtboxesif max_ratio < 1.0:return img, gtboxesh, w, c &#61; img.shaperatio_x &#61; random.uniform(1, max_ratio)if keep_ratio:ratio_y &#61; ratio_xelse:ratio_y &#61; random.uniform(1, max_ratio)oh &#61; int(h * ratio_y)ow &#61; int(w * ratio_x)off_x &#61; random.randint(0, ow - w)off_y &#61; random.randint(0, oh - h)out_img &#61; np.zeros((oh, ow, c))if fill and len(fill) &#61;&#61; c:for i in range(c):out_img[:, :, i] &#61; fill[i] * 255.0out_img[off_y:off_y &#43; h, off_x:off_x &#43; w, :] &#61; imggtboxes[:, 0] &#61; ((gtboxes[:, 0] * w) &#43; off_x) / float(ow)gtboxes[:, 1] &#61; ((gtboxes[:, 1] * h) &#43; off_y) / float(oh)gtboxes[:, 2] &#61; gtboxes[:, 2] / ratio_xgtboxes[:, 3] &#61; gtboxes[:, 3] / ratio_yreturn out_img.astype(&#39;uint8&#39;), gtboxes
import numpy as npdef multi_box_iou_xywh(box1, box2):"""In this case, box1 or box2 can contain multi boxes.Only two cases can be processed in this method:1, box1 and box2 have the same shape, box1.shape &#61;&#61; box2.shape2, either box1 or box2 contains only one box, len(box1) &#61;&#61; 1 or len(box2) &#61;&#61; 1If the shape of box1 and box2 does not match, and both of them contain multi boxes, it will be wrong."""assert box1.shape[-1] &#61;&#61; 4, "Box1 shape[-1] should be 4."assert box2.shape[-1] &#61;&#61; 4, "Box2 shape[-1] should be 4."b1_x1, b1_x2 &#61; box1[:, 0] - box1[:, 2] / 2, box1[:, 0] &#43; box1[:, 2] / 2b1_y1, b1_y2 &#61; box1[:, 1] - box1[:, 3] / 2, box1[:, 1] &#43; box1[:, 3] / 2b2_x1, b2_x2 &#61; box2[:, 0] - box2[:, 2] / 2, box2[:, 0] &#43; box2[:, 2] / 2b2_y1, b2_y2 &#61; box2[:, 1] - box2[:, 3] / 2, box2[:, 1] &#43; box2[:, 3] / 2inter_x1 &#61; np.maximum(b1_x1, b2_x1)inter_x2 &#61; np.minimum(b1_x2, b2_x2)inter_y1 &#61; np.maximum(b1_y1, b2_y1)inter_y2 &#61; np.minimum(b1_y2, b2_y2)inter_w &#61; inter_x2 - inter_x1inter_h &#61; inter_y2 - inter_y1inter_w &#61; np.clip(inter_w, a_min&#61;0., a_max&#61;None)inter_h &#61; np.clip(inter_h, a_min&#61;0., a_max&#61;None)inter_area &#61; inter_w * inter_hb1_area &#61; (b1_x2 - b1_x1) * (b1_y2 - b1_y1)b2_area &#61; (b2_x2 - b2_x1) * (b2_y2 - b2_y1)return inter_area / (b1_area &#43; b2_area - inter_area)def box_crop(boxes, labels, crop, img_shape):x, y, w, h &#61; map(float, crop)im_w, im_h &#61; map(float, img_shape)boxes &#61; boxes.copy()boxes[:, 0], boxes[:, 2] &#61; (boxes[:, 0] - boxes[:, 2] / 2) * im_w, (boxes[:, 0] &#43; boxes[:, 2] / 2) * im_wboxes[:, 1], boxes[:, 3] &#61; (boxes[:, 1] - boxes[:, 3] / 2) * im_h, (boxes[:, 1] &#43; boxes[:, 3] / 2) * im_hcrop_box &#61; np.array([x, y, x &#43; w, y &#43; h])centers &#61; (boxes[:, :2] &#43; boxes[:, 2:]) / 2.0mask &#61; np.logical_and(crop_box[:2] <&#61; centers, centers <&#61; crop_box[2:]).all(axis&#61;1)boxes[:, :2] &#61; np.maximum(boxes[:, :2], crop_box[:2])boxes[:, 2:] &#61; np.minimum(boxes[:, 2:], crop_box[2:])boxes[:, :2] -&#61; crop_box[:2]boxes[:, 2:] -&#61; crop_box[:2]mask &#61; np.logical_and(mask, (boxes[:, :2] < boxes[:, 2:]).all(axis&#61;1))boxes &#61; boxes * np.expand_dims(mask.astype(&#39;float32&#39;), axis&#61;1)labels &#61; labels * mask.astype(&#39;float32&#39;)boxes[:, 0], boxes[:, 2] &#61; (boxes[:, 0] &#43; boxes[:, 2]) / 2 / w, (boxes[:, 2] - boxes[:, 0]) / wboxes[:, 1], boxes[:, 3] &#61; (boxes[:, 1] &#43; boxes[:, 3]) / 2 / h, (boxes[:, 3] - boxes[:, 1]) / hreturn boxes, labels, mask.sum()
def random_crop(img,boxes,labels,scales&#61;[0.3, 1.0],max_ratio&#61;2.0,constraints&#61;None,max_trial&#61;50):if len(boxes) &#61;&#61; 0:return img, boxesif not constraints:constraints &#61; [(0.1, 1.0), (0.3, 1.0), (0.5, 1.0), (0.7, 1.0),(0.9, 1.0), (0.0, 1.0)]img &#61; Image.fromarray(img)w, h &#61; img.sizecrops &#61; [(0, 0, w, h)]for min_iou, max_iou in constraints:for _ in range(max_trial):scale &#61; random.uniform(scales[0], scales[1])aspect_ratio &#61; random.uniform(max(1 / max_ratio, scale * scale), \min(max_ratio, 1 / scale / scale))crop_h &#61; int(h * scale / np.sqrt(aspect_ratio))crop_w &#61; int(w * scale * np.sqrt(aspect_ratio))crop_x &#61; random.randrange(w - crop_w)crop_y &#61; random.randrange(h - crop_h)crop_box &#61; np.array([[(crop_x &#43; crop_w / 2.0) / w,(crop_y &#43; crop_h / 2.0) / h,crop_w / float(w), crop_h / float(h)]])iou &#61; multi_box_iou_xywh(crop_box, boxes)if min_iou <&#61; iou.min() and max_iou >&#61; iou.max():crops.append((crop_x, crop_y, crop_w, crop_h))breakwhile crops:crop &#61; crops.pop(np.random.randint(0, len(crops)))crop_boxes, crop_labels, box_num &#61; box_crop(boxes, labels, crop, (w, h))if box_num < 1:continueimg &#61; img.crop((crop[0], crop[1], crop[0] &#43; crop[2],crop[1] &#43; crop[3])).resize(img.size, Image.LANCZOS)img &#61; np.asarray(img)return img, crop_boxes, crop_labelsimg &#61; np.asarray(img)return img, boxes, labels
def random_interp(img, size, interp&#61;None):interp_method &#61; [cv2.INTER_NEAREST,cv2.INTER_LINEAR,cv2.INTER_AREA,cv2.INTER_CUBIC,cv2.INTER_LANCZOS4,]if not interp or interp not in interp_method:interp &#61; interp_method[random.randint(0, len(interp_method) - 1)]h, w, _ &#61; img.shapeim_scale_x &#61; size / float(w)im_scale_y &#61; size / float(h)img &#61; cv2.resize(img, None, None, fx&#61;im_scale_x, fy&#61;im_scale_y, interpolation&#61;interp)return img
def random_flip(img, gtboxes, thresh&#61;0.5):if random.random() > thresh:img &#61; img[:, ::-1, :]gtboxes[:, 0] &#61; 1.0 - gtboxes[:, 0]return img, gtboxes
def shuffle_gtbox(gtbox, gtlabel):gt &#61; np.concatenate([gtbox, gtlabel[:, np.newaxis]], axis&#61;1)idx &#61; np.arange(gt.shape[0])np.random.shuffle(idx)gt &#61; gt[idx, :]return gt[:, :4], gt[:, 4]
def image_augment(img, gtboxes, gtlabels, size, means&#61;None):img &#61; random_distort(img)img, gtboxes &#61; random_expand(img, gtboxes, fill&#61;means)img, gtboxes, gtlabels, &#61; random_crop(img, gtboxes, gtlabels)img &#61; random_interp(img, size)img, gtboxes &#61; random_flip(img, gtboxes)gtboxes, gtlabels &#61; shuffle_gtbox(gtboxes, gtlabels)return img.astype(&#39;float32&#39;), gtboxes.astype(&#39;float32&#39;), gtlabels.astype(&#39;int32&#39;)