はじめに
OpenCV3にDeep Flow[1]というDeep Learningでオプティカルフローを推定するアルゴリズムが実装さてたので,試してみました.
このDeep Flowは,opencv_contribにしか入っていないので,使用するにはopencv_contribを含むビルドが必要です.
サクッと試してみただけなので,コード載せるだけで特にアルゴリズムの説明とかありません.
使用したデータセットは,KTH Human Action Datasetです.
ソースコード
作成したソースコードは,KTHのデータセットの一つの動画を読み込んで,Deep Flowを計算し,
フローの結果をHSV変換して表示するプログラムです.
#define USE_CUDA 0
の部分の0を1にするとCUDA使用の「Dual TV L1」という別のアルゴリズムが試せます(ちょっとCUDA使ってみたかっただけ).
#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;
}
出力結果
フローをHSVで表現していて,色がフローの方向を示し,色の彩度が移動量を示しています.
参考サイトリンク
[1]Deep Flow
[2]OpenCVでDeepFlow
