Visual Studio 2017とOpenCVでカラートラッキング

#きっかけ
視線計測の装置SteelSeries Sentry Gaming Eye Trackerを買った．
けれど座標とかの取得方法がわからない．
そこで動画からのカラートラッキングで座標を取得する．

**元動画．**紅い丸を追跡させたい．
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">カラートラッキング元動画 <a href="https://t.co/phxVS7KdfO">pic.twitter.com/phxVS7KdfO</a></p>&mdash; 640 (@640Qiita) <a href="https://twitter.com/640Qiita/status/943338811823742978?ref_src=twsrc%5Etfw">2017年12月20日</a></blockquote>
#環境
- Windows 8.1
- Visual Studio Community 2017 (Version 15.5.1)
- OpenCV 3.3.1
- C++

#Visual Studio 2017でOpenCVを使う
三つの導入方法があるらしい．

- CMakeでライブラリをビルドする方法
- NuGet（パッケージ管理システム）を使った方法
- 公式パッケージを使った方法

CMakeは面倒くさそう．
NuGetが楽らしいけど，僕の環境ではうまくいかなかったので公式パッケージを使う．
（追記：どうやらNuGetでとってきたパッケージopencv3はVisual Studio 2017には対応してなかったよう．VS2017で使うならopencv.win.native 一択らしい．[OpenCVのNuGetパッケージまとめ（2017年版）](https://qiita.com/dandelion1124/items/89445b54bf9f4e00c8e5)）

##公式パッケージのダウンロード
[OpenCVの配布サイト](https://opencv.org/releases.html)からOpenCV 3.3.1のWin Packをダウンロード．
opencv-3.3.1-vc14.exeがダウンロードされるので実行して，場所を指定して展開する（今回はC:¥に指定）．

![opencv-3.3.1-vc14.exeの実行](https://qiita-image-store.s3.amazonaws.com/0/224844/842db2c6-845f-c734-21b2-a2b7ec01fcca.png)

##Visual Studio 2017での設定

###空のプロジェクトの作成
空のプロジェクトを作成しようと思ったらそんな項目が見つからない．
どうやらVisual Studio 2017 Update 3 から「Win32」の項目がなくなり，代わりに「Windowsデスクトップ」 が追加されたよう．
（参考：[Visual Studio 2017 Update 3 で Win32 プロジェクトが作成できなくなった時の対処法](https://qiita.com/sasakenotolab/items/9fe86626d206ce4d6668)）

そこで「Windowsデスクトップ」の「Windowsデスクトップウィザード」を選択し，プロジェクトの名前と保存場所を指定して「OK」をクリックする．
![visualstudio.PNG](https://qiita-image-store.s3.amazonaws.com/0/224844/086eb58f-0576-779b-7e8e-d6a896e6c2ce.png)
「Windows デスクトップ プロジェクト」というダイアログが現れるので，「空のプロジェクト」にチェックを入れ，他のチェックボックスのチェックを外し，「OK」をクリックする．
![visualstudio2.PNG](https://qiita-image-store.s3.amazonaws.com/0/224844/9ecd646b-7b01-beb7-5e23-87cebd4fd1c7.png)

###ディレクトリ，リンカー，PATHの設定
プロジェクトを作るたびにプロジェクトのプロパティを開いて毎回設定しなければならない．
（参考：[Visual Studio 2017 + OpenCV 3.2.0 + x64の初期設定](http://phst.hateblo.jp/entry/2016/11/30/081749)）
![プロジェクトのプロパティ](https://qiita-image-store.s3.amazonaws.com/0/224844/636598b9-65a2-d65c-3f23-bade438f6630.png)

**ディレクトリの設定**
「VC++ディレクトリ > インクルードディレクトリ」に以下を追加．

- C:\opencv\build\include

「VC++ディレクトリ > ライブラリディレクトリ」に以下を追加．

- C:\opencv\build\x64\vc14\lib

ただし，OpenCVを展開した場所を指定することに注意．

**リンカーの設定**
「リンカー > 入力 > 追加の依存ファイル」に以下を追加．

- opencv_world331.lib
- opencv_world331d.lib

ただし，331の数字はOpenCVのバージョンに合わせて変えることに注意．

**PATHの設定**
「構成プロパティ > デバッグ > 環境」に以下を追加．

- PATH=C:\opencv\build\x64\vc14\bin;%PATH%

ただし，OpenCVを展開した場所を指定することに注意．

#カラートラッキング
ここまででOpenCVをVisual Studioで使う準備はできたので，早速カラートラッキングのコードを書く．
「プロジェクト > 新しい項目の追加」でC++ファイルを追加する．
動画ファイルは追加したC++ファイルと同じ場所に置く．

カラートラッキングの方針は以下の通り．

1. 動画を読み込み，フレームごとに画像として切り出す．（cap >> image）
1. 画像をRGBからHSVに変換．（cvtColor(image, hsv, CV_BGR2HSV)）
1. カラートラッキングしたい対象のHSV値がギリギリ含まれるHSVの範囲を指定し，その範囲に入っている画素を白，範囲外の画素を黒で表す．（inRange関数で2値化）
1. 白の領域の重心を求めて座標を取得．（moments(hsv, false)）
1. 元の画像にも重心位置を表示させる．

```c++:main.cpp
#include "opencv2/video/tracking.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"

#include <iostream>

using namespace cv;
using namespace std;


int main(int argc, const char** argv){

	VideoCapture cap;
	cap.open("test.mp4");
	namedWindow("ColorTracking", 0);

	Mat image,hsv,mask;

	for (;;){

		//動画からフレームごとに画像の切り出し
		cap >> image;
		if (image.empty())	break;
		
		//RGBからHSVへの変換
		cvtColor(image, hsv, COLOR_BGR2HSV);

		//HSV値の下限と上限を設定し，範囲内と範囲外で画素の2値化
		inRange(hsv, Scalar(0, 230, 230), Scalar(10, 255, 255), mask);

		//重心を求める
		Moments mu = moments(mask, false);
		Point2d mc = Point2d(mu.m10/mu.m00, mu.m01/mu.m00);
		
		//重心を描画
		circle(image, mc, 4, Scalar(100), 2, 4);
		
		//重心の出力
		cout << mc.x << "," << mc.y << endl;
		
		//画像の表示
		imshow("ColorTracking", image);
		waitKey(10);
	}
	return 0;
}
```
##カラートラッキング結果
**元動画．**紅い丸を追跡させる．
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">カラートラッキング元動画 <a href="https://t.co/phxVS7KdfO">pic.twitter.com/phxVS7KdfO</a></p>&mdash; 640 (@640Qiita) <a href="https://twitter.com/640Qiita/status/943338811823742978?ref_src=twsrc%5Etfw">2017年12月20日</a></blockquote>
**2値化の動画**（mask）．
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">カラートラッキング2値化動画 <a href="https://t.co/GxwaEdOcqE">pic.twitter.com/GxwaEdOcqE</a></p>&mdash; 640 (@640Qiita) <a href="https://twitter.com/640Qiita/status/943366992722923521?ref_src=twsrc%5Etfw">2017年12月20日</a></blockquote>
**結果．**紅い丸の中に重心を表示している（点が小さいな）．
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">カラートラッキング　結果 <a href="https://t.co/IJVUSQQMcF">pic.twitter.com/IJVUSQQMcF</a></p>&mdash; 640 (@640Qiita) <a href="https://twitter.com/640Qiita/status/943367325155131393?ref_src=twsrc%5Etfw">2017年12月20日</a></blockquote>

座標はコンソールに出力される．ファイルに吐き出したければfstreamなどを使う．
![コンソール画面](https://qiita-image-store.s3.amazonaws.com/0/224844/05b34014-ae88-6da6-e007-9e0a0c4f057e.png)

今回用いた動画は，カラートラッキングしたい対象と色の近いものがバックグラウンドにほぼないため，HSV値の上限値，下限値を雑にとっている．
近い色がある場合はその画素も重心の計算に入れてしまうため，よりギリギリの値をとる必要がある．
HSV値の範囲はOpenCVでは以下のように定義されているので，トラッキングしたい対象のカラーに合わせてスケールする．

- Hue(色相)：0～180
- Saturation(彩度)：0～255
- Value(明度)：0～255


［参考サイト］
[Webカメラでカラートラッキング―画像処理速報(改二)](http://opencv.blog.jp/cpp/color_tracking)
[色情報を取り出すプログラムを書こう―OpenCVで遊ぼう!](https://reiji1020.gitbooks.io/play-opencv/content/pickupcolor.html)
[厳密な重心の求め方―OpenCV画像解析入門](http://www.cellstat.net/centroid/)