macOS上の scikit-image で画像表示（pyenv/Python 3）

macOSでpyenvを使用してセットアップしたPython環境で[scikit-image](http://scikit-image.org/)を使う場合の話。

scikit-imageで画像表示をしようとするとプラグインとして[matplotlib]()を使わざるを得ない。
macOS上でpyenvでインストールしたPython環境では[matplotlib](http://matplotlib.org/index.html)のbackendを変更しないとエラーが出て動かないので対処方法。  

結論を先に書くと、matplotlibのバックエンドを`TkAgg`か`Qt5Agg`にする（必要なライブラリはインストールする前提）。

## 環境

- macOS Sierra
- Python 3.5 (pyenv)
- scikit-image

### scikit-image のインストール手順

そもそもどうやってインストールしたのかというと下記の手順。

```
$ pip install -U scikit-image
$ pip install scipy
$ pip install matplotlib
```

`pip`は`pyenv`でインストールしたPython 3.5.3のもの。


## やりたいこと

[scikit-image](https://github.com/scikit-image/scikit-image)というライブラリの、`io.show()`で画像を表示したい。


## 問題

何も考えずに`pip`で scikit-image パッケージをインストールすると、下記のエラーに遭遇して画像を表示できない。
`io.show()`を呼び出して画像を表示したいが、その前に`io.imshow()`で表示する画像を割り当てる必要がある。
この時点でRuntimeError。

```
>>> io.imshow(img)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/atuyosi/.pyenv/versions/3.5.3/lib/python3.5/site-packages/skimage/io/_io.py", line 156, in imshow
    return call_plugin('imshow', arr, plugin=plugin, **plugin_args)
  File "/Users/atuyosi/.pyenv/versions/3.5.3/lib/python3.5/site-packages/skimage/io/manage_plugins.py", line 198, in call_plugin
    raise RuntimeError(msg % kind)
RuntimeError: No suitable plugin registered for imshow.

You may load I/O plugins with the `skimage.io.use_plugin` command.  A list of all available plugins are shown in the `skimage.io` docstring.
```

画面表示に利用可能なプラグインがないというメッセージのようなので、まずはプラグインを調べる。

```
>>> io.find_available_plugins()
{'gdal': ['imread', 'imread_collection'], 'imread': ['imread', 'imsave', 'imread_collection'], 'simpleitk': ['imread', 'imsave', 'imread_collection'], 'test': ['imsave', 'imshow', 'imread', 'imread_collection', 'imshow_collection'], 'pil': ['imread', 'imsave', 'imread_collection'], 'matplotlib': ['imshow', 'imread', 'imshow_collection', 'imread_collection'], 'imageio': ['imread', 'imsave', 'imread_collection'], 'qt': ['imshow', 'imsave', 'imread', 'imread_collection'], 'gtk': ['imshow'], 'freeimage': ['imread', 'imsave', 'imread_collection'], 'tifffile': ['imread', 'imsave', 'imread_collection'], 'fits': ['imread', 'imread_collection']}
```

プラグインごとに使用可能な機能がプラグインの名称の後に配列として保持されている。`imshow`に対応しているのは、`test`を覗くと`matplotlib`と、`qt`、`gtk`の3つ。このうち`qt`はPyQt4を要求する。  

インストール済みのMatplotlib を使おうとすると、下記のエラーに遭遇する。

```
>>> io.use_plugin('matplotlib')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/atuyosi/.pyenv/versions/3.5.3/lib/python3.5/site-packages/skimage/io/manage_plugins.py", line 255, in use_plugin
    _load(name)
  File "/Users/atuyosi/.pyenv/versions/3.5.3/lib/python3.5/site-packages/skimage/io/manage_plugins.py", line 299, in _load
    fromlist=[modname])
  File "/Users/atuyosi/.pyenv/versions/3.5.3/lib/python3.5/site-packages/skimage/io/_plugins/matplotlib_plugin.py", line 3, in <module>
    import matplotlib.pyplot as plt
  File "/Users/atuyosi/.pyenv/versions/3.5.3/lib/python3.5/site-packages/matplotlib/pyplot.py", line 115, in <module>
    _backend_mod, new_figure_manager, draw_if_interactive, _show = pylab_setup()
  File "/Users/atuyosi/.pyenv/versions/3.5.3/lib/python3.5/site-packages/matplotlib/backends/__init__.py", line 32, in pylab_setup
    globals(),locals(),[backend_name],0)
  File "/Users/atuyosi/.pyenv/versions/3.5.3/lib/python3.5/site-packages/matplotlib/backends/backend_macosx.py", line 19, in <module>
    from matplotlib.backends import _macosx
RuntimeError: Python is not installed as a framework. The Mac OS X backend will not be able to function correctly if Python is not installed as a framework. See the Python documentation for more information on installing Python as a framework on Mac OS X. Please either reinstall Python as a framework, or try one of the other backends. If you are using (Ana)Conda please install python.app and replace the use of 'python' with 'pythonw'. See 'Working with Matplotlib on OSX' in the Matplotlib FAQ for more information.
```

と言われてmatplotlib側のバックエンド設定の問題で利用できない。Python自体をframework形式でインストールしろと言っているようだがさすがに面倒。

存在するプラグインではなく実際に有効なプラグインを調べる。

```
>>> io.find_available_plugins(loaded=True)
{'pil': ['imread', 'imsave', 'imread_collection']}
```

`pil`というプラグインしか有効になっていない。

## 対処方法

何らかのバックエンドが利用できるようにすれば良い。Qt4自体がサポート切れなのでPyQt4はやめておく。Tkを使ってもいいが、Qt5の方がモダンでいいような気がする。

そこで[PyQt5](https://pypi.python.org/pypi/PyQt5)をインストールし、matplotlib 経由で使うことにする。

まずはQt5本体をインストール。

```
$ brew install qt
```

続いてPyQt5。

```
$ pip install PyQt5
```

PyQt5-5.9 がインストールされる。依存関係で必要なライブラリも勝手に入るはず。

設定ファイルの修正。

matplotlibの設定ファイルの場所は下記の手順で確認できる。

```
>>> import matplotlib
>>> matplotlib.matplotlib_fname()
'/Users/atuyosi/.pyenv/versions/3.5.3/lib/python3.5/site-packages/matplotlib/mpl-data/matplotlibrc'
```
エディタで上記のファイルを編集。

```
$ vi .pyenv/versions/3.5.3/lib/python3.5/site-packages/matplotlib/mpl-data/matplotlibrc
```

バックエンドを指定している箇所を探す。

```修正前
backend      : macosx
```


使用するバックエンドを指定する。

```修正後
backend      : Qt5Agg
```

## 動作確認

ちゃんとプラグインが有効かを確かめる。

```
>>> from skimage import io
>>> io.use_plugin('matplotlib')
>>> io.find_available_plugins(loaded=True)
{'matplotlib': ['imshow', 'imread', 'imshow_collection', 'imread_collection'], 'pil': ['imread', 'imsave', 'imread_collection']}
```

画像の表示は以下のようにする。

```
>>> from skimage import io
>>> img =  io.imread("test.jpg")
>>> io.imshow(img)
<matplotlib.image.AxesImage object at 0x110ba1160>
>>> io.show()
^C
```

`io.imshow() `を呼び出さずに`io.show()`を呼び出しても何も表示されないので注意。

実際の表示は以下のようになる。

scikit-image ライブラリの、`data`モジュールを読み込むとテスト画像が読み込めるのでこれを使う。

```
>>> from skimage import data
>>> io.imshow(data.camera())
<matplotlib.image.AxesImage object at 0x1138707b8>
>>> io.show()
```

![スクリーンショット 2017-09-13 5.00.41.png](https://qiita-image-store.s3.amazonaws.com/0/98220/a60d201d-31c5-50a0-66a6-e8240f481107.png)



プラグインの順序によっては明示的に`matplotlib`を使うように指定すればいい。

```
>>> io.use_plugin('matplotlib')
```



## 参考

- [[短文メモ]matplotlibで、showしても何も表示されない→backend設定を確認 - Qiita](http://qiita.com/gyu-don/items/062fd82e4dd2a9b6dfbb)
- [Python 3.3でmatplitlibとpylabを使おうとしたら RuntimeError: Python is not installed as a frameworkというエラーが発生したときの解決方法 - Qiita](http://qiita.com/katryo/items/918667f28301fdec89ba)
- [matplotlibを使ってみる - abcdefg.....](http://pppurple.hatenablog.com/entry/2016/02/28/213152)