Raspberry Pi サーボモーターとOpen CVで物体追跡カメラ（Meanshift）

物体追跡カメラをRaspberryPiで作ってみました。Python3系で動きます。指定した枠内に最初に映ったものを追尾します。「青りんご」で試してみます。

![2017-03-14 21_55_34.gif](https://qiita-image-store.s3.amazonaws.com/0/47128/92bfeada-4d12-2160-41a7-236c744efd80.gif)

こんな感じです。ちょっと小動物みたいで可愛いですね。

## 環境

![IMG_9069.JPG](https://qiita-image-store.s3.amazonaws.com/0/47128/6e256d15-831d-499f-0847-c8d0b9bf971c.jpeg)

- Raspberry Pi3 (RASPBIAN JESSIE WITH PIXEL 4.4　/ Python 3.4.2)
- LOGICOOL ウェブカム HD画質 120万画素 C270
- PCA9685 16Channel 12bit PWM（Adafruit 16-Channel Servo Driver互換品）
- SG90サーボ用 2軸 カメラマウント
- 電池ケース 単3×3本用（4.5V）

RaspberryPiのGPIOから直接サーボモーターを制御すると、電圧の変化でショートしてしまうようです。今回はモータドライバーを使い、単４電池３本から本体とは別に電源を取り込んでいます。

Python3系で制御できるので、OpenCVから取り込んだデータをそのまま利用することが出来ました。モーターの制御とOpenCVからデータを取得するのと大きく２つに分けて解説してみたいと思います。


## RaspberryPiでサーボモーターを制御する

以下のモーターシールドを利用してサーボモーターを制御します。半田付けがしてあるので初心者にも安心です。

<a href="https://www.amazon.co.jp/gp/product/B00WBYELB2/ref=as_li_ss_il?ie=UTF8&psc=1&linkCode=li3&tag=pondadamazon-22&linkId=2632da36bf26a1777f23c38a49b0b508" target="_blank"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B00WBYELB2&Format=_SL250_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=pondadamazon-22" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=pondadamazon-22&l=li3&o=9&a=B00WBYELB2" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />

[GPG PCA9685 16Channel 12bit PWM サーボドライバー Arduino等の電子工作用 (Droidfun型)　- Amazon.co.jp](http://amzn.to/2n5rsjF)

Adafruit 16-Channel Servo Driverという比較的ポピュラーなモータードライバの互換機なので、Adafruit社の用意してくれているPythonライブラリがそのまま利用できます。

[adafruit/Adafruit_Python_PCA9685 -GitHub](https://github.com/adafruit/Adafruit_Python_PCA9685)

結構この手のライブラリは２系で書かれたものが多いのですが、3系で動作しましたので助かりました。

[PCA9685.py - Gist](https://gist.github.com/PonDad/b03540a2dbd3d64bb68b89ca2664d908#file-pca9685-py)

[servo_test.py - Gist](https://gist.github.com/PonDad/b03540a2dbd3d64bb68b89ca2664d908#file-servo_test-py)

上記の２ファイルで下記の様に動作します。

![2017-03-14 22_59_23.gif](https://qiita-image-store.s3.amazonaws.com/0/47128/90e38f1d-cb43-ed52-8703-34df230b93c6.gif)

端子の接続は下記写真を参考にして下さい。

![IMG_9074.JPG](https://qiita-image-store.s3.amazonaws.com/0/47128/e3ed1001-3f0c-c0a3-7100-8e4014d282f2.jpeg)

webカメラは既存の台座から外し、ネジでカメラマウントに固定しました。

## OpenCVのMeanshiftで物体検出する

今回は物体検出をするのにOpenCVのMeanshiftというアルゴリズムを利用しました。

[Meanshift と Camshift - OpenCV-Python Tutorials](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_video/py_meanshift/py_meanshift.html)

最初に指定したウインドウの色ヒストグラムを元に、同じ重みを持つ点をスライドしながら検索していくアルゴリズムです。

![Mean Shift Algorithm - YouTube 2017-03-14 23-47-34.png](https://qiita-image-store.s3.amazonaws.com/0/47128/1c356fe8-9a65-bcf1-6f7c-c3093225e46b.png)

[Mean Shift Algorithm -YouTube](https://www.youtube.com/watch?v=nuLYrSZ3fRo)

こちらの動画を見るとなんとなくイメージが湧きました。

サンプルコードを試して見ると、うまく動作したので、物体追跡した中心点に向かってカメラを移動させてみました。

[meanshift.py -Gist](https://gist.github.com/PonDad/b03540a2dbd3d64bb68b89ca2664d908#file-meanshift-py)

サーボモーターの角度は、ニュートラルの角度がx軸475、y軸325。最小角度が150、最大角度が600です。物体の中心点が画面の中心点から離れた距離をOpenCVで算出して、それを元にサーボモーターの角度を変更する様にしてみました。

## ちょっとハマった点とまとめ

カメラマウントをもう少しダイナミックに動かしてみたかったんですが、移動角度が大きくなるとカメラ上の物体認識が大きくぶれてしまいカメラがガクンガクンと大きくぶれてしまいます。

OpenCVの画像を小さめにすることで（320x320ピクセル）今回は対応してみました。

超音波センサーなどのアナログセンサーを使った方が実用的なのかもしれませんね。

ともあれ以前より試してみたかった物がやっと作れたので良しとします。では。

## 参考にさせていただきました

[raspberry pi2 + カメラ付きサーボで特定の色を追っかけるカメラを作る - やったことの説明](http://ksknw.hatenablog.com/entry/2016/02/28/145001)

[Python3 OpenCV3を使って物体検出 - from umentu import stupid](https://www.blog.umentu.work/python3-opencv3%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E7%89%A9%E4%BD%93%E6%A4%9C%E5%87%BA/)