OpenCVで密なオプティカルフローを計算する
オプティカルフロー
動画から密なオプティカルフローの計算を行う.SimpleFlowアルゴリズムによるオプティカルフロー,TV‐L1オプティカルフロー,Farnebackのオプティカルフロー,Broxのオプティカルフロー,Lucas-Kanade法によるオプティカルフロー等によって密なオプティカルフローの計算ができる.
ソースコード
cv::calcOpticalFlow○○メソッドを使うと,呼び出すたびにパラメータを渡さなくてはいけなくて見た目がすっきりしないのと,アルゴリズムによって3チャンネルの画像だったり1チャンネルの画像だったりで面倒.
cv::superress::createOptFlow_○○でDenseOpticalFlowExtクラスのオブジェクトを作れば,そこら辺の面倒な処理を中でやってくれるので楽.以下,ソースコード.色符号化によるオプティカルフローの可視化を行っている.オプティカルフローの計算自体は一行で済むため,色符号化のコードが大部分を占めている.
パラメータを確認したり設定したりしたいときは,以下の記事を参考.
OpenCVでcv::Algorithmのパラメータを表示する - whoopsidaisies's diary
#include <opencv2/opencv.hpp> #include <opencv2/superres/optical_flow.hpp> using namespace cv; using namespace cv::superres; void main() { // 動画ファイルの読み込み VideoCapture capture = VideoCapture("movie.mp4"); // TV-L1アルゴリズムによるオプティカルフロー計算オブジェクトの生成 Ptr<DenseOpticalFlowExt> opticalFlow = superres::createOptFlow_DualTVL1(); // 前のフレームを保存しておく Mat prev; capture >> prev; while (waitKey(1) == -1) { // 現在のフレームを保存 Mat curr; capture >> curr; // オプティカルフローの計算 Mat flowX, flowY; opticalFlow->calc(prev, curr, flowX, flowY); // オプティカルフローの可視化(色符号化) // オプティカルフローを極座標に変換(角度は[deg]) Mat magnitude, angle; cartToPolar(flowX, flowY, magnitude, angle, true); // 色相(H)はオプティカルフローの角度 // 彩度(S)は0~1に正規化したオプティカルフローの大きさ // 明度(V)は1 Mat hsvPlanes[3]; hsvPlanes[0] = angle; normalize(magnitude, magnitude, 0, 1, NORM_MINMAX); // 正規化 hsvPlanes[1] = magnitude; hsvPlanes[2] = Mat::ones(magnitude.size(), CV_32F); // HSVを合成して一枚の画像にする Mat hsv; merge(hsvPlanes, 3, hsv); // HSVからBGRに変換 Mat flowBgr; cvtColor(hsv, flowBgr, cv::COLOR_HSV2BGR); // 表示 cv::imshow("input", curr); cv::imshow("optical flow", flowBgr); // 前のフレームを保存 prev = curr; } }
cv::superress::createOptFlow_○○で使えるアルゴリズム
上記ソースの
Ptr<DenseOpticalFlowExt> opticalFlow = superres::createOptFlow_DualTVL1();
のcreateOptFlow_DualTVL1()を置き換えるだけで,他のアルゴリズムでオプティカルフローを計算できる.以下に,指定できるアルゴリズムをまとめる.
CPU | OpenCL | CUDA | |
---|---|---|---|
SimpleFlow | createOptFlow_Simple | なし | なし |
TV‐L1 | createOptFlow_DualTVL1 | createOptFlow_DualTVL1_OCL | createOptFlow_DualTVL1_GPU |
Farneback | createOptFlow_Farneback | createOptFlow_Farneback_OCL | createOptFlow_Farneback_GPU |
Brox | なし | なし | createOptFlow_Brox_GPU |
LK法 | なし | createOptFlow_PyrLK_OCL | createOptFlow_PyrLK_GPU |
OpenCLやCUDAでの計算ができるものもある.OpenCLおよびCUDAでの計算の場合は少し変更が必要.上記ソースの
opticalFlow->calc(prev, curr, flowX, flowY);
の部分を以下のように書き換える.
OpenCLの場合
ocl::oclMat oclCurr(curr), oclPrev(prev), oclFlowX, oclFlowY; opticalFlow->calc(oclPrev, oclCurr, oclFlowX, oclFlowY); oclFlowX.download(flowX); oclFlowY.download(flowY);
インクルードファイルの追加も必要.
#include <opencv2/ocl/ocl.hpp>
CUDAの場合
gpu::GpuMat gpuCurr(curr), gpuPrev(prev), gpuFlowX, gpuFlowY; opticalFlow->calc(gpuPrev, gpuCurr, gpuFlowX, gpuFlowY); gpuFlowX.download(flowX); gpuFlowY.download(flowY);
インクルードファイルの追加も必要.
#include <opencv2/gpu/gpu.hpp>