OpenCV3をPython3で動かす。画像データ分析入門の為の下準備。

#はじめに

Pythonを使った画像のハンドリングについての記事となります。
自分自身の勉強と知識の整理という目的で本記事を書きました。技術ブログ投稿は初なので、暖かい目でご容赦いただけると幸いです。

#OpenCV3をインストール

以下の環境で行いました。

```
macOS 10.14.2
Python 3.6.5
anaconda3-5.2.0
Jupyter Notebook
```

（19/01/25 記載）
現状ですと、以下の通りにインストールすると、手取り早いようです。

```
$ pip install opencv-python
```

なお、pyenvによる仮想環境設定については、今回は割愛します。



#OpenCV3の動作確認

まず、正しくOpenCV3がimportされているかどうかを確認します。

```python

import numpy as np
import cv2, matplotlib
import matplotlib.pyplot as plt

print(cv2.__version__)
```

エラーが出ずversion表示されればOKです。


#画像入力と画像表示
まず、今回はjupyterで動かしながら、画像の埋め込み表示を行います。matplotlibを使いますが、以下のおまじないを書きます。

```py
%matplotlib inline
```

次に、画像分野で良く使われているlennaの画像をググって入手し、画像を読み込んで表示します。
RGBへの変換も必要です。

```py
%matplotlib inline
def read_img(name_i):
    img = cv2.imread(name_i)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    return img

# 画像の読み込み
img = read_img('lenna.png')
    
# 画像の表示
plt.imshow(img)
```
![スクリーンショット 2016-12-18 22.46.55.png](https://qiita-image-store.s3.amazonaws.com/0/151217/9f38a431-e28d-2034-299c-e5a6c47a567d.png)

lennaさんが無事に表示されました。

#顔認識と顔座標の検出
引数:画像ファイル名,顔認識の特徴量パス
返り値:画像ファイルから検出された顔画像の配列

で、以下の処理を行います。

・画像入力
・入力画像をグレー画像に変換
・顔認識実行。特徴量のpathを引数から入力。
・検出した顔を囲む矩形を作成し、１枚の画像ずつ、配列へ追加。
・画像に枠を枠を書く
・画像の表示

```py3

def detect_face(img_name , cascade_path):
    #画像入力
    img = read_img(img_name)
    width = img.shape[1]
    height = img.shape[0]
    img = cv2.resize(img , (width , height))

    #入力画像をグレー画像に変換    
    gry = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)

    #顔認識実行。特徴量のpathを引数から入力。
    cascade = cv2.CascadeClassifier(cascade_path)
    
    #minNeighbors=20, minSize=(30, 30)→検出枠が近すぎるのと、小さすぎるのは間引く。
    facerect = cascade.detectMultiScale(gry, scaleFactor=1.05, minNeighbors=20, minSize=(30, 30))
    dst_img = []
    if len(facerect) > 0:
        color = (255, 0, 0)
        for rect in facerect:
            x = rect[0]
            y = rect[1]
            w = rect[2]
            h = rect[3]
            #検出した顔を囲む矩形を作成し、１枚の画像ずつ追加。
            add_image = cv2.resize(img[y : y+h , x : x + w] , (64 , 64))
            dst_img.append(add_image)
            
            #画像に枠を枠を書く
            cv2.rectangle(img, tuple(rect[0:2]),tuple(rect[0:2]+rect[2:4]), color, thickness=2)
        # 画像の表示
        plt.imshow(img)
            
    return dst_img
```

以下、openCVであらかじめ持っている学習済み顔特徴量を指定し、実行。

```py3
cascade_path = '/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml'
res_images = detect_face("lenna.png" ,  cascade_path)
```
![スクリーンショット 2016-12-18 22.47.08.png](https://qiita-image-store.s3.amazonaws.com/0/151217/917ce62f-3758-3b7d-a250-cdd960fe7fb4.png)


lennaさんの顔が赤い枠で囲まれました。

次に、顔検出の画像のみを表示します。今回は1画像から検出顔を１つなので、indexは0番目です。

```py3
plt.imshow(res_images[0])
```
![スクリーンショット 2016-12-18 22.47.17.png](https://qiita-image-store.s3.amazonaws.com/0/151217/762cab08-3959-1e11-606e-a49e5456b232.png)


#1枚の画像から複数顔検出

1枚の画像から複数顔の検出を行う場合です。
画像の引用元は以下になります。
https://www.pakutaso.com/model.html



```py3
res_images = detect_face("sample.png" , cascade_path)
```
![スクリーンショット 2016-12-18 22.47.24.png](https://qiita-image-store.s3.amazonaws.com/0/151217/1a20626f-9d76-2415-cf7a-815d986c3c10.png)
このような実行結果となりました。真正面でないと検出されないようです。

また、複数の画像を保持できているかの確認のため、0番目以外の画像で表示されるかを確認します。今回はindexが1で実行します。

```py3
plt.imshow(res_images[1])
```
![スクリーンショット 2016-12-18 22.47.41.png](https://qiita-image-store.s3.amazonaws.com/0/151217/474372ef-fbf2-fa34-a3c5-e28b9f35558a.png)

#ヒストグラム算出と基本的な統計量の算出
ごく基本な統計量に注目するということで、ヒストグラムを算出します。

```py3
#Green画素のみを抽出し、Green画像でヒストグラム算出
RGB =cv2.split(res_images[1])
Gr = RGB[1]
hist = cv2.calcHist([Gr],[0],None,[256],[0,256])
hist
```

![スクリーンショット 2016-12-18 22.47.59.png](https://qiita-image-store.s3.amazonaws.com/0/151217/7926ef84-2e8f-c11f-881d-19a1ff91ce34.png)
配列でヒストグラムを持つことができます。
次にプロットします。

```py3

plt.plot(hist)
plt.xlim([0,256])
plt.show()
```
![スクリーンショット 2016-12-18 22.48.10.png](https://qiita-image-store.s3.amazonaws.com/0/151217/031c2d11-cfd8-24c5-2729-83011c1023dc.png)

サチっているというか、明るめの画像なので、真面目に分析を行い際には、正規化も必要になるでしょう。

得られたヒストグラムに対して、基本的な統計量を見て見ます。

```py3
print("積算値:", np.sum(hist))
print("最大値:", np.max(hist))
print("最小値:", np.min(hist))
print("平均値:", np.mean(hist))
print("中央値:", np.median(hist))
print("分散値:", np.var(hist))
```

![スクリーンショット 2016-12-18 22.48.17.png](https://qiita-image-store.s3.amazonaws.com/0/151217/8b8567b4-884e-2aaa-8fa3-e5c21e17e1aa.png)


#今回はここで終わりです
OpenCVのちょっとした動作確認も行いつつ、基本的な統計量を算出することまでできました。
統計量だけで考えなくても、世の中に画像特徴量の作成方法はたくさんあります。また、作成した特徴量に対してbag-of-featuresの形式にすれば、特徴量エンジニアリングを行ったことになり、機械学習実践の第一歩を踏み出せるかと思います。実務的なところは、また別の機会で紹介できたらと思います。