Skip to content

Instantly share code, notes, and snippets.

@tarun-ssharma
Last active June 4, 2022 08:25
Show Gist options
  • Save tarun-ssharma/a3a3dfe3ebd7b1ee18472af52ca75730 to your computer and use it in GitHub Desktop.
Save tarun-ssharma/a3a3dfe3ebd7b1ee18472af52ca75730 to your computer and use it in GitHub Desktop.
  1. Install imgaug pip install imgaug
  2. Import neccessary libs:
import numpy as np
import imgaug as ia
import imgaug.augmenters as iaa
import glob
from PIL import Image
  1. run sample code to check its working
images = np.zeros((2, 128, 128, 3), dtype=np.uint8)  # two example images
images[:, 64, 64, :] = 255
bbs = [
    [ia.BoundingBox(x1=10.5, y1=15.5, x2=30.5, y2=50.5)],
    [ia.BoundingBox(x1=10.5, y1=20.5, x2=50.5, y2=50.5),
     ia.BoundingBox(x1=40.5, y1=75.5, x2=70.5, y2=100.5)]
]

seq = iaa.Sequential([
    iaa.AdditiveGaussianNoise(scale=0.05*255),
    iaa.Affine(translate_px={"x": (1, 5)})
])

images_aug, bbs_aug = seq(images=images, bounding_boxes=bbs)
  1. Create a mapping of image key (filename without extension) v/s a list of annotations (bbox+label)
anno = {}
with open("./sprint1_ssd_mobilenetv2/gt.txt", 'r') as f:
    for line in f:
        items = line.strip().split(';')
        key = items[0].replace('.ppm','')
        if key in anno:
            anno[key].append(items[1:])
        else:
            anno[key] = [items[1:]]
  1. for each label, augment:
for label in LIST_OF_LABELS:
  augment_for_label()
  1. Define augment_for_label:
def get_ia_bboxes(anno):
  bbs = []
  images = []
  #need to keep track of image key vs index to later create gt file
  image_to_index = {}
  for key in anno:
          bb = []
          for bbox_arr in anno[key]:
              l = int(bbox_arr[4])
              if(l!=label):
                  continue
              bbox_xmin = float(bbox_arr[0])
              bbox_ymin = float(bbox_arr[1])
              bbox_xmax = float(bbox_arr[2])
              bbox_ymax = float(bbox_arr[3])
              bb.append(ia.BoundingBox(x1=bbox_xmin, y1=bbox_ymin, x2=bbox_xmax, y2=bbox_ymax, label=l))
          if(len(bb)==0):
              continue
          path = img_path + key + '.jpg'
          im = Image.open(path)
          image = np.array(im)
          images.append(image)
          bbs.append(bb)
          image_to_index[key] = len(images)-1
  return bbs, images, image_to_index
  
def augment_for_label():
  bbs, images, image_to_index = get_ia_bboxes(anno)
  images = np.asarray(images)
  image_count = len(bbs)
  for ctr in range(int(800/image_count)+1):
    augment_remaining = False
    if(ctr == int(800/image_count)):
        num_remaining = 800 - image_count*int(800/image_count)
        augment_remaining = True
    ia.seed(1+ctr)
    sometimes = lambda aug: iaa.Sometimes(0.5, aug)
    seq = get_chain_of_augs()
    ### NEED TO MAKE SURE THERE IS ONE-ON-ONE Mapping between images and bbs
    if augment_remaining:
        images_aug, bbs_aug = seq(images=images[:num_remaining], bounding_boxes=bbs[:num_remaining])
    else:
        images_aug, bbs_aug = seq(images=images, bounding_boxes=bbs)
    anno_lines = []
    for key in image_to_index:
        #new image
        if image_to_index[key] < len(images_aug):
            new_image = Image.fromarray(images_aug[image_to_index[key]])
            new_key = str(label)+'-'+str(ctr)+'-'+key
            new_image.save(new_img_dir+new_key+'.jpg')
            #new annotations
            anno_lines.extend([f'{new_key}.ppm;{round(bb.x1,6)};{round(bb.y1,6)};'
                               f'{round(bb.x2, 6)};{round(bb.y2, 6)};{bb.label}' \
                               for bb in bbs_aug[image_to_index[key]] ])

    if(len(anno_lines) != 0):
        with open("./complete_gtsdb_augmented_3/gt.txt", 'a+') as f:
            f.seek(0)
            line_data = f.readlines()

            if len(line_data) != 0:
                f.seek(0, 2)
                f.writelines([line+'\n' for line in anno_lines])
            else:
                f.writelines([line+'\n' for line in anno_lines])
  1. Define the chain of augmentations:
<details>
  <summary> augmentations..</summary>

def get_chain_of_augs():
  return iaa.Sequential(
            [
                #iaa.Crop(percent=(0, 0.05)),
                iaa.Affine(
                    scale={"x": (0.9, 1.2), "y": (0.9, 1.2)},
                    translate_percent={"x": (-0.1, 0.1), "y": (-0.1, 0.1)},
                    rotate=(-5, 5),#degrees
                    shear=(-5, 5),#degrees
                    order=[0, 1],
                    cval=(0, 255),
                    mode=ia.ALL
                ),
                iaa.SomeOf((0,5), [
                        # Blur each image with varying strength using
                        # gaussian blur (sigma between 0 and 3.0),
                        # average/uniform blur (kernel size between 2x2 and 7x7)
                        # median blur (kernel size between 3x3 and 11x11).
                        iaa.OneOf([
                            iaa.GaussianBlur((0, 3.0)),
                            iaa.AverageBlur(k=(2, 7)),
                            iaa.MedianBlur(k=(3, 11)),
                        ]),

                        # Sharpen each image, overlay the result with the original
                        # image using an alpha between 0 (no sharpening) and 1
                        # (full sharpening effect).
                        iaa.Sharpen(alpha=(0, 1.0), lightness=(0.75, 1.5)),

                        # Same as sharpen, but for an embossing effect.
                        iaa.Emboss(alpha=(0, 1.0), strength=(0, 2.0)),

                        # Search in some images either for all edges or for
                        # directed edges. These edges are then marked in a black
                        # and white image and overlayed with the original image
                        # using an alpha of 0 to 0.7.
                        iaa.OneOf([
                            iaa.EdgeDetect(alpha=(0, 0.7)),
                            iaa.DirectedEdgeDetect(
                                alpha=(0, 0.7), direction=(0.0, 1.0)
                            ),
                        ]),

                        # Add gaussian noise to some images.
                        # In 50% of these cases, the noise is randomly sampled per
                        # channel and pixel.
                        # In the other 50% of all cases it is sampled once per
                        # pixel (i.e. brightness change).
                        iaa.AdditiveGaussianNoise(
                            loc=0, scale=(0.0, 0.05*255), per_channel=0.5
                        ),

                        # Either drop randomly 1 to 10% of all pixels (i.e. set
                        # them to black) or drop them on an image with 2-5% percent
                        # of the original size, leading to large dropped
                        # rectangles.
                        iaa.OneOf([
                            iaa.Dropout((0.01, 0.1), per_channel=0.5),
                            iaa.CoarseDropout(
                                (0.03, 0.15), size_percent=(0.02, 0.05),
                                per_channel=0.2
                            ),
                        ]),

                        # Invert each image's channel with 5% probability.
                        # This sets each pixel value v to 255-v.
                        iaa.Invert(0.05, per_channel=True), # invert color channels

                        # Add a value of -10 to 10 to each pixel.
                        iaa.Add((-10, 10), per_channel=0.5),

                        # Change brightness of images (50-150% of original value).
                        iaa.Multiply((0.5, 1.5), per_channel=0.5),

                        # Improve or worsen the contrast of images.
                        iaa.LinearContrast((0.5, 2.0), per_channel=0.5),

                        # Convert each image to grayscale and then overlay the
                        # result with the original with random alpha. I.e. remove
                        # colors with varying strengths.
                        iaa.Grayscale(alpha=(0.0, 1.0)),

                        # In some images move pixels locally around (with random
                        # strengths).
                        iaa.ElasticTransformation(alpha=(0.5, 3.5), sigma=0.25),

                        # In some images distort local areas with varying strength.
                        iaa.PiecewiseAffine(scale=(0.01, 0.05))
                ],
                random_order=True)
            ],
            random_order=True
        )
</details>

  1. Perform augmentation.
  2. Check per class count from terminal:
#per class count
#classes: 0,1,2,3,4,5,7,8,14
!cat -n ./complete_gtsdb_augmented/gt.txt | egrep -c ';0$'
!cat -n ./complete_gtsdb_augmented/gt.txt | egrep -c ';1$'
!cat -n ./complete_gtsdb_augmented/gt.txt | egrep -c ';2$'
!cat -n ./complete_gtsdb_augmented/gt.txt | egrep -c ';3$'
!cat -n ./complete_gtsdb_augmented/gt.txt | egrep -c ';4$'
!cat -n ./complete_gtsdb_augmented/gt.txt | egrep -c ';5$'
!cat -n ./complete_gtsdb_augmented/gt.txt | egrep -c ';7$'
!cat -n ./complete_gtsdb_augmented/gt.txt | egrep -c ';8$'
!cat -n ./complete_gtsdb_augmented/gt.txt | egrep -c ';14$'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment