画像処理ライブラリによる画像ファイルのnumpy.ndarray変換の速度比較

# 画像ファイルをnumpy.ndarrayに最速で変換したい
　「画像ファイルをnumpy.ndarrayに最速に変換したい」

　漢であれば、誰もが1度はそう夢見たのではないのでしょうか？最速を決める戦いが…今、はじまるッ…！

　全選手入場です!!!!

Intel生まれ！Willow Garage育ち!Intel出戻り!（Itseez経由） 
画像処理界の永遠のデファクトスタンダード!!「Open CV」だ!!!

読み込み・保存・リサイズに特化!! それ以外の全ては置いてきた!!
次世代の最速王子「Lycon」!!!

親殺しが帰ってきた！枕なのか？画像処理ライブラリなのか？
狂気の画像処理ライブラリ！「Pillow」だ！！！

# 「Open CV」「Lycon」「Pillow」「jpeg4py」の速度比較
　すみません、前置きが長くなりました。一回やってみたかっただけです。

　画像ファイルをnumpy.ndarrayに変換するのに、一番速い方法を知りたくて比較してみました。きっかけは、以下の記事をみたことです。

[Day-107 Pythonの高速画像処理ライブラリLyconが速い](https://hyper-pigeon.hatenablog.com/entry/2020/07/22/231055)

　使い方としては、ディープラーニングの学習・推論の高速化を想定しています。

## 速度測定の前提
　比較はGoogle Colaboratory（Google Colab）上で行いました。Google Colab上での利用を想定しているためです。より正確な速度比較は、ローカルPCの方が正確な値となるかと思います。

　Google Colabの使い方に関しては、以下のブログ記事を参照ください。
[Google Colaboratoryを使えば環境構築不要・無料でPythonの機械学習ができて最高](https://karaage.hatenadiary.jp/entry/2018/03/21/073000)

　その他の条件は以下です。

- Jpeg画像をRGB順でnumpy.ndarray形式に変換するまでの比較です。OpenCVの場合はBGRの並びなので、RGBに並び替える時間も含まれます。また、Pillowは単体ではnumpy.ndarrayに変換してくれないので、Numpyの変換の時間を組み合わせています。
- 初期化の関係で1回目だけ時間がかかるライブラリがあるので、1度画像を読み込ませてから別の画像を読み込んだときの時間を測定しています（詳細は後述します）

　使用したPython、ライブラリのバージョンは以下の通りです。

```
python==3.6.9
peg4py==0.1.4
lycon==0.2.0
numpy==1.18.5
opencv-python==4.1.2.30
Pillow==7.0.0
```

　あくまで、自分にとって便利な形式（RGB順のnumpy.ndarray）に変換するのが速いライブラリを知るのが目的なので、純粋な画像処理ライブラリのアルゴリズムによる速度比較では無い点はご了承ください。例えば、PNG形式だとまた結果は大きく変わってきます。

## 速度比較結果
　結果は以下となりました。

![converting_time.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/b75c52ec-719b-0a4f-e7c0-470e5bb11ea8.png)


　測定に使用したGoogle ColabのNotebookは以下です。

[Lycon vs Open CV vs Pillow vs Jpeg4py速度比較](https://colab.research.google.com/drive/19CsglwKfpx65I278dPFKkWt_-JCvoZlo?usp=sharing)

# 使用上の注意点等
## Lyconの注意点
　MacでpipでインストールしたLyconは、何故か画像を読み込んでも「None」になってしまいました。

　何かのバグっぽいですね。以下によるとソースから入れればOKのようです。

[Lycon issues #142](https://github.com/eriklindernoren/PyTorch-YOLOv3/issues/142)

　また、ラズパイでも残念ながらpip3で簡単にはセットアップできませんでした。残念です。

## PillowとPillow-SIMDの比較
　Pillow-SIMD（Pillowを高速化したライブラリ）が速いという話を聞いて、そちらも比較したのですが、結果としてはほとんど速くなりませんでした。画像ファイルを開くところは、PillowとPillow-SIMDでは、ほとんど差がないのではないかと思います（コードでは確認できていないです）。あとNumpyでの変換にもかなり時間がかかっています。

　ただ、KerasのImageDataGeneratorが内部的にPillowを使っていたりするので、ImageDataGeneratorを使ったコードだと、Pillow-SIMDに置き換えるだけで高速化できるようです。

　以下の記事がとても詳しく参考になります。

[Pillow-SIMDを使った画像処理やディープラーニングの高速化の紹介](https://qiita.com/koshian2/items/c26656a565e42093069d)

# jpeg4py
　jpeg4pyというライブラリもあるということをTwitterで教えていただいたので、追加で試してみました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">手元で試したところjpeg4pyがlyconとほぼ同じくらいの速さだった。 <a href="https://t.co/oA4TkJSsNx">https://t.co/oA4TkJSsNx</a> <a href="https://t.co/tp7YrC8BxM">pic.twitter.com/tp7YrC8BxM</a></p>&mdash; かまろ/Camaro (@mlaass1) <a href="https://twitter.com/mlaass1/status/1286936795330961410?ref_src=twsrc%5Etfw">July 25, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

~~試してみましたが、速度は50sとPillowより2倍近く遅かったです。2回目から速くなるので、恐らくキャッシュされているのかなと思います（Pillowも2回目から速くなります）。なので、何度も同じ処理をするような測定の仕方だとまずそうです。ラズパイでも簡単にセットアップできたので、手軽に使えてよさそうだったのですが、残念でした。~~

　測定の仕方がまずかっただけで、Lyconに次いで高速でした。後述します。

## 速度比較の注意点
　Twitterで速度比較に関してアドバイスいただきました。

<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">jpeg4pyのソースをざっと読みましたが、初回呼び出し時にlibjpegturbo関係のロード・初期化をやっています。別に画像単位でキャッシュしているわけではないので、初回を除いて測るので問題ないと思います</p>&mdash; kounoikeが取れなかったんです (@ko_noike) <a href="https://twitter.com/ko_noike/status/1286951759768743942?ref_src=twsrc%5Etfw">July 25, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

　ライブラリ関係のロード・初期化をするため、初回と2回目で速度が変わるライブラリがあるようです。てっきり同じ画像を読み込んでいるから、画像がキャッシュされているのかと思ったのですが、そういうわけではなかったようです（よく考えたら、そりゃそうか）。

　そのため、測定時は初期化用の画像を別に用意し、初期化用画像を読み込んだあと、テスト用の画像を読み込んでいます。

## 続々と現れる最速のライブラリ
　次々と見知らぬライブラリが現れました。比較はそのうちに…

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">tensorflowのimage.decode_imageも入れてほしい、手元で計ったら最速だったので<a href="https://t.co/YuagcdzZ5N">https://t.co/YuagcdzZ5N</a> <a href="https://t.co/KSbsVhBGk8">https://t.co/KSbsVhBGk8</a></p>&mdash; wakame@求職中 (@wakame1367) <a href="https://twitter.com/wakame1367/status/1287035817689354242?ref_src=twsrc%5Etfw">July 25, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">もしGPUを使ってもいいなら是非DALIも比較していただきたい<a href="https://t.co/lCO5Utnfil">https://t.co/lCO5Utnfil</a> <a href="https://t.co/AAaJcbWbs8">https://t.co/AAaJcbWbs8</a></p>&mdash; ひるね (@hirune924) <a href="https://twitter.com/hirune924/status/1287034513025937414?ref_src=twsrc%5Etfw">July 25, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

　すぐ知りたい人は、[@wakame1367](https://twitter.com/wakame1367)さんの以下のベンチマークが参考になると思います。

[wakamezake/imread_benchmark](https://github.com/wakamezake/imread_benchmark)

# まとめ
　画像処理ライブラリによる画像ファイルのnumpy.ndarray変換の比較をしました。「Lycon」は確かに速かったです。推論で最速を目指したり、大量に何度も画像を読み込むケースには使えそうですね。その分、MacとRaspberry Piでpipで簡単にセットアップできない点が残念です。

　Pillow-SIMDは置き換えるだけで高速化できるというのは大きなメリットですね。今回の目的（画像ファイルのnumpy.ndarray変換）では大きな差がありませんでしたが、コードによっては、簡単に高速化ができるのはとても良いと思いました。調べてみた思わぬ収穫でした。

　jpeg4pyは、Lyconに次いで高速ですし、Raspberry Piで手軽に使えるのは良いのですが、jpegしか扱えないのがネックですね。

　というわけで、結論としては適材適所なのですが、MacやRaspberry Piでも手軽に使いたい自分の場合はやっぱりOpen CVかな…

# 関連記事
[AI時代にこそ読みたい画像処理の本](https://karaage.hatenadiary.jp/entry/2020/06/26/073000)

[Google Colaboratoryを便利に使うためのTIPSまとめ](https://karaage.hatenadiary.jp/entry/2018/12/17/073000)

[Pythonで基礎から機械学習まとめ](https://karaage.hatenadiary.jp/machine-learning-study)

# 変更履歴
- 2020/07/28 前提条件を追記
- 2020/07/25 jpeg4pyに関して追記・測定方法を修正