gapi: Full calcOpticalFlowPyrLK implementation (2 overloads) and tests

- opencv_gapi module is linked with opencv_video module (optional dependency)
     - kernels added to a new cv::gapi::video namespace and a brand new files created to provide gapi_video environment
     - there are 2 different kernels as G-API should provide GMat AND GArray<GMat> implementation: cv::calcOptFlowPyrLK doesn't calculate pyramids if vector<Mat> is given so just the cast GMat -> GArray<GMat> wouldn't represent all the cv:: functionality
     - tests to check both kernels (based on cv::video tests for cv::calcOpticalFlowPyrLK())
     - tests for internal purposes added
     - vectors<T> comparison in tests implemented
     - new (and old too) common test structures refactored to avoid code copypasting
     - "modules/gapi/test/common/gapi_video_tests_common.hpp" created to share some code snippets between perf and acc tests and avoid code copypasting
This commit is contained in:
OrestChura 2020-04-08 17:05:43 +03:00
parent acede976e4
commit d50c21e571
22 changed files with 921 additions and 26 deletions

View File

@ -15,7 +15,12 @@ endif()
set(the_description "OpenCV G-API Core Module") set(the_description "OpenCV G-API Core Module")
ocv_add_module(gapi opencv_imgproc) ocv_add_module(gapi
REQUIRED
opencv_imgproc
OPTIONAL
opencv_video
)
if(MSVC) if(MSVC)
# Disable obsollete warning C4503 popping up on MSVC <<2017 # Disable obsollete warning C4503 popping up on MSVC <<2017
@ -55,6 +60,7 @@ set(gapi_srcs
src/api/operators.cpp src/api/operators.cpp
src/api/kernels_core.cpp src/api/kernels_core.cpp
src/api/kernels_imgproc.cpp src/api/kernels_imgproc.cpp
src/api/kernels_video.cpp
src/api/render.cpp src/api/render.cpp
src/api/render_ocv.cpp src/api/render_ocv.cpp
src/api/ginfer.cpp src/api/ginfer.cpp
@ -87,6 +93,7 @@ set(gapi_srcs
src/backends/cpu/gcpubackend.cpp src/backends/cpu/gcpubackend.cpp
src/backends/cpu/gcpukernel.cpp src/backends/cpu/gcpukernel.cpp
src/backends/cpu/gcpuimgproc.cpp src/backends/cpu/gcpuimgproc.cpp
src/backends/cpu/gcpuvideo.cpp
src/backends/cpu/gcpucore.cpp src/backends/cpu/gcpucore.cpp
# Fluid Backend (also built-in, FIXME:move away) # Fluid Backend (also built-in, FIXME:move away)

View File

@ -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

View File

@ -261,7 +261,6 @@ namespace imgproc {
} //namespace imgproc } //namespace imgproc
//! @addtogroup gapi_filters //! @addtogroup gapi_filters
//! @{ //! @{
/** @brief Applies a separable linear filter to a matrix(image). /** @brief Applies a separable linear filter to a matrix(image).

View File

@ -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

View File

@ -49,5 +49,6 @@ class YUV2BGRPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCo
class RGB2HSVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {}; class RGB2HSVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class BayerGR2RGBPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {}; class BayerGR2RGBPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class RGB2YUV422PerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {}; class RGB2YUV422PerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
} } // opencv_test
#endif //OPENCV_GAPI_IMGPROC_PERF_TESTS_HPP #endif //OPENCV_GAPI_IMGPROC_PERF_TESTS_HPP

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -220,4 +220,4 @@ INSTANTIATE_TEST_CASE_P(RGB2YUV422PerfTestCPU, RGB2YUV422PerfTest,
Combine(Values(ToleranceColor(1e-3).to_compare_f()), Combine(Values(ToleranceColor(1e-3).to_compare_f()),
Values(szVGA, sz720p, sz1080p), Values(szVGA, sz720p, sz1080p),
Values(cv::compile_args(IMGPROC_CPU)))); Values(cv::compile_args(IMGPROC_CPU))));
} } // opencv_test

View File

@ -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

View File

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#ifndef __OPENCV_GAPI_PERF_PRECOMP_HPP__ #ifndef __OPENCV_GAPI_PERF_PRECOMP_HPP__
@ -14,6 +14,7 @@
#include <opencv2/ts.hpp> #include <opencv2/ts.hpp>
#include <opencv2/gapi.hpp> #include <opencv2/gapi.hpp>
#include <opencv2/gapi/imgproc.hpp> #include <opencv2/gapi/imgproc.hpp>
#include <opencv2/gapi/video.hpp>
#include <opencv2/gapi/core.hpp> #include <opencv2/gapi/core.hpp>
#include <opencv2/gapi/cpu/gcpukernel.hpp> #include <opencv2/gapi/cpu/gcpukernel.hpp>
#include <opencv2/gapi/gpu/ggpukernel.hpp> #include <opencv2/gapi/gpu/ggpukernel.hpp>

View File

@ -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

View File

@ -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

View File

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp" #include "precomp.hpp"
@ -38,8 +38,9 @@
// <FIXME:> // <FIXME:>
#if !defined(GAPI_STANDALONE) #if !defined(GAPI_STANDALONE)
#include <opencv2/gapi/cpu/core.hpp> // Also directly refer to Core #include <opencv2/gapi/cpu/core.hpp> // Also directly refer to Core,
#include <opencv2/gapi/cpu/imgproc.hpp> // ...and Imgproc kernel implementations #include <opencv2/gapi/cpu/imgproc.hpp> // ...Imgproc
#include <opencv2/gapi/cpu/video.hpp> // ...and Video kernel implementations
#include <opencv2/gapi/render/render.hpp> // render::ocv::backend() #include <opencv2/gapi/render/render.hpp> // render::ocv::backend()
#endif // !defined(GAPI_STANDALONE) #endif // !defined(GAPI_STANDALONE)
// </FIXME:> // </FIXME:>
@ -66,9 +67,9 @@ namespace
static auto ocv_pkg = static auto ocv_pkg =
#if !defined(GAPI_STANDALONE) #if !defined(GAPI_STANDALONE)
// FIXME add N-arg version combine combine(cv::gapi::core::cpu::kernels(),
combine(combine(cv::gapi::core::cpu::kernels(), cv::gapi::imgproc::cpu::kernels(),
cv::gapi::imgproc::cpu::kernels()), cv::gapi::video::cpu::kernels(),
cv::gapi::render::ocv::kernels()); cv::gapi::render::ocv::kernels());
#else #else
cv::gapi::GKernelPackage(); cv::gapi::GKernelPackage();

View File

@ -784,7 +784,6 @@ TEST_P(RGB2YUV422Test, AccuracyTest)
EXPECT_EQ(out_mat_gapi.size(), sz); EXPECT_EQ(out_mat_gapi.size(), sz);
} }
} }
} // opencv_test } // opencv_test
#endif //OPENCV_GAPI_IMGPROC_TESTS_INL_HPP #endif //OPENCV_GAPI_IMGPROC_TESTS_INL_HPP

View File

@ -196,25 +196,32 @@ public:
} }
} }
void initMatsFromImages(int channels, const std::string& pattern, int imgNum)
{
initTestDataPath();
GAPI_Assert(channels == 1 || channels == 3 || channels == 4);
const int flags = (channels == 1) ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR;
cv::Mat m1 = cv::imread(findDataFile(cv::format(pattern.c_str(), imgNum)), flags);
cv::Mat m2 = cv::imread(findDataFile(cv::format(pattern.c_str(), imgNum + 1)), flags);
if (channels == 4)
{
cvtColor(m1, in_mat1, cv::COLOR_BGR2BGRA);
cvtColor(m2, in_mat2, cv::COLOR_BGR2BGRA);
}
else
{
std::tie(in_mat1, in_mat2) = std::make_tuple(m1, m2);
}
}
// empty function intended to show that nothing is to be initialized via TestFunctional methods // empty function intended to show that nothing is to be initialized via TestFunctional methods
void initNothing(int, cv::Size, int, bool = true) {} void initNothing(int, cv::Size, int, bool = true) {}
}; };
template<class T>
class TestParams: public TestFunctional, public TestWithParam<T>{};
template<class T> template<class T>
class TestPerfParams: public TestFunctional, public perf::TestBaseWithParam<T>{}; class TestPerfParams: public TestFunctional, public perf::TestBaseWithParam<T>{};
using compare_f = std::function<bool(const cv::Mat &a, const cv::Mat &b)>;
using compare_scalar_f = std::function<bool(const cv::Scalar &a, const cv::Scalar &b)>;
template<typename Elem>
using compare_vector_f = std::function<bool(const std::vector<Elem> &a,
const std::vector<Elem> &b)>;
// FIXME: re-use MatType. current problem: "special values" interpreted incorrectly (-1 is printed // FIXME: re-use MatType. current problem: "special values" interpreted incorrectly (-1 is printed
// as 16FC512) // as 16FC512)
struct MatType2 struct MatType2
@ -368,6 +375,14 @@ struct TestWithParamsSpecific : public TestWithParamsBase<ParamsSpecific<Specifi
// Example: FIXTURE_API(int, bool) expands to <int, bool> // Example: FIXTURE_API(int, bool) expands to <int, bool>
#define FIXTURE_API(...) <__VA_ARGS__> #define FIXTURE_API(...) <__VA_ARGS__>
using compare_f = std::function<bool(const cv::Mat &a, const cv::Mat &b)>;
using compare_scalar_f = std::function<bool(const cv::Scalar &a, const cv::Scalar &b)>;
template<typename Elem>
using compare_vector_f = std::function<bool(const std::vector<Elem> &a,
const std::vector<Elem> &b)>;
template<typename T1, typename T2> template<typename T1, typename T2>
struct CompareF struct CompareF
{ {

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
// FIXME: OpenCV header // FIXME: OpenCV header
@ -16,8 +16,9 @@
#include <opencv2/ts.hpp> #include <opencv2/ts.hpp>
#include <opencv2/gapi.hpp> #include <opencv2/gapi.hpp>
#include <opencv2/gapi/imgproc.hpp>
#include <opencv2/gapi/core.hpp> #include <opencv2/gapi/core.hpp>
#include <opencv2/gapi/imgproc.hpp>
#include <opencv2/gapi/video.hpp>
#include <opencv2/gapi/cpu/gcpukernel.hpp> #include <opencv2/gapi/cpu/gcpukernel.hpp>
#include <opencv2/gapi/gpu/ggpukernel.hpp> #include <opencv2/gapi/gpu/ggpukernel.hpp>
#include <opencv2/gapi/gpu/imgproc.hpp> #include <opencv2/gapi/gpu/imgproc.hpp>