mirror of
https://github.com/opencv/opencv.git
synced 2025-08-06 06:26:29 +08:00
Merge pull request #17082 from OrestChura:oc/buildPyramid
This commit is contained in:
commit
189fc43765
@ -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>>;
|
||||
using GBuildPyrOutput = std::tuple<GArray<GMat>, GScalar>;
|
||||
|
||||
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 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)
|
||||
{
|
||||
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());
|
||||
}
|
||||
return std::make_tuple(empty_array_desc(), empty_scalar_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")
|
||||
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(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());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
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…
Reference in New Issue
Block a user