Deep Flow試してみたよ【OpenCV3】

# はじめに

OpenCV3にDeep Flow[[1]](https://thoth.inrialpes.fr/src/deepflow/)というDeep Learningでオプティカルフローを推定するアルゴリズムが実装さてたので，試してみました．
このDeep Flowは，[opencv_contrib](https://github.com/opencv/opencv_contrib)にしか入っていないので，使用するにはopencv_contribを含むビルドが必要です．
サクッと試してみただけなので，コード載せるだけで特にアルゴリズムの説明とかありません．

使用したデータセットは，[KTH Human Action Dataset](http://www.nada.kth.se/cvap/actions/)です．

# ソースコード

作成したソースコードは，KTHのデータセットの一つの動画を読み込んで，Deep Flowを計算し，
フローの結果をHSV変換して表示するプログラムです．

```cpp
#define USE_CUDA 0
```
の部分の0を1にするとCUDA使用の「[Dual TV L1](http://www.ipol.im/pub/art/2013/26/)」という別のアルゴリズムが試せます（ちょっとCUDA使ってみたかっただけ）．



```cpp
#include<iostream>
#include<vector>
//自作のOpenCVヘッダ
#include"opencv320.h"

#define USE_CUDA 0 //0:Deep Flow 1:TVL1

using namespace cv;
using namespace std;


int main() 
{
	// 動画読み込み
	cv::VideoCapture cap("person22_jogging_d3_uncomp.avi");
	if (!cap.isOpened()) { return -1; }

	//オプティカルフローの初期化
#if USE_CUDA
	cv::Ptr<cv::cuda::OpticalFlowDual_TVL1> opt = cv::cuda::OpticalFlowDual_TVL1::create();
#else
	cv::Ptr<cv::DenseOpticalFlow> opt = cv::optflow::createOptFlow_DeepFlow();
#endif

	//グレースケール変換
	cv::Mat bimg,gbimg;
	cap >> bimg;
	cv::cvtColor(bimg, gbimg, cv::COLOR_BGR2GRAY);

	//動画保存準備
	cv::Size video_size = cv::Size(bimg.cols + bimg.cols,bimg.rows);
	cv::VideoWriter writer("sample.mp4", cv::VideoWriter::fourcc('m', 'p', '4', 'v'), 25.0, video_size);

	//実行
	while (true) {
		//フレーム読み込み，グレースケール変換
		cv::Mat img,gimg;
		cap >> img;
		if (img.empty()) { break; }
		cv::cvtColor(img, gimg, cv::COLOR_BGR2GRAY);

		//フローの計算
#if USE_CUDA
		cv::cuda::GpuMat ggbimg;
		cv::cuda::GpuMat ggimg;
		ggbimg.upload(gbimg);
		ggimg.upload(gimg);

		cv::cuda::GpuMat flow;
		opt->calc(ggimg, ggbimg,flow);

		cv::Mat nflow;
		flow.download(nflow);
#else
		cv::Mat nflow;
		opt->calc(gimg, gbimg, nflow);
#endif

		//描画用の変換
		std::vector<cv::Mat> vflow;
		cv::split(nflow, vflow);

		cv::Mat magnitude, angle;
		cv::cartToPolar(vflow[0], vflow[1], magnitude, angle, true);

		cv::Mat hsvPlanes[3];
		hsvPlanes[0] = angle;
		normalize(magnitude, magnitude, 0.0, 1.0, cv::NORM_MINMAX); // 正規化
		hsvPlanes[1] = magnitude;
		hsvPlanes[2] = cv::Mat::ones(magnitude.size(), CV_32F);
		
		//HSVを合成して一枚の画像にする
		cv::Mat hsv;
		merge(hsvPlanes, 3, hsv);
		
		//HSVからBGRに変換
		cv::Mat buf,flowBgr;
		cv::cvtColor(hsv, buf, cv::COLOR_HSV2BGR);
		buf *= 255.0;
		buf.convertTo(flowBgr, CV_8UC3);

		//	2つの画像を横に並べた大きさのMat型を作成する
		Mat base = cv::Mat::zeros(video_size, CV_8UC3);
		
		//	img1を張り付ける領域をあらわすMat型を作成する
		Mat roi1(base, Rect(0, 0, img.cols, img.rows));
		//	img1をroi1にコピーする
		img.copyTo(roi1);
		//	img2を張り付ける領域をあらわすMat型を作成する
		Mat roi2(base, Rect(img.cols, 0, flowBgr.cols, flowBgr.rows));
		//	img2をroi2にコピーする
		flowBgr.copyTo(roi2);

		cv::imshow("Match", base);

		writer << base;

		if (cv::waitKey(25) == 27) { //Escで終了
			break;
		}

		gbimg = gimg;  //前フレームをコピー
	}

	return 0;
}
```

# 出力結果

フローをＨＳＶで表現していて，色がフローの方向を示し，色の彩度が移動量を示しています．

![Match.png](https://qiita-image-store.s3.amazonaws.com/0/104675/cd08ed3b-9c7d-3a58-b9e8-675518f42617.png)


# 参考サイトリンク

[1][Deep Flow](https://thoth.inrialpes.fr/src/deepflow/)
[2][OpenCVでDeepFlow](http://whoopsidaisies.hatenablog.com/entry/2014/08/21/221642)