gapi_video_tests_common.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html.
  4. //
  5. // Copyright (C) 2020 Intel Corporation
  6. #ifndef OPENCV_GAPI_VIDEO_TESTS_COMMON_HPP
  7. #define OPENCV_GAPI_VIDEO_TESTS_COMMON_HPP
  8. #include "gapi_tests_common.hpp"
  9. #include "../../include/opencv2/gapi/video.hpp"
  10. #ifdef HAVE_OPENCV_VIDEO
  11. #include <opencv2/video.hpp>
  12. #endif // HAVE_OPENCV_VIDEO
  13. namespace opencv_test
  14. {
  15. namespace
  16. {
  17. G_TYPED_KERNEL(GMinScalar, <GScalar(GScalar,GScalar)>, "custom.MinScalar") {
  18. static GScalarDesc outMeta(GScalarDesc,GScalarDesc) { return empty_scalar_desc(); }
  19. };
  20. GAPI_OCV_KERNEL(GCPUMinScalar, GMinScalar) {
  21. static void run(const Scalar &sc1, const Scalar &sc2, Scalar &scOut) {
  22. scOut = Scalar(std::min(sc1[0], sc2[0]));
  23. }
  24. };
  25. inline void initTrackingPointsArray(std::vector<cv::Point2f>& points, int width, int height,
  26. int nPointsX, int nPointsY)
  27. {
  28. if (nPointsX > width || nPointsY > height)
  29. {
  30. FAIL() << "Specified points number is too big";
  31. }
  32. int stepX = width / nPointsX;
  33. int stepY = height / nPointsY;
  34. points.clear();
  35. GAPI_Assert((nPointsX >= 0) && (nPointsY) >= 0);
  36. points.reserve(nPointsX * nPointsY);
  37. for (int x = stepX / 2; x < width; x += stepX)
  38. {
  39. for (int y = stepY / 2; y < height; y += stepY)
  40. {
  41. Point2f pt(static_cast<float>(x), static_cast<float>(y));
  42. points.push_back(pt);
  43. }
  44. }
  45. }
  46. struct BuildOpticalFlowPyramidTestOutput
  47. {
  48. BuildOpticalFlowPyramidTestOutput(std::vector<Mat> &pyr, int maxLvl) :
  49. pyramid(pyr), maxLevel(maxLvl) { }
  50. std::vector<Mat> &pyramid;
  51. int maxLevel = 0;
  52. };
  53. template<typename Type>
  54. struct OptFlowLKTestInput
  55. {
  56. Type& prevData;
  57. Type& nextData;
  58. std::vector<cv::Point2f>& prevPoints;
  59. };
  60. struct OptFlowLKTestOutput
  61. {
  62. std::vector<cv::Point2f> &nextPoints;
  63. std::vector<uchar> &statuses;
  64. std::vector<float> &errors;
  65. };
  66. struct BuildOpticalFlowPyramidTestParams
  67. {
  68. BuildOpticalFlowPyramidTestParams() = default;
  69. BuildOpticalFlowPyramidTestParams(const std::string& name, int winSz, int maxLvl,
  70. bool withDeriv, int pBorder, int dBorder,
  71. bool tryReuse, const GCompileArgs& compArgs):
  72. fileName(name), winSize(winSz), maxLevel(maxLvl),
  73. withDerivatives(withDeriv), pyrBorder(pBorder),
  74. derivBorder(dBorder), tryReuseInputImage(tryReuse),
  75. compileArgs(compArgs) { }
  76. std::string fileName = "";
  77. int winSize = -1;
  78. int maxLevel = -1;
  79. bool withDerivatives = false;
  80. int pyrBorder = -1;
  81. int derivBorder = -1;
  82. bool tryReuseInputImage = false;
  83. cv::GCompileArgs compileArgs;
  84. };
  85. struct OptFlowLKTestParams
  86. {
  87. OptFlowLKTestParams(): fileNamePattern(""), format(1), channels(0), pointsNum{0, 0},
  88. winSize(0), maxLevel(3), minEigThreshold(1e-4), flags(0) { }
  89. OptFlowLKTestParams(const std::string& namePat, int chans,
  90. const std::tuple<int,int>& ptsNum, int winSz,
  91. const cv::TermCriteria& crit, const cv::GCompileArgs& compArgs,
  92. int flgs = 0, int fmt = 1, int maxLvl = 3, double minEigThresh = 1e-4):
  93. fileNamePattern(namePat), format(fmt), channels(chans),
  94. pointsNum(ptsNum), winSize(winSz), maxLevel(maxLvl),
  95. criteria(crit), minEigThreshold(minEigThresh), compileArgs(compArgs),
  96. flags(flgs) { }
  97. std::string fileNamePattern = "";
  98. int format = 1;
  99. int channels = 0;
  100. std::tuple<int,int> pointsNum = std::make_tuple(0, 0);
  101. int winSize = 0;
  102. int maxLevel = 3;
  103. cv::TermCriteria criteria;
  104. double minEigThreshold = 1e-4;
  105. cv::GCompileArgs compileArgs;
  106. int flags = 0;
  107. };
  108. inline void compareOutputPyramids(const BuildOpticalFlowPyramidTestOutput& outGAPI,
  109. const BuildOpticalFlowPyramidTestOutput& outOCV)
  110. {
  111. GAPI_Assert(outGAPI.maxLevel == outOCV.maxLevel);
  112. GAPI_Assert(outOCV.maxLevel >= 0);
  113. const size_t maxLevel = static_cast<size_t>(outOCV.maxLevel);
  114. for (size_t i = 0; i <= maxLevel; i++)
  115. {
  116. EXPECT_TRUE(AbsExact().to_compare_f()(outGAPI.pyramid[i], outOCV.pyramid[i]));
  117. }
  118. }
  119. template <typename Elem>
  120. inline bool compareVectorsAbsExactForOptFlow(const std::vector<Elem>& outGAPI,
  121. const std::vector<Elem>& outOCV)
  122. {
  123. return AbsExactVector<Elem>().to_compare_f()(outGAPI, outOCV);
  124. }
  125. inline void compareOutputsOptFlow(const OptFlowLKTestOutput& outGAPI,
  126. const OptFlowLKTestOutput& outOCV)
  127. {
  128. EXPECT_TRUE(compareVectorsAbsExactForOptFlow(outGAPI.nextPoints, outOCV.nextPoints));
  129. EXPECT_TRUE(compareVectorsAbsExactForOptFlow(outGAPI.statuses, outOCV.statuses));
  130. EXPECT_TRUE(compareVectorsAbsExactForOptFlow(outGAPI.errors, outOCV.errors));
  131. }
  132. inline std::ostream& operator<<(std::ostream& os, const cv::TermCriteria& criteria)
  133. {
  134. os << "{";
  135. switch (criteria.type) {
  136. case cv::TermCriteria::COUNT:
  137. os << "COUNT; ";
  138. break;
  139. case cv::TermCriteria::EPS:
  140. os << "EPS; ";
  141. break;
  142. case cv::TermCriteria::COUNT | cv::TermCriteria::EPS:
  143. os << "COUNT | EPS; ";
  144. break;
  145. default:
  146. os << "TypeUndefined; ";
  147. break;
  148. };
  149. return os << criteria.maxCount << "; " << criteria.epsilon <<"}";
  150. }
  151. #ifdef HAVE_OPENCV_VIDEO
  152. inline GComputation runOCVnGAPIBuildOptFlowPyramid(TestFunctional& testInst,
  153. const BuildOpticalFlowPyramidTestParams& params,
  154. BuildOpticalFlowPyramidTestOutput& outOCV,
  155. BuildOpticalFlowPyramidTestOutput& outGAPI)
  156. {
  157. testInst.initMatFromImage(CV_8UC1, params.fileName);
  158. // OpenCV code /////////////////////////////////////////////////////////////
  159. {
  160. outOCV.maxLevel = cv::buildOpticalFlowPyramid(testInst.in_mat1, outOCV.pyramid,
  161. Size(params.winSize, params.winSize),
  162. params.maxLevel, params.withDerivatives,
  163. params.pyrBorder, params.derivBorder,
  164. params.tryReuseInputImage);
  165. }
  166. // G-API code //////////////////////////////////////////////////////////////
  167. GMat in;
  168. GArray<GMat> out;
  169. GScalar outMaxLevel;
  170. std::tie(out, outMaxLevel) =
  171. cv::gapi::buildOpticalFlowPyramid(in, Size(params.winSize, params.winSize),
  172. params.maxLevel, params.withDerivatives,
  173. params.pyrBorder, params.derivBorder,
  174. params.tryReuseInputImage);
  175. GComputation c(GIn(in), GOut(out, outMaxLevel));
  176. Scalar outMaxLevelSc;
  177. c.apply(gin(testInst.in_mat1), gout(outGAPI.pyramid, outMaxLevelSc),
  178. std::move(const_cast<GCompileArgs&>(params.compileArgs)));
  179. outGAPI.maxLevel = static_cast<int>(outMaxLevelSc[0]);
  180. return c;
  181. }
  182. template<typename GType, typename Type>
  183. cv::GComputation runOCVnGAPIOptFlowLK(OptFlowLKTestInput<Type>& in,
  184. int width, int height,
  185. const OptFlowLKTestParams& params,
  186. OptFlowLKTestOutput& ocvOut,
  187. OptFlowLKTestOutput& gapiOut)
  188. {
  189. int nPointsX = 0, nPointsY = 0;
  190. std::tie(nPointsX, nPointsY) = params.pointsNum;
  191. initTrackingPointsArray(in.prevPoints, width, height, nPointsX, nPointsY);
  192. cv::Size winSize(params.winSize, params.winSize);
  193. // OpenCV code /////////////////////////////////////////////////////////////
  194. {
  195. cv::calcOpticalFlowPyrLK(in.prevData, in.nextData, in.prevPoints,
  196. ocvOut.nextPoints, ocvOut.statuses, ocvOut.errors,
  197. winSize, params.maxLevel, params.criteria,
  198. params.flags, params.minEigThreshold);
  199. }
  200. // G-API code //////////////////////////////////////////////////////////////
  201. {
  202. GType inPrev, inNext;
  203. GArray<cv::Point2f> prevPts, predPts, nextPts;
  204. GArray<uchar> statuses;
  205. GArray<float> errors;
  206. std::tie(nextPts, statuses, errors) = cv::gapi::calcOpticalFlowPyrLK(
  207. inPrev, inNext,
  208. prevPts, predPts, winSize,
  209. params.maxLevel, params.criteria,
  210. params.flags, params.minEigThreshold);
  211. cv::GComputation c(cv::GIn(inPrev, inNext, prevPts, predPts),
  212. cv::GOut(nextPts, statuses, errors));
  213. c.apply(cv::gin(in.prevData, in.nextData, in.prevPoints, std::vector<cv::Point2f>{ }),
  214. cv::gout(gapiOut.nextPoints, gapiOut.statuses, gapiOut.errors),
  215. std::move(const_cast<cv::GCompileArgs&>(params.compileArgs)));
  216. return c;
  217. }
  218. }
  219. inline cv::GComputation runOCVnGAPIOptFlowLK(TestFunctional& testInst,
  220. std::vector<cv::Point2f>& inPts,
  221. const OptFlowLKTestParams& params,
  222. OptFlowLKTestOutput& ocvOut,
  223. OptFlowLKTestOutput& gapiOut)
  224. {
  225. testInst.initMatsFromImages(params.channels,
  226. params.fileNamePattern,
  227. params.format);
  228. OptFlowLKTestInput<cv::Mat> in{ testInst.in_mat1, testInst.in_mat2, inPts };
  229. return runOCVnGAPIOptFlowLK<cv::GMat>(in,
  230. testInst.in_mat1.cols,
  231. testInst.in_mat1.rows,
  232. params,
  233. ocvOut,
  234. gapiOut);
  235. }
  236. inline cv::GComputation runOCVnGAPIOptFlowLKForPyr(TestFunctional& testInst,
  237. OptFlowLKTestInput<std::vector<cv::Mat>>& in,
  238. const OptFlowLKTestParams& params,
  239. bool withDeriv,
  240. OptFlowLKTestOutput& ocvOut,
  241. OptFlowLKTestOutput& gapiOut)
  242. {
  243. testInst.initMatsFromImages(params.channels,
  244. params.fileNamePattern,
  245. params.format);
  246. cv::Size winSize(params.winSize, params.winSize);
  247. OptFlowLKTestParams updatedParams(params);
  248. updatedParams.maxLevel = cv::buildOpticalFlowPyramid(testInst.in_mat1, in.prevData,
  249. winSize, params.maxLevel, withDeriv);
  250. updatedParams.maxLevel = cv::buildOpticalFlowPyramid(testInst.in_mat2, in.nextData,
  251. winSize, params.maxLevel, withDeriv);
  252. return runOCVnGAPIOptFlowLK<cv::GArray<cv::GMat>>(in,
  253. testInst.in_mat1.cols,
  254. testInst.in_mat1.rows,
  255. updatedParams,
  256. ocvOut,
  257. gapiOut);
  258. }
  259. inline GComputation runOCVnGAPIOptFlowPipeline(TestFunctional& testInst,
  260. const BuildOpticalFlowPyramidTestParams& params,
  261. OptFlowLKTestOutput& outOCV,
  262. OptFlowLKTestOutput& outGAPI,
  263. std::vector<Point2f>& prevPoints)
  264. {
  265. testInst.initMatsFromImages(3, params.fileName, 1);
  266. initTrackingPointsArray(prevPoints, testInst.in_mat1.cols, testInst.in_mat1.rows, 15, 15);
  267. Size winSize = Size(params.winSize, params.winSize);
  268. // OpenCV code /////////////////////////////////////////////////////////////
  269. {
  270. std::vector<Mat> pyr1, pyr2;
  271. int maxLevel1 = cv::buildOpticalFlowPyramid(testInst.in_mat1, pyr1, winSize,
  272. params.maxLevel, params.withDerivatives,
  273. params.pyrBorder, params.derivBorder,
  274. params.tryReuseInputImage);
  275. int maxLevel2 = cv::buildOpticalFlowPyramid(testInst.in_mat2, pyr2, winSize,
  276. params.maxLevel, params.withDerivatives,
  277. params.pyrBorder, params.derivBorder,
  278. params.tryReuseInputImage);
  279. cv::calcOpticalFlowPyrLK(pyr1, pyr2, prevPoints,
  280. outOCV.nextPoints, outOCV.statuses, outOCV.errors,
  281. winSize, std::min(maxLevel1, maxLevel2));
  282. }
  283. // G-API code //////////////////////////////////////////////////////////////
  284. GMat in1, in2;
  285. GArray<GMat> gpyr1, gpyr2;
  286. GScalar gmaxLevel1, gmaxLevel2;
  287. GArray<cv::Point2f> gprevPts, gpredPts, gnextPts;
  288. GArray<uchar> gstatuses;
  289. GArray<float> gerrors;
  290. std::tie(gpyr1, gmaxLevel1) = cv::gapi::buildOpticalFlowPyramid(
  291. in1, winSize, params.maxLevel,
  292. params.withDerivatives, params.pyrBorder,
  293. params.derivBorder, params.tryReuseInputImage);
  294. std::tie(gpyr2, gmaxLevel2) = cv::gapi::buildOpticalFlowPyramid(
  295. in2, winSize, params.maxLevel,
  296. params.withDerivatives, params.pyrBorder,
  297. params.derivBorder, params.tryReuseInputImage);
  298. GScalar gmaxLevel = GMinScalar::on(gmaxLevel1, gmaxLevel2);
  299. std::tie(gnextPts, gstatuses, gerrors) = cv::gapi::calcOpticalFlowPyrLK(
  300. gpyr1, gpyr2, gprevPts, gpredPts, winSize,
  301. gmaxLevel);
  302. cv::GComputation c(GIn(in1, in2, gprevPts, gpredPts), cv::GOut(gnextPts, gstatuses, gerrors));
  303. c.apply(cv::gin(testInst.in_mat1, testInst.in_mat2, prevPoints, std::vector<cv::Point2f>{ }),
  304. cv::gout(outGAPI.nextPoints, outGAPI.statuses, outGAPI.errors),
  305. std::move(const_cast<cv::GCompileArgs&>(params.compileArgs)));
  306. return c;
  307. }
  308. inline void testBackgroundSubtractorStreaming(cv::GStreamingCompiled& gapiBackSub,
  309. const cv::Ptr<cv::BackgroundSubtractor>& pOCVBackSub,
  310. const int diffPercent, const int tolerance,
  311. const double lRate, const std::size_t testNumFrames)
  312. {
  313. cv::Mat frame, gapiForeground, ocvForeground;
  314. double numDiff = diffPercent / 100.0;
  315. gapiBackSub.start();
  316. EXPECT_TRUE(gapiBackSub.running());
  317. compare_f cmpF = AbsSimilarPoints(tolerance, numDiff).to_compare_f();
  318. // Comparison of G-API and OpenCV substractors
  319. std::size_t frames = 0u;
  320. while (frames <= testNumFrames && gapiBackSub.pull(cv::gout(frame, gapiForeground)))
  321. {
  322. pOCVBackSub->apply(frame, ocvForeground, lRate);
  323. EXPECT_TRUE(cmpF(gapiForeground, ocvForeground));
  324. frames++;
  325. }
  326. if (gapiBackSub.running())
  327. gapiBackSub.stop();
  328. EXPECT_LT(0u, frames);
  329. EXPECT_FALSE(gapiBackSub.running());
  330. }
  331. inline void initKalmanParams(const int type, const int dDim, const int mDim, const int cDim,
  332. cv::gapi::KalmanParams& kp)
  333. {
  334. kp.state = Mat::zeros(dDim, 1, type);
  335. cv::randu(kp.state, Scalar::all(0), Scalar::all(0.1));
  336. kp.errorCov = Mat::eye(dDim, dDim, type);
  337. kp.transitionMatrix = Mat::ones(dDim, dDim, type) * 2;
  338. kp.processNoiseCov = Mat::eye(dDim, dDim, type) * (1e-5);
  339. kp.measurementMatrix = Mat::eye(mDim, dDim, type) * 2;
  340. kp.measurementNoiseCov = Mat::eye(mDim, mDim, type) * (1e-5);
  341. if (cDim > 0)
  342. kp.controlMatrix = Mat::eye(dDim, cDim, type) * (1e-3);
  343. }
  344. inline void initKalmanFilter(const cv::gapi::KalmanParams& kp, const bool control,
  345. cv::KalmanFilter& ocvKalman)
  346. {
  347. kp.state.copyTo(ocvKalman.statePost);
  348. kp.errorCov.copyTo(ocvKalman.errorCovPost);
  349. kp.transitionMatrix.copyTo(ocvKalman.transitionMatrix);
  350. kp.measurementMatrix.copyTo(ocvKalman.measurementMatrix);
  351. kp.measurementNoiseCov.copyTo(ocvKalman.measurementNoiseCov);
  352. kp.processNoiseCov.copyTo(ocvKalman.processNoiseCov);
  353. if (control)
  354. kp.controlMatrix.copyTo(ocvKalman.controlMatrix);
  355. }
  356. #else // !HAVE_OPENCV_VIDEO
  357. inline cv::GComputation runOCVnGAPIBuildOptFlowPyramid(TestFunctional&,
  358. const BuildOpticalFlowPyramidTestParams&,
  359. BuildOpticalFlowPyramidTestOutput&,
  360. BuildOpticalFlowPyramidTestOutput&)
  361. {
  362. GAPI_Assert(0 && "This function shouldn't be called without opencv_video");
  363. }
  364. inline cv::GComputation runOCVnGAPIOptFlowLK(TestFunctional&,
  365. std::vector<cv::Point2f>&,
  366. const OptFlowLKTestParams&,
  367. OptFlowLKTestOutput&,
  368. OptFlowLKTestOutput&)
  369. {
  370. GAPI_Assert(0 && "This function shouldn't be called without opencv_video");
  371. }
  372. inline cv::GComputation runOCVnGAPIOptFlowLKForPyr(TestFunctional&,
  373. OptFlowLKTestInput<std::vector<cv::Mat>>&,
  374. const OptFlowLKTestParams&,
  375. bool,
  376. OptFlowLKTestOutput&,
  377. OptFlowLKTestOutput&)
  378. {
  379. GAPI_Assert(0 && "This function shouldn't be called without opencv_video");
  380. }
  381. inline GComputation runOCVnGAPIOptFlowPipeline(TestFunctional&,
  382. const BuildOpticalFlowPyramidTestParams&,
  383. OptFlowLKTestOutput&,
  384. OptFlowLKTestOutput&,
  385. std::vector<Point2f>&)
  386. {
  387. GAPI_Assert(0 && "This function shouldn't be called without opencv_video");
  388. }
  389. #endif // HAVE_OPENCV_VIDEO
  390. } // namespace
  391. } // namespace opencv_test
  392. // Note: namespace must match the namespace of the type of the printed object
  393. namespace cv { namespace gapi { namespace video
  394. {
  395. inline std::ostream& operator<<(std::ostream& os, const BackgroundSubtractorType op)
  396. {
  397. #define CASE(v) case BackgroundSubtractorType::v: os << #v; break
  398. switch (op)
  399. {
  400. CASE(TYPE_BS_MOG2);
  401. CASE(TYPE_BS_KNN);
  402. default: GAPI_Assert(false && "unknown BackgroundSubtractor type");
  403. }
  404. #undef CASE
  405. return os;
  406. }
  407. }}} // namespace cv::gapi::video
  408. #endif // OPENCV_GAPI_VIDEO_TESTS_COMMON_HPP