Merge pull request #17082 from OrestChura:oc/buildPyramid

pull/17144/head
Alexander Alekhin 5 years ago
commit 189fc43765
  1. 6
      modules/gapi/include/opencv2/gapi/cpu/gcpukernel.hpp
  2. 105
      modules/gapi/include/opencv2/gapi/video.hpp
  3. 5
      modules/gapi/perf/common/gapi_video_perf_tests.hpp
  4. 69
      modules/gapi/perf/common/gapi_video_perf_tests_inl.hpp
  5. 39
      modules/gapi/perf/cpu/gapi_video_perf_tests_cpu.cpp
  6. 15
      modules/gapi/src/api/kernels_video.cpp
  7. 34
      modules/gapi/src/backends/cpu/gcpuvideo.cpp
  8. 10
      modules/gapi/test/common/gapi_video_tests.hpp
  9. 171
      modules/gapi/test/common/gapi_video_tests_common.hpp
  10. 40
      modules/gapi/test/common/gapi_video_tests_inl.hpp
  11. 38
      modules/gapi/test/cpu/gapi_video_tests_cpu.cpp

@ -255,6 +255,12 @@ template<typename U> struct get_out<cv::GArray<U>>
return ctx.outVecR<U>(idx);
}
};
//FIXME(dm): GArray<Mat>/GArray<GMat> conversion should be done more gracefully in the system
template<> struct get_out<cv::GArray<cv::GMat> >: public get_out<cv::GArray<cv::Mat> >
{
};
template<typename U> struct get_out<cv::GOpaque<U>>
{
static U& get(GCPUContext &ctx, int idx)

@ -18,42 +18,83 @@
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")
using GBuildPyrOutput = std::tuple<GArray<GMat>, GScalar>;
using GOptFlowLKOutput = std::tuple<cv::GArray<cv::Point2f>,
cv::GArray<uchar>,
cv::GArray<float>>;
G_TYPED_KERNEL(GBuildOptFlowPyramid, <GBuildPyrOutput(GMat,Size,GScalar,bool,int,int,bool)>,
"org.opencv.video.buildOpticalFlowPyramid")
{
static std::tuple<GArrayDesc,GScalarDesc>
outMeta(GMatDesc,const Size&,GScalarDesc,bool,int,int,bool)
{
return std::make_tuple(empty_array_desc(), empty_scalar_desc());
}
};
G_TYPED_KERNEL(GCalcOptFlowLK,
<GOptFlowLKOutput(GMat,GMat,cv::GArray<cv::Point2f>,cv::GArray<cv::Point2f>,Size,
GScalar,TermCriteria,int,double)>,
"org.opencv.video.calcOpticalFlowPyrLK")
{
static std::tuple<GArrayDesc,GArrayDesc,GArrayDesc> outMeta(GMatDesc,GMatDesc,GArrayDesc,
GArrayDesc,const Size&,GScalarDesc,
const TermCriteria&,int,double)
{
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")
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,GScalar,
TermCriteria,int,double)>,
"org.opencv.video.calcOpticalFlowPyrLKForPyr")
{
static std::tuple<GArrayDesc,GArrayDesc,GArrayDesc> outMeta(GArrayDesc,GArrayDesc,
GArrayDesc,GArrayDesc,
const Size&,GScalarDesc,
const TermCriteria&,int,double)
{
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());
}
};
return std::make_tuple(empty_array_desc(), empty_array_desc(), empty_array_desc());
}
};
} //namespace video
//! @addtogroup gapi_video
//! @{
/** @brief Constructs the image pyramid which can be passed to calcOpticalFlowPyrLK.
@note Function textual ID is "org.opencv.video.buildOpticalFlowPyramid"
@param img 8-bit input image.
@param winSize window size of optical flow algorithm. Must be not less than winSize
argument of calcOpticalFlowPyrLK. It is needed to calculate required
padding for pyramid levels.
@param maxLevel 0-based maximal pyramid level number.
@param withDerivatives set to precompute gradients for the every pyramid level. If pyramid is
constructed without the gradients then calcOpticalFlowPyrLK will calculate
them internally.
@param pyrBorder the border mode for pyramid layers.
@param derivBorder the border mode for gradients.
@param tryReuseInputImage put ROI of input image into the pyramid if possible. You can pass false
to force data copying.
@return output pyramid.
@return number of levels in constructed pyramid. Can be less than maxLevel.
*/
GAPI_EXPORTS std::tuple<GArray<GMat>, GScalar>
buildOpticalFlowPyramid(const GMat &img,
const Size &winSize,
const GScalar &maxLevel,
bool withDerivatives = true,
int pyrBorder = BORDER_REFLECT_101,
int derivBorder = BORDER_CONSTANT,
bool tryReuseInputImage = true);
/** @brief Calculates an optical flow for a sparse feature set using the iterative Lucas-Kanade
method with pyramids.
@ -104,7 +145,7 @@ calcOpticalFlowPyrLK(const GMat &prevImg,
const GArray<Point2f> &prevPts,
const GArray<Point2f> &predPts,
const Size &winSize = Size(21, 21),
int maxLevel = 3,
const GScalar &maxLevel = 3,
const TermCriteria &criteria = TermCriteria(TermCriteria::COUNT |
TermCriteria::EPS,
30, 0.01),
@ -121,7 +162,7 @@ calcOpticalFlowPyrLK(const GArray<GMat> &prevPyr,
const GArray<Point2f> &prevPts,
const GArray<Point2f> &predPts,
const Size &winSize = Size(21, 21),
int maxLevel = 3,
const GScalar &maxLevel = 3,
const TermCriteria &criteria = TermCriteria(TermCriteria::COUNT |
TermCriteria::EPS,
30, 0.01),

@ -16,11 +16,16 @@ using namespace perf;
//------------------------------------------------------------------------------
class BuildOptFlowPyramidPerfTest : public TestPerfParams<tuple<std::string,int,int,bool,int,int,
bool,GCompileArgs>> {};
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>> {};
class BuildPyr_CalcOptFlow_PipelinePerfTest : public TestPerfParams<tuple<std::string,int,int,bool,
cv::GCompileArgs>> {};
} // opencv_test
#endif // OPENCV_GAPI_VIDEO_PERF_TESTS_HPP

@ -18,6 +18,37 @@ namespace opencv_test
//------------------------------------------------------------------------------
PERF_TEST_P_(BuildOptFlowPyramidPerfTest, TestPerformance)
{
std::vector<Mat> outPyrOCV, outPyrGAPI;
int outMaxLevelOCV = 0, outMaxLevelGAPI = 0;
Scalar outMaxLevelSc;
BuildOpticalFlowPyramidTestParams params;
std::tie(params.fileName, params.winSize,
params.maxLevel, params.withDerivatives,
params.pyrBorder, params.derivBorder,
params.tryReuseInputImage, params.compileArgs) = GetParam();
BuildOpticalFlowPyramidTestOutput outOCV { outPyrOCV, outMaxLevelOCV };
BuildOpticalFlowPyramidTestOutput outGAPI { outPyrGAPI, outMaxLevelGAPI };
GComputation c = runOCVnGAPIBuildOptFlowPyramid(*this, params, outOCV, outGAPI);
declare.in(in_mat1).out(outPyrGAPI);
TEST_CYCLE()
{
c.apply(cv::gin(in_mat1), cv::gout(outPyrGAPI, outMaxLevelSc));
}
outMaxLevelGAPI = static_cast<int>(outMaxLevelSc[0]);
// Comparison //////////////////////////////////////////////////////////////
compareOutputPyramids(outOCV, outGAPI);
SANITY_CHECK_NOTHING();
}
PERF_TEST_P_(OptFlowLKPerfTest, TestPerformance)
{
std::vector<cv::Point2f> outPtsOCV, outPtsGAPI, inPts;
@ -83,6 +114,44 @@ PERF_TEST_P_(OptFlowLKForPyrPerfTest, TestPerformance)
SANITY_CHECK_NOTHING();
}
PERF_TEST_P_(BuildPyr_CalcOptFlow_PipelinePerfTest, TestPerformance)
{
std::vector<Point2f> outPtsOCV, outPtsGAPI, inPts;
std::vector<uchar> outStatusOCV, outStatusGAPI;
std::vector<float> outErrOCV, outErrGAPI;
BuildOpticalFlowPyramidTestParams params;
params.pyrBorder = BORDER_DEFAULT;
params.derivBorder = BORDER_DEFAULT;
params.tryReuseInputImage = true;
std::tie(params.fileName, params.winSize,
params.maxLevel, params.withDerivatives,
params.compileArgs) = GetParam();
auto customKernel = gapi::kernels<GCPUMinScalar>();
auto kernels = gapi::combine(customKernel,
params.compileArgs[0].get<gapi::GKernelPackage>());
params.compileArgs = compile_args(kernels);
OptFlowLKTestOutput outOCV { outPtsOCV, outStatusOCV, outErrOCV };
OptFlowLKTestOutput outGAPI { outPtsGAPI, outStatusGAPI, outErrGAPI };
cv::GComputation c = runOCVnGAPIOptFlowPipeline(*this, params, outOCV, outGAPI, inPts);
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();
}
//------------------------------------------------------------------------------
} // opencv_test

@ -27,6 +27,29 @@ namespace
namespace opencv_test
{
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildOptFlowPyramidPerfTestCPU),
BuildOptFlowPyramidPerfTest,
Combine(Values("cv/optflow/rock_1.bmp",
"cv/optflow/frames/1080p_01.png"),
Values(7, 11),
Values(1000),
testing::Bool(),
Values(BORDER_DEFAULT, BORDER_TRANSPARENT),
Values(BORDER_DEFAULT, BORDER_TRANSPARENT),
testing::Bool(),
Values(cv::compile_args(VIDEO_CPU))));
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildOptFlowPyramidInternalPerfTestCPU),
BuildOptFlowPyramidPerfTest,
Combine(Values("cv/optflow/rock_1.bmp"),
Values(15),
Values(3),
Values(true),
Values(BORDER_REFLECT_101),
Values(BORDER_CONSTANT),
Values(true),
Values(cv::compile_args(VIDEO_CPU))));
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKPerfTestCPU), OptFlowLKPerfTest,
Combine(Values("cv/optflow/rock_%01d.bmp",
"cv/optflow/frames/1080p_%02d.png"),
@ -61,4 +84,20 @@ INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKInternalPerfTestCPU),
21, 0.05)),
Values(true),
Values(cv::compile_args(VIDEO_CPU))));
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildPyr_CalcOptFlow_PipelinePerfTestCPU),
BuildPyr_CalcOptFlow_PipelinePerfTest,
Combine(Values("cv/optflow/frames/1080p_%02d.png"),
Values(7, 11),
Values(1000),
Values(true, false),
Values(cv::compile_args(VIDEO_CPU))));
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildPyr_CalcOptFlow_PipelineInternalTestPerfCPU),
BuildPyr_CalcOptFlow_PipelinePerfTest,
Combine(Values("cv/optflow/rock_%01d.bmp"),
Values(15),
Values(3),
Values(true),
Values(cv::compile_args(VIDEO_CPU))));
} // opencv_test

@ -12,13 +12,24 @@
namespace cv { namespace gapi {
using namespace video;
GBuildPyrOutput buildOpticalFlowPyramid(const GMat &img,
const Size &winSize,
const GScalar &maxLevel,
bool withDerivatives,
int pyrBorder,
int derivBorder,
bool tryReuseInputImage)
{
return GBuildOptFlowPyramid::on(img, winSize, maxLevel, withDerivatives, pyrBorder,
derivBorder, tryReuseInputImage);
}
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 GScalar &maxLevel,
const TermCriteria &criteria,
int flags,
double minEigThresh)
@ -32,7 +43,7 @@ GOptFlowLKOutput calcOpticalFlowPyrLK(const cv::GArray<cv::GMat> &prevPyr,
const cv::GArray<cv::Point2f> &prevPts,
const cv::GArray<cv::Point2f> &predPts,
const Size &winSize,
int maxLevel,
const GScalar &maxLevel,
const TermCriteria &criteria,
int flags,
double minEigThresh)

@ -17,6 +17,25 @@
#ifdef HAVE_OPENCV_VIDEO
GAPI_OCV_KERNEL(GCPUBuildOptFlowPyramid, cv::gapi::video::GBuildOptFlowPyramid)
{
static void run(const cv::Mat &img,
const cv::Size &winSize,
const cv::Scalar &maxLevel,
bool withDerivatives,
int pyrBorder,
int derivBorder,
bool tryReuseInputImage,
std::vector<cv::Mat> &outPyr,
cv::Scalar &outMaxLevel)
{
outMaxLevel = cv::buildOpticalFlowPyramid(img, outPyr, winSize,
static_cast<int>(maxLevel[0]),
withDerivatives, pyrBorder,
derivBorder, tryReuseInputImage);
}
};
GAPI_OCV_KERNEL(GCPUCalcOptFlowLK, cv::gapi::video::GCalcOptFlowLK)
{
static void run(const cv::Mat &prevImg,
@ -24,7 +43,7 @@ GAPI_OCV_KERNEL(GCPUCalcOptFlowLK, cv::gapi::video::GCalcOptFlowLK)
const std::vector<cv::Point2f> &prevPts,
const std::vector<cv::Point2f> &predPts,
const cv::Size &winSize,
int maxLevel,
const cv::Scalar &maxLevel,
const cv::TermCriteria &criteria,
int flags,
double minEigThresh,
@ -34,8 +53,8 @@ GAPI_OCV_KERNEL(GCPUCalcOptFlowLK, cv::gapi::video::GCalcOptFlowLK)
{
if (flags & cv::OPTFLOW_USE_INITIAL_FLOW)
outPts = predPts;
cv::calcOpticalFlowPyrLK(prevImg, nextImg, prevPts, outPts, status, err, winSize, maxLevel,
criteria, flags, minEigThresh);
cv::calcOpticalFlowPyrLK(prevImg, nextImg, prevPts, outPts, status, err, winSize,
static_cast<int>(maxLevel[0]), criteria, flags, minEigThresh);
}
};
@ -46,7 +65,7 @@ GAPI_OCV_KERNEL(GCPUCalcOptFlowLKForPyr, cv::gapi::video::GCalcOptFlowLKForPyr)
const std::vector<cv::Point2f> &prevPts,
const std::vector<cv::Point2f> &predPts,
const cv::Size &winSize,
int maxLevel,
const cv::Scalar &maxLevel,
const cv::TermCriteria &criteria,
int flags,
double minEigThresh,
@ -56,15 +75,16 @@ GAPI_OCV_KERNEL(GCPUCalcOptFlowLKForPyr, cv::gapi::video::GCalcOptFlowLKForPyr)
{
if (flags & cv::OPTFLOW_USE_INITIAL_FLOW)
outPts = predPts;
cv::calcOpticalFlowPyrLK(prevPyr, nextPyr, prevPts, outPts, status, err, winSize, maxLevel,
criteria, flags, minEigThresh);
cv::calcOpticalFlowPyrLK(prevPyr, nextPyr, prevPts, outPts, status, err, winSize,
static_cast<int>(maxLevel[0]), criteria, flags, minEigThresh);
}
};
cv::gapi::GKernelPackage cv::gapi::video::cpu::kernels()
{
static auto pkg = cv::gapi::kernels
< GCPUCalcOptFlowLK
< GCPUBuildOptFlowPyramid
, GCPUCalcOptFlowLK
, GCPUCalcOptFlowLKForPyr
>();
return pkg;

@ -11,6 +11,11 @@
namespace opencv_test
{
GAPI_TEST_FIXTURE_SPEC_PARAMS(BuildOptFlowPyramidTest,
FIXTURE_API(std::string,int,int,bool,int,int,bool), 7,
fileName, winSize, maxLevel, withDerivatives, pyrBorder,
derivBorder, tryReuseInputImage)
GAPI_TEST_FIXTURE_SPEC_PARAMS(OptFlowLKTest, FIXTURE_API(std::string,int,tuple<int,int>,int,
cv::TermCriteria),
5, fileNamePattern, channels, pointsNum, winSize, criteria)
@ -18,6 +23,11 @@ GAPI_TEST_FIXTURE_SPEC_PARAMS(OptFlowLKTest, FIXTURE_API(std::string,int,tuple<i
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)
GAPI_TEST_FIXTURE_SPEC_PARAMS(BuildPyr_CalcOptFlow_PipelineTest,
FIXTURE_API(std::string,int,int,bool), 4,
fileNamePattern, winSize, maxLevel, withDerivatives)
} // opencv_test

@ -20,6 +20,15 @@ namespace opencv_test
{
namespace
{
G_TYPED_KERNEL(GMinScalar, <GScalar(GScalar,GScalar)>, "custom.MinScalar") {
static GScalarDesc outMeta(GScalarDesc,GScalarDesc) { return empty_scalar_desc(); }
};
GAPI_OCV_KERNEL(GCPUMinScalar, GMinScalar) {
static void run(const Scalar &sc1, const Scalar &sc2, Scalar &scOut) {
scOut = Scalar(std::min(sc1[0], sc2[0]));
}
};
inline void initTrackingPointsArray(std::vector<cv::Point2f>& points, int width, int height,
int nPointsX, int nPointsY)
{
@ -46,6 +55,14 @@ inline void initTrackingPointsArray(std::vector<cv::Point2f>& points, int width,
}
}
struct BuildOpticalFlowPyramidTestOutput
{
BuildOpticalFlowPyramidTestOutput(std::vector<Mat> &pyr, int maxLvl) :
pyramid(pyr), maxLevel(maxLvl) { }
std::vector<Mat> &pyramid;
int maxLevel = 0;
};
template<typename Type>
struct OptFlowLKTestInput
{
@ -61,6 +78,31 @@ struct OptFlowLKTestOutput
std::vector<float> &errors;
};
struct BuildOpticalFlowPyramidTestParams
{
BuildOpticalFlowPyramidTestParams(): fileName(""), winSize(-1), maxLevel(-1),
withDerivatives(false), pyrBorder(-1),
derivBorder(-1), tryReuseInputImage(false) { }
BuildOpticalFlowPyramidTestParams(const std::string& name, int winSz, int maxLvl,
bool withDeriv, int pBorder, int dBorder,
bool tryReuse, const GCompileArgs& compArgs):
fileName(name), winSize(winSz), maxLevel(maxLvl),
withDerivatives(withDeriv), pyrBorder(pBorder),
derivBorder(dBorder), tryReuseInputImage(tryReuse),
compileArgs(compArgs) { }
std::string fileName = "";
int winSize = -1;
int maxLevel = -1;
bool withDerivatives = false;
int pyrBorder = -1;
int derivBorder = -1;
bool tryReuseInputImage = false;
cv::GCompileArgs compileArgs;
};
struct OptFlowLKTestParams
{
OptFlowLKTestParams(): fileNamePattern(""), format(1), channels(0), pointsNum{0, 0},
@ -90,6 +132,42 @@ struct OptFlowLKTestParams
#ifdef HAVE_OPENCV_VIDEO
inline GComputation runOCVnGAPIBuildOptFlowPyramid(TestFunctional& testInst,
const BuildOpticalFlowPyramidTestParams& params,
BuildOpticalFlowPyramidTestOutput& outOCV,
BuildOpticalFlowPyramidTestOutput& outGAPI)
{
testInst.initMatFromImage(CV_8UC1, params.fileName);
// OpenCV code /////////////////////////////////////////////////////////////
{
outOCV.maxLevel = cv::buildOpticalFlowPyramid(testInst.in_mat1, outOCV.pyramid,
Size(params.winSize, params.winSize),
params.maxLevel, params.withDerivatives,
params.pyrBorder, params.derivBorder,
params.tryReuseInputImage);
}
// G-API code //////////////////////////////////////////////////////////////
GMat in;
GArray<GMat> out;
GScalar outMaxLevel;
std::tie(out, outMaxLevel) =
cv::gapi::buildOpticalFlowPyramid(in, Size(params.winSize, params.winSize),
params.maxLevel, params.withDerivatives,
params.pyrBorder, params.derivBorder,
params.tryReuseInputImage);
GComputation c(GIn(in), GOut(out, outMaxLevel));
Scalar outMaxLevelSc;
c.apply(gin(testInst.in_mat1), gout(outGAPI.pyramid, outMaxLevelSc),
std::move(const_cast<GCompileArgs&>(params.compileArgs)));
outGAPI.maxLevel = static_cast<int>(outMaxLevelSc[0]);
return c;
}
template<typename GType, typename Type>
cv::GComputation runOCVnGAPIOptFlowLK(OptFlowLKTestInput<Type>& in,
int width, int height,
@ -184,8 +262,77 @@ inline cv::GComputation runOCVnGAPIOptFlowLKForPyr(TestFunctional& testInst,
gapiOut);
}
inline GComputation runOCVnGAPIOptFlowPipeline(TestFunctional& testInst,
const BuildOpticalFlowPyramidTestParams& params,
OptFlowLKTestOutput& outOCV,
OptFlowLKTestOutput& outGAPI,
std::vector<Point2f>& prevPoints)
{
testInst.initMatsFromImages(3, params.fileName, 1);
initTrackingPointsArray(prevPoints, testInst.in_mat1.cols, testInst.in_mat1.rows, 15, 15);
Size winSize = Size(params.winSize, params.winSize);
// OpenCV code /////////////////////////////////////////////////////////////
{
std::vector<Mat> pyr1, pyr2;
int maxLevel1 = cv::buildOpticalFlowPyramid(testInst.in_mat1, pyr1, winSize,
params.maxLevel, params.withDerivatives,
params.pyrBorder, params.derivBorder,
params.tryReuseInputImage);
int maxLevel2 = cv::buildOpticalFlowPyramid(testInst.in_mat2, pyr2, winSize,
params.maxLevel, params.withDerivatives,
params.pyrBorder, params.derivBorder,
params.tryReuseInputImage);
cv::calcOpticalFlowPyrLK(pyr1, pyr2, prevPoints,
outOCV.nextPoints, outOCV.statuses, outOCV.errors,
winSize, std::min(maxLevel1, maxLevel2));
}
// G-API code //////////////////////////////////////////////////////////////
GMat in1, in2;
GArray<GMat> gpyr1, gpyr2;
GScalar gmaxLevel1, gmaxLevel2;
GArray<cv::Point2f> gprevPts, gpredPts, gnextPts;
GArray<uchar> gstatuses;
GArray<float> gerrors;
std::tie(gpyr1, gmaxLevel1) = cv::gapi::buildOpticalFlowPyramid(
in1, winSize, params.maxLevel,
params.withDerivatives, params.pyrBorder,
params.derivBorder, params.tryReuseInputImage);
std::tie(gpyr2, gmaxLevel2) = cv::gapi::buildOpticalFlowPyramid(
in2, winSize, params.maxLevel,
params.withDerivatives, params.pyrBorder,
params.derivBorder, params.tryReuseInputImage);
GScalar gmaxLevel = GMinScalar::on(gmaxLevel1, gmaxLevel2);
std::tie(gnextPts, gstatuses, gerrors) = cv::gapi::calcOpticalFlowPyrLK(
gpyr1, gpyr2, gprevPts, gpredPts, winSize,
gmaxLevel);
cv::GComputation c(GIn(in1, in2, gprevPts, gpredPts), cv::GOut(gnextPts, gstatuses, gerrors));
c.apply(cv::gin(testInst.in_mat1, testInst.in_mat2, prevPoints, std::vector<cv::Point2f>{ }),
cv::gout(outGAPI.nextPoints, outGAPI.statuses, outGAPI.errors),
std::move(const_cast<cv::GCompileArgs&>(params.compileArgs)));
return c;
}
#else // !HAVE_OPENCV_VIDEO
inline cv::GComputation runOCVnGAPIBuildOptFlowPyramid(TestFunctional&,
const BuildOpticalFlowPyramidTestParams&,
BuildOpticalFlowPyramidTestOutput&,
BuildOpticalFlowPyramidTestOutput&)
{
GAPI_Assert(0 && "This function shouldn't be called without opencv_video");
}
inline cv::GComputation runOCVnGAPIOptFlowLK(TestFunctional&,
std::vector<cv::Point2f>&,
const OptFlowLKTestParams&,
@ -205,8 +352,29 @@ inline cv::GComputation runOCVnGAPIOptFlowLKForPyr(TestFunctional&,
GAPI_Assert(0 && "This function shouldn't be called without opencv_video");
}
inline GComputation runOCVnGAPIOptFlowPipeline(TestFunctional&,
const BuildOpticalFlowPyramidTestParams&,
OptFlowLKTestOutput&,
OptFlowLKTestOutput&,
std::vector<Point2f>&)
{
GAPI_Assert(0 && "This function shouldn't be called without opencv_video");
}
#endif // HAVE_OPENCV_VIDEO
inline void compareOutputPyramids(const BuildOpticalFlowPyramidTestOutput& outOCV,
const BuildOpticalFlowPyramidTestOutput& outGAPI)
{
GAPI_Assert(outGAPI.maxLevel == outOCV.maxLevel);
GAPI_Assert(outOCV.maxLevel >= 0);
size_t maxLevel = static_cast<size_t>(outOCV.maxLevel);
for (size_t i = 0; i <= maxLevel; i++)
{
EXPECT_TRUE(AbsExact().to_compare_f()(outOCV.pyramid[i], outGAPI.pyramid[i]));
}
}
template <typename Elem>
inline bool compareVectorsAbsExactForOptFlow(std::vector<Elem> outOCV, std::vector<Elem> outGAPI)
{
@ -221,7 +389,6 @@ inline void compareOutputsOptFlow(const OptFlowLKTestOutput& outOCV,
EXPECT_TRUE(compareVectorsAbsExactForOptFlow(outGAPI.errors, outOCV.errors));
}
inline std::ostream& operator<<(std::ostream& os, const cv::TermCriteria& criteria)
{
os << "{";
@ -236,7 +403,7 @@ inline std::ostream& operator<<(std::ostream& os, const cv::TermCriteria& criter
os << "COUNT | EPS; ";
break;
default:
os << "TypeUndifined; ";
os << "TypeUndefined; ";
break;
};

@ -12,6 +12,23 @@
namespace opencv_test
{
TEST_P(BuildOptFlowPyramidTest, AccuracyTest)
{
std::vector<Mat> outPyrOCV, outPyrGAPI;
int outMaxLevelOCV = 0, outMaxLevelGAPI = 0;
BuildOpticalFlowPyramidTestParams params { fileName, winSize, maxLevel,
withDerivatives, pyrBorder, derivBorder,
tryReuseInputImage, getCompileArgs() };
BuildOpticalFlowPyramidTestOutput outOCV { outPyrOCV, outMaxLevelOCV };
BuildOpticalFlowPyramidTestOutput outGAPI { outPyrGAPI, outMaxLevelGAPI };
runOCVnGAPIBuildOptFlowPyramid(*this, params, outOCV, outGAPI);
compareOutputPyramids(outOCV, outGAPI);
}
TEST_P(OptFlowLKTest, AccuracyTest)
{
std::vector<cv::Point2f> outPtsOCV, outPtsGAPI, inPts;
@ -48,6 +65,29 @@ TEST_P(OptFlowLKTestForPyr, AccuracyTest)
compareOutputsOptFlow(outOCV, outGAPI);
}
TEST_P(BuildPyr_CalcOptFlow_PipelineTest, AccuracyTest)
{
std::vector<Point2f> outPtsOCV, outPtsGAPI, inPts;
std::vector<uchar> outStatusOCV, outStatusGAPI;
std::vector<float> outErrOCV, outErrGAPI;
BuildOpticalFlowPyramidTestParams params { fileNamePattern, winSize, maxLevel,
withDerivatives, BORDER_DEFAULT, BORDER_DEFAULT,
true, getCompileArgs() };
auto customKernel = gapi::kernels<GCPUMinScalar>();
auto kernels = gapi::combine(customKernel,
params.compileArgs[0].get<gapi::GKernelPackage>());
params.compileArgs = compile_args(kernels);
OptFlowLKTestOutput outOCV { outPtsOCV, outStatusOCV, outErrOCV };
OptFlowLKTestOutput outGAPI { outPtsGAPI, outStatusGAPI, outErrGAPI };
runOCVnGAPIOptFlowPipeline(*this, params, outOCV, outGAPI, inPts);
compareOutputsOptFlow(outOCV, outGAPI);
}
} // opencv_test
#endif // OPENCV_GAPI_VIDEO_TESTS_INL_HPP

@ -26,6 +26,28 @@ namespace
namespace opencv_test
{
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildOptFlowPyramidTestCPU), BuildOptFlowPyramidTest,
Combine(Values(VIDEO_CPU),
Values("cv/optflow/rock_1.bmp",
"cv/optflow/frames/1080p_01.png"),
Values(7, 11),
Values(1000),
testing::Bool(),
Values(BORDER_DEFAULT, BORDER_TRANSPARENT),
Values(BORDER_DEFAULT, BORDER_TRANSPARENT),
testing::Bool()));
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildOptFlowPyramidInternalTestCPU),
BuildOptFlowPyramidTest,
Combine(Values(VIDEO_CPU),
Values("cv/optflow/rock_1.bmp"),
Values(15),
Values(3),
Values(true),
Values(BORDER_REFLECT_101),
Values(BORDER_CONSTANT),
Values(true)));
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKTestCPU), OptFlowLKTest,
Combine(Values(VIDEO_CPU),
Values("cv/optflow/rock_%01d.bmp",
@ -59,4 +81,20 @@ INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKInternalTestCPU), OptFlowLKTes
cv::TermCriteria::EPS,
21, 0.05)),
Values(true)));
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildPyr_CalcOptFlow_PipelineTestCPU),
BuildPyr_CalcOptFlow_PipelineTest,
Combine(Values(VIDEO_CPU),
Values("cv/optflow/frames/1080p_%02d.png"),
Values(7, 11),
Values(1000),
testing::Bool()));
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildPyr_CalcOptFlow_PipelineInternalTestCPU),
BuildPyr_CalcOptFlow_PipelineTest,
Combine(Values(VIDEO_CPU),
Values("cv/optflow/rock_%01d.bmp"),
Values(15),
Values(3),
Values(true)));
} // opencv_test

Loading…
Cancel
Save