Intel Edison + OpenCVで顔認識

Intel EdisonでOpenCVを用いた顔認識を行う。USBカメラの認識やOpenCVのインストールではまったところがあるので、もし同じようなところで困っている人がいれば役に立つかもしれない。

# 検証環境
* 操作端末

<table>
<tbody>
<tr><td>OS X Yosemite</td><td>10.10.3</td></tr>
<tr><td> Kernel </td><td>Darwin 14.3.0</td></tr>
</tbody>
</table>

* Intel Edison（2015/06/23時点での最新イメージを[ココ](https://software.intel.com/en-us/iot/hardware/edison/downloads)から取得）

<table>
<tbody>
<tr><td>borad</td><td>Arduino Board</td></tr>
<tr><td>hostname</td><td>edison02</td></tr>
<tr><td>/etc/version</td><td>weekly-146</td></tr>
<tr><td>uname -r</td><td>3.10.17-poky-edison+</td></tr>
</tbody>
</table>

# Intel Edisonのセットアップ

```text:モジュールアップデート
root@edison02:~# opkg update
root@edison02:~# opkg upgrade
```

```text:OpenCVセットアップ
root@edison02:~# echo "src/gz all http://repo.opkg.net/edison/repo/all" >> /etc/opkg/base-feeds.conf 
root@edison02:~# echo "src/gz core2-32 http://repo.opkg.net/edison/repo/core2-32" >> /etc/opkg/base-feeds.conf 
root@edison02:~# opkg update

root@edison02:~# opkg install opencv
root@edison02:~# opkg install python-opencv
```

## ストレージ空き容量に対する注意

Edisonに最新イメージを導入すると、/bootパーティションが枯渇した状態になる。

```text:ストレージの使用状況
root@edison02:~# df -h
Filesystem                Size      Used Available Use% Mounted on
/dev/root                 1.4G    485.1M    856.3M  36% /
devtmpfs                479.9M         0    479.9M   0% /dev
tmpfs                   480.2M         0    480.2M   0% /dev/shm
tmpfs                   480.2M    536.0K    479.6M   0% /run
tmpfs                   480.2M         0    480.2M   0% /sys/fs/cgroup
systemd-1                 5.8M      5.3M    460.0K  92% /boot
systemd-1                 1.3G      2.0M      1.3G   0% /home
tmpfs                   480.2M      4.0K    480.2M   0% /tmp
tmpfs                   480.2M         0    480.2M   0% /var/volatile
/dev/mmcblk0p5         1003.0K     19.0K    913.0K   2% /factory
/dev/mmcblk0p10           1.3G      2.0M      1.3G   0% /home
/dev/mmcblk0p7            5.8M      5.3M    460.0K  92% /boot
```

`opkg upgrade` を用いてカーネルやモジュールを一挙に更新すると、upgradeの途中で/bootパーティションがfullになり、カーネルが壊れたりモジュールが不完全になる場合がある。（この現象の追跡に非常に時間が取られた。。。）


>参考
>http://matsup.blogspot.jp/2015/03/intel-edison-opkg-upgrade-windows-usb.html
>https://communities.intel.com/message/270269#270269

もしカーネルが壊れたら、カーネルイメージをflashして初期化し、最初からやり直さなければならなくなる。そのためbase-feeds.confにリポジトリを追加した後は、不用意に `opkg upgrade` をしない方が良い。

# USBカメラの接続

今回はUSBカメラに給電しなければならないため、EdisonをUSBホストモードで動作させる。そのためSW1はDCジャック側（下図の向きからみて左側）に設定し、またJ16経由のUSB給電ではなく、DCジャックからの給電を行う。

![DSC_0202.JPG](https://qiita-image-store.s3.amazonaws.com/0/37648/38854abb-fc3d-efe7-4017-ab784e82f72b.jpeg)

上図のような状態で`lsusb` してUSBカメラが認識されていることを確認する。

```text:USBカメラが認識されていることを確認
root@edison02:~# lsusb
Bus 001 Device 002: ID 046d:0825 Logitech, Inc. Webcam C270
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
```

`lsusb` で下記のようなエラーメッセージが表示された場合、USBがデバイスモードになっているので、SW1の設定を確認すると良い。

```text:デバイスモードの場合
root@edison02:~# lsusb
unable to initialize libusb: -99
```

## DCアダプタ

今回はAV-DSW9という、9V 660mAのDC給電が行えるアダプタを使った。内径2.1φ、外形5.5φ、中心がプラスのDCジャックが、Arduino Boardにうまく適合するようである。

# 顔認識プログラムの作成

今回はOpenCVのHAAR分類器を用いた顔認識のプログラムを、Python2.7.3を用いて作成する。

## 「正面顔」のサンプルの特徴量データを取得

Intel EdisonのリポジトリにあるOpenCVにはサンプルデータが含まれないため、OpenCVが提供している「正面顔」のサンプルの特徴量データをgithubから取得する。

```text:正面顔のHAAR分類器特徴量データ取得
root@edison02:~# wget https://raw.githubusercontent.com/Itseez/opencv/master/data/haarcascades/haarcascade_frontalface_alt.xml --no-check-certificate
```

## Pythonプログラム

以下のPythonプログラムでは、カメラに向いている顔の数を表示する処理を、「スペース」が入力されるまで繰り返し実行する。

※先ほど取得した「正面顔のHAAR分類器特徴量データ」のフルパスをCASCADE_PATHに設定すること

```py:facedetect.py
#! /usr/bin/env python

import cv2
import sys
import thread
from time import localtime, strftime

CASCADE_PATH = "/home/root/haarcascade_frontalface_alt.xml"

def init():
    global faceClassifier
    faceClassifier = cv2.CascadeClassifier(CASCADE_PATH)

def detect():
    while True:
        video = cv2.VideoCapture(0)
        ret, frame = video.read()
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        faces = faceClassifier.detectMultiScale(
            gray,
            scaleFactor=1.1,
            minNeighbors=5,
            minSize=(20, 20)
        )
        now = strftime("%H:%M:%S", localtime())
        print "[%s] %d face(s) detected" % (now, len(faces))
        video.release()

if __name__ == "__main__":
    print "facedetect start"
    init()
    thread.start_new_thread(detect, ())
    while True:
        c = sys.stdin.read(1)
        if c == ' ':
            print "facedetect end"
            sys.exit()
```

# Intel Edisonでの実行結果

上記のpythonプログラムを実行すると、下記のように出力された。Intel Edisonでの顔認識の計算処理には、8秒程度を要するようである。

```text:実行結果
root@edison02:~# ./facedetect.py 
facedetect start
[02:20:01] 0 face(s) detected
[02:20:08] 0 face(s) detected
[02:20:15] 0 face(s) detected
[02:20:23] 3 face(s) detected
[02:20:31] 2 face(s) detected
[02:20:39] 13 face(s) detected
[02:20:47] 2 face(s) detected
[02:20:55] 5 face(s) detected
[02:21:04] 4 face(s) detected
[02:21:11] 0 face(s) detected
 
facedetect end
```

# まとめ

Intel EdisonにOpenCVをインストールし、pythonプログラムから顔認識を行わせることができた。ただし環境のセットアップには落とし穴があるため、注意が必要である。