はじめに
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