機械学習のデータセット画像枚数を増やす方法

## 画像水増しの意義
ディープラーニングのCNN等のクラス分類の精度を向上させるためには、優れた学習データセットが必要です。精度を担保するためには、以下のような工夫をする必要があります。

* 十分な画像枚数を用意する。
* 各タグの画像枚数を揃える
* タグ付けをより正確に行う
* 同じ分類のものでも、見た目が異なる場合は細かくタグを分ける
  
これらを行うためには、とにかく枚数が必要です。種類によって枚数に偏りがある場合もあり、すべて手作業で抽出・タグ付けしていると大変です。

そこで、ある程度タグ付けされた画像たちを加工することで、画像の枚数を増やすことを考えます。その手法を幾つか紹介します。なお説明には、[高城れにさんを画像処理のサンプルに使うべき](http://bohemia.hatenablog.com/entry/2016/01/07/104017)との意見に基づき、高城れにさんを利用します。  


## 水増し手法
OpenCV 3.0 Pythonで実装します。  
実際に水増しに使えるソースをこちらに用意しておきます。

[Github](https://github.com/bohemian916/deeplearning_tool/blob/master/increase_picture.py)


### コントラスト調整
コントラストを強調、低減させた画像を作ります。  
強調するには、一定以下の低輝度の画素を0,　一定以上の高輝度の画素を255にし、中間の輝度のものを調整します。
逆に低減するには、輝度の幅を小さくするように調整します。こちらの図がわかりやすいです。
![http://livedoor.blogimg.jp/progr-python2/imgs/f/8/f867a2e8.png](https://qiita-image-store.s3.amazonaws.com/0/50474/5fbabaa6-f134-b630-fe7b-7794f3fe0307.png)

  
```py
# ルックアップテーブルの生成
min_table = 50
max_table = 205
diff_table = max_table - min_table

LUT_HC = np.arange(256, dtype = 'uint8' )
LUT_LC = np.arange(256, dtype = 'uint8' )

# ハイコントラストLUT作成
for i in range(0, min_table):
    LUT_HC[i] = 0
for i in range(min_table, max_table):
    LUT_HC[i] = 255 * (i - min_table) / diff_table
for i in range(max_table, 255):
    LUT_HC[i] = 255

# ローコントラストLUT作成
for i in range(256):
    LUT_LC[i] = min_table + i * (diff_table) / 255

# 変換
src = cv2.imread("reni.jpg", 1)
high_cont_img = cv2.LUT(src, LUT_HC)
low_cont_img = cv2.LUT(src, LUT_LC)
```
コントラストを強調したもの
![reni_takagi_2012_04_15_1.jpg](https://qiita-image-store.s3.amazonaws.com/0/50474/9ef8d5eb-ee91-0eff-3c3c-ec9a7d9af9e4.jpeg)

コントラストを低減したもの
![reni_takagi_2012_04_15_2.jpg](https://qiita-image-store.s3.amazonaws.com/0/50474/7cdca8f9-1eb2-f456-9d09-7747e17d9fb5.jpeg)


参考
[トーンカーブで画像の濃度変換](http://opencv.blog.jp/algorithm/tone_curve)

### ガンマ変換
ディスプレイの表示などの際に使われる変換で、輝度値をγの値によって変化させます。
![http://livedoor.blogimg.jp/progr-python2/imgs/0/4/043dfda9.png](https://qiita-image-store.s3.amazonaws.com/0/50474/1ac70b0f-7b74-05dd-64d8-f74d8cf17a65.png)

コントラスト調整のソースのルックアップテーブルを、こちらに置き換えてください。

```py
# ガンマ変換ルックアップテーブル
gamma1 = 0.75
gamma2 = 1.5
for i in range(256):
    LUT_G1[i] = 255 * pow(float(i) / 255, 1.0 / gamma1)
    LUT_G2[i] = 255 * pow(float(i) / 255, 1.0 / gamma2)
```
γ=1.5のとき
![reni_takagi_2012_04_15_3.jpg](https://qiita-image-store.s3.amazonaws.com/0/50474/aa56dec8-1893-7f58-d417-ed858b1bb895.jpeg)


γ=0.75のとき
![reni_takagi_2012_04_15_2.jpg](https://qiita-image-store.s3.amazonaws.com/0/50474/1c3c7562-9ee0-54b7-6086-aaf2c5dfdde7.jpeg)

参考  
[ルックアップテーブル（ガンマ補正の例）] (http://imagingsolution.blog107.fc2.com/blog-entry-67.html)  

### 平滑化
画像を滑らかにします。ここでは平均化フィルタをかけています。
  
```py
average_square = (10,10)
src = cv2.imread("reni.jpg", 1)
blur_img = cv2.blur(src, average_square)
```

10×10平均化フィルタ  
![reni_takagi_2012_04_15_5.jpg](https://qiita-image-store.s3.amazonaws.com/0/50474/461a821f-5bfc-3ae6-567e-08abf89e53f5.jpeg)
  
参考
[平滑化（移動平均、ガウシアン）フィルタ](http://imagingsolution.blog107.fc2.com/blog-entry-88.html)

### ガウス分布に基づくノイズ
各画素にガウス分布に基づく生成値を足して、ノイズを付加します。

σ=15のガウシアンノイズ
![reni_takagi_2012_04_15_7.jpg](https://qiita-image-store.s3.amazonaws.com/0/50474/37b71800-c31e-b700-845d-8d70aa096829.jpeg)
  
  
```py
src = cv2.imread("reni.jpg", 1)
row,col,ch= src.shape
mean = 0
sigma = 15
gauss = np.random.normal(mean,sigma,(row,col,ch))
gauss = gauss.reshape(row,col,ch)
gauss_img = src + gauss
```

参考
[画像情報（輝度データ）の変換](http://www.comp.tmu.ac.jp/morbier/imagproc/imageconvert.html)

### Salt&Pepperノイズ
塩と胡椒をかけたようなノイズなので、こう呼ばれます。インパルスノイズとも言うそうです。

```py
src = cv2.imread("reni.jpg", 1)
row,col,ch = src.shape
s_vs_p = 0.5
amount = 0.004
sp_img = src.copy()

# 塩モード
num_salt = np.ceil(amount * src.size * s_vs_p)
coords = [np.random.randint(0, i-1 , int(num_salt)) for i in src.shape]
sp_img[coords[:-1]] = (255,255,255)

# 胡椒モード
num_pepper = np.ceil(amount* src.size * (1. - s_vs_p))
coords = [np.random.randint(0, i-1 , int(num_pepper)) for i in src.shape]
sp_img[coords[:-1]] = (0,0,0)

```
0.4%の画素にノイズ
![reni_takagi_2012_04_15_8.jpg](https://qiita-image-store.s3.amazonaws.com/0/50474/cb4288e8-8dd7-bcce-1159-9606ac6178af.jpeg)


### 反転
左右の反転、上下の反転を行います。

```py
src = cv2.imread("reni.jpg", 1)
hflip_img = cv2.flip(src, 1)
vflip_img = cv2.flip(src, 0)
```

### 拡大縮小
画像の一部を拡大、縮小します。

```py
src = cv2.imread("reni.jpg", 1)
hight = src.shape[0]
width = src.shape[1]
half_img = cv2.resize(src,(hight/2,width/2))
```