def Resize(it): """ Resizes images according to the resize dimensions image: (array) Image resize: (tuple of integers) New dimensions target: (Dictionary) Containing BBox, Area, Labels and Index Returns normalized_image, target """ image, target = it resize = res new_target = target.copy() bbs = BoundingBoxesOnImage([ BoundingBox(x1=new_target['boxes'][0].item(), y1=new_target['boxes'][1].item(), x2=new_target['boxes'][2].item(), y2=new_target['boxes'][3].item()) ], image.shape) img = ia.imresize_single_image(np.array(image), resize) new_bbs = bbs.on(img) bbox = torch.tensor( [new_bbs[0].x1, new_bbs[0].y1, new_bbs[0].x2, new_bbs[0].y2]) new_target['area'] = torch.tensor([ (new_bbs[0].x2 - new_bbs[0].x1) * (new_bbs[0].y2 - new_bbs[0].y1) ]) new_target['boxes'] = bbox.unsqueeze(0) return img, [new_target]
def chapter_examples_bounding_boxes_projection(): import imgaug as ia from imgaug.augmentables.bbs import BoundingBox, BoundingBoxesOnImage ia.seed(1) # Define image with two bounding boxes image = ia.quokka(size=(256, 256)) bbs = BoundingBoxesOnImage([ BoundingBox(x1=25, x2=75, y1=25, y2=75), BoundingBox(x1=100, x2=150, y1=25, y2=75) ], shape=image.shape) # Rescale image and bounding boxes image_rescaled = ia.imresize_single_image(image, (512, 512)) bbs_rescaled = bbs.on(image_rescaled) # Draw image before/after rescaling and with rescaled bounding boxes image_bbs = bbs.draw_on_image(image, size=2) image_rescaled_bbs = bbs_rescaled.draw_on_image(image_rescaled, size=2) # ------------ save("examples_bounding_boxes", "projection.jpg", grid([image_bbs, image_rescaled_bbs], cols=2, rows=1), quality=90)
def quokka_bounding_boxes(size=None, extract=None): """Return example bounding boxes on the standard example quokke image. Currently only a single bounding box is returned that covers the quokka. Added in 0.5.0. (Moved from ``imgaug.imgaug``.) Parameters ---------- size : None or float or tuple of int or tuple of float, optional Size of the output image on which the BBs are placed. If ``None``, then the BBs are not projected to any new size (positions on the original image are used). ``float`` s lead to relative size changes, ``int`` s to absolute sizes in pixels. extract : None or 'square' or tuple of number or imgaug.augmentables.bbs.BoundingBox or imgaug.augmentables.bbs.BoundingBoxesOnImage Subarea to extract from the image. See :func:`~imgaug.imgaug.quokka`. Returns ------- imgaug.augmentables.bbs.BoundingBoxesOnImage Example BBs on the quokka image. """ # TODO get rid of this deferred import from imgaug.augmentables.bbs import BoundingBox, BoundingBoxesOnImage left, top = 0, 0 if extract is not None: bb_extract = _quokka_normalize_extract(extract) left = bb_extract.x1 top = bb_extract.y1 with open(_QUOKKA_ANNOTATIONS_FP, "r") as f: json_dict = json.load(f) bbs = [] for bb_dict in json_dict["bounding_boxes"]: bbs.append( BoundingBox( x1=bb_dict["x1"] - left, y1=bb_dict["y1"] - top, x2=bb_dict["x2"] - left, y2=bb_dict["y2"] - top ) ) if extract is not None: shape = (bb_extract.height, bb_extract.width, 3) else: shape = (643, 960, 3) bbsoi = BoundingBoxesOnImage(bbs, shape=shape) if size is not None: shape_resized = _compute_resized_shape(shape, size) bbsoi = bbsoi.on(shape_resized) return bbsoi
def augment_image_and_bboxes( image: np.ndarray, cutouts: Union[List[Tuple[float]], np.ndarray, None], proposal_boxes: Union[List[Tuple[float]], np.ndarray, None], angle: Optional[Union[float, int]], new_size: Optional[Union[int, Tuple[int]]], verbose: bool = False, ) -> Tuple[Any, Union[List[Tuple[float]], np.ndarray], np.ndarray]: bounding_boxes = [] prop_boxes = [] seg_boxes = [] new_size = image.shape[0] new_crop = int( np.ceil(image.shape[0]) ) # Is 200 for 282, which is what is wanted, and works for others seq = iaa.Sequential([ iaa.Affine(rotate=angle), iaa.CropToFixedSize(width=new_crop, height=new_crop, position="center"), ]) for cutout in cutouts: bounding_boxes.append( BoundingBox(cutout[1] + 0.5, cutout[0] + 0.5, cutout[3] + 0.5, cutout[2] + 0.5)) for pbox in proposal_boxes: prop_boxes.append( BoundingBox(pbox[1] + 0.5, pbox[0] + 0.5, pbox[3] + 0.5, pbox[2] + 0.5)) bbs = BoundingBoxesOnImage(bounding_boxes, shape=image.shape) pbbs = BoundingBoxesOnImage(prop_boxes, shape=image.shape) if seg_boxes: sbbs = BoundingBoxesOnImage(seg_boxes, shape=image.shape) _, sbbs = seq(image=image, bounding_boxes=sbbs) _, bbs = seq(image=image, bounding_boxes=bbs) image, pbbs = seq(image=image, bounding_boxes=pbbs) # Rescale image and bounding boxes if type(new_size) == int: image_rescaled = ia.imresize_single_image(image, (new_size, new_size)) else: image_rescaled = ia.imresize_single_image( image, (image.shape[0], image.shape[1])) bbs_rescaled = bbs.on(image_rescaled) pbbs_rescaled = pbbs.on(image_rescaled) if seg_boxes: sbbs_rescaled = sbbs.on(image_rescaled) sbbs_rescaled = sbbs_rescaled.remove_out_of_image( partly=False).clip_out_of_image() # Remove bounding boxes that go out of bounds pbbs_rescaled = pbbs_rescaled.remove_out_of_image( partly=False).clip_out_of_image() # But only clip source bounding boxes that are partly out of frame, so that no sources are lost bbs_rescaled = bbs_rescaled.remove_out_of_image( partly=False).clip_out_of_image() # Also remove those and clip of segmentation maps for index, bbox in enumerate(bbs_rescaled): cutouts[index][0] = bbox.x1 cutouts[index][1] = bbox.y1 cutouts[index][2] = bbox.x2 cutouts[index][3] = bbox.y2 # Convert proposal boxes as well pbs = [] for index, bbox in enumerate(pbbs_rescaled): pbs.append(np.asarray((bbox.x1, bbox.y1, bbox.x2, bbox.y2))) pbs = np.asarray(pbs) sbs = [] try: for index, bbox in enumerate(sbbs_rescaled): sbs.append(np.asarray((bbox.x1, bbox.y1, bbox.x2, bbox.y2))) except: if verbose: print("Empty sbbs_rescaled") sbs = np.asarray(sbs) return image_rescaled, cutouts, pbs
def get_random_data_1(annotation_line, input_shape, random=True, max_boxes=20, jitter=.3, hue=.1, sat=1.5, val=1.5, proc_img=True): '''random preprocessing for real-time data augmentation''' line = annotation_line.split() image = Image.open(line[0]) iw, ih = image.size h, w = input_shape box = np.array( [np.array(list(map(int, box.split(',')))) for box in line[1:]]) if not random: # resize image scale = min(w / iw, h / ih) nw = int(iw * scale) nh = int(ih * scale) dx = (w - nw) // 2 dy = (h - nh) // 2 image_data = 0 if proc_img: image = image.resize((nw, nh), Image.BICUBIC) new_image = Image.new('RGB', (w, h), (128, 128, 128)) new_image.paste(image, (dx, dy)) image_data = np.array(new_image) / 255. # correct boxes box_data = np.zeros((max_boxes, 5)) if len(box) > 0: np.random.shuffle(box) if len(box) > max_boxes: box = box[:max_boxes] box[:, [0, 2]] = box[:, [0, 2]] * scale + dx box[:, [1, 3]] = box[:, [1, 3]] * scale + dy box_data[:len(box)] = box return image_data, box_data img_data = np.array(image) bbs = BoundingBoxesOnImage( [BoundingBox(x1, y1, x2, y2, label) for x1, y1, x2, y2, label in box], shape=img_data.shape) image = np.array(image) image_rescaled = ia.imresize_single_image(image, input_shape) bbs_rescaled = bbs.on(image_rescaled) shaped_img, shaped_bbx = seq(image=image_rescaled, bounding_boxes=bbs_rescaled) # boxed = shaped_bbx.draw_on_image(shaped_img) shaped_bbx = [[x.x1, x.y1, x.x2, x.y2, x.label] for x in bbs_rescaled.bounding_boxes] box = np.array(shaped_bbx) box_data = np.zeros((max_boxes, 5)) if len(box) > 0: np.random.shuffle(box) if len(box) > max_boxes: box = box[:max_boxes] box[:, [0, 2]] = box[:, [0, 2]] box[:, [1, 3]] = box[:, [1, 3]] box_data[:len(box)] = box return shaped_img, box_data
def __getitem__(self, index): """ Returns - path: (str) Image filename - img: (Tensor) - annos: (Tensor) Annotation with size [100, 5] 5 = [xc, yc, w, h, label] """ coco = self.coco img_id = self.ids[index] ann_ids = coco.getAnnIds(imgIds=img_id) path = coco.loadImgs(img_id)[0]['file_name'] img = Image.open(os.path.join(self.root, path)).convert('RGB') w, h = img.size target = coco.loadAnns(ann_ids) annos = torch.zeros(len(target), 5) # if self.reso is None, skip the whole image augmentation part. # Apply image augmentations before coordinate conversion, resizing and toTensor transform. if self.reso is not None: #Convert image to numpy array img = np.array(img) # Get all the annotations (bboxes) bboxes = [] for i in range(len(target)): bbox = torch.Tensor(target[i]['bbox']) bbox_x = bbox[0] bbox_y = bbox[1] bbox_w = bbox[2] bbox_h = bbox[3] bboxes.append( BoundingBox(x1=bbox_x, y1=bbox_y, x2=bbox_x + bbox_w, y2=bbox_y + bbox_h)) bbs = BoundingBoxesOnImage(bboxes, shape=img.shape) # NOTE: resize first, otherwise rotating will crop the image (since image is not square) # Rescale image and bounding boxes img = ia.imresize_single_image(img, (self.reso, self.reso)) bbs = bbs.on(img) # Define augmentations seq = iaa.Sequential([ iaa.ChangeColorspace(from_colorspace="RGB", to_colorspace="HSV"), iaa.WithChannels(1, iaa.Add((-50, 50))), # Change saturation iaa.WithChannels(2, iaa.Add((-50, 50))), # Change intensity iaa.ChangeColorspace(from_colorspace="HSV", to_colorspace="RGB"), iaa.Sometimes( 0.5, iaa.Affine(rotate=90)), # Rotate 90 deg. (0.5 probability) iaa.Affine(shear=(-2, 2)), # Shear (-2 +2 degrees) iaa.Flipud(0.5), # Flip up-down (with 0.5 probability) iaa.Fliplr(0.5) # Flip left-right (with 0.5 probability) ]) img_aug, bbs_aug = seq(image=img, bounding_boxes=bbs) # # DEBUG: output image # image_after = bbs_aug.draw_on_image(img_aug) # # Convert numpy array to PIL image # image_after = Image.fromarray(image_after, 'RGB') # image_after.save('debug.png') # print(path) # print("DEBUG IMAGE SAVED") # print(bbox) # print(bbs_aug) # # sys.exit(0) # Overwrite original image img = img_aug for i in range(len(target)): # [x1, y1, w, h] => [xc, yc, w, h] # if self.reso is not None it means we have to update the bounding boxes coordinates if self.reso is not None: bbox = [] bbox.append(int(bbs_aug.bounding_boxes[i].x1)) bbox.append(int(bbs_aug.bounding_boxes[i].y1)) bbox.append( int(bbs_aug.bounding_boxes[i].x2) - int(bbs_aug.bounding_boxes[i].x1)) bbox.append( int(bbs_aug.bounding_boxes[i].y2) - int(bbs_aug.bounding_boxes[i].y1)) bbox = torch.Tensor(bbox) w = self.reso h = self.reso # print(bbox) # print() else: bbox = torch.Tensor(target[i]['bbox']) annos[i, 0] = (bbox[0] + bbox[2] / 2) / w annos[i, 1] = (bbox[1] + bbox[3] / 2) / h annos[i, 2] = bbox[2] / w annos[i, 3] = bbox[3] / h annos[i, 4] = self.class_map[int(target[i]['category_id'])] #if self.transform is not None: # img = self.transform(img) # ndarray -> Tensor conversion img = torch.from_numpy(img.transpose((2, 0, 1)).copy()) if isinstance(img, torch.ByteTensor): img = img.float().div(255) return path, img, annos