Keras、cv2、PILの画像水増しの比較

## 画像の水増しをしたい…！

ディープラーニングをやっていると画像分類をしたくなる時が来る。
そんな時、圧倒的に足りなくなるのが画像データだと思う。

賢明な皆さんは画像の水増しに思い当っているはずなので、それぞれのライブラリの比較を行う。

私のおすすめは、Keras ImageDataGeneratorである。作るのがだいぶ楽ちんなので。

#### 前提条件
- 元の画像はjpg形式とする。
- 画像編集としてではなく、あくまでディープラーニングを目的とした、大規模なデータセットの作成を目的とする。

### 前準備
```python:main.py
import os

path = os.getcwd()
input_dir = os.path.join(path,"images")　# 画像があるディレクトリ
output_dir = os.path.join(path,"Data_augmentation")　# 保存先ディレクトリ

# ディレクトリ作成
if os.path.isdir(input_dir) is False:
  os.mkdir(input_dir)
if os.path.isdir(output_dir) is False:
  os.mkdir(output_dir)
```

### PIL
>最もシンプルで使いやすいライブラリ。
>numpyにするだけなので感覚的な理解も容易。

サンプルを以下に記す。

```python:example_PIL.py
from PIL import Image
import glob
import os

class PIL_img():
  def __init__(self, input_dir, output_dir, name):
    self.image = Image.open(input_dir)
    self.name = name
    self.output_dir = output_dir

  def rot(self, degree=60, expand=True):
    # 画像の回転
    self.image = self.image.rotate(degree, expand=expand)
    # 画像の保存
    tag = "rot"+str(degree)
    save_name = os.path.join(self.output_dir,name+tag+".jpg")
    self.image.save(save_name)
                      
for input_img in input_imgs:
  pil_img = PIL_img(input_img, output_dir, name)
  pil_img.rot()

```

完成した画像がこちら
![catrot60.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1068192/0c346473-84da-b223-e441-27a63ea2645a.jpeg)



### openCV cv2
>シンプルかつ、幅広い使い道があるライブラリ。
>様々なメソッドがあり、より学習結果の向上が見込める画像を作れる。
>※配列化するとき一般的にRGBなのだが、cv2はBGRになっているので注意が必要！！

サンプルを以下に記す。

```python:example_cv2.py
import os
import cv2

class cv2_img():
  def __init__(self, input_img, output_dir, name):
    self.img = cv2.imread(input_img)
    self.img_gray = cv2.imread(input_img, 0)
    self.name = os.path.join(output_dir, name)

  def hsv(self, hue=1, saturation=1, value=1):
    # bgr→hsvに変換
    hsv_img = cv2.cvtColor(self.img, cv2.COLOR_BGR2HSV)
    # hsvの数値の変更
    hsv_img[:, :, (0)] = hsv_img[:, :, (0)] * hue
    hsv_img[:, :, (1)] = hsv_img[:, :, (1)] * saturation
    hsv_img[:, :, (2)] = hsv_img[:, :, (2)] * value
    # hsv→bgrに変換
    hsv_img = cv2.cvtColor(hsv_img, cv2.COLOR_HSV2BGR)
    # jpgの名前に処理の内容を記述
    tag = "-hsv" + str(hue) + "-" + str(saturation) + "-" + str(value)
    jpg_name = self.name + tag + '.jpg'
    # ec2にjpgの保存
    cv2.imwrite(jpg_name, hsv_img)

  def thresh(self, threshold=128):
    # 閾値を基準に白と黒に分ける
    ret, thresh_img = cv2.threshold(self.img_gray, threshold, 255, cv2.THRESH_BINARY)
    # jpgの名前に処理の内容を記述
    tag = "-thresh-" + str(threshold)
    jpg_name = self.name + tag + '.jpg'
    # ec2にjpgの保存
    cv2.imwrite(jpg_name, thresh_img)

input_imgs = glob.glob(input_dir + "/*.jpg")
name = "cat"
for input_img in input_imgs:
  CV2_img = cv2_img(input_img, output_dir, name)
  CV2_img.thresh()
  CV2_img.hsv(1, 1, 0.5)
```

このように、明るさを変えたり白と黒の二色で表すこともできる。


![cat-hsv1-1-0.5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1068192/30b85c09-0135-ba9a-d3ea-4b7ece805b6b.jpeg)
![cat-thresh-128.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1068192/11a5127e-0255-fe71-aada-ae4a663f424f.jpeg)
### Keras ImageDataGenerator
> 特殊な処理をせずともgif画像が読み取れる
> openCVより多い画像処理
> 画像のURLをリストの状態で渡せるため、ディレクトリ丸ごと作成が可能！
> 名前を付ける必要がない！

```python:ImageDataGenerator_ex.py
import os
from keras.preprocessing.image import load_img, img_to_array
from keras.preprocessing.image import ImageDataGenerator
import numpy as np
import glob


class gen_img():
  def __init__(self, input_dir, output_dir):
    self.files = glob.glob(input_dir + "/*.jpg")
    self.output_dir = output_dir

  # 画像の回転
  def rot(self, num=9, ranger=100):
    for i, file in enumerate(self.files):
      # ファイルの配列化
      img = load_img(file)
      x = img_to_array(img)
      x = np.expand_dims(x, axis=0)
      # データの作成
      datagen_rotation = ImageDataGenerator(rotation_range=ranger)
      img_rotation = datagen_rotation.flow(x, batch_size=1, save_to_dir=self.output_dir, save_prefix='img', save_format='png')

      # 任意の回数保存
      for i in range(num):
        batch_rotation = img_rotation.next()
      return batch_rotation

  # 画像の拡大
  def zoom(self, num=9, ranger=0.5):
    for i, file in enumerate(self.files):
      # ファイルの配列化
      img = load_img(file)
      x = img_to_array(img)
      x = np.expand_dims(x, axis=0)
      # データの作成
      datagen_zoom = ImageDataGenerator(zoom_range=ranger)
      img_zoom = datagen_zoom.flow(x, batch_size=1, save_to_dir=self.output_dir, save_prefix='img', save_format='jpg')
      # 任意の回数保存
      for i in range(num):
        batch_zoom = img_zoom.next()
      return batch_zoom

  # 色の変更
  def channel(self, num=9, ranger=100):
    for i, file in enumerate(self.files):
      # ファイルの配列化
      img = load_img(file)
      x = img_to_array(img)
      x = np.expand_dims(x, axis=0)
      # データの作成
      datagen_channel = ImageDataGenerator(channel_shift_range=ranger)
      img_channel = datagen_channel.flow(x, batch_size=1, save_to_dir=self.output_dir, save_prefix='img', save_format='jpg')
      # 任意の回数保存
      for i in range(num):
        batch_channel = img_channel.next()
      return batch_channel

  def shear(self, num=9, ranger=0.2):
      for i, file in enumerate(self.files):
        # ファイルの配列化
        img = load_img(file)
        x = img_to_array(img)
        x = np.expand_dims(x, axis=0)
        # データの作成
        datagen_channel = ImageDataGenerator(shear_range=ranger)
        img_channel = datagen_channel.flow(x, batch_size=1, save_to_dir=self.output_dir, save_prefix='img', save_format='jpg')
        # 任意の回数保存
        for i in range(num):
          batch_channel = img_channel.next()
        return batch_channel

dig = gen_img(input_dir, output_dir)
dig.rot()
dig.zoom()
dig.channel()
dig.shear()

```

また、このように引き延ばしたりも可能である
![img_0_9285.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1068192/4b8f4076-88c4-5b75-a9f7-cb4a6c07e38b.jpeg)


### 終わりに

deep learningでは前処理が結果の８割を占めているといわれている。
今回取り扱ったものはほんの一部でしかないので、各々自分に必要なものを使ってほしい。