【E資格対策01】画像データ拡張

# はじめに
今回記事作成者のE資格受験勉強のために記事を作成しています
間違いなどありましたらコメントにてご指摘いただけると幸いです。

# 目的
E資格受験対策としてデータ拡張の種類について学ぶ

# 参考書籍

<a href="https://hb.afl.rakuten.co.jp/ichiba/2132e914.2fe6209c.2132e915.6ace3022/?pc=https%3A%2F%2Fitem.rakuten.co.jp%2Fbook%2F16715251%2F&link_type=text&ut=eyJwYWdlIjoiaXRlbSIsInR5cGUiOiJ0ZXh0Iiwic2l6ZSI6IjI0MHgyNDAiLCJuYW0iOjEsIm5hbXAiOiJyaWdodCIsImNvbSI6MSwiY29tcCI6ImRvd24iLCJwcmljZSI6MSwiYm9yIjoxLCJjb2wiOjEsImJidG4iOjEsInByb2QiOjAsImFtcCI6ZmFsc2V9" target="_blank" rel="nofollow sponsored noopener" style="word-wrap:break-word;"  >徹底攻略ディープラーニングE資格エンジニア問題集 第2版 [ スキルアップAI株式会社　小縣 信也 ]</a>

<a href="https://hb.afl.rakuten.co.jp/ichiba/2132e914.2fe6209c.2132e915.6ace3022/?pc=https%3A%2F%2Fitem.rakuten.co.jp%2Fbook%2F16715251%2F&link_type=pict&ut=eyJwYWdlIjoiaXRlbSIsInR5cGUiOiJwaWN0Iiwic2l6ZSI6IjI0MHgyNDAiLCJuYW0iOjEsIm5hbXAiOiJyaWdodCIsImNvbSI6MSwiY29tcCI6ImRvd24iLCJwcmljZSI6MSwiYm9yIjoxLCJjb2wiOjEsImJidG4iOjEsInByb2QiOjAsImFtcCI6ZmFsc2V9" target="_blank" rel="nofollow sponsored noopener" style="word-wrap:break-word;"  ><img src="https://hbb.afl.rakuten.co.jp/hgb/2132e914.2fe6209c.2132e915.6ace3022/?me_id=1213310&item_id=20340049&pc=https%3A%2F%2Fthumbnail.image.rakuten.co.jp%2F%400_mall%2Fbook%2Fcabinet%2F1583%2F9784295011583.jpg%3F_ex%3D240x240&s=240x240&t=pict" border="0" style="margin:2px" alt="" title=""></a>


# 画像データ拡張の種類

画像データ拡張方法は多くあります。
下記サイトにも色々あり参考になります。

https://pystyle.info/pytorch-list-of-transforms/#outline__6_7

# データ拡張に向けた準備

画像処理するために、PILを呼び出します。
PIL(Python Imaging Library)とは、Pythonで画像を処理するためのライブラリです。

PILについては下記サイトが参考になります。

https://techacademy.jp/magazine/21485

```py
# pipコマンドを用いてライブラリをインストールします。
pip install Pillow
# PILのライブラリを呼び出します。
import PIL
#イメージ画像を呼び出せるようにします。
from PIL import Image
```

今回データ拡張するための画像を下記のように用意します。

画像変換.ipynb ⇨ Pythonプログラム
cat.jpg ⇨ 今回の入力画像

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/5368969a-d19f-7ae5-2572-4340e3fb713c.png)


```py
#　画像を呼び出す
img = Image.open("cat.jpg")
# 呼び出した画像を出力する
display(img)

#transformsのライブラリ呼び出し
from torchvision import transforms
#numpy　呼び出し
import numpy as np
#グラフなど出力のライブラリ呼び出し
import matplotlib.pyplot as plt

```

そうすると下記のように出力される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/aa9d17e3-4ee4-ba0b-4eb0-fcaf1dffb5f3.png)

今回画像サイズを224✖️224にしたいため、下記内容でプログラムを実行する。

```py
#イメージのサイズを変更する
from PIL import Image
# リサイズ前の画像を読み込み
img = Image.open("cat.jpg")

print("入力画像のサイズ確認")
print(img.size)
print("入力画像")
display(img)
print("")

# 読み込んだ画像の幅、高さを取得し半分に
(width, height) = (img.width // 2, img.height // 2)
# 画像をリサイズする
img_resized = img.resize((width, height))

print("リサイズ後の画像サイズ")
print(img_resized.size)
print("リサイズ後の画像")
display(img_resized)


# ファイルを保存
img_resized.save('output.jpg', quality=90)


```

出力は下記のようになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/839ff8d8-dd1e-b181-5c8e-abe9d5b1f171.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/c3f07eab-d6e8-ac4c-81bd-c6a758ed4bf3.png)




# アフィン変換

アフィン変換(Affine変換)とは
画像の拡大縮小、回転、平行移動などを行列を使って座標を変換することをアフィン変換と呼びます。

アフィン変換を行列での表現については下記サイトが参考になります。


https://imagingsolution.net/imaging/affine-transformation/#:~:text=%E7%94%BB%E5%83%8F%E3%81%AE%E6%8B%A1%E5%A4%A7%E7%B8%AE%E5%B0%8F%E3%80%81%E5%9B%9E%E8%BB%A2,%E3%82%A2%E3%83%95%E3%82%A3%E3%83%B3%E5%A4%89%E6%8F%9B%E3%81%A8%E5%91%BC%E3%81%B3%E3%81%BE%E3%81%99%E3%80%82

アフィン変換の詳細については下記記事が参考になります。

https://qiita.com/koshian2/items/c133e2e10c261b8646bf


ランダムにアフィン変換を下記ULRを参考にしながら実装してみます。


https://pystyle.info/pytorch-list-of-transforms/#outline__6_7


```py
# ランダムにアフィン変換を行う
#アフィン変換=平面のアフィン変換とは三角形の移動（写像）を与えることで決まる変換のこと

img = Image.open("output.jpg")
print("元画像")
display(img)
transform=transforms.Compose([
    transforms.ToTensor(),
    transforms.RandomAffine(degrees=[-10, 10], translate=(0.1, 0.1), scale=(0.5, 1.5))
])
img = transform(img)
img = img.numpy().reshape((3, 224, 224))
img = np.transpose(img,(1,2,0))

plt.figure(figsize=(5, 5))
print("RandomAffine")
print("画像の拡大縮小、回転、平行移動などを行列を使って座標を変換する事をアフィン変換")
#img = Image.open("output.jpg")

plt.imshow(img)

```

出力すると下記のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/ebfcd6be-dbfd-409e-4290-9d0c93ba4577.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/e77d88a5-1862-fac2-df7c-ba3580490f39.png)


# ポスタリゼーション (posterize)

ポスタリゼーションとは？
ポスタリゼーションという用語は、かつてアーティストが写真を印刷ポスターにするために使った処理方法から由来しています。大量に印刷するには、色のバリエーションを少なくし、少ない色数で印刷する必要がありました。
ポスタリゼーションを施すことで、色の数を少なくし、繊細なグラデーションを大まかな色合いにすることで、絵の具を塗ったような、またはエアブラシを使ったような効果を画像に加えることができます。

参考URL：

https://www.adobe.com/jp/creativecloud/photography/discover/posterize-photo.html

# Random Flip

Random Flipは画像を反転させるデータ拡張方法です。

## RandomHorizontalFlip (水平方向に反転）
水平方向に確率pに従って反転させます。

下記のように実装してみます。

```py
# RandomHorizontalFlip　水平方向に反転
img = Image.open("output.jpg")
print("元画像")
display(img)

transform=transforms.Compose([
     transforms.ToTensor(),
     transforms.RandomHorizontalFlip(p=1.0) 
])
img = transform(img)
img = img.numpy().reshape((3, 224, 224))
img = np.transpose(img,(1,2,0))

plt.figure(figsize=(5, 5))
print("Random Flip")
print("水平方向に反転後")
plt.imshow(img)

```
出力結果は下記のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/d55d44c2-9b5a-d6f2-12a6-397cb83bf1fb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/7e3e4a11-48d3-58f2-1966-545c446712f6.png)




## RandomVerticalFlip (垂直方向に反転）
垂直方向に確率pに従って反転させます。

下記のように実装してみます。

```py
# RandomVerticalFlipは垂直方向
img = Image.open("output.jpg")
print("元画像")
display(img)

transform=transforms.Compose([
     transforms.ToTensor(),
     transforms.RandomVerticalFlip(p=1.0) 
])
img = transform(img)
img = img.numpy().reshape((3, 224, 224))
img = np.transpose(img,(1,2,0))

plt.figure(figsize=(5, 5))
print("Random Flip")
print("垂直方向に反転後")
plt.imshow(img)

```

出力結果は下記のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/336a45fc-ae40-e01b-dbfc-0e3d9f1b9a20.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/9f048c7e-1eb1-1578-e4bc-90d3918d643f.png)


# Erase
ピクセルを消去させるデータ拡張方法です。

今回は
RandomErasing
を実装してみます。


```py
# ランダムにピクセルを消去させるデータ拡張方法
img = Image.open("output.jpg")
print("元画像")
display(img)
print("")
transform=transforms.Compose([
     transforms.ToTensor(),
     transforms.RandomErasing(p=1, scale=(0.05, 0.06), ratio=(0.3, 3.0), value=0) 
])

# p : 画像を反転させる確率 (p=0.5)
# scale : 入力画像に対する消去領域の比率の範囲 (scale=(0.05, 0.06))
# ratio : 消去領域のアスペクト比の範囲 (ratio=(0.3, 3.0))
# value : 消去に関するパラメータで、RGBチャンネルをそれぞれ消去する際は、長さ3のタプルを指定 (value=0)

img = transform(img)
img = img.numpy().reshape((3, 224, 224))
img = np.transpose(img,(1,2,0))

plt.figure(figsize=(5, 5))
print("Erase")
print("画像の中の長方形領域をランダムに選択しそのピクセル消去後")
plt.imshow(img)


```

出力結果は下記のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/338a3d27-2bd5-6896-23c8-17df2195e627.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/0697fe7e-91c8-1719-7979-54ae0325f15b.png)


# Crop
画像の切り取りによって得られるデータ拡張方法です。

今回は
CeterCropを実装します。
これは与えられた画像を中央で切り取ります。

```py
img = Image.open("output.jpg")
print("元画像")
display(img)
print("")

transform=transforms.Compose(
    [transforms.Resize(300),
     transforms.CenterCrop(224), 
     transforms.ToTensor()
     ]
)
#size : 切り取るサイズ (ex. size=300, size=(200, 300))

img = transform(img)
img = img.numpy().reshape((3, 224, 224))
img = np.transpose(img,(1,2,0))

plt.figure(figsize=(5, 5))
print("Crop")
print("画像の切り取り後")
print("CenterCrop⇨画像の中央で切り取り")
plt.imshow(img)

```

出力すると下記のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/76331240-7f29-4199-8b9f-74896e661772.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/ebc780cf-d02e-5f3a-1015-2b9d69bc5db8.png)


# Brightness
画像の明るさを変更させることによって得られるデータ拡張方法です。

今回はColorJitterを実装してみます。
これは、画像の明るさ、コントラスト、彩度、色合いをランダムに変化させます。

```py
img = Image.open("output.jpg")
print("元画像")
display(img)
print("")

transform=transforms.Compose([
     transforms.ToTensor(),
     transforms.ColorJitter(brightness=0.7, contrast=0.8, saturation=0.9, hue=0.5) 
])
#brightness : 明るさを調整するパラメータ (brightness=0.70)
#contrast : コントラストを調整するパラメータ (contrast=0.80)
#saturation : 彩度を調整するパラメータ (saturation=0.90)
#hue : 色合いを調整するパラメータ (hue=0.50)

img = transform(img)
img = img.numpy().reshape((3, 224, 224))
img = np.transpose(img,(1,2,0))

plt.figure(figsize=(5, 5))
print("Brightness")
print("ランダムに色の明るさ、コントラスト、彩度、色合いを変更後の画像")
plt.imshow(img)

```

出力すると下記のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/f7aa990f-1cf9-6cd7-7f1d-ccdd477923ff.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/d7774cea-99b9-4aa8-326a-f520218d2445.png)

# Rotate
画像を回転させることによって得られるデータ拡張方法です。

今回はRandomRotationを実装してみます。

```pyimg = Image.open("output.jpg")
print("元画像")
display(img)
print("")

transform=transforms.Compose([
     transforms.ToTensor(),
     transforms.RandomRotation(degrees=60, expand=False, fill=0,) 
])

#degrees : 選択する角度の範囲を指定するパラメータ (degrees=60)
#expand : 拡張を実行するか決定するパラメータ。
#         trueの場合、出力を拡大して、回転した画像全体を格納できる大きさにし、
#         falseまたは省略された場合は、出力画像を入力画像と同じ大きさにする。
#fill : 回転した画像の外側の領域を埋める値 ( fill=255)

img = transform(img)
img = img.numpy().reshape((3, 224, 224))
img = np.transpose(img,(1,2,0))

plt.figure(figsize=(5, 5))
print("Rotate")
print("画像を回転させた後の画像")
plt.imshow(img)
```

出力すると下記のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/f9a7aab8-6c9e-f54d-58ea-eb607609383b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1786195/92deadaf-e0ac-9656-b7d5-923935c5e7f9.png)


# 最後に
画像を拡張することによってディープラーニングの精度が向上しやすくなります。
画像の拡張方法はたくさんあります。
ぜひ色々な拡張方法について学んでみてください。
私も引き続き学んでいきたいと思います。


# 参考書籍

<a href="https://hb.afl.rakuten.co.jp/ichiba/2132e914.2fe6209c.2132e915.6ace3022/?pc=https%3A%2F%2Fitem.rakuten.co.jp%2Fbook%2F16715251%2F&link_type=text&ut=eyJwYWdlIjoiaXRlbSIsInR5cGUiOiJ0ZXh0Iiwic2l6ZSI6IjI0MHgyNDAiLCJuYW0iOjEsIm5hbXAiOiJyaWdodCIsImNvbSI6MSwiY29tcCI6ImRvd24iLCJwcmljZSI6MSwiYm9yIjoxLCJjb2wiOjEsImJidG4iOjEsInByb2QiOjAsImFtcCI6ZmFsc2V9" target="_blank" rel="nofollow sponsored noopener" style="word-wrap:break-word;"  >徹底攻略ディープラーニングE資格エンジニア問題集 第2版 [ スキルアップAI株式会社　小縣 信也 ]</a>

<a href="https://hb.afl.rakuten.co.jp/ichiba/2132e914.2fe6209c.2132e915.6ace3022/?pc=https%3A%2F%2Fitem.rakuten.co.jp%2Fbook%2F16715251%2F&link_type=pict&ut=eyJwYWdlIjoiaXRlbSIsInR5cGUiOiJwaWN0Iiwic2l6ZSI6IjI0MHgyNDAiLCJuYW0iOjEsIm5hbXAiOiJyaWdodCIsImNvbSI6MSwiY29tcCI6ImRvd24iLCJwcmljZSI6MSwiYm9yIjoxLCJjb2wiOjEsImJidG4iOjEsInByb2QiOjAsImFtcCI6ZmFsc2V9" target="_blank" rel="nofollow sponsored noopener" style="word-wrap:break-word;"  ><img src="https://hbb.afl.rakuten.co.jp/hgb/2132e914.2fe6209c.2132e915.6ace3022/?me_id=1213310&item_id=20340049&pc=https%3A%2F%2Fthumbnail.image.rakuten.co.jp%2F%400_mall%2Fbook%2Fcabinet%2F1583%2F9784295011583.jpg%3F_ex%3D240x240&s=240x240&t=pict" border="0" style="margin:2px" alt="" title=""></a>

<a href="https://hb.afl.rakuten.co.jp/ichiba/2132e914.2fe6209c.2132e915.6ace3022/?pc=https%3A%2F%2Fitem.rakuten.co.jp%2Fbook%2F14424645%2F&link_type=text&ut=eyJwYWdlIjoiaXRlbSIsInR5cGUiOiJ0ZXh0Iiwic2l6ZSI6IjI0MHgyNDAiLCJuYW0iOjEsIm5hbXAiOiJyaWdodCIsImNvbSI6MSwiY29tcCI6ImRvd24iLCJwcmljZSI6MCwiYm9yIjoxLCJjb2wiOjEsImJidG4iOjEsInByb2QiOjAsImFtcCI6ZmFsc2V9" target="_blank" rel="nofollow sponsored noopener" style="word-wrap:break-word;"  >ゼロから作るDeep Learning Pythonで学ぶディープラーニングの理論と実装 [ 斎藤 康毅 ]</a>

<a href="https://hb.afl.rakuten.co.jp/ichiba/2132e914.2fe6209c.2132e915.6ace3022/?pc=https%3A%2F%2Fitem.rakuten.co.jp%2Fbook%2F14424645%2F&link_type=pict&ut=eyJwYWdlIjoiaXRlbSIsInR5cGUiOiJwaWN0Iiwic2l6ZSI6IjI0MHgyNDAiLCJuYW0iOjEsIm5hbXAiOiJyaWdodCIsImNvbSI6MSwiY29tcCI6ImRvd24iLCJwcmljZSI6MCwiYm9yIjoxLCJjb2wiOjEsImJidG4iOjEsInByb2QiOjAsImFtcCI6ZmFsc2V9" target="_blank" rel="nofollow sponsored noopener" style="word-wrap:break-word;"  ><img src="https://hbb.afl.rakuten.co.jp/hgb/2132e914.2fe6209c.2132e915.6ace3022/?me_id=1213310&item_id=18172266&pc=https%3A%2F%2Fthumbnail.image.rakuten.co.jp%2F%400_mall%2Fbook%2Fcabinet%2F7584%2F9784873117584.jpg%3F_ex%3D240x240&s=240x240&t=pict" border="0" style="margin:2px" alt="" title=""></a>


<a href="https://hb.afl.rakuten.co.jp/ichiba/2132e914.2fe6209c.2132e915.6ace3022/?pc=https%3A%2F%2Fitem.rakuten.co.jp%2Fbook%2F16877191%2F&link_type=text&ut=eyJwYWdlIjoiaXRlbSIsInR5cGUiOiJ0ZXh0Iiwic2l6ZSI6IjI0MHgyNDAiLCJuYW0iOjEsIm5hbXAiOiJyaWdodCIsImNvbSI6MSwiY29tcCI6ImRvd24iLCJwcmljZSI6MCwiYm9yIjoxLCJjb2wiOjEsImJidG4iOjEsInByb2QiOjAsImFtcCI6ZmFsc2V9" target="_blank" rel="nofollow sponsored noopener" style="word-wrap:break-word;"  >最短コースでわかる PyTorch ＆深層学習プログラミング [ 赤石 雅典 ]</a>

<a href="https://hb.afl.rakuten.co.jp/ichiba/2132e914.2fe6209c.2132e915.6ace3022/?pc=https%3A%2F%2Fitem.rakuten.co.jp%2Fbook%2F16877191%2F&link_type=pict&ut=eyJwYWdlIjoiaXRlbSIsInR5cGUiOiJwaWN0Iiwic2l6ZSI6IjI0MHgyNDAiLCJuYW0iOjEsIm5hbXAiOiJyaWdodCIsImNvbSI6MSwiY29tcCI6ImRvd24iLCJwcmljZSI6MCwiYm9yIjoxLCJjb2wiOjEsImJidG4iOjEsInByb2QiOjAsImFtcCI6ZmFsc2V9" target="_blank" rel="nofollow sponsored noopener" style="word-wrap:break-word;"  ><img src="https://hbb.afl.rakuten.co.jp/hgb/2132e914.2fe6209c.2132e915.6ace3022/?me_id=1213310&item_id=20461687&pc=https%3A%2F%2Fthumbnail.image.rakuten.co.jp%2F%400_mall%2Fbook%2Fcabinet%2F0322%2F9784296110322.jpg%3F_ex%3D240x240&s=240x240&t=pict" border="0" style="margin:2px" alt="" title=""></a>