mirror of https://github.com/opencv/opencv.git
Merge pull request #16788 from OrestChura:oc/optFlowPyrLK
G-API: gapi::calcOpticalFlowPyrLK() Implementationpull/17026/head
commit
016f9ab16e
22 changed files with 921 additions and 26 deletions
@ -0,0 +1,25 @@ |
||||
// 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.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_CPU_VIDEO_API_HPP |
||||
#define OPENCV_GAPI_CPU_VIDEO_API_HPP |
||||
|
||||
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace video { |
||||
namespace cpu { |
||||
|
||||
GAPI_EXPORTS GKernelPackage kernels(); |
||||
|
||||
} // namespace cpu
|
||||
} // namespace video
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
|
||||
#endif // OPENCV_GAPI_CPU_VIDEO_API_HPP
|
@ -0,0 +1,135 @@ |
||||
// 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.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_VIDEO_HPP |
||||
#define OPENCV_GAPI_VIDEO_HPP |
||||
|
||||
#include <utility> // std::tuple |
||||
|
||||
#include <opencv2/gapi/gkernel.hpp> |
||||
|
||||
|
||||
/** \defgroup gapi_video G-API Video processing functionality
|
||||
*/ |
||||
|
||||
namespace cv { namespace gapi { |
||||
namespace video |
||||
{ |
||||
using GOptFlowLKOutput = std::tuple<cv::GArray<cv::Point2f>, |
||||
cv::GArray<uchar>, |
||||
cv::GArray<float>>; |
||||
|
||||
G_TYPED_KERNEL(GCalcOptFlowLK, |
||||
<GOptFlowLKOutput(GMat,GMat,cv::GArray<cv::Point2f>,cv::GArray<cv::Point2f>,Size, |
||||
int,TermCriteria,int,double)>, |
||||
"org.opencv.video.calcOpticalFlowPyrLK") |
||||
{ |
||||
static std::tuple<GArrayDesc,GArrayDesc,GArrayDesc> outMeta(GMatDesc,GMatDesc,GArrayDesc, |
||||
GArrayDesc,const Size&,int, |
||||
const TermCriteria&,int,double) |
||||
{ |
||||
return std::make_tuple(empty_array_desc(), empty_array_desc(), empty_array_desc()); |
||||
} |
||||
|
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GCalcOptFlowLKForPyr, |
||||
<GOptFlowLKOutput(cv::GArray<cv::GMat>,cv::GArray<cv::GMat>, |
||||
cv::GArray<cv::Point2f>,cv::GArray<cv::Point2f>,Size,int, |
||||
TermCriteria,int,double)>, |
||||
"org.opencv.video.calcOpticalFlowPyrLKForPyr") |
||||
{ |
||||
static std::tuple<GArrayDesc,GArrayDesc,GArrayDesc> outMeta(GArrayDesc,GArrayDesc, |
||||
GArrayDesc,GArrayDesc, |
||||
const Size&,int, |
||||
const TermCriteria&,int,double) |
||||
{ |
||||
return std::make_tuple(empty_array_desc(), empty_array_desc(), empty_array_desc()); |
||||
} |
||||
}; |
||||
} //namespace video
|
||||
|
||||
//! @addtogroup gapi_video
|
||||
//! @{
|
||||
/** @brief Calculates an optical flow for a sparse feature set using the iterative Lucas-Kanade
|
||||
method with pyramids. |
||||
|
||||
See @cite Bouguet00 . |
||||
|
||||
@note Function textual ID is "org.opencv.video.calcOpticalFlowPyrLK" |
||||
|
||||
@param prevImg first 8-bit input image (GMat) or pyramid (GArray<GMat>) constructed by |
||||
buildOpticalFlowPyramid. |
||||
@param nextImg second input image (GMat) or pyramid (GArray<GMat>) of the same size and the same |
||||
type as prevImg. |
||||
@param prevPts GArray of 2D points for which the flow needs to be found; point coordinates must be |
||||
single-precision floating-point numbers. |
||||
@param predPts GArray of 2D points initial for the flow search; make sense only when |
||||
OPTFLOW_USE_INITIAL_FLOW flag is passed; in that case the vector must have the same size as in |
||||
the input. |
||||
@param winSize size of the search window at each pyramid level. |
||||
@param maxLevel 0-based maximal pyramid level number; if set to 0, pyramids are not used (single |
||||
level), if set to 1, two levels are used, and so on; if pyramids are passed to input then |
||||
algorithm will use as many levels as pyramids have but no more than maxLevel. |
||||
@param criteria parameter, specifying the termination criteria of the iterative search algorithm |
||||
(after the specified maximum number of iterations criteria.maxCount or when the search window |
||||
moves by less than criteria.epsilon). |
||||
@param flags operation flags: |
||||
- **OPTFLOW_USE_INITIAL_FLOW** uses initial estimations, stored in nextPts; if the flag is |
||||
not set, then prevPts is copied to nextPts and is considered the initial estimate. |
||||
- **OPTFLOW_LK_GET_MIN_EIGENVALS** use minimum eigen values as an error measure (see |
||||
minEigThreshold description); if the flag is not set, then L1 distance between patches |
||||
around the original and a moved point, divided by number of pixels in a window, is used as a |
||||
error measure. |
||||
@param minEigThresh the algorithm calculates the minimum eigen value of a 2x2 normal matrix of |
||||
optical flow equations (this matrix is called a spatial gradient matrix in @cite Bouguet00), divided |
||||
by number of pixels in a window; if this value is less than minEigThreshold, then a corresponding |
||||
feature is filtered out and its flow is not processed, so it allows to remove bad points and get a |
||||
performance boost. |
||||
|
||||
@return GArray of 2D points (with single-precision floating-point coordinates) |
||||
containing the calculated new positions of input features in the second image. |
||||
@return status GArray (of unsigned chars); each element of the vector is set to 1 if |
||||
the flow for the corresponding features has been found, otherwise, it is set to 0. |
||||
@return GArray of errors (doubles); each element of the vector is set to an error for the |
||||
corresponding feature, type of the error measure can be set in flags parameter; if the flow wasn't |
||||
found then the error is not defined (use the status parameter to find such cases). |
||||
*/ |
||||
GAPI_EXPORTS std::tuple<GArray<Point2f>, GArray<uchar>, GArray<float>> |
||||
calcOpticalFlowPyrLK(const GMat &prevImg, |
||||
const GMat &nextImg, |
||||
const GArray<Point2f> &prevPts, |
||||
const GArray<Point2f> &predPts, |
||||
const Size &winSize = Size(21, 21), |
||||
int maxLevel = 3, |
||||
const TermCriteria &criteria = TermCriteria(TermCriteria::COUNT | |
||||
TermCriteria::EPS, |
||||
30, 0.01), |
||||
int flags = 0, |
||||
double minEigThresh = 1e-4); |
||||
|
||||
/**
|
||||
@overload |
||||
@note Function textual ID is "org.opencv.video.calcOpticalFlowPyrLKForPyr" |
||||
*/ |
||||
GAPI_EXPORTS std::tuple<GArray<Point2f>, GArray<uchar>, GArray<float>> |
||||
calcOpticalFlowPyrLK(const GArray<GMat> &prevPyr, |
||||
const GArray<GMat> &nextPyr, |
||||
const GArray<Point2f> &prevPts, |
||||
const GArray<Point2f> &predPts, |
||||
const Size &winSize = Size(21, 21), |
||||
int maxLevel = 3, |
||||
const TermCriteria &criteria = TermCriteria(TermCriteria::COUNT | |
||||
TermCriteria::EPS, |
||||
30, 0.01), |
||||
int flags = 0, |
||||
double minEigThresh = 1e-4); |
||||
|
||||
//! @} gapi_video
|
||||
} //namespace gapi
|
||||
} //namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_VIDEO_HPP
|
@ -0,0 +1,9 @@ |
||||
// 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.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
|
||||
|
||||
#include "../perf_precomp.hpp" |
||||
#include "gapi_video_perf_tests_inl.hpp" |
@ -0,0 +1,26 @@ |
||||
// 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.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_VIDEO_PERF_TESTS_HPP |
||||
#define OPENCV_GAPI_VIDEO_PERF_TESTS_HPP |
||||
|
||||
#include "../../test/common/gapi_video_tests_common.hpp" |
||||
|
||||
namespace opencv_test |
||||
{ |
||||
|
||||
using namespace perf; |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class OptFlowLKPerfTest : public TestPerfParams<tuple<std::string,int,tuple<int,int>,int, |
||||
cv::TermCriteria,cv::GCompileArgs>> {}; |
||||
class OptFlowLKForPyrPerfTest : public TestPerfParams<tuple<std::string,int,tuple<int,int>,int, |
||||
cv::TermCriteria,bool, |
||||
cv::GCompileArgs>> {}; |
||||
} // opencv_test
|
||||
|
||||
#endif // OPENCV_GAPI_VIDEO_PERF_TESTS_HPP
|
@ -0,0 +1,90 @@ |
||||
// 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.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_VIDEO_PERF_TESTS_INL_HPP |
||||
#define OPENCV_GAPI_VIDEO_PERF_TESTS_INL_HPP |
||||
|
||||
#include <iostream> |
||||
|
||||
#include "gapi_video_perf_tests.hpp" |
||||
|
||||
namespace opencv_test |
||||
{ |
||||
|
||||
using namespace perf; |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PERF_TEST_P_(OptFlowLKPerfTest, TestPerformance) |
||||
{ |
||||
std::vector<cv::Point2f> outPtsOCV, outPtsGAPI, inPts; |
||||
std::vector<uchar> outStatusOCV, outStatusGAPI; |
||||
std::vector<float> outErrOCV, outErrGAPI; |
||||
|
||||
OptFlowLKTestParams params; |
||||
std::tie(params.fileNamePattern, params.channels, |
||||
params.pointsNum, params.winSize, params.criteria, |
||||
params.compileArgs) = GetParam(); |
||||
|
||||
OptFlowLKTestOutput outOCV { outPtsOCV, outStatusOCV, outErrOCV }; |
||||
OptFlowLKTestOutput outGAPI { outPtsGAPI, outStatusGAPI, outErrGAPI }; |
||||
|
||||
cv::GComputation c = runOCVnGAPIOptFlowLK(*this, inPts, params, outOCV, outGAPI); |
||||
|
||||
declare.in(in_mat1, in_mat2, inPts).out(outPtsGAPI, outStatusGAPI, outErrGAPI); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(cv::gin(in_mat1, in_mat2, inPts, std::vector<cv::Point2f>{ }), |
||||
cv::gout(outPtsGAPI, outStatusGAPI, outErrGAPI)); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
compareOutputsOptFlow(outOCV, outGAPI); |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PERF_TEST_P_(OptFlowLKForPyrPerfTest, TestPerformance) |
||||
{ |
||||
std::vector<cv::Mat> inPyr1, inPyr2; |
||||
std::vector<cv::Point2f> outPtsOCV, outPtsGAPI, inPts; |
||||
std::vector<uchar> outStatusOCV, outStatusGAPI; |
||||
std::vector<float> outErrOCV, outErrGAPI; |
||||
|
||||
bool withDeriv = false; |
||||
OptFlowLKTestParams params; |
||||
std::tie(params.fileNamePattern, params.channels, |
||||
params.pointsNum, params.winSize, params.criteria, |
||||
withDeriv, params.compileArgs) = GetParam(); |
||||
|
||||
OptFlowLKTestInput<std::vector<cv::Mat>> in { inPyr1, inPyr2, inPts }; |
||||
OptFlowLKTestOutput outOCV { outPtsOCV, outStatusOCV, outErrOCV }; |
||||
OptFlowLKTestOutput outGAPI { outPtsGAPI, outStatusGAPI, outErrGAPI }; |
||||
|
||||
cv::GComputation c = runOCVnGAPIOptFlowLKForPyr(*this, in, params, withDeriv, outOCV, outGAPI); |
||||
|
||||
declare.in(inPyr1, inPyr2, inPts).out(outPtsGAPI, outStatusGAPI, outErrGAPI); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(cv::gin(inPyr1, inPyr2, inPts, std::vector<cv::Point2f>{ }), |
||||
cv::gout(outPtsGAPI, outStatusGAPI, outErrGAPI)); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
compareOutputsOptFlow(outOCV, outGAPI); |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
} // opencv_test
|
||||
|
||||
#endif // OPENCV_GAPI_VIDEO_PERF_TESTS_INL_HPP
|
@ -0,0 +1,64 @@ |
||||
// 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.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
|
||||
|
||||
#include "../perf_precomp.hpp" |
||||
|
||||
#include "../common/gapi_video_perf_tests.hpp" |
||||
#include <opencv2/gapi/cpu/video.hpp> |
||||
|
||||
namespace |
||||
{ |
||||
#define VIDEO_CPU cv::gapi::video::cpu::kernels() |
||||
|
||||
#ifdef HAVE_OPENCV_VIDEO |
||||
#define WITH_VIDEO(X) X |
||||
#else |
||||
#define WITH_VIDEO(X) DISABLED_##X |
||||
#endif // HAVE_OPENCV_VIDEO
|
||||
|
||||
#define INSTANTIATE_TEST_CASE_MACRO_P(prefix, test_case_name, generator, ...) \ |
||||
INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, __VA_ARGS__) |
||||
} // namespace
|
||||
|
||||
|
||||
namespace opencv_test |
||||
{ |
||||
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKPerfTestCPU), OptFlowLKPerfTest, |
||||
Combine(Values("cv/optflow/rock_%01d.bmp", |
||||
"cv/optflow/frames/1080p_%02d.png"), |
||||
Values(1, 3, 4), |
||||
Values(std::make_tuple(9, 9), std::make_tuple(15, 15)), |
||||
Values(7, 11), |
||||
Values(cv::TermCriteria(cv::TermCriteria::COUNT | |
||||
cv::TermCriteria::EPS, |
||||
30, 0.01)), |
||||
Values(cv::compile_args(VIDEO_CPU)))); |
||||
|
||||
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKForPyrPerfTestCPU), OptFlowLKForPyrPerfTest, |
||||
Combine(Values("cv/optflow/rock_%01d.bmp", |
||||
"cv/optflow/frames/1080p_%02d.png"), |
||||
Values(1, 3, 4), |
||||
Values(std::make_tuple(9, 9), std::make_tuple(15, 15)), |
||||
Values(7, 11), |
||||
Values(cv::TermCriteria(cv::TermCriteria::COUNT | |
||||
cv::TermCriteria::EPS, |
||||
30, 0.01)), |
||||
Values(true, false), |
||||
Values(cv::compile_args(VIDEO_CPU)))); |
||||
|
||||
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKInternalPerfTestCPU), |
||||
OptFlowLKForPyrPerfTest, |
||||
Combine(Values("cv/optflow/rock_%01d.bmp"), |
||||
Values(1), |
||||
Values(std::make_tuple(10, 10)), |
||||
Values(15), |
||||
Values(cv::TermCriteria(cv::TermCriteria::COUNT | |
||||
cv::TermCriteria::EPS, |
||||
21, 0.05)), |
||||
Values(true), |
||||
Values(cv::compile_args(VIDEO_CPU)))); |
||||
} // opencv_test
|
@ -0,0 +1,45 @@ |
||||
// 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.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
|
||||
|
||||
#include "precomp.hpp" |
||||
|
||||
#include <opencv2/gapi/video.hpp> |
||||
|
||||
namespace cv { namespace gapi { |
||||
using namespace video; |
||||
|
||||
|
||||
GOptFlowLKOutput calcOpticalFlowPyrLK(const GMat &prevImg, |
||||
const GMat &nextImg, |
||||
const cv::GArray<cv::Point2f> &prevPts, |
||||
const cv::GArray<cv::Point2f> &predPts, |
||||
const Size &winSize, |
||||
int maxLevel, |
||||
const TermCriteria &criteria, |
||||
int flags, |
||||
double minEigThresh) |
||||
{ |
||||
return GCalcOptFlowLK::on(prevImg, nextImg, prevPts, predPts, winSize, maxLevel, |
||||
criteria, flags, minEigThresh); |
||||
} |
||||
|
||||
GOptFlowLKOutput calcOpticalFlowPyrLK(const cv::GArray<cv::GMat> &prevPyr, |
||||
const cv::GArray<cv::GMat> &nextPyr, |
||||
const cv::GArray<cv::Point2f> &prevPts, |
||||
const cv::GArray<cv::Point2f> &predPts, |
||||
const Size &winSize, |
||||
int maxLevel, |
||||
const TermCriteria &criteria, |
||||
int flags, |
||||
double minEigThresh) |
||||
{ |
||||
return GCalcOptFlowLKForPyr::on(prevPyr, nextPyr, prevPts, predPts, winSize, maxLevel, |
||||
criteria, flags, minEigThresh); |
||||
} |
||||
|
||||
} //namespace gapi
|
||||
} //namespace cv
|
@ -0,0 +1,80 @@ |
||||
// 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.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
|
||||
|
||||
#include "precomp.hpp" |
||||
|
||||
#include <opencv2/gapi/video.hpp> |
||||
#include <opencv2/gapi/cpu/video.hpp> |
||||
#include <opencv2/gapi/cpu/gcpukernel.hpp> |
||||
|
||||
#ifdef HAVE_OPENCV_VIDEO |
||||
#include <opencv2/video.hpp> |
||||
#endif // HAVE_OPENCV_VIDEO
|
||||
|
||||
#ifdef HAVE_OPENCV_VIDEO |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCalcOptFlowLK, cv::gapi::video::GCalcOptFlowLK) |
||||
{ |
||||
static void run(const cv::Mat &prevImg, |
||||
const cv::Mat &nextImg, |
||||
const std::vector<cv::Point2f> &prevPts, |
||||
const std::vector<cv::Point2f> &predPts, |
||||
const cv::Size &winSize, |
||||
int maxLevel, |
||||
const cv::TermCriteria &criteria, |
||||
int flags, |
||||
double minEigThresh, |
||||
std::vector<cv::Point2f> &outPts, |
||||
std::vector<uchar> &status, |
||||
std::vector<float> &err) |
||||
{ |
||||
if (flags & cv::OPTFLOW_USE_INITIAL_FLOW) |
||||
outPts = predPts; |
||||
cv::calcOpticalFlowPyrLK(prevImg, nextImg, prevPts, outPts, status, err, winSize, maxLevel, |
||||
criteria, flags, minEigThresh); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCalcOptFlowLKForPyr, cv::gapi::video::GCalcOptFlowLKForPyr) |
||||
{ |
||||
static void run(const std::vector<cv::Mat> &prevPyr, |
||||
const std::vector<cv::Mat> &nextPyr, |
||||
const std::vector<cv::Point2f> &prevPts, |
||||
const std::vector<cv::Point2f> &predPts, |
||||
const cv::Size &winSize, |
||||
int maxLevel, |
||||
const cv::TermCriteria &criteria, |
||||
int flags, |
||||
double minEigThresh, |
||||
std::vector<cv::Point2f> &outPts, |
||||
std::vector<uchar> &status, |
||||
std::vector<float> &err) |
||||
{ |
||||
if (flags & cv::OPTFLOW_USE_INITIAL_FLOW) |
||||
outPts = predPts; |
||||
cv::calcOpticalFlowPyrLK(prevPyr, nextPyr, prevPts, outPts, status, err, winSize, maxLevel, |
||||
criteria, flags, minEigThresh); |
||||
} |
||||
}; |
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::video::cpu::kernels() |
||||
{ |
||||
static auto pkg = cv::gapi::kernels |
||||
< GCPUCalcOptFlowLK |
||||
, GCPUCalcOptFlowLKForPyr |
||||
>(); |
||||
return pkg; |
||||
} |
||||
|
||||
#else |
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::video::cpu::kernels() |
||||
{ |
||||
return GKernelPackage(); |
||||
} |
||||
|
||||
#endif // HAVE_OPENCV_VIDEO
|
@ -0,0 +1,9 @@ |
||||
// 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.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
|
||||
|
||||
#include "../test_precomp.hpp" |
||||
#include "gapi_video_tests_inl.hpp" |
@ -0,0 +1,24 @@ |
||||
// 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.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_VIDEO_TESTS_HPP |
||||
#define OPENCV_GAPI_VIDEO_TESTS_HPP |
||||
|
||||
#include "gapi_video_tests_common.hpp" |
||||
|
||||
namespace opencv_test |
||||
{ |
||||
GAPI_TEST_FIXTURE_SPEC_PARAMS(OptFlowLKTest, FIXTURE_API(std::string,int,tuple<int,int>,int, |
||||
cv::TermCriteria), |
||||
5, fileNamePattern, channels, pointsNum, winSize, criteria) |
||||
|
||||
GAPI_TEST_FIXTURE_SPEC_PARAMS(OptFlowLKTestForPyr, FIXTURE_API(std::string,int,tuple<int,int>,int, |
||||
cv::TermCriteria,bool), |
||||
6, fileNamePattern, channels, pointsNum, winSize, criteria,withDeriv) |
||||
} // opencv_test
|
||||
|
||||
|
||||
#endif // OPENCV_GAPI_VIDEO_TESTS_HPP
|
@ -0,0 +1,249 @@ |
||||
// 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.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_VIDEO_TESTS_COMMON_HPP |
||||
#define OPENCV_GAPI_VIDEO_TESTS_COMMON_HPP |
||||
|
||||
#include "gapi_tests_common.hpp" |
||||
#include "../../include/opencv2/gapi/video.hpp" |
||||
|
||||
#ifdef HAVE_OPENCV_VIDEO |
||||
#include <opencv2/video.hpp> |
||||
#endif // HAVE_OPENCV_VIDEO
|
||||
|
||||
|
||||
|
||||
namespace opencv_test |
||||
{ |
||||
namespace |
||||
{ |
||||
inline void initTrackingPointsArray(std::vector<cv::Point2f>& points, int width, int height, |
||||
int nPointsX, int nPointsY) |
||||
{ |
||||
if (nPointsX > width || nPointsY > height) |
||||
{ |
||||
FAIL() << "Specified points number is too big"; |
||||
} |
||||
|
||||
int stepX = width / nPointsX; |
||||
int stepY = height / nPointsY; |
||||
|
||||
|
||||
points.clear(); |
||||
GAPI_Assert((nPointsX >= 0) && (nPointsY) >= 0); |
||||
points.reserve(static_cast<size_t>(nPointsX * nPointsY)); |
||||
|
||||
for (int x = stepX / 2; x < width; x += stepX) |
||||
{ |
||||
for (int y = stepY / 2; y < height; y += stepY) |
||||
{ |
||||
Point2f pt(static_cast<float>(x), static_cast<float>(y)); |
||||
points.push_back(pt); |
||||
} |
||||
} |
||||
} |
||||
|
||||
template<typename Type> |
||||
struct OptFlowLKTestInput |
||||
{ |
||||
Type& prevData; |
||||
Type& nextData; |
||||
std::vector<cv::Point2f>& prevPoints; |
||||
}; |
||||
|
||||
struct OptFlowLKTestOutput |
||||
{ |
||||
std::vector<cv::Point2f> &nextPoints; |
||||
std::vector<uchar> &statuses; |
||||
std::vector<float> &errors; |
||||
}; |
||||
|
||||
struct OptFlowLKTestParams |
||||
{ |
||||
OptFlowLKTestParams(): fileNamePattern(""), format(1), channels(0), pointsNum{0, 0}, |
||||
winSize(0), maxLevel(3), minEigThreshold(1e-4), flags(0) { } |
||||
|
||||
OptFlowLKTestParams(const std::string& namePat, int chans, |
||||
const std::tuple<int,int>& ptsNum, int winSz, |
||||
const cv::TermCriteria& crit, const cv::GCompileArgs& compArgs, |
||||
int flgs = 0, int fmt = 1, int maxLvl = 3, double minEigThresh = 1e-4): |
||||
|
||||
fileNamePattern(namePat), format(fmt), channels(chans), |
||||
pointsNum(ptsNum), winSize(winSz), maxLevel(maxLvl), |
||||
criteria(crit), minEigThreshold(minEigThresh), compileArgs(compArgs), |
||||
flags(flgs) { } |
||||
|
||||
std::string fileNamePattern = ""; |
||||
int format = 1; |
||||
int channels = 0; |
||||
std::tuple<int,int> pointsNum = std::make_tuple(0, 0); |
||||
int winSize = 0; |
||||
int maxLevel = 3; |
||||
cv::TermCriteria criteria; |
||||
double minEigThreshold = 1e-4; |
||||
cv::GCompileArgs compileArgs; |
||||
int flags = 0; |
||||
}; |
||||
|
||||
#ifdef HAVE_OPENCV_VIDEO |
||||
|
||||
template<typename GType, typename Type> |
||||
cv::GComputation runOCVnGAPIOptFlowLK(OptFlowLKTestInput<Type>& in, |
||||
int width, int height, |
||||
const OptFlowLKTestParams& params, |
||||
OptFlowLKTestOutput& ocvOut, |
||||
OptFlowLKTestOutput& gapiOut) |
||||
{ |
||||
|
||||
int nPointsX = 0, nPointsY = 0; |
||||
std::tie(nPointsX, nPointsY) = params.pointsNum; |
||||
|
||||
initTrackingPointsArray(in.prevPoints, width, height, nPointsX, nPointsY); |
||||
|
||||
cv::Size winSize(params.winSize, params.winSize); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::calcOpticalFlowPyrLK(in.prevData, in.nextData, in.prevPoints, |
||||
ocvOut.nextPoints, ocvOut.statuses, ocvOut.errors, |
||||
winSize, params.maxLevel, params.criteria, |
||||
params.flags, params.minEigThreshold); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
{ |
||||
GType inPrev, inNext; |
||||
GArray<cv::Point2f> prevPts, predPts, nextPts; |
||||
GArray<uchar> statuses; |
||||
GArray<float> errors; |
||||
std::tie(nextPts, statuses, errors) = cv::gapi::calcOpticalFlowPyrLK( |
||||
inPrev, inNext, |
||||
prevPts, predPts, winSize, |
||||
params.maxLevel, params.criteria, |
||||
params.flags, params.minEigThreshold); |
||||
|
||||
cv::GComputation c(cv::GIn(inPrev, inNext, prevPts, predPts), |
||||
cv::GOut(nextPts, statuses, errors)); |
||||
|
||||
c.apply(cv::gin(in.prevData, in.nextData, in.prevPoints, std::vector<cv::Point2f>{ }), |
||||
cv::gout(gapiOut.nextPoints, gapiOut.statuses, gapiOut.errors), |
||||
std::move(const_cast<cv::GCompileArgs&>(params.compileArgs))); |
||||
|
||||
return c; |
||||
} |
||||
} |
||||
|
||||
inline cv::GComputation runOCVnGAPIOptFlowLK(TestFunctional& testInst, |
||||
std::vector<cv::Point2f>& inPts, |
||||
const OptFlowLKTestParams& params, |
||||
OptFlowLKTestOutput& ocvOut, |
||||
OptFlowLKTestOutput& gapiOut) |
||||
{ |
||||
testInst.initMatsFromImages(params.channels, |
||||
params.fileNamePattern, |
||||
params.format); |
||||
|
||||
OptFlowLKTestInput<cv::Mat> in{ testInst.in_mat1, testInst.in_mat2, inPts }; |
||||
|
||||
return runOCVnGAPIOptFlowLK<cv::GMat>(in, |
||||
testInst.in_mat1.cols, |
||||
testInst.in_mat1.rows, |
||||
params, |
||||
ocvOut, |
||||
gapiOut); |
||||
} |
||||
|
||||
inline cv::GComputation runOCVnGAPIOptFlowLKForPyr(TestFunctional& testInst, |
||||
OptFlowLKTestInput<std::vector<cv::Mat>>& in, |
||||
const OptFlowLKTestParams& params, |
||||
bool withDeriv, |
||||
OptFlowLKTestOutput& ocvOut, |
||||
OptFlowLKTestOutput& gapiOut) |
||||
{ |
||||
testInst.initMatsFromImages(params.channels, |
||||
params.fileNamePattern, |
||||
params.format); |
||||
|
||||
cv::Size winSize(params.winSize, params.winSize); |
||||
|
||||
OptFlowLKTestParams updatedParams(params); |
||||
updatedParams.maxLevel = cv::buildOpticalFlowPyramid(testInst.in_mat1, in.prevData, |
||||
winSize, params.maxLevel, withDeriv); |
||||
updatedParams.maxLevel = cv::buildOpticalFlowPyramid(testInst.in_mat2, in.nextData, |
||||
winSize, params.maxLevel, withDeriv); |
||||
|
||||
|
||||
return runOCVnGAPIOptFlowLK<cv::GArray<cv::GMat>>(in, |
||||
testInst.in_mat1.cols, |
||||
testInst.in_mat1.rows, |
||||
updatedParams, |
||||
ocvOut, |
||||
gapiOut); |
||||
} |
||||
|
||||
#else // !HAVE_OPENCV_VIDEO
|
||||
|
||||
inline cv::GComputation runOCVnGAPIOptFlowLK(TestFunctional&, |
||||
std::vector<cv::Point2f>&, |
||||
const OptFlowLKTestParams&, |
||||
OptFlowLKTestOutput&, |
||||
OptFlowLKTestOutput&) |
||||
{ |
||||
GAPI_Assert(0 && "This function shouldn't be called without opencv_video"); |
||||
} |
||||
|
||||
inline cv::GComputation runOCVnGAPIOptFlowLKForPyr(TestFunctional&, |
||||
OptFlowLKTestInput<std::vector<cv::Mat>>&, |
||||
const OptFlowLKTestParams&, |
||||
bool, |
||||
OptFlowLKTestOutput&, |
||||
OptFlowLKTestOutput&) |
||||
{ |
||||
GAPI_Assert(0 && "This function shouldn't be called without opencv_video"); |
||||
} |
||||
|
||||
#endif // HAVE_OPENCV_VIDEO
|
||||
|
||||
template <typename Elem> |
||||
inline bool compareVectorsAbsExactForOptFlow(std::vector<Elem> outOCV, std::vector<Elem> outGAPI) |
||||
{ |
||||
return AbsExactVector<Elem>().to_compare_f()(outOCV, outGAPI); |
||||
} |
||||
|
||||
inline void compareOutputsOptFlow(const OptFlowLKTestOutput& outOCV, |
||||
const OptFlowLKTestOutput& outGAPI) |
||||
{ |
||||
EXPECT_TRUE(compareVectorsAbsExactForOptFlow(outGAPI.nextPoints, outOCV.nextPoints)); |
||||
EXPECT_TRUE(compareVectorsAbsExactForOptFlow(outGAPI.statuses, outOCV.statuses)); |
||||
EXPECT_TRUE(compareVectorsAbsExactForOptFlow(outGAPI.errors, outOCV.errors)); |
||||
} |
||||
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const cv::TermCriteria& criteria) |
||||
{ |
||||
os << "{"; |
||||
switch (criteria.type) { |
||||
case cv::TermCriteria::COUNT: |
||||
os << "COUNT; "; |
||||
break; |
||||
case cv::TermCriteria::EPS: |
||||
os << "EPS; "; |
||||
break; |
||||
case cv::TermCriteria::COUNT | cv::TermCriteria::EPS: |
||||
os << "COUNT | EPS; "; |
||||
break; |
||||
default: |
||||
os << "TypeUndifined; "; |
||||
break; |
||||
}; |
||||
|
||||
return os << criteria.maxCount << "; " << criteria.epsilon <<"}"; |
||||
} |
||||
} // namespace
|
||||
} // namespace opencv_test
|
||||
|
||||
|
||||
#endif // OPENCV_GAPI_VIDEO_TESTS_COMMON_HPP
|
@ -0,0 +1,53 @@ |
||||
// 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.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_VIDEO_TESTS_INL_HPP |
||||
#define OPENCV_GAPI_VIDEO_TESTS_INL_HPP |
||||
|
||||
#include "gapi_video_tests.hpp" |
||||
|
||||
namespace opencv_test |
||||
{ |
||||
|
||||
TEST_P(OptFlowLKTest, AccuracyTest) |
||||
{ |
||||
std::vector<cv::Point2f> outPtsOCV, outPtsGAPI, inPts; |
||||
std::vector<uchar> outStatusOCV, outStatusGAPI; |
||||
std::vector<float> outErrOCV, outErrGAPI; |
||||
|
||||
OptFlowLKTestParams params { fileNamePattern, channels, pointsNum, |
||||
winSize, criteria, getCompileArgs() }; |
||||
|
||||
OptFlowLKTestOutput outOCV { outPtsOCV, outStatusOCV, outErrOCV }; |
||||
OptFlowLKTestOutput outGAPI { outPtsGAPI, outStatusGAPI, outErrGAPI }; |
||||
|
||||
runOCVnGAPIOptFlowLK(*this, inPts, params, outOCV, outGAPI); |
||||
|
||||
compareOutputsOptFlow(outOCV, outGAPI); |
||||
} |
||||
|
||||
TEST_P(OptFlowLKTestForPyr, AccuracyTest) |
||||
{ |
||||
std::vector<cv::Mat> inPyr1, inPyr2; |
||||
std::vector<cv::Point2f> outPtsOCV, outPtsGAPI, inPts; |
||||
std::vector<uchar> outStatusOCV, outStatusGAPI; |
||||
std::vector<float> outErrOCV, outErrGAPI; |
||||
|
||||
OptFlowLKTestParams params { fileNamePattern, channels, pointsNum, |
||||
winSize, criteria, getCompileArgs() }; |
||||
|
||||
OptFlowLKTestInput<std::vector<cv::Mat>> in { inPyr1, inPyr2, inPts }; |
||||
OptFlowLKTestOutput outOCV { outPtsOCV, outStatusOCV, outErrOCV }; |
||||
OptFlowLKTestOutput outGAPI { outPtsGAPI, outStatusGAPI, outErrGAPI }; |
||||
|
||||
runOCVnGAPIOptFlowLKForPyr(*this, in, params, withDeriv, outOCV, outGAPI); |
||||
|
||||
compareOutputsOptFlow(outOCV, outGAPI); |
||||
} |
||||
|
||||
} // opencv_test
|
||||
|
||||
#endif // OPENCV_GAPI_VIDEO_TESTS_INL_HPP
|
@ -0,0 +1,62 @@ |
||||
// 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.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
|
||||
|
||||
#include "../test_precomp.hpp" |
||||
|
||||
#include "../common/gapi_video_tests.hpp" |
||||
#include <opencv2/gapi/cpu/video.hpp> |
||||
|
||||
namespace |
||||
{ |
||||
#define VIDEO_CPU [] () { return cv::compile_args(cv::gapi::video::cpu::kernels()); } |
||||
|
||||
#ifdef HAVE_OPENCV_VIDEO |
||||
#define WITH_VIDEO(X) X |
||||
#else |
||||
#define WITH_VIDEO(X) DISABLED_##X |
||||
#endif // HAVE_OPENCV_VIDEO
|
||||
|
||||
#define INSTANTIATE_TEST_CASE_MACRO_P(prefix, test_case_name, generator, ...) \ |
||||
INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, __VA_ARGS__) |
||||
} // anonymous namespace
|
||||
|
||||
namespace opencv_test |
||||
{ |
||||
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKTestCPU), OptFlowLKTest, |
||||
Combine(Values(VIDEO_CPU), |
||||
Values("cv/optflow/rock_%01d.bmp", |
||||
"cv/optflow/frames/1080p_%02d.png"), |
||||
Values(1, 3, 4), |
||||
Values(std::make_tuple(9, 9), std::make_tuple(15, 15)), |
||||
Values(7, 11), |
||||
Values(cv::TermCriteria(cv::TermCriteria::COUNT | |
||||
cv::TermCriteria::EPS, |
||||
30, 0.01)))); |
||||
|
||||
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKTestForPyrCPU), OptFlowLKTestForPyr, |
||||
Combine(Values(VIDEO_CPU), |
||||
Values("cv/optflow/rock_%01d.bmp", |
||||
"cv/optflow/frames/1080p_%02d.png"), |
||||
Values(1, 3, 4), |
||||
Values(std::make_tuple(9, 9), std::make_tuple(15, 15)), |
||||
Values(7, 11), |
||||
Values(cv::TermCriteria(cv::TermCriteria::COUNT | |
||||
cv::TermCriteria::EPS, |
||||
30, 0.01)), |
||||
testing::Bool())); |
||||
|
||||
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKInternalTestCPU), OptFlowLKTestForPyr, |
||||
Combine(Values(VIDEO_CPU), |
||||
Values("cv/optflow/rock_%01d.bmp"), |
||||
Values(1), |
||||
Values(std::make_tuple(10, 10)), |
||||
Values(15), |
||||
Values(cv::TermCriteria(cv::TermCriteria::COUNT | |
||||
cv::TermCriteria::EPS, |
||||
21, 0.05)), |
||||
Values(true))); |
||||
} // opencv_test
|
Loading…
Reference in new issue