Pythonの画像読み込み: PIL, OpenCV, scikit-image

Pythonで画像を扱う上で便利なライブラリがいくつかありますが、
大体はnumpy配列にしてくれると思います。
基本的に色の形式さえあっていれば相互に変換・比較可能なのでどれを使ってもいいかなと思っています。

今回は読み込み方法やパフォーマンス？を調べたのでメモしておきます。
(画像形式とかのサポート範囲はちゃんと調べられてないです。)

今回調べたのは以下のライブラリです。

- [PIL(Pillow)](https://pillow.readthedocs.io)
- [OpenCV](http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_setup/py_intro/py_intro.html)
- [scikit-image](http://scikit-image.org/)

## PIL

一番お手軽です。
インストールは`pip install Pillow`で終わりです。

### 使い方
Python image libraryと言うだけあって、使いやすいです。

```py
from PIL import Image
from io import BytesIO 

filename = 'image.png'

# 画像ファイルパスから読み込み
img = Image.open(filename)

# バイナリから読み込み(python3なのでbinaryモードで読み込み)
with open(filename, 'rb') as f:
    binary = f.read()
img = Image.open(BytesIO(data))

# numpy配列の取得
img_array = np.asarray(img)

# 色の変換も簡単ですが、できる色が制限されます。
print(img.mode) # RGBA
rgb = img.convert('RGB')
```


## OpenCV

インストールが一番面倒です。環境によって異なります。
### pipでインストール
wheel対応のパッケージが[pypiにunofficialに上がっている](https://pypi.python.org/pypi/opencv-python)のでそれをインストールして見ます。
追加でlibXext, libSM, libXrenderなどが必要みたいです。
参考:[Jupyterでmatplotlibのインポートした時にImportErrorが出た時の対処法](https://qiita.com/iamdaisuke/items/b25af3db3507752f9fd0)

```shell-session
$ pip install opencv-python
// ない場合は追加でインストールが必要です。以下はubuntu/debian等の場合
$ apt install libsm6 libxrender1 libxext6
```

### condaでインストール
anaconda等で環境構築している場合には
インストールは` conda install -c menpo opencv3`等でインストールできる場合があります。
ただし、pythonバージョンとビット環境等によってはバイナリが上がっていないケースもあるのでその場合は他の方法で。。
対応してそうなプラットフォームは[ここ](https://anaconda.org/menpo/opencv3/files)でわかりそうです。

### apt等でinstall or 自分でビルド
自分で好きなバージョンを入れたい場合はこの方法しかないです。
今回は特に触れません。

### 使い方

基本的にcの関数をバインドして呼んでいる？ので呼び方があまりpythonぽくないことも多いです。
慣れると使いやすいかなと思います。

```py
import cv2

filename = 'image.png'

# 画像ファイルパスから読み込み
img = cv2.imread(filename)

# バイナリから読み込み(python3なのでbinaryモードで読み込み)
with open(filename, 'rb') as f:
    binary = f.read()
# 一度ndarrayに変換してからdecodeします。reshapeだけしてると思われます.
arr = np.asarray(bytearray(binary), dtype=np.uint8)
img = cv2.imdecode(arr, -1)  # 'load it as it is'

# numpy配列の取得、インスタンス自体がndarrayです
type(img) # numpy.ndarray

# デフォルトの色がBGR。
# 色の変換は充実。ただし指定のチェックは甘い(間違えて指定しても普通に変換される)
rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
```


## Scikit-image

これもインストールはPILと同じに簡単です。
インストールは`pip install scikit-image`で終わりです。

### 使い方

PILと同じくらいには使いやすいかなと思います。

```py
from skimage import io, color
from io import BytesIO

filename = 'image.png'

# 画像ファイルパスから読み込み
img = io.imread(filename)

# バイナリから読み込み(python3なのでbinaryモードで読み込み)
with open(filename, 'rb') as f:
    binary = f.read()
img = io.imread(BytesIO(data))

# numpy配列の取得、インスタンス自体がndarrayです
type(img) # numpy.ndarray

# デフォルトの色はRGB/RGBAです
# 色の変換も充実しています。割とチェックもされる印象
rgb = color.rgba2rgb(img)
lab = color.rgb2lab(rgb)
```
# まとめ

## 速度
気になる速度は
opencv > pillow == skimage
でした。

38KBの画像の場合の比較です。
<img width="533" alt="スクリーンショット 2017-09-21 14.03.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/42594/5c3d0c69-af5a-f0ac-0fa9-0e6f1a3d7175.png">

pillowはndarrayに変換時に時間がかかっていそうですが、きちんとタイプを指定すればskimageと同程度か少し早いくらいでした。
opencvが一番早かったですが、これは単にnumpyの速度かもしれません。
画像サイズを2MBくらいのものにしても結果の傾向は変わりませんでした。

加工も含めたopencvとpillowの比較は誰かがしてくれていました。
[PIL vs Opencv](https://www.kaggle.com/vfdev5/pil-vs-opencv/notebook)

読み込みレベルだとほとんど差がないので、
それ以降の加工内容や使い勝手でライブラリを選定する、のがいいと思います。

個人的にはPyData公認のscikit-imageが好きですね。