OpenCVでDeepFlow

opencv_contribを見てたら,DeepFlowというオプティカルフローのアルゴリズムが実装されていたので勉強ついでに使ってみる.

DeepFlow

DeepFlowはコンピュータビジョンの分野では有名な国際学会ICCV2013でWeinzaepfelらによって発表されたアルゴリズムである.
HAL - INRIA :: [hal-00873592, version 1] DeepFlow: Large displacement optical flow with deep matching

DeepFlowではDeep Matchingという画像のマッチング手法(これも同論文内で提案されている)を用いてオプティカルフローを求めている.

以下の画像にアルゴリズムの全体像がまとめられている.

f:id:whoopsidaisies:20140821140023j:plain

LEAR - DeepMatchingFlow

パワーポイントの資料はこちら

Deep Matching

Deep Matchingでは,畳み込み,プーリング,サブサンプリングを繰り返しすことで,画像間のQuasi-Denseなマッチング(日本語でなんていうかわからない.準密?)を求める.

Deep Learningで注目を集めているConvolutional Neural Networks(CNN)に似たアプローチとなっている.

Deep Matchingを使うと以下のように非剛体のマッチングもうまく出来るようである.

f:id:whoopsidaisies:20140821152916p:plainf:id:whoopsidaisies:20140821152927p:plain

Jerome Revaud

オプティカルフロー

DeepFlowでは,時間的輝度勾配と空間的輝度勾配の拘束条件に加えて,Deep Matchingで求めた対応とオプティカルフローとの差異も拘束条件として目的関数に入れることで,密でかつ大きな動きにも強いオプティカルフローを得るようである.

目的関数の最小化はSOR法という反復法で行っているようである.

DeepFlowで以下の画像みたいな感じにマッチングとオプティカルフローが得られるらしい.

f:id:whoopsidaisies:20140821180059p:plain

LEAR - DeepMatchingFlow

OpenCVで動かしてみる

DeepFlowは2014/8/21現在opencv_contribに入っているが,opencv_contribは開発用リポジトリらしいので自己責任で.

ここからソースを落としてきて,OpenCVのCMakeのオプションで「OPENCV_EXTRA_MODULES_PATH」を「(opencv_contribのパス)/modules」としてgenerate,ビルドしてやるとOpenCVにopencv_contrib内のモジュールが組み込まれる.

実際にDeepFlowを動かしてみたソースコードは以下.
DeepFlowのパラメータはここを参照.

#include <opencv2/opencv.hpp>
#include <opencv2/optflow.hpp>

void main()
{
	using namespace cv;

	// DeepFlow計算用のインスタンスを生成
	auto deepflow = optflow::createOptFlow_DeepFlow();
	// 動画読み込み
	auto capture = VideoCapture("video.mp4");
	
	// 前のフレーム保存
	// まだグレースケールしか対応してないようなので変換
	Mat prev, tmp;
	capture >> tmp;
	cvtColor(tmp, prev, COLOR_RGB2GRAY);

	while (cv::waitKey(1) == -1)
	{
		Mat curr;
		capture >> tmp;
		if (tmp.empty())
			break;
		cvtColor(tmp, curr, COLOR_RGB2GRAY);

		// オプティカルフローの計算
		Mat flow;
		deepflow->calc(prev, curr, flow);

		// 表示するようにX成分とY成分に分解
		Mat flowXY[2];
		split(flow, flowXY);

		// 極座標に変換
		Mat magnitude, angle;
		cartToPolar(flowXY[0], flowXY[1], magnitude, angle, true);

		//  色相(H)はオプティカルフローの角度
		//  彩度(S)は0~1に正規化したオプティカルフローの大きさ
		//  明度(V)は1
		Mat hsvPlanes[3];
		hsvPlanes[0] = angle;
		hsvPlanes[1] = magnitude;
		hsvPlanes[2] = Mat::ones(angle.size(), CV_32F);
		//  HSVを合成して一枚の画像にする
		Mat hsv;
		merge(hsvPlanes, 3, hsv);

		// 表示
		imshow("DeepFlow", hsv);

		// 前のフレームを保存
		prev = curr;
	}
}

結果はこんな感じ.かなり時間かかった.
ちょいちょい真っ赤になるのは仕様なのかバグなのか.


OpenCVでDeepFlow - YouTube