Commit 1c9e2374 authored by tsenst's avatar tsenst Committed by Alexander Alekhin

Merge pull request #1940 from tsenst:add_robust_optical_flow_implementation

Add robust local optical flow (RLOF) implementations (#1940)

* Add robust local optical flow (RLOF) implementations which is an improved pyramidal iterative Lucas-Kanade approach. This implementations contains interfaces for sparse optical flow for feature tracking and dense optical flow based on sparse-to-dense interpolation schemes.
Add performance and accuracy tests have been implementation as well as documentation with the related publications

* - exchange tabs with spaces
- fix optflow.bib indentation
- remove optflow_o.hpp
- change RLOFOpticalFlowParameter interfaces to Ptr<RLOFOpticalFlowParameter>
to remove error on building. Fix warnings

* introducing precompiler flag RLOD_SSE

* remove header that could not be found

* remove whitespaces
fix perf and accuracy tests

* remove x86intrin.h header

* fix ios and arm by removing last sse commands

* fix warnings for windows compilation

* fix documentation RLOFOpticalFlowParameter

* integrate cast to remove last warnings

* * add create method and function inferfaces to RLOFOpticalFlowParamter to enable python wrapper interfaces

* white space fixes / coding style

* fix perf test

* other changes: precomp.hpp / static

* use Matx44f and Vec4f instead of Mat

* normSigmas into constants

* replace ceil() calls

* maximum level is set to 5 so that it is similar value used in the papers

* implement paralellized horizontal cross segmentation as used in Geistert2016

* drop dead code

* Avoid using "data" and "step" calculations. Use .ptr<mat_type>(row, col) instead.

* Avoid using "data" and "step" calculations. Use .ptr<mat_type>(row, col) instead.

* bugfix on BEPLK with ica and adapt the accuracy tests

* more 'static' functions

* bugfix after changing ptr + step to .ptr(y,x) calls by adjusting ROI of
prevImage, currImage and derivI as well as changing the offset of the
points in the invoker classes.

* add some static_cast to avoid warning

* remove 50 grid size sample from perf test. This grid size is to sparse
for the epic interpolation

* remove notSameColor function since it is not used anymore
parent b1e9dd54
set(the_description "Optical Flow Algorithms")
ocv_define_module(optflow opencv_core opencv_imgproc opencv_video opencv_ximgproc opencv_imgcodecs opencv_flann WRAP python)
ocv_define_module(optflow opencv_core opencv_imgproc opencv_calib3d opencv_video opencv_ximgproc opencv_imgcodecs opencv_flann WRAP python)
......@@ -61,3 +61,52 @@
month = {June},
year = {2016}
}
@inproceedings{Geistert2016,
author = {Jonas Geistert and Tobias Senst and Thomas Sikora},
title = {Robust Local Optical Flow: Dense Motion Vector Field Interpolation},
booktitle = {Picture Coding Symposium},
year = {2016},
pages = {1--5},
}
@inproceedings{Senst2016,
author = {Tobias Senst and Jonas Geistert and Thomas Sikora},
title = {Robust local optical flow: Long-range motions and varying illuminations},
booktitle = {IEEE International Conference on Image Processing},
year = {2016},
pages = {4478--4482},
}
@inproceedings{Senst2014,
author = {Tobias Senst and Thilo Borgmann and Ivo Keller and Thomas Sikora},
title = {Cross based Robust Local Optical Flow},
booktitle = {21th IEEE International Conference on Image Processing},
year = {2014},
pages = {1967--1971},
}
@inproceedings{Senst2013,
author = {Tobias Senst and Jonas Geistert and Ivo Keller and Thomas Sikora},
title = {Robust Local Optical Flow Estimation using Bilinear Equations for Sparse Motion Estimation},
booktitle = {20th IEEE International Conference on Image Processing},
year = {2013},
pages = {2499--2503},
}
@article{Senst2012,
author = {Tobias Senst and Volker Eiselein and Thomas Sikora},
title = {Robust Local Optical Flow for Feature Tracking},
journal = {IEEE Transactions on Circuits and Systems for Video Technology},
year = {2012},
pages = {1377--1387},
volume = {22},
number = {9},
}
@article{Tibshirani2008,
title={Fast computation of the median by successive binning},
author={Tibshirani, Ryan J},
journal={arXiv preprint arXiv:0806.3301},
year={2008}
}
......@@ -68,7 +68,7 @@ Functions reading and writing .flo files in "Middlebury" format, see: <http://vi
#include "opencv2/optflow/pcaflow.hpp"
#include "opencv2/optflow/sparse_matching_gpc.hpp"
#include "opencv2/optflow/rlofflow.hpp"
namespace cv
{
namespace optflow
......
This diff is collapsed.
#include "perf_precomp.hpp"
namespace opencv_test { namespace {
typedef tuple<std::string, std::string, bool> ST_SR_IM_Sparse_t;
typedef TestBaseWithParam<ST_SR_IM_Sparse_t> ST_SR_IM_Sparse;
PERF_TEST_P(ST_SR_IM_Sparse, OpticalFlow_SparseRLOF,
testing::Combine(
testing::Values<std::string>("ST_BILINEAR", "ST_STANDART"),
testing::Values<std::string>("SR_CROSS", "SR_FIXED"),
testing::Values(true, false))
)
{
Mat frame1 = imread(getDataPath("cv/optflow/RubberWhale1.png"));
Mat frame2 = imread(getDataPath("cv/optflow/RubberWhale2.png"));
ASSERT_FALSE(frame1.empty());
ASSERT_FALSE(frame2.empty());
vector<Point2f> prevPts, currPts;
for (int r = 0; r < frame1.rows; r += 10)
{
for (int c = 0; c < frame1.cols; c += 10)
{
prevPts.push_back(Point2f(static_cast<float>(c), static_cast<float>(r)));
}
}
vector<uchar> status(prevPts.size());
vector<float> err(prevPts.size());
Ptr<RLOFOpticalFlowParameter> param = Ptr<RLOFOpticalFlowParameter>(new RLOFOpticalFlowParameter);
if (get<0>(GetParam()) == "ST_BILINEAR")
param->solverType = ST_BILINEAR;
if (get<0>(GetParam()) == "ST_STANDART")
param->solverType = ST_STANDART;
if (get<1>(GetParam()) == "SR_CROSS")
param->supportRegionType = SR_CROSS;
if (get<1>(GetParam()) == "SR_FIXED")
param->supportRegionType = SR_FIXED;
param->useIlluminationModel = get<2>(GetParam());
PERF_SAMPLE_BEGIN()
calcOpticalFlowSparseRLOF(frame1, frame2, prevPts, currPts, status, err, param, 1.f);
PERF_SAMPLE_END()
SANITY_CHECK_NOTHING();
}
typedef tuple<std::string, int> INTERP_GRID_Dense_t;
typedef TestBaseWithParam<INTERP_GRID_Dense_t> INTERP_GRID_Dense;
PERF_TEST_P(INTERP_GRID_Dense, OpticalFlow_DenseRLOF,
testing::Combine(
testing::Values<std::string>("INTERP_EPIC", "INTERP_GEO"),
testing::Values<int>(4,10))
)
{
Mat flow;
Mat frame1 = imread(getDataPath("cv/optflow/RubberWhale1.png"));
Mat frame2 = imread(getDataPath("cv/optflow/RubberWhale1.png"));
ASSERT_FALSE(frame1.empty());
ASSERT_FALSE(frame2.empty());
Ptr<RLOFOpticalFlowParameter> param = Ptr<RLOFOpticalFlowParameter>(new RLOFOpticalFlowParameter);;
Ptr< DenseRLOFOpticalFlow> algo = DenseRLOFOpticalFlow::create();
InterpolationType interp_type = INTERP_EPIC;
if (get<0>(GetParam()) == "INTERP_EPIC")
interp_type = INTERP_EPIC;
if (get<0>(GetParam()) == "INTERP_GEO")
interp_type = INTERP_GEO;
PERF_SAMPLE_BEGIN()
calcOpticalFlowDenseRLOF(frame1, frame2,flow, param, 1.0f, Size(get<1>(GetParam()), get<1>(GetParam())), interp_type);
PERF_SAMPLE_END()
SANITY_CHECK_NOTHING();
}
}} // namespace
This diff is collapsed.
This diff is collapsed.
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef _GEO_INTERPOLATION_HPP_
#define _GEO_INTERPOLATION_HPP_
namespace cv {
namespace optflow {
typedef Vec<float, 8> Vec8f;
Mat getGraph(const Mat & image, float edge_length);
Mat sgeo_dist(const Mat& gra, int y, int x, float max, Mat &prev);
Mat sgeo_dist(const Mat& gra, const std::vector<Point2f> & points, float max, Mat &prev);
Mat interpolate_irregular_nw(const Mat &in, const Mat &mask, const Mat &color_img, float max_d, float bandwidth, float pixeldistance);
Mat interpolate_irregular_nn(
const std::vector<Point2f> & prevPoints,
const std::vector<Point2f> & nextPoints,
const std::vector<uchar> & status,
const Mat &color_img,
float pixeldistance);
Mat interpolate_irregular_knn(
const std::vector<Point2f> & _prevPoints,
const std::vector<Point2f> & _nextPoints,
const std::vector<uchar> & status,
const Mat &color_img,
int k,
float pixeldistance);
Mat interpolate_irregular_nn_raster(const std::vector<Point2f> & prevPoints,
const std::vector<Point2f> & nextPoints,
const std::vector<uchar> & status,
const Mat & i1);
}} // namespace
#endif
This diff is collapsed.
This diff is collapsed.
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef _RLOF_INVOKERBASE_HPP_
#define _RLOF_INVOKERBASE_HPP_
#if CV_SSE4_1
#define RLOF_SSE
#endif
//#define DEBUG_INVOKER
#ifndef CV_DESCALE
#define CV_DESCALE(x, n) (((x) + (1 << ((n)-1))) >> (n))
#endif
#define FLT_RESCALE 1
#include "rlof_localflow.h"
#include <unordered_map>
#include "opencv2/core/hal/intrin.hpp"
using namespace std;
using namespace cv;
namespace cv {
namespace optflow {
typedef short deriv_type;
#ifdef RLOF_SSE
static inline void get4BitMask(const int & width, __m128i & mask)
{
int noBits = width - static_cast<int>(floor(width / 4.f) * 4.f);
unsigned int val[4];
for (int n = 0; n < 4; n++)
{
val[n] = (noBits > n) ? (std::numeric_limits<unsigned int>::max()) : 0;
}
mask = _mm_set_epi32(val[3], val[2], val[1], val[0]);
}
static inline void getWBitMask(const int & width, __m128i & t0, __m128i & t1, __m128i & t2)
{
int noBits = width - static_cast<int>(floor(width / 8.f) * 8.f);
unsigned short val[8];
for (int n = 0; n < 8; n++)
{
val[n] = (noBits > n) ? (0xffff) : 0;
}
t1 = _mm_set_epi16(val[7], val[7], val[6], val[6], val[5], val[5], val[4], val[4]);
t0 = _mm_set_epi16(val[3], val[3], val[2], val[2], val[1], val[1], val[0], val[0]);
t2 = _mm_set_epi16(val[7], val[6], val[5], val[4], val[3], val[2], val[1], val[0]);
}
#endif
typedef uchar tMaskType;
#define tCVMaskType CV_8UC1
#define MaskSet 0xffffffff
static
void getLocalPatch(
const cv::Mat & src,
const cv::Point2i & prevPoint, // feature points
cv::Mat & winPointMask,
int & noPoints,
cv::Rect & winRoi,
int minWinSize)
{
int maxWinSizeH = (winPointMask.cols - 1) / 2;
winRoi.x = prevPoint.x;// - maxWinSizeH;
winRoi.y = prevPoint.y;// - maxWinSizeH;
winRoi.width = winPointMask.cols;
winRoi.height = winPointMask.rows;
if( minWinSize == winPointMask.cols || prevPoint.x < 0 || prevPoint.y < 0
|| prevPoint.x + 2*maxWinSizeH >= src.cols || prevPoint.y + 2*maxWinSizeH >= src.rows)
{
winRoi.x = prevPoint.x - maxWinSizeH;
winRoi.y = prevPoint.y - maxWinSizeH;
winPointMask.setTo(1);
noPoints = winPointMask.size().area();
return;
}
winPointMask.setTo(0);
noPoints = 0;
int c = prevPoint.x + maxWinSizeH;
int r = prevPoint.y + maxWinSizeH;
int min_c = c;
int max_c = c;
int border_left = c - maxWinSizeH;
int border_top = r - maxWinSizeH;
cv::Vec4i bounds = src.at<cv::Vec4i>(r,c);
int min_r = bounds.val[2];
int max_r = bounds.val[3];
for( int _r = min_r; _r <= max_r; _r++)
{
cv::Rect roi(maxWinSizeH, _r - border_top, winPointMask.cols, 1);
if( _r >= 0 && _r < src.cols)
{
bounds = src.at<cv::Vec4i>(_r,c);
roi.x = bounds.val[0] - border_left;
roi.width = bounds.val[1] - bounds.val[0];
}
else
{
bounds.val[0] = border_left;
bounds.val[1] = border_left + roi.width;
}
cv::Mat(winPointMask, roi).setTo(1);
min_c = MIN(min_c, bounds.val[0]);
max_c = MAX(max_c, bounds.val[1]);
noPoints += roi.width;
}
if( noPoints < minWinSize * minWinSize)
{
cv::Rect roi( winPointMask.cols / 2 - (minWinSize-1)/2,
winPointMask.rows / 2 - (minWinSize-1)/2,
minWinSize, minWinSize);
cv::Mat(winPointMask, roi).setTo(1);
roi.x += border_left;
roi.y += border_top;
min_c = MIN(MIN(min_c, roi.tl().x),roi.br().x);
max_c = MAX(MAX(max_c, roi.tl().x),roi.br().x);
min_r = MIN(MIN(min_r, roi.tl().y),roi.br().y);
max_r = MAX(MAX(max_r, roi.tl().y),roi.br().y);
noPoints += minWinSize * minWinSize;
}
winRoi.x = min_c - maxWinSizeH;
winRoi.y = min_r - maxWinSizeH;
winRoi.width = max_c - min_c;
winRoi.height = max_r - min_r;
winPointMask = winPointMask(cv::Rect(min_c - border_left, min_r - border_top, winRoi.width, winRoi.height));
}
static inline
bool calcWinMaskMat(
const cv::Mat & BI,
const int windowType,
const cv::Point2i & iprevPt,
cv::Mat & winMaskMat,
cv::Size & winSize,
cv::Point2f & halfWin,
int & winArea,
const int minWinSize,
const int maxWinSize)
{
if (windowType == SR_CROSS && maxWinSize != minWinSize)
{
// patch generation
cv::Rect winRoi;
getLocalPatch(BI, iprevPt, winMaskMat, winArea, winRoi, minWinSize);
if (winArea == 0)
return false;
winSize = winRoi.size();
halfWin = Point2f(static_cast<float>(iprevPt.x - winRoi.tl().x),
static_cast<float>(iprevPt.y - winRoi.tl().y));
}
else
{
winSize = cv::Size(maxWinSize, maxWinSize);
halfWin = Point2f((winSize.width - 1) / 2.f, (winSize.height - 1) / 2.f);
winMaskMat.setTo(1);
}
return true;
}
static inline
short estimateScale(cv::Mat & residuals)
{
cv::Mat absMat = cv::abs(residuals);
return quickselect<short>(absMat, absMat.rows / 2);
}
}} // namespace
#endif
This diff is collapsed.
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef _RLOF_LOCALFLOW_H_
#define _RLOF_LOCALFLOW_H_
#include <limits>
#include <math.h>
#include <float.h>
#include <stdio.h>
#include "opencv2/imgproc.hpp"
#include "opencv2/optflow/rlofflow.hpp"
//! Fast median estimation method based on @cite Tibshirani2008. This implementation relates to http://www.stat.cmu.edu/~ryantibs/median/
using namespace cv;
template<typename T>
T quickselect(const Mat & inp, int k)
{
unsigned long i;
unsigned long ir;
unsigned long j;
unsigned long l;
unsigned long mid;
Mat values = inp.clone();
T a;
l = 0;
ir = MAX(values.rows, values.cols) - 1;
while(true)
{
if (ir <= l + 1)
{
if (ir == l + 1 && values.at<T>(ir) < values.at<T>(l))
std::swap(values.at<T>(l), values.at<T>(ir));
return values.at<T>(k);
}
else
{
mid = (l + ir) >> 1;
std::swap(values.at<T>(mid), values.at<T>(l+1));
if (values.at<T>(l) > values.at<T>(ir))
std::swap(values.at<T>(l), values.at<T>(ir));
if (values.at<T>(l+1) > values.at<T>(ir))
std::swap(values.at<T>(l+1), values.at<T>(ir));
if (values.at<T>(l) > values.at<T>(l+1))
std::swap(values.at<T>(l), values.at<T>(l+1));
i = l + 1;
j = ir;
a = values.at<T>(l+1);
while (true)
{
do
{
i++;
}
while (values.at<T>(i) < a);
do
{
j--;
}
while (values.at<T>(j) > a);
if (j < i) break;
std::swap(values.at<T>(i), values.at<T>(j));
}
values.at<T>(l+1) = values.at<T>(j);
values.at<T>(j) = a;
if (j >= static_cast<unsigned long>(k)) ir = j - 1;
if (j <= static_cast<unsigned long>(k)) l = i;
}
}
}
namespace cv {
namespace optflow {
class CImageBuffer
{
public:
CImageBuffer()
: m_Overwrite(true)
{}
void setGrayFromRGB(const cv::Mat & inp)
{
if(m_Overwrite)
cv::cvtColor(inp, m_Image, cv::COLOR_BGR2GRAY);
}
void setImage(const cv::Mat & inp)
{
if(m_Overwrite)
inp.copyTo(m_Image);
}
void setBlurFromRGB(const cv::Mat & inp)
{
if(m_Overwrite)
cv::GaussianBlur(inp, m_BlurredImage, cv::Size(7,7), -1);
}
int buildPyramid(cv::Size winSize, int maxLevel, float levelScale[2]);
cv::Mat & getImage(int level) {return m_ImagePyramid[level];}
std::vector<cv::Mat> m_ImagePyramid;
cv::Mat m_BlurredImage;
cv::Mat m_Image;
std::vector<cv::Mat> m_CrossPyramid;
int m_maxLevel;
bool m_Overwrite;
};
void calcLocalOpticalFlow(
const Mat prevImage,
const Mat currImage,
Ptr<CImageBuffer> prevPyramids[2],
Ptr<CImageBuffer> currPyramids[2],
const std::vector<Point2f> & prevPoints,
std::vector<Point2f> & currPoints,
const RLOFOpticalFlowParameter & param);
}} // namespace
#endif
This diff is collapsed.
......@@ -83,7 +83,20 @@ static float calcRMSE(Mat flow1, Mat flow2)
}
return (float)sqrt(sum / (1e-9 + counter));
}
static float calcRMSE(vector<Point2f> prevPts, vector<Point2f> currPts, Mat flow)
{
vector<float> ee;
for (unsigned int n = 0; n < prevPts.size(); n++)
{
Point2f gtFlow = flow.at<Point2f>(prevPts[n]);
if (isFlowCorrect(gtFlow.x) && isFlowCorrect(gtFlow.y))
{
Point2f diffFlow = (currPts[n] - prevPts[n]) - gtFlow;
ee.push_back(sqrt(diffFlow.x * diffFlow.x + diffFlow.y * diffFlow.y));
}
}
return static_cast<float>(mean(ee).val[0]);
}
static float calcAvgEPE(vector< pair<Point2i, Point2i> > corr, Mat flow)
{
double sum = 0;
......@@ -111,9 +124,13 @@ static float calcAvgEPE(vector< pair<Point2i, Point2i> > corr, Mat flow)
bool readRubberWhale(Mat &dst_frame_1, Mat &dst_frame_2, Mat &dst_GT)
{
const string frame1_path = getRubberWhaleFrame1();
const string frame2_path = getRubberWhaleFrame2();
const string gt_flow_path = getRubberWhaleGroundTruth();
string frame1_path = getRubberWhaleFrame1();
string frame2_path = getRubberWhaleFrame2();
string gt_flow_path = getRubberWhaleGroundTruth();
// removing space may be an issue on windows machines
frame1_path.erase(std::remove_if(frame1_path.begin(), frame1_path.end(), isspace), frame1_path.end());
frame2_path.erase(std::remove_if(frame2_path.begin(), frame2_path.end(), isspace), frame2_path.end());
gt_flow_path.erase(std::remove_if(gt_flow_path.begin(), gt_flow_path.end(), isspace), gt_flow_path.end());
dst_frame_1 = imread(frame1_path);
dst_frame_2 = imread(frame2_path);
......@@ -125,6 +142,7 @@ bool readRubberWhale(Mat &dst_frame_1, Mat &dst_frame_2, Mat &dst_GT)
return true;
}
TEST(DenseOpticalFlow_SimpleFlow, ReferenceAccuracy)
{
Mat frame1, frame2, GT;
......@@ -157,6 +175,102 @@ TEST(DenseOpticalFlow_DeepFlow, ReferenceAccuracy)
EXPECT_LE(calcRMSE(GT, flow), target_RMSE);
}
TEST(SparseOpticalFlow, ReferenceAccuracy)
{
// with the following test each invoker class should be tested once
Mat frame1, frame2, GT;
ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
vector<Point2f> prevPts, currPts;
for (int r = 0; r < frame1.rows; r+=10)
{
for (int c = 0; c < frame1.cols; c+=10)
{
prevPts.push_back(Point2f(static_cast<float>(c), static_cast<float>(r)));
}
}
vector<uchar> status(prevPts.size());
vector<float> err(prevPts.size());
Ptr<SparseRLOFOpticalFlow> algo = SparseRLOFOpticalFlow::create();
algo->setForwardBackward(0.0f);
Ptr<RLOFOpticalFlowParameter> param = Ptr<RLOFOpticalFlowParameter>(new RLOFOpticalFlowParameter);
param->supportRegionType = SR_CROSS;
param->useIlluminationModel = true;
param->solverType = ST_BILINEAR;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.3f);
param->solverType = ST_STANDART;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.34f);
param->useIlluminationModel = false;
param->solverType = ST_BILINEAR;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.27f);
param->solverType = ST_STANDART;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.27f);
param->normSigma0 = numeric_limits<float>::max();
param->normSigma1 = numeric_limits<float>::max();
param->useIlluminationModel = true;
param->solverType = ST_BILINEAR;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.28f);
param->solverType = ST_STANDART;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.28f);
param->useIlluminationModel = false;
param->solverType = ST_BILINEAR;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.80f);
param->solverType = ST_STANDART;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.28f);
}
TEST(DenseOpticalFlow_RLOF, ReferenceAccuracy)
{
Mat frame1, frame2, GT;
ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
Mat flow;
Ptr<DenseRLOFOpticalFlow> algo = DenseRLOFOpticalFlow::create();
Ptr<RLOFOpticalFlowParameter> param = Ptr<RLOFOpticalFlowParameter>(new RLOFOpticalFlowParameter);
param->supportRegionType = SR_CROSS;
param->solverType = ST_BILINEAR;
algo->setRLOFOpticalFlowParameter(param);
algo->setForwardBackward(1.0f);
algo->setGridStep(cv::Size(4, 4));
algo->setInterpolation(INTERP_EPIC);
algo->calc(frame1, frame2, flow);
ASSERT_EQ(GT.rows, flow.rows);
ASSERT_EQ(GT.cols, flow.cols);
EXPECT_LE(calcRMSE(GT, flow), 0.44f);
algo->setInterpolation(INTERP_GEO);
algo->calc(frame1, frame2, flow);
ASSERT_EQ(GT.rows, flow.rows);
ASSERT_EQ(GT.cols, flow.cols);
EXPECT_LE(calcRMSE(GT, flow), 0.55f);
}
TEST(DenseOpticalFlow_SparseToDenseFlow, ReferenceAccuracy)
{
Mat frame1, frame2, GT;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment