OpenCV 3（core + contrib）をWindows & Python 3の環境にインストール＆OpenCV 2とOpenCV 3の違い＆簡単な動作チェック

# はじめに
OpenCV(Open Source Computer Vision Library)はBSDライセンスの映像/画像処理ライブラリ集です。画像のフィルタ処理、テンプレートマッチング、物体認識、映像解析、機械学習などのアルゴリズムが多数用意されています。

OpenCVを使った動体追跡の例 (OpenCV Google Summer of Code 2015)
https://www.youtube.com/watch?v=OUbUFn71S4s

pipは、Python 3.3以降からPython標準ライブラリの１つになったPythonのパッケージ管理ツールです。
本ページでは、Python 3.5にOpenCVパッケージとPyNumパッケージのみ追加して、OpenCVを試してみるための環境構築について説明します。

# OpenCVのインストール方法の動向
Anaconda → OpenCV の順にインストールするのが最近の流れのようです。
[簡単にpython3とOpenCV3を導入する](http://qiita.com/sugurunatsuno/items/ce3c0d486bdc93688192)

でも、「Anacondaって巨大だよね。」とか、「Anacondaを入れると、今までのpip環境はどうなるの？」とか、Anacondaを使っていない私の環境に与える影響がよくわからなかったので、pipでOpenCVのインストールを試みてみました。

+ 調査対象の環境
    - Windows 10（Intel Core i5）
    - Python 3.5.1（pythonとpipは予めインストール済み）
    - OpenCV 3.1.0（core + opencv_contrib）

+ 結果
    pipを使た簡単なモジュール追加で、上記環境が問題なく動作しました。

# pipを使ったOpenCV 3.1.0（core + opencv_contrib）のインストール
+ **ダウンロード**  
    リンク（[http://www.lfd.uci.edu/~gohlke/pythonlibs/#opencv](http://www.lfd.uci.edu/~gohlke/pythonlibs/#opencv)） から opencv_python-3.1.0+contrib_opencl-cp35-cp35m-win32.whl をダウンロードします。  
        　      
+ **インストール**  
    pip installコマンドでインストールします。  
    - 32bit版Pythonの場合  
        ```bash
        $ pip install opencv_python-3.1.0+contrib_opencl-cp35-cp35m-win32.whl
        ```  
    - 64bit版Pythonの場合  
        ```bash
        $ pip install opencv_python-3.1.0+contrib_opencl-cp35-cp35m-win_amd64.whl
        ```  
        　      
+ **バージョンを確認**  
    
    ```bash
    $ python
    Python 3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:38:48) [MSC v.1900 32 bit     (Intel)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import cv2
    >>> cv2.__version__
    '3.1.0'
    >>> exit()
    ```
    
+ **OpenCV 3.1.0 の各種サンプル**  
    - ダウンロード  
        OpenCVのGitHubからダウンロードします。  
        [https://github.com/opencv](https://github.com/opencv)  
    - 展開  
        opencv → releases → OpenCV 3.1 → Downloads → opencv-3.1.0.exe → 実行 → 展開フォルダを指定 → Extract  
        サンプル（写真、動画）は、以下に格納されています。  
        opencv\sources\samples\data  
        　  
+ **NumPyのインストール**  
    PythonでOpenCVを使う場合、行列計算/数値計算ライブラリNumPyも必要になることが多いので、あわせてインストール。  
    
    ```bash
    $ conda install numpy
    ```
    　  
+ **Anaconda + opencv_ontrib付きのOpenCV**
    Anacondaにopencv_contrib付きのOpenCVをインストールする方法も参考までに載せておきます。
    Anacondaをインストール後、下記でopencv_contrib付きのOpenCVをインストールすることができます。
    
    > conda install -c https://conda.anaconda.org/menpo opencv3
    
    インストールされたOpenCVのライブラリは以下のディレクトリに展開されています。
    
    > ~/Anaconda3/pkgs/opencv3-3.1.0-py35_0/Library/bin
    
    ディープラーニングのライブラリ（opencv_dnn310.lib）や[ディープフロー](http://lear.inrialpes.fr/src/deepflow/)も可能なオプティカルフローのライブラリ（opencv_optflow310.lib）がインストールされていることが分かります。
    　  
    
+ **OpenCV 3のAPI一覧**
    こちらを参考にしてください。⇒ [OpenCV3のPython API一覧](http://qiita.com/olympic2020/items/83e08082a12beb25ff46)
    
# OpenCV 2.4とOpenCV 3.xの違い

OpenCV 2.4のサンプルプログラムをOpenCV 3.5で動かしてみて気づいた部分がいくつかあるのであげておきます。

+ **cv2.cvがなくなった**
    OpenCV 2.4では、
    
    ```
    import cv2.cv as cv
    ```
    というコードがスクリプトの先頭によく登場していましたが、OpenCV 3.xではなくなったようです。
    これをOpenCV 3.xで書くとこんなエラーがでます。

    ```
    Traceback (most recent call last):
      File "~\sample.py", line 4, in <module>
        import cv2.cv as cv
    ImportError: No module named 'cv2.cv'; 'cv2' is not a package
    ```
    
+ **メソッド名が変更された**
    例えば、OpenCV2.4の`cv2.cv.CV_FOURCC`が、OpenCV3.1では`cv2.VideoWriter_fourcc`に変わっています。

    ```opencv2.4.py
    import cv2.cv as cv
    cv.CV_FOURCC('X', 'V', 'I', 'D')
    ```

    ```opencv3.1.py
    import cv2
    cv2.VideoWriter_fourcc(*'XVID')
    ```

    もし、OpenCV2.xとOpenCV3.xで共通で動作するプログラムにしなければいけない場合は、以下のように自分で同等のメソッドを定義しなければならなりません。
    例）

    ```opencv2.4_3.1.py
    # cv2.cv.CV_FOURCC, cv2.VideoWriter_fourcc
    def cv_fourcc(c1, c2, c3, c4):
        return (ord(c1) & 255) + ((ord(c2) & 255) << 8) + \
            ((ord(c3) & 255) << 16) + ((ord(c4) & 255) << 24)
    
    cv_fourcc('X', 'V', 'I', 'D')
    ```
    もしくは、ビデオのコーデックがプログラム内で決まっている場合は、これでＯＫです。
    
    ```opencv3.1.py
    XVID = 0x44495658
    ````
    他のコーデックについては、こちらの記事にまとめましたので（中ほどの「コーデックの指定方法」の章）、必要な方は参考にしてください。
    [コーデックとFOURCC対応表](http://qiita.com/olympic2020/items/ce00fab38d829965db3b)
    　
+ **非標準ライブラリopencv_contribに移動したメソッドがある**
    代表的なものは、`updateMotionHistory(...)`や`calcGlobalOrientation(...)`でしょうか。
    OpenCV 2.4ではこうでしたが、
    
    ```
    cv2.updateMotionHistory(...)
    cv2.calcGlobalOrientation(...)
    ```

    OpenCV 3.xでは、opencv_contribのmotemplに移動したため、opencv_contribをインストールし以下のように書く必要があります。
    
    ```
    cv2.motempl.updateMotionHistory(...)
    cv2.motempl.calcGlobalOrientation(...)
    ```
    
    OpenCV 2.xのときと同じように、OpenCV 3.xに対して `cv2.updateMotionHistory(...)` と書くと、以下のエラーがでます。
    
    ```
    Traceback (most recent call last):
      File "~\sample.py", line 10, in <module>
        cv2.updateMotionHistory(...)
    AttributeError: module 'cv2' has no attribute 'updateMotionHistory'
    ```

+ **消えた定数がある**
    線や丸を描くときにアンチエイリアスを指定する定数`cv2.CV_AA`がOpenCV 3.xでは定義がなくなりました。`cv2.CV_AA`を指定すると以下のエラーが表示されます。  
    
    ```
    AttributeError: module 'cv2' has no attribute 'CV_AA'
    ```
    アンチエイリアスを指定する場合は、プログラム内で直接、値を定数定義すると、この問題を回避することができます。  
    
    ```
    CV_AA = 16
    ```  
    
    また、πの値を格納した定数`cv2.CV_PI`もOpenCV 3.xでは定義がなくなりました。`cv2.CV_PI`を指定すると以下のエラーが表示されます。
    
    ```
    AttributeError: module 'cv2' has no attribute 'CV_PI'
    ```
    OpenCVで定数πといえば、「度 → ラジアン」、「ラジアン → 度」といった角度の変換でよく使用すると思います。
    実は、Pythonは、これらの定数や変換メソッドを標準ライブラリで提供しています。OpenCVの定数πではなく、Pythonが標準で提供している定数πを利用すれば、OpenCV 3.xで定数πの定義がなくなった問題を回避することができます。
    
    ```
    import math
    # 定数π : 3.141592653589793
    math.pi
    # 度 → ラジアン 変換
    math.radians([deg])
    # ラジアン → 度 変換
    math.degrees([rad])
    ```
    
+ **バグで動作しないメソッドがある**
    OpenCV 2では動作していたメソッドが、OpenCV 3に移行する際にバグで動作しなくなってしまっているケースがありました。
    顔認識で使うcv2.faceモジュールのFaceRecognizerのpredict()メソッドが、この記事を書いている時点の最新正式版（opencv_contrib ver.3.1.0 2015/12/18 Release）では動作しませんでした。
    実行するとpredict()メソッドの行で以下のエラーがでます。
    > TypeError: 'int' object is not iterable
    
    2016/4/21に修正がGitHubにコミットされましたので、最新のソースコードをGitHubからダウンロードし、自分でコンパイルしなければならないようです。
    - バグを指摘している質問サイト
        （[リンク](https://www.reddit.com/r/opencv/comments/47ar09/python_face_recognition_typeerror_int_object_is/?st=is37n6vt&sh=6e50dfc7)）   
    - 解決方法を書いたサイト
        （[リンク](http://answers.opencv.org/question/82294/cant-get-predict-confidence/)）  
    - 2016/4/21にGitHubに入った修正
        （[リンク](https://github.com/opencv/opencv_contrib/commit/48903ef96d37ae2b9716268e0975943fe83c194f)）   
    - Repository for OpenCV's extra modules
        （[リンク](https://github.com/opencv/opencv_contrib)）   
        
+ **チュートリアルが動作しない**
    - OpenCV 3 for Pythonのチュートリアル（[リンク](http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_tutorials.html)）
        OpenCV 3 for Pythonのチュートリアルは、OpenCV 2のままになっています。
        動作しないのでみんな困っていますが、放置されたままです。
        例えば、特徴量マッチングのチュートリアル。
        http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_feature2d/py_matcher/py_matcher.html
        FLANN based Matcherのサンプルを実行してみると下記の行でエラーが発生します。
        
        > matches = flann.knnMatch(des1,des2,k=2)
        > 
        > \# 以下のエラー発生
        > \# error: C:\dev\opencv-3.1.0\modules\python\src2\cv2.cpp:163: error: (-215) The data should normally be NULL! in function NumpyAllocator::allocate
        

# OpenCV 3の簡単な動作チェック

OpenCV 3でカラー画像をグレースケールに変換するプログラムを作成してみます。

```readImage.py
import cv2

filename = "sample.png"
img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE)
cv2.imshow('window title', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
```

imread(filename, flags)の第１引数にはファイル名を指定します。
対応しているファイルフォーマットは以下になります。


| フォーマット              | 拡張子         |
|:-------------------------|:--------------|
|Windowsビットマップ        |BMP, DIB       |
|JPEG                      |JPEG, JPG, JPE |
|JPEG 2000                 |JP2            |
|Portable Network Graphics |PNG            |
|TIFF                      |TIFF, TIF      |
|Portable Anymap Format    |PBM, PGM, PPM  |
|Sunラスタ形式              |SR, RAS        |

imread(filename, flags)の第２引数は以下から選択します。

| 定数               | 値 | 意味                    |
|:-------------------|:--|:------------------------|
|cv2.IMREAD_UNCHANGED|-1 |無変換（αチャネルも保持）  |
|cv2.IMREAD_GRAYSCALE|0  |グレー（8bit １チャンネル）|
|cv2.IMREAD_COLOR    |1  |カラー（8bit ３チャンネル）|
|cv2.IMREAD_ANYDEPTH |2  |任意の深度                |
|cv2.IMREAD_ANYCOLOR |3  |任意のカラー              |

今回は、カラー→グレー 変換をするので、`cv2.IMREAD_GRAYSCALE` を選択します。

imshow()の第１引数は、ウィンドウのタイトルを指定します。

![sample.png](https://qiita-image-store.s3.amazonaws.com/0/107056/2e723fda-2244-e0d8-dfb7-79da16c9791c.png)
**元画像（カラー）：sample.png**

スクリプトを実行すると、カラー → 白黒変換 された画像が別ウィンドウに表示されます。
ウィンドウがアクティブな状態（フォーカスがあたった状態）で何かキーを押すとウィンドウが閉じてスクリプトが終了します。

![Gray.png](https://qiita-image-store.s3.amazonaws.com/0/107056/90d23f20-84ae-949f-0435-a7c3d844fec3.png)
**グレースケール化した画像**

Anacondaをインストールしませんでしたが、既にpipがインストールされている場合は、pipを使った簡単なモジュール追加で、OpenCVが動作するようです。また、python3で問題はないようです。

# イメージの中身を見てみる
OpenCVでは、画像をNumpyライブラリのnumpy.ndarray（N-dimensional array）という単位で扱います。
Python標準のリストは、内部で要素をリストでつないでいますが、ndarrayはC言語の配列のように固定長なため、以下のような違いがあります。
+ 大量のデータを効率的に扱うことができます。
+ 配列内の要素はすべて同じデータ型である必要があります。
+ 各次元ごとの要素数が等しくなくてはなりません。
+ 配列長を変更する場合は元の配列を削除して新しく配列を作り直します。

それでは、下記のような５×２ピクセルの画像がndarrayではどのようになるのか見てみます。

![color_l.png](https://qiita-image-store.s3.amazonaws.com/0/107056/78d404c3-00c0-f961-c997-956795507f26.png)
**カラー画像**

```ndarray.py
import cv2

filename_c = "color.png"
array_c = cv2.imread(filename_c, cv2.IMREAD_COLOR)
print("===== color image array =====")
print(array_c)

print("")

filename_g = "gray.png"
array_g = cv2.imread(filename_g, cv2.IMREAD_GRAYSCALE)
print("===== gray image array =====")
print(array_g)
```

```bash
===== color image array =====
[[[ 36  28 237]
  [  0   0   0]
  [ 36  28 237]
  [255 255 255]
  [ 76 177  34]]

 [[ 76 177  34]
  [204  72  63]
  [127 127 127]
  [204  72  63]
  [ 36  28 237]]]
```

OpenCVでは、BGRの順にピクセルデータが格納されます。Webの世界ではRGBの順が標準なので注意が必要です。なぜRGBではなくBGRなのかは、こちらの[リンク](http://www.learnopencv.com/why-does-opencv-use-bgr-color-format/)を参照してください。

![color_gry.png](https://qiita-image-store.s3.amazonaws.com/0/107056/f83548ab-9811-0109-681d-f745d480d6d1.png)
**グレー画像**

```bash
===== gray image array =====
[[138   0 138 255 142]
 [142  98 127  98 138]]
```

カラー画像は３次元、グレー画像は２次元の配列になっていることが分かります。

# 参考情報
下記、チュートリアルを参考にしました。
[OpenCV本家](http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_gui/py_table_of_contents_gui/py_table_of_contents_gui.html)
[Qiita日本語訳](http://qiita.com/nonbiri15/items/facf9e6cf4f73cb69d9b)

★ matplotlib をインストールしたい場合は、やはり Anaconda がおすすめです。

# つづく
次は、画像のエッジを検出してみます。
[http://qiita.com/olympic2020/items/2c3a2bfefe73ab5c86a4](http://qiita.com/olympic2020/items/2c3a2bfefe73ab5c86a4)