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