Google Colaboratoryで画像処理(初級編)

Google Colaboratory上で画像処理を試す方法の紹介。Jupyter NotebookあるいはGoogle Colaboratoryを触ったことがある人向け。

# Google Colaboratoryで画像処理を試すメリット
* 環境構築の必要がない。ブラウザがあればいつでもどこからでも試せる。iPadからでも!
* REPL形式で、途中の状態を確認したり書き換えたりしながら作業できる
* Pythonで書くので、APIサーバーなどの形に移植しやすい

そして、何より無料で使える。

# 新しいNotebookの作成
https://colab.research.google.com/notebooks/welcome.ipynb#recent=true

<img width="865" alt="Screen Shot 2019-01-06 at 10.48.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/14097/1f4df869-7616-a3c6-7caf-d444dceb5c73.png">

「NEW PYTHON 3 NOTEBOOK」を選ぶ。Python 2系はまもなくサポートが終了してしまうので、特別な理由がなければPython 3系を選ぶ。

# 画像をアップロードして表示する

処理したいファイルをアップロードする。Google Driveから読み込ませることもできるが、枚数が少ない、あるいは確認用に色々な画像を使いたい場合は`files.upload()`を使ってブラウザからアップロードするのが便利。

```
from google.colab import files
uploaded_file = files.upload()
```

<img width="396" alt="Screen Shot 2019-01-06 at 10.55.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/14097/255d91c9-aff4-ead0-2527-a8ec5abad98e.png">

コードブロックを実行すると、アップロードフォームが表示される。適当な画像を選んでアップロードする。

`files.upload()`の返り値には、アップロードしたファイルの情報が含まれるDictionaryが入っている。キーがファイル名になっているので、アップロードされたファイルのファイル名は`next(iter(uploaded_file))`で取得できる。

```
uploaded_file_name = next(iter(uploaded_file))
print(uploaded_file_name)
```

「CODE」ブロックを追加して、アップロードしたファイル名を確認してみる。

<img width="575" alt="Screen Shot 2019-01-06 at 11.02.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/14097/137e50d2-1ca9-979d-98ed-23da4fc6eeeb.png">

OpenCVを使って画像を読み込む。[OpenCVでは画像は色が(現在では)一般的なRGBではなくBGRで扱われる](https://www.learnopencv.com/why-does-opencv-use-bgr-color-format/)。それだと後々不便なので、`cvtColor`を使ってRGBに変換しておく。

```
import cv2

orig = cv2.imread(uploaded_file_name)
src = cv2.cvtColor(orig, cv2.COLOR_BGR2RGB)
```

読み込んだ画像を`matplotlib`を使って画面に表示する。画像は[ぱくたそ](https://www.pakutaso.com/20190133003post-19097.html)から拝借。

```
from matplotlib import pyplot as plt

plt.imshow(src)
```

<img width="593" alt="Screen Shot 2019-01-06 at 11.20.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/14097/ad43ba48-0df0-d0ef-598c-4bf8dffd7079.png">

デフォルトの状態では、グリッドが表示される。グリッドを表示したくない場合は、`plt.axis('off')`を指定して非表示にできる。

# OpenCVの機能で加工してみる

```
blurred = cv2.blur(src, (20, 20))
plt.imshow(blurred)
```

`blur`を使って、画像にブラーをかけてみる。

<img width="561" alt="Screen Shot 2019-01-06 at 11.24.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/14097/2c4ff7cc-5ab9-dd36-e441-40abb647754a.png">

上のコードではブラーのサイズを20 x 20にしたが、違う値で試してみよう。

<img width="564" alt="Screen Shot 2019-01-06 at 11.26.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/14097/4afaa778-e837-45c4-8355-8bcfd431a6a8.png">

ブラーのサイズを100 x 100に変更して、左側の「Run Cell」ボタンを押して実行し直してみた。このように、処理の途中でパラメータを変更して再実行、すぐに実行結果を確認できるのはREPLならでは。これは便利。

OpenCVのドキュメントは[ここ](https://docs.opencv.org/3.4/d6/d00/tutorial_py_root.html)

# NumPyを使って画像処理をする

NumPyを使って、ピクセルを直接操作して画像処理してみる。NumPyを使っておくと、あとあと機械学習系のライブラリ(Tensorflowとか)を使って処理をしたくなった時に便利なので、ちょっと試しておこう。

```
import numpy as np

pixels = np.array(src)
pixels = 255 - pixels
plt.imshow(pixels)
```

PythonのOpenCVは内部的にNumPyのndarrayを使っているらしいので、読み込んだデータをそのまま`np.array()`の引数に渡せばピクセルデータのndarrayを生成できる。

NumPy自体の使い方については省略するが、ここでは全てのピクセルのRGB値それぞれに対して255から引くことで色を反転させている。

処理結果はそのまま`plt.imshow`で表示できるから便利だ。

<img width="562" alt="Screen Shot 2019-01-06 at 11.42.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/14097/d4760b28-446b-2e44-f09f-660eccba444b.png">

OpenCVで読み込んだ元データは24bit(uint8 * RGBの3チャンネル)、各チャンネルはuint8になっている。uint8では加工すると精度が落ちてしまうので、floatに変換する。

```
pixels = np.array(src, dtype = 'float32')
```

表示のタイミングで`uint8`の配列に戻してやることを忘れずに。

```
plt.imshow(pixels.astype('uint8'))
```

<img width="570" alt="Screen Shot 2019-01-06 at 12.04.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/14097/bdccbd5b-fd9b-631f-69a5-b11099f108b9.png">


# まとめ
ブラウザ上で、REPL環境で画像処理をできるというのは、実際に試してみるととても快適で良い。