Pillow(PIL; Python Imaging Library)の概要とData Augmentationの実装

## Pillowの基本トピック
### Pillowの概要
`Pillow`(PIL; Python Imaging Library)は`Python`で画像処理(image processing)を行うにあたって用いられるライブラリです。

https://pillow.readthedocs.io/en/stable/index.html


### インストールと基本コードの実行
`Pillow`は下記を実行することでPyPIから入手かつインストールが可能です。

```
$ pip install pillow
```

たとえば下記を実行することによって、`NumPy`形式の配列を`Pillow`の形式に変換することができます。

```python
import numpy as np
from PIL import Image

img_1 = np.zeros([100, 100])
img_2 = Image.fromarray(img_1)

print(type(img_1))
print(img_1.shape)
print(type(img_2))
```

・実行結果
```
<class 'numpy.ndarray'>
(100, 100)
<class 'PIL.Image.Image'>
```

上記の実行結果より、`PIL.Image.fromarray`を用いることによって`NumPy`形式の配列を`Pillow`の形式に変換できることが確認できます。


### サンプル画像のロード
`Pillow`を用いてサンプル画像のロードを行う場合、下記のように`PIL.Image.open`を用いれば良いです。

```python
import numpy as np
from PIL import Image

img = Image.open("./data/2007_000256.jpg")
img_np = np.array(img)

print(type(img))
print(img.info.items())
print(type(img_np))
```

・実行結果
```
<class 'PIL.Image.Image'>
dict_items([('jfif', 257), ('jfif_version', (1, 1)), ('jfif_unit', 0), ('jfif_density', (1, 1))])
<class 'numpy.ndarray'>
```


## Pillowを用いたData Augmentationの実装
以下、`Pillow`を用いたDeepLearningにおけるデータ拡張(Data Augmentation)の実装について確認します。

https://qiita.com/Chi_corp_123/items/8cc59f03490b37a79373


### 回転
`Pillow`を用いた回転は下記のように実装することができます。

```python
import numpy as np
from PIL import Image

img = Image.open("./data/2007_000256.jpg")

dst_1 = img.rotate(25)
dst_2 = img.rotate(25, expand=True)
dst_3 = img.transpose(Image.FLIP_LEFT_RIGHT)
dst_1.save("./png/rotate1.jpg", "JPEG")
dst_2.save("./png/rotate2.jpg", "JPEG")
dst_3.save("./png/rotate3.jpg", "JPEG")
```

・実行結果
![output1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/71a0247b-a30e-4010-8a4c-014064e89200.jpeg)
![output2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/e49a8c48-9ca3-d585-340a-e7a570f510a2.jpeg)
![output3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/739f2f10-e633-375b-0053-93ec55d4737a.jpeg)


### Shear
```math
\begin{align}
\left(\begin{array}{c} x' \\ y' \\ 1 \end{array} \right) &= A \left(\begin{array}{c} x \\ y \\ 1 \end{array} \right) \\
A = \left(\begin{array}{ccc} a & b & c \\ d & e & f \\ 0 & 0 & 1 \end{array} \right) &= \left(\begin{array}{ccc} 1 & \tan{\theta_x} & 0 \\ \tan{\theta_y} & 1 & 0 \\ 0 & 0 & 1 \end{array} \right)
\end{align}
```

Shearは上記の数式で表されるAffine変換を用いて下記のように実装されます。

```python
import numpy as np
import PIL
from PIL import Image

img = Image.open("./data/2007_000256.jpg")

dst_1 = img.transform(img.size, PIL.Image.AFFINE, (1, 0.1, 0, 0, 1, 0))
dst_2 = img.transform(img.size, PIL.Image.AFFINE, (1, 0, 0, 0.1, 1, 0))
dst_3 = img.transform(img.size, PIL.Image.AFFINE, (1, -0.1, 0, 0, 1, 0))
dst_1.save("./png/shear1.jpg", "JPEG")
dst_2.save("./png/shear2.jpg", "JPEG")
dst_3.save("./png/shear3.jpg", "JPEG")
```

・実行結果
![shear1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/1b49d13c-dcb5-3ead-3a69-3d1ca1f46939.jpeg)
![shear2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/d74f7bcd-f941-04a6-78ac-c6a01e390f7e.jpeg)
![shear3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/72c3439b-35e3-5443-a070-c551c9cdd420.jpeg)

`img.transform`の引数には数式の$a$〜$f$を`(a, b, c, d, e, f)`のようなタプルの形式で与えることは抑えておくと良いと思います。


### Sharpness
画像のシャープネス(sharpness)は画像の輪郭を強調する処理です。基本的には微分フィルタを用いたエッジ検出と同様の処理であると理解しておけば良いと思います。`Pillow`では下記のような処理によってシャープネス処理を行うことができます。

```python
import numpy as np
import PIL.ImageEnhance
from PIL import Image

img = Image.open("./data/2007_000256.jpg")

dst_1 = PIL.ImageEnhance.Sharpness(img).enhance(5)
dst_2 = PIL.ImageEnhance.Sharpness(img).enhance(20)
dst_3 = PIL.ImageEnhance.Sharpness(img).enhance(-2)
dst_1.save("./png/sharpness1.jpg", "JPEG")
dst_2.save("./png/sharpness2.jpg", "JPEG")
dst_3.save("./png/sharpness3.jpg", "JPEG")
```

・実行結果
![sharpness1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/8106a968-d96e-c237-91de-3a07d62cc003.jpeg)
![sharpness2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/1670c90f-9e52-cf76-5982-2fa63fbd9f28.jpeg)
![sharpness3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/d28dd489-35b2-33d9-8d4c-afc50b1f9949.jpeg)


### コントラスト(Contrast)


```python
import numpy as np
import PIL.ImageEnhance
from PIL import Image

img = Image.open("./data/2007_000256.jpg")

dst_1 = PIL.ImageEnhance.Contrast(img).enhance(2)
dst_2 = PIL.ImageEnhance.Contrast(img).enhance(10)
dst_3 = PIL.ImageEnhance.Contrast(img).enhance(-1)
dst_1.save("./png/contrast1.jpg", "JPEG")
dst_2.save("./png/contrast2.jpg", "JPEG")
dst_3.save("./png/contrast3.jpg", "JPEG")
```

・実行結果
![contrast1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/bd57b78e-5a13-1842-a31d-04ac80355ffc.jpeg)
![contrast2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/f94a7e93-786f-c95f-fd6b-74950e6ac901.jpeg)
![contrast3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/755e3d89-24d5-96a8-36ab-78f83019b84b.jpeg)


### Color
```python
import numpy as np
import PIL.ImageEnhance
from PIL import Image

img = Image.open("./data/2007_000256.jpg")

dst_1 = PIL.ImageEnhance.Color(img).enhance(5)
dst_2 = PIL.ImageEnhance.Color(img).enhance(20)
dst_3 = PIL.ImageEnhance.Color(img).enhance(-1)
dst_1.save("./png/color1.jpg", "JPEG")
dst_2.save("./png/color2.jpg", "JPEG")
dst_3.save("./png/color3.jpg", "JPEG")
```

・実行結果
![color1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/b9067b16-c8dc-a09a-735b-80f0a2c832ba.jpeg)
![color2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/96e698b0-17fb-b07c-f510-e027da667875.jpeg)
![color3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/0ea81c42-aa8f-cef0-b3be-12dd8cc7c74a.jpeg)


### 明るさ(Brightness)
```python
import numpy as np
import PIL.ImageEnhance
from PIL import Image

img = Image.open("./data/2007_000256.jpg")

dst_1 = PIL.ImageEnhance.Brightness(img).enhance(1.5)
dst_2 = PIL.ImageEnhance.Brightness(img).enhance(5)
dst_3 = PIL.ImageEnhance.Brightness(img).enhance(0.5)
dst_1.save("./png/brightness1.jpg", "JPEG")
dst_2.save("./png/brightness2.jpg", "JPEG")
dst_3.save("./png/brightness3.jpg", "JPEG")
```

・実行結果
![brightness1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/69179113-8a7b-392b-17c9-f75bc6742e05.jpeg)
![brightness2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/040153bb-7c11-83d8-22e9-a7c71d459223.jpeg)
![brightness3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/cb00a2ed-2c0a-4880-16fd-f923184a3f1b.jpeg)


### Posterize
```python
import numpy as np
import PIL.ImageEnhance
from PIL import Image

img = Image.open("./data/2007_000256.jpg")

dst_1 = PIL.ImageOps.posterize(img, 2)
dst_2 = PIL.ImageOps.posterize(img, 5)
dst_3 = PIL.ImageOps.posterize(img, 1)
dst_1.save("./png/posterize1.jpg", "JPEG")
dst_2.save("./png/posterize2.jpg", "JPEG")
dst_3.save("./png/posterize3.jpg", "JPEG")
```

・実行結果
![posterize1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/b0b826e1-2f69-5ba1-1112-ae8cb76d4c41.jpeg)
![posterize2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/651f2803-91bd-7e46-2799-349a22e5f47a.jpeg)
![posterize3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/7c8054a6-f157-5c38-7888-976ebfd70490.jpeg)


### Solarize
```python
import numpy as np
import PIL.ImageOps
from PIL import Image

img = Image.open("./data/2007_000256.jpg")

dst_1 = PIL.ImageOps.solarize(img, 256 - 50)
dst_2 = PIL.ImageOps.solarize(img, 256 - 200)
dst_3 = PIL.ImageOps.solarize(img, 256 - 0)
dst_1.save("./png/solarize1.jpg", "JPEG")
dst_2.save("./png/solarize2.jpg", "JPEG")
dst_3.save("./png/solarize3.jpg", "JPEG")
```

・実行結果
![solarize1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/d25b1746-dfd2-d043-8ef1-91706e84f116.jpeg)
![solarize2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/3261e46e-90c0-74af-63d8-4fb98cc72b2b.jpeg)
![solarize3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/23946ce0-a553-1085-10d8-202a66fcd9ec.jpeg)


### AutoContrast
```python
import numpy as np
import PIL.ImageOps
from PIL import Image

img = Image.open("./data/2007_000256.jpg")

dst_1 = PIL.ImageOps.autocontrast(img)
dst_1.save("./png/autocontrast1.jpg", "JPEG")
```

・実行結果
![autocontrast1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/bbe42b2d-2971-e5fe-9e11-a9537a2aef91.jpeg)