본문 바로가기

Computer Vision/Classification

imgaug 패키지를 이용하여 데이터 증강하기

이번 포스팅은 imgaug 패키지를 이용하여 classify 모델의 성능을 증가시킬 수 있는
imgaug를 소개하고자 한다.

imgaug는 파이썬 패키지 형태로 배포되었기 때문에 설치가 매우매우 간단하다.

pip3 install imgaug

 

하지만, imgaug를 pip3 로 설치할 경우 opencv 등 의존성 패키지들이 같이 설치되어 가지고 있던 패키지들의 version이 변경되게 된다. 그런 경우를 방지하고자 한다면 다음을 참고하여 설치

imgaug dependencies

  • six
  • numpy
  • scipy
  • Pillow
  • matplotlib
  • scikit-image
  • opencv-python
  • imageio

 

위 목록들 중에 본인이 이미 설치가 되어있고, version을 망치고 싶지 않다면,
의존성 패키지를 따로 설치해준 뒤에 다음 명령어로 imgaug를 설치하면 된다.

pip install --no-dependencies imgaug

 

imgaug 패키지에는 classify를 위한 이미지부터 heatmap, Segments, Keypoints, Bounding Box, Polygons 등
다양한 형태의 데이터 증강을 지원한다.

본 포스팅에서는 이미지 데이터 증강의 예제 사용을 소개한다.

가장 먼저, imgaug github 및 docs에 있는 예제를 클래스 형태로 작성해 주었다.

#-- filename : img_aug.py --

import numpy as np
import imgaug as ia
import imgaug.augmenters as iaa

# random example images
images = np.random.randint(0, 255, (16, 128, 128, 3), dtype=np.uint8)

class Img_aug :
    def __init__(self) :
        # Sometimes(0.5, ...) applies the given augmenter in 50% of all cases,
        # e.g. Sometimes(0.5, GaussianBlur(0.3)) would blur roughly every second image.
        self.sometimes = lambda aug: iaa.Sometimes(0.5, aug)

        # Define our sequence of augmentation steps that will be applied to every image
        # All augmenters with per_channel=0.5 will sample one value _per image_
        # in 50% of all cases. In all other cases they will sample new values
        # _per channel_.
        self.seq = iaa.Sequential(
            [
                # apply the following augmenters to most images
                iaa.Fliplr(0.5), # horizontally flip 50% of all images
                iaa.Flipud(0.2), # vertically flip 20% of all images
                # crop images by -5% to 10% of their height/width
                self.sometimes(iaa.CropAndPad(
                    percent=(-0.05, 0.1),
                    pad_mode=ia.ALL,
                    pad_cval=(0, 255)
                )),
                self.sometimes(iaa.Affine(
                    scale={"x": (0.8, 1.2), "y": (0.8, 1.2)}, # scale images to 80-120% of their size, individually per axis
                    translate_percent={"x": (-0.2, 0.2), "y": (-0.2, 0.2)}, # translate by -20 to +20 percent (per axis)
                    rotate=(-45, 45), # rotate by -45 to +45 degrees
                    shear=(-16, 16), # shear by -16 to +16 degrees
                    order=[0, 1], # use nearest neighbour or bilinear interpolation (fast)
                    cval=(0, 255), # if mode is constant, use a cval between 0 and 255
                    mode=ia.ALL # use any of scikit-image's warping modes (see 2nd image from the top for examples)
                )),
                # execute 0 to 5 of the following (less important) augmenters per image
                # don't execute all of them, as that would often be way too strong
                iaa.SomeOf((0, 5),
                    [
                        self.sometimes(iaa.Superpixels(p_replace=(0, 1.0), n_segments=(20, 200))), # convert images into their superpixel representation
                        iaa.OneOf([
                            iaa.GaussianBlur((0, 3.0)), # blur images with a sigma between 0 and 3.0
                            iaa.AverageBlur(k=(2, 7)), # blur image using local means with kernel sizes between 2 and 7
                            iaa.MedianBlur(k=(3, 11)), # blur image using local medians with kernel sizes between 2 and 7
                        ]),
                        iaa.Sharpen(alpha=(0, 1.0), lightness=(0.75, 1.5)), # sharpen images
                        iaa.Emboss(alpha=(0, 1.0), strength=(0, 2.0)), # emboss images
                        # search either for all edges or for directed edges,
                        # blend the result with the original image using a blobby mask
                        iaa.SimplexNoiseAlpha(iaa.OneOf([
                            iaa.EdgeDetect(alpha=(0.5, 1.0)),
                            iaa.DirectedEdgeDetect(alpha=(0.5, 1.0), direction=(0.0, 1.0)),
                        ])),
                        iaa.AdditiveGaussianNoise(loc=0, scale=(0.0, 0.05*255), per_channel=0.5), # add gaussian noise to images
                        iaa.OneOf([
                            iaa.Dropout((0.01, 0.1), per_channel=0.5), # randomly remove up to 10% of the pixels
                            iaa.CoarseDropout((0.03, 0.15), size_percent=(0.02, 0.05), per_channel=0.2),
                        ]),
                        iaa.Invert(0.05, per_channel=True), # invert color channels
                        iaa.Add((-10, 10), per_channel=0.5), # change brightness of images (by -10 to 10 of original value)
                        iaa.AddToHueAndSaturation((-20, 20)), # change hue and saturation
                        # either change the brightness of the whole image (self.sometimes
                        # per channel) or change the brightness of subareas
                        iaa.OneOf([
                            iaa.Multiply((0.5, 1.5), per_channel=0.5),
                            iaa.FrequencyNoiseAlpha(
                                exponent=(-4, 0),
                                first=iaa.Multiply((0.5, 1.5), per_channel=True),
                                second=iaa.ContrastNormalization((0.5, 2.0))
                            )
                        ]),
                        iaa.ContrastNormalization((0.5, 2.0), per_channel=0.5), # improve or worsen the contrast
                        iaa.Grayscale(alpha=(0.0, 1.0)),
                        self.sometimes(iaa.ElasticTransformation(alpha=(0.5, 3.5), sigma=0.25)), # move pixels locally around (with random strengths)
                        self.sometimes(iaa.PiecewiseAffine(scale=(0.01, 0.05))), # self.sometimes move parts of the image around
                        self.sometimes(iaa.PerspectiveTransform(scale=(0.01, 0.1)))
                    ],
                    random_order=True
                )
            ],
            random_order=True
        )

매우매우 길기에 우리 코드에 넣어서 그냥 사용하기에는 부담스럽기 때문에 클래스로 따로 선언하여 스크립트를 작성했다.
코드 내용을 보면 imgaug패키지의 다양한 증강기법이 사용된 것을 확인해 볼 수 있다.

heatmap, Segments, Keypoints, Bounding Box, Polygons 등 같은 방식으로 docs에서 사용하려고 하는 함수명을 확인한 후에 Sequential 안에 선언해주어서 사용이 가능하다.

안쪽의 파라미터들은 docs를 보면서 직접 확인해보고, 사용해보면서 변경해주면 된다.
본 포스팅에서는 예제 그대로 사용하여 데이터를 증강시켜 주었다.

class로 선언하였기 때문에 사용하고자 하는 python 스크립트에서는 간단하게 쓸 수 있다.
(위와 같은 방법으로 본인만의 데이터 증강 모듈을 만들 수 있다.)

#-- filename : main.py -- 

import cv2
import numpy as np
from img_aug import Img_aug #데이터 증강 class를 불러옴

aug = Img_aug()		#데이터 증강 class 선언
augment_num = 40	#증강결과로 출력되는 이미지의 갯수 선언
save_path = 'augment/'

img = cv2.imread('pizza.jpg')
images_aug = aug.seq.augment_images([img for i in range(augment_num)])

for num,aug_img in enumerate(images_aug) :
    cv2.imwrite(save_path+'pizza_{}.jpg'.format(num),aug_img)

print('Complete augmenting images')

 

피자 이미지의 데이터 증강이 잘 되었는지 확인해보자.

피자이미지가 정말 다양하게 증강된 것을 확인할 수 있다.
예제를 그냥 그대로 사용하기 보다는 본인이 원하는 증강기법을 선택하여 random 으로 데이터 증강을 시킨다면,
classify의 성능이 매우 올라갈 것이다.
(물론, 데이터 증강만이 성능개선의 정답은 아니다.)

본 포스팅에서는 증강기법 패키지를 소개하고, 이미지를 직접 확인하기 위해 저장하는 방법을 작성하였지만,
실제 훈련시에는 images_aug = aug.seq.augment_images([img for i in range(augment_num)])
이 부분을 batch에 이미지와 함께 입력하여 훈련시키고자 하는 network에 삽입하여 주면 된다.

본 포스팅에서는 소개의 목적으로 정~말 간단하게 풀어내었지만, 사용용도에 따라 다양하게 사용하면 좋을듯하다.

https://github.com/aleju/imgaug

 

aleju/imgaug

Image augmentation for machine learning experiments. - aleju/imgaug

github.com

https://imgaug.readthedocs.io/en/latest/index.html

 

imgaug — imgaug 0.4.0 documentation

© Copyright 2020, Alexander Jung Revision 7443efbf.

imgaug.readthedocs.io

 

'Computer Vision > Classification' 카테고리의 다른 글

개와 고양이 분류하기 - 2  (0) 2020.06.23
개와 고양이 분류하기 - 1  (0) 2020.06.18
개와 고양이 분류하기 - 0  (0) 2020.06.18