- 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
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)
# Disable obsollete warning C4503 popping up on MSVC <<2017
src/api/operators.cpp
src/api/kernels_core.cpp
src/api/kernels_imgproc.cpp
+ src/api/kernels_video.cpp
src/api/render.cpp
src/api/render_ocv.cpp
src/api/ginfer.cpp
src/backends/cpu/gcpubackend.cpp
src/backends/cpu/gcpukernel.cpp
src/backends/cpu/gcpuimgproc.cpp
+ src/backends/cpu/gcpuvideo.cpp
src/backends/cpu/gcpucore.cpp
# Fluid Backend (also built-in, FIXME:move away)
--- /dev/null
+// 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
} //namespace imgproc
-
//! @addtogroup gapi_filters
//! @{
/** @brief Applies a separable linear filter to a matrix(image).
--- /dev/null
+// 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
class RGB2HSVPerfTest : 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>> {};
-}
+} // opencv_test
+
#endif //OPENCV_GAPI_IMGPROC_PERF_TESTS_HPP
--- /dev/null
+// 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"
--- /dev/null
+// 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
--- /dev/null
+// 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
Combine(Values(ToleranceColor(1e-3).to_compare_f()),
Values(szVGA, sz720p, sz1080p),
Values(cv::compile_args(IMGPROC_CPU))));
-}
+} // opencv_test
--- /dev/null
+// 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
// 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) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef __OPENCV_GAPI_PERF_PRECOMP_HPP__
#include <opencv2/ts.hpp>
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/imgproc.hpp>
+#include <opencv2/gapi/video.hpp>
#include <opencv2/gapi/core.hpp>
#include <opencv2/gapi/cpu/gcpukernel.hpp>
#include <opencv2/gapi/gpu/ggpukernel.hpp>
--- /dev/null
+// 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
--- /dev/null
+// 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
// 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) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
// <FIXME:>
#if !defined(GAPI_STANDALONE)
-#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/core.hpp> // Also directly refer to Core,
+#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()
#endif // !defined(GAPI_STANDALONE)
// </FIXME:>
static auto ocv_pkg =
#if !defined(GAPI_STANDALONE)
- // FIXME add N-arg version combine
- combine(combine(cv::gapi::core::cpu::kernels(),
- cv::gapi::imgproc::cpu::kernels()),
+ combine(cv::gapi::core::cpu::kernels(),
+ cv::gapi::imgproc::cpu::kernels(),
+ cv::gapi::video::cpu::kernels(),
cv::gapi::render::ocv::kernels());
#else
cv::gapi::GKernelPackage();
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
-
} // opencv_test
#endif //OPENCV_GAPI_IMGPROC_TESTS_INL_HPP
}
}
+ 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
void initNothing(int, cv::Size, int, bool = true) {}
};
template<class T>
-class TestParams: public TestFunctional, public TestWithParam<T>{};
-
-template<class 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
// as 16FC512)
struct MatType2
// Example: FIXTURE_API(int, bool) expands to <int, bool>
#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>
struct CompareF
{
--- /dev/null
+// 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"
--- /dev/null
+// 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
--- /dev/null
+// 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
--- /dev/null
+// 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
--- /dev/null
+// 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
// 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) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
// FIXME: OpenCV header
#include <opencv2/ts.hpp>
#include <opencv2/gapi.hpp>
-#include <opencv2/gapi/imgproc.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/gpu/ggpukernel.hpp>
#include <opencv2/gapi/gpu/imgproc.hpp>