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

More than 1 year has passed since last update.

Pythonで画像を扱う上で便利なライブラリがいくつかありますが、

大体はnumpy配列にしてくれると思います。

基本的に色の形式さえあっていれば相互に変換・比較可能なのでどれを使ってもいいかなと思っています。

今回は読み込み方法やパフォーマンス?を調べたのでメモしておきます。

(画像形式とかのサポート範囲はちゃんと調べられてないです。)

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


PIL

一番お手軽です。

インストールはpip install Pillowで終わりです。


使い方

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

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に上がっているのでそれをインストールして見ます。

追加でlibXext, libSM, libXrenderなどが必要みたいです。

参考:Jupyterでmatplotlibのインポートした時にImportErrorが出た時の対処法

$ pip install opencv-python

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


condaでインストール

anaconda等で環境構築している場合には

インストールはconda install -c menpo opencv3等でインストールできる場合があります。

ただし、pythonバージョンとビット環境等によってはバイナリが上がっていないケースもあるのでその場合は他の方法で。。

対応してそうなプラットフォームはここでわかりそうです。


apt等でinstall or 自分でビルド

自分で好きなバージョンを入れたい場合はこの方法しかないです。

今回は特に触れません。


使い方

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

慣れると使いやすいかなと思います。

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と同じくらいには使いやすいかなと思います。

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の画像の場合の比較です。

スクリーンショット 2017-09-21 14.03.39.png

pillowはndarrayに変換時に時間がかかっていそうですが、きちんとタイプを指定すればskimageと同程度か少し早いくらいでした。

opencvが一番早かったですが、これは単にnumpyの速度かもしれません。

画像サイズを2MBくらいのものにしても結果の傾向は変わりませんでした。

加工も含めたopencvとpillowの比較は誰かがしてくれていました。

PIL vs Opencv

読み込みレベルだとほとんど差がないので、

それ以降の加工内容や使い勝手でライブラリを選定する、のがいいと思います。

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