Publishing 2019 R3 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / fluid / modules / gapi / test / common / gapi_tests_common.hpp
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) 2018-2019 Intel Corporation
6
7 #ifndef OPENCV_GAPI_TESTS_COMMON_HPP
8 #define OPENCV_GAPI_TESTS_COMMON_HPP
9
10 #include <iostream>
11 #include <tuple>
12 #include <type_traits>
13
14 #include <opencv2/ts.hpp>
15 #include <opencv2/gapi.hpp>
16 #include <opencv2/gapi/util/util.hpp>
17
18 #include "gapi_tests_helpers.hpp"
19
20 namespace
21 {
22     inline std::ostream& operator<<(std::ostream& o, const cv::GCompileArg& arg)
23     {
24         return o << (arg.tag.empty() ? "empty" : arg.tag);
25     }
26 }
27
28 namespace opencv_test
29 {
30
31 class TestFunctional
32 {
33 public:
34     cv::Mat in_mat1;
35     cv::Mat in_mat2;
36     cv::Mat out_mat_gapi;
37     cv::Mat out_mat_ocv;
38
39     cv::Scalar sc;
40
41     cv::Scalar initScalarRandU(unsigned upper)
42     {
43         auto& rng = cv::theRNG();
44         double s1 = rng(upper);
45         double s2 = rng(upper);
46         double s3 = rng(upper);
47         double s4 = rng(upper);
48         return cv::Scalar(s1, s2, s3, s4);
49     }
50
51     void initOutMats(cv::Size sz_in, int dtype)
52     {
53         if (dtype != -1)
54         {
55             out_mat_gapi = cv::Mat(sz_in, dtype);
56             out_mat_ocv = cv::Mat(sz_in, dtype);
57         }
58     }
59
60     void initMatsRandU(int type, cv::Size sz_in, int dtype, bool createOutputMatrices = true)
61     {
62         in_mat1 = cv::Mat(sz_in, type);
63         in_mat2 = cv::Mat(sz_in, type);
64
65         sc = initScalarRandU(100);
66         cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
67         cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(255));
68
69         if (createOutputMatrices)
70         {
71             initOutMats(sz_in, dtype);
72         }
73     }
74
75     void initMatrixRandU(int type, cv::Size sz_in, int dtype, bool createOutputMatrices = true)
76     {
77         in_mat1 = cv::Mat(sz_in, type);
78
79         sc = initScalarRandU(100);
80         cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
81
82         if (createOutputMatrices)
83         {
84             initOutMats(sz_in, dtype);
85         }
86     }
87
88     void initMatrixRandN(int type, cv::Size sz_in, int dtype, bool createOutputMatrices = true)
89     {
90         in_mat1 = cv::Mat(sz_in, type);
91         cv::randn(in_mat1, cv::Scalar::all(127), cv::Scalar::all(40.f));
92
93         if (createOutputMatrices)
94         {
95             initOutMats(sz_in, dtype);
96         }
97     }
98
99     // empty function intended to show that nothing is to be initialized via TestFunctional methods
100     void initNothing(int, cv::Size, int, bool = true) {}
101
102     static cv::Mat nonZeroPixels(const cv::Mat& mat)
103     {
104         int channels = mat.channels();
105         std::vector<cv::Mat> split(channels);
106         cv::split(mat, split);
107         cv::Mat result;
108         for (int c=0; c < channels; c++)
109         {
110             if (c == 0)
111                 result = split[c] != 0;
112             else
113                 result = result | (split[c] != 0);
114         }
115         return result;
116     }
117
118     static int countNonZeroPixels(const cv::Mat& mat)
119     {
120         return cv::countNonZero( nonZeroPixels(mat) );
121     }
122
123 };
124
125 template<class T>
126 class TestParams: public TestFunctional, public TestWithParam<T>{};
127
128 template<class T>
129 class TestPerfParams: public TestFunctional, public perf::TestBaseWithParam<T>{};
130
131 using compare_f = std::function<bool(const cv::Mat &a, const cv::Mat &b)>;
132
133 using compare_scalar_f = std::function<bool(const cv::Scalar &a, const cv::Scalar &b)>;
134
135 // FIXME: re-use MatType. current problem: "special values" interpreted incorrectly (-1 is printed
136 //        as 16FC512)
137 struct MatType2
138 {
139 public:
140     MatType2(int val = 0) : _value(val) {}
141     operator int() const { return _value; }
142     friend std::ostream& operator<<(std::ostream& os, const MatType2& t)
143     {
144         switch (t)
145         {
146             case -1: return os << "SAME_TYPE";
147             default: PrintTo(MatType(t), &os); return os;
148         }
149     }
150 private:
151     int _value;
152 };
153
154 // Universal parameter wrapper for common (pre-defined) and specific (user-defined) parameters
155 template<typename ...SpecificParams>
156 struct Params
157 {
158     using gcomp_args_function_t = cv::GCompileArgs(*)();
159     using common_params_t = std::tuple<MatType2, cv::Size, MatType2, gcomp_args_function_t>;
160     using specific_params_t = std::tuple<SpecificParams...>;
161     using params_t = std::tuple<MatType2, cv::Size, MatType2, gcomp_args_function_t, SpecificParams...>;
162     static constexpr const size_t common_params_size = std::tuple_size<common_params_t>::value;
163     static constexpr const size_t specific_params_size = std::tuple_size<specific_params_t>::value;
164
165     template<size_t I>
166     static const typename std::tuple_element<I, common_params_t>::type&
167     getCommon(const params_t& t)
168     {
169         static_assert(I < common_params_size, "Index out of range");
170         return std::get<I>(t);
171     }
172
173     template<size_t I>
174     static const typename std::tuple_element<I, specific_params_t>::type&
175     getSpecific(const params_t& t)
176     {
177         static_assert(specific_params_size > 0,
178             "Impossible to call this function: no specific parameters specified");
179         static_assert(I < specific_params_size, "Index out of range");
180         return std::get<common_params_size + I>(t);
181     }
182 };
183
184 // Base class for test fixtures
185 template<typename ...SpecificParams>
186 struct TestWithParamBase : TestFunctional,
187     TestWithParam<typename Params<SpecificParams...>::params_t>
188 {
189     using AllParams = Params<SpecificParams...>;
190
191     MatType2 type = getCommonParam<0>();
192     cv::Size sz = getCommonParam<1>();
193     MatType2 dtype = getCommonParam<2>();
194
195     // Get common (pre-defined) parameter value by index
196     template<size_t I>
197     inline auto getCommonParam() const
198         -> decltype(AllParams::template getCommon<I>(this->GetParam()))
199     {
200         return AllParams::template getCommon<I>(this->GetParam());
201     }
202
203     // Get specific (user-defined) parameter value by index
204     template<size_t I>
205     inline auto getSpecificParam() const
206         -> decltype(AllParams::template getSpecific<I>(this->GetParam()))
207     {
208         return AllParams::template getSpecific<I>(this->GetParam());
209     }
210
211     // Return G-API compile arguments specified for test fixture
212     inline cv::GCompileArgs getCompileArgs() const
213     {
214         return getCommonParam<3>()();
215     }
216 };
217
218 /**
219  * @private
220  * @brief Create G-API test fixture with TestWithParamBase base class
221  * @param Fixture   test fixture name
222  * @param InitF     callable that will initialize default available members (from TestFunctional)
223  * @param API       base class API. Specifies types of user-defined parameters. If there are no such
224  *                  parameters, empty angle brackets ("<>") must be specified.
225  * @param Number    number of user-defined parameters (corresponds to the number of types in API).
226  *                  if there are no such parameters, 0 must be specified.
227  * @param ...       list of names of user-defined parameters. if there are no parameters, the list
228  *                  must be empty.
229  */
230 #define GAPI_TEST_FIXTURE(Fixture, InitF, API, Number, ...) \
231     struct Fixture : public TestWithParamBase API { \
232         static_assert(Number == AllParams::specific_params_size, \
233             "Number of user-defined parameters doesn't match size of __VA_ARGS__"); \
234         __WRAP_VAARGS(DEFINE_SPECIFIC_PARAMS_##Number(__VA_ARGS__)) \
235         Fixture() { InitF(type, sz, dtype); } \
236     };
237
238 // Wrapper for test fixture API. Use to specify multiple types.
239 // Example: FIXTURE_API(int, bool) expands to <int, bool>
240 #define FIXTURE_API(...) <__VA_ARGS__>
241
242 template<typename T1, typename T2>
243 struct CompareF
244 {
245     using callable_t = std::function<bool(const T1& a, const T2& b)>;
246     CompareF(callable_t&& cmp, std::string&& cmp_name) :
247         _comparator(std::move(cmp)), _name(std::move(cmp_name)) {}
248     bool operator()(const T1& a, const T2& b) const
249     {
250         return _comparator(a, b);
251     }
252     friend std::ostream& operator<<(std::ostream& os, const CompareF<T1, T2>& obj)
253     {
254         return os << obj._name;
255     }
256 private:
257     callable_t _comparator;
258     std::string _name;
259 };
260
261 using CompareMats = CompareF<cv::Mat, cv::Mat>;
262 using CompareScalars = CompareF<cv::Scalar, cv::Scalar>;
263
264 template<typename T>
265 struct Wrappable
266 {
267     compare_f to_compare_f()
268     {
269         T t = *static_cast<T*const>(this);
270         return [t](const cv::Mat &a, const cv::Mat &b)
271         {
272             return t(a, b);
273         };
274     }
275
276     CompareMats to_compare_obj()
277     {
278         T t = *static_cast<T*const>(this);
279         std::stringstream ss;
280         ss << t;
281         return CompareMats(to_compare_f(), ss.str());
282     }
283 };
284
285 template<typename T>
286 struct WrappableScalar
287 {
288     compare_scalar_f to_compare_f()
289     {
290         T t = *static_cast<T*const>(this);
291         return [t](const cv::Scalar &a, const cv::Scalar &b)
292         {
293             return t(a, b);
294         };
295     }
296
297     CompareScalars to_compare_obj()
298     {
299         T t = *static_cast<T*const>(this);
300         std::stringstream ss;
301         ss << t;
302         return CompareScalars(to_compare_f(), ss.str());
303     }
304 };
305
306
307 class AbsExact : public Wrappable<AbsExact>
308 {
309 public:
310     AbsExact() {}
311     bool operator() (const cv::Mat& in1, const cv::Mat& in2) const
312     {
313         if (cv::norm(in1, in2, NORM_INF) != 0)
314         {
315             std::cout << "AbsExact error: G-API output and reference output matrixes are not bitexact equal."  << std::endl;
316             return false;
317         }
318         else
319         {
320             return true;
321         }
322     }
323     friend std::ostream& operator<<(std::ostream& os, const AbsExact&)
324     {
325         return os << "AbsExact()";
326     }
327 };
328
329 class AbsTolerance : public Wrappable<AbsTolerance>
330 {
331 public:
332     AbsTolerance(double tol) : _tol(tol) {}
333     bool operator() (const cv::Mat& in1, const cv::Mat& in2) const
334     {
335         if (cv::norm(in1, in2, NORM_INF) > _tol)
336         {
337             std::cout << "AbsTolerance error: Number of different pixels in " << std::endl;
338             std::cout << "G-API output and reference output matrixes exceeds " << _tol << " pixels threshold." << std::endl;
339             return false;
340         }
341         else
342         {
343             return true;
344         }
345     }
346     friend std::ostream& operator<<(std::ostream& os, const AbsTolerance& obj)
347     {
348         return os << "AbsTolerance(" << std::to_string(obj._tol) << ")";
349     }
350 private:
351     double _tol;
352 };
353
354 class Tolerance_FloatRel_IntAbs : public Wrappable<Tolerance_FloatRel_IntAbs>
355 {
356 public:
357     Tolerance_FloatRel_IntAbs(double tol, double tol8u) : _tol(tol), _tol8u(tol8u) {}
358     bool operator() (const cv::Mat& in1, const cv::Mat& in2) const
359     {
360         int depth = CV_MAT_DEPTH(in1.type());
361         {
362             double err = depth >= CV_32F ? cv::norm(in1, in2, NORM_L1 | NORM_RELATIVE)
363                                                      : cv::norm(in1, in2, NORM_INF);
364             double tolerance = depth >= CV_32F ? _tol : _tol8u;
365             if (err > tolerance)
366             {
367                 std::cout << "Tolerance_FloatRel_IntAbs error: err=" << err
368                           << "  tolerance=" << tolerance
369                           << "  depth=" << cv::typeToString(depth) << std::endl;
370                 return false;
371             }
372             else
373             {
374                 return true;
375             }
376         }
377     }
378     friend std::ostream& operator<<(std::ostream& os, const Tolerance_FloatRel_IntAbs& obj)
379     {
380         return os << "Tolerance_FloatRel_IntAbs(" << obj._tol << ", " << obj._tol8u << ")";
381     }
382 private:
383     double _tol;
384     double _tol8u;
385 };
386
387
388 class AbsSimilarPoints : public Wrappable<AbsSimilarPoints>
389 {
390 public:
391     AbsSimilarPoints(double tol, double percent) : _tol(tol), _percent(percent) {}
392     bool operator() (const cv::Mat& in1, const cv::Mat& in2) const
393     {
394         Mat diff;
395         cv::absdiff(in1, in2, diff);
396         Mat err_mask = diff > _tol;
397         int err_points = cv::countNonZero(err_mask.reshape(1));
398         double max_err_points = _percent * std::max((size_t)1000, in1.total());
399         if (err_points > max_err_points)
400         {
401             std::cout << "AbsSimilarPoints error: err_points=" << err_points
402                       << "  max_err_points=" << max_err_points << " (total=" << in1.total() << ")"
403                       << "  diff_tolerance=" << _tol << std::endl;
404             return false;
405         }
406         else
407         {
408             return true;
409         }
410     }
411     friend std::ostream& operator<<(std::ostream& os, const AbsSimilarPoints& obj)
412     {
413         return os << "AbsSimilarPoints(" << obj._tol << ", " << obj._percent << ")";
414     }
415 private:
416     double _tol;
417     double _percent;
418 };
419
420
421 class ToleranceFilter : public Wrappable<ToleranceFilter>
422 {
423 public:
424     ToleranceFilter(double tol, double tol8u, double inf_tol = 2.0) : _tol(tol), _tol8u(tol8u), _inf_tol(inf_tol) {}
425     bool operator() (const cv::Mat& in1, const cv::Mat& in2) const
426     {
427         int depth = CV_MAT_DEPTH(in1.type());
428         {
429             double err_Inf = cv::norm(in1, in2, NORM_INF);
430             if (err_Inf > _inf_tol)
431             {
432                 std::cout << "ToleranceFilter error: err_Inf=" << err_Inf << "  tolerance=" << _inf_tol << std::endl;
433                 return false;
434             }
435             double err = cv::norm(in1, in2, NORM_L2 | NORM_RELATIVE);
436             double tolerance = depth >= CV_32F ? _tol : _tol8u;
437             if (err > tolerance)
438             {
439                 std::cout << "ToleranceFilter error: err=" << err << "  tolerance=" << tolerance
440                           << "  depth=" << cv::depthToString(depth)
441                           << std::endl;
442                 return false;
443             }
444         }
445         return true;
446     }
447     friend std::ostream& operator<<(std::ostream& os, const ToleranceFilter& obj)
448     {
449         return os << "ToleranceFilter(" << obj._tol << ", " << obj._tol8u << ", "
450                   << obj._inf_tol << ")";
451     }
452 private:
453     double _tol;
454     double _tol8u;
455     double _inf_tol;
456 };
457
458 class ToleranceColor : public Wrappable<ToleranceColor>
459 {
460 public:
461     ToleranceColor(double tol, double inf_tol = 2.0) : _tol(tol), _inf_tol(inf_tol) {}
462     bool operator() (const cv::Mat& in1, const cv::Mat& in2) const
463     {
464         {
465             double err_Inf = cv::norm(in1, in2, NORM_INF);
466             if (err_Inf > _inf_tol)
467             {
468                 std::cout << "ToleranceColor error: err_Inf=" << err_Inf << "  tolerance=" << _inf_tol << std::endl;;
469                 return false;
470             }
471             double err = cv::norm(in1, in2, NORM_L1 | NORM_RELATIVE);
472             if (err > _tol)
473             {
474                 std::cout << "ToleranceColor error: err=" << err << "  tolerance=" << _tol << std::endl;;
475                 return false;
476             }
477         }
478         return true;
479     }
480     friend std::ostream& operator<<(std::ostream& os, const ToleranceColor& obj)
481     {
482         return os << "ToleranceColor(" << obj._tol << ", " << obj._inf_tol << ")";
483     }
484 private:
485     double _tol;
486     double _inf_tol;
487 };
488
489 class AbsToleranceScalar : public WrappableScalar<AbsToleranceScalar>
490 {
491 public:
492     AbsToleranceScalar(double tol) : _tol(tol) {}
493     bool operator() (const cv::Scalar& in1, const cv::Scalar& in2) const
494     {
495         double abs_err = std::abs(in1[0] - in2[0]) / std::max(1.0, std::abs(in2[0]));
496         if (abs_err > _tol)
497         {
498             std::cout << "AbsToleranceScalar error: abs_err=" << abs_err << "  tolerance=" << _tol << " in1[0]" << in1[0] << " in2[0]" << in2[0] << std::endl;;
499             return false;
500         }
501         else
502         {
503             return true;
504         }
505     }
506     friend std::ostream& operator<<(std::ostream& os, const AbsToleranceScalar& obj)
507     {
508         return os << "AbsToleranceScalar(" << std::to_string(obj._tol) << ")";
509     }
510 private:
511     double _tol;
512 };
513 } // namespace opencv_test
514
515 namespace
516 {
517 inline std::ostream& operator<<(std::ostream& os, const opencv_test::compare_f&)
518 {
519     return os << "compare_f";
520 }
521
522 inline std::ostream& operator<<(std::ostream& os, const opencv_test::compare_scalar_f&)
523 {
524     return os << "compare_scalar_f";
525 }
526 }  // anonymous namespace
527
528 // Note: namespace must match the namespace of the type of the printed object
529 namespace cv
530 {
531 inline std::ostream& operator<<(std::ostream& os, CmpTypes op)
532 {
533 #define CASE(v) case CmpTypes::v: os << #v; break
534     switch (op)
535     {
536         CASE(CMP_EQ);
537         CASE(CMP_GT);
538         CASE(CMP_GE);
539         CASE(CMP_LT);
540         CASE(CMP_LE);
541         CASE(CMP_NE);
542         default: GAPI_Assert(false && "unknown CmpTypes value");
543     }
544 #undef CASE
545     return os;
546 }
547
548 inline std::ostream& operator<<(std::ostream& os, NormTypes op)
549 {
550 #define CASE(v) case NormTypes::v: os << #v; break
551     switch (op)
552     {
553         CASE(NORM_INF);
554         CASE(NORM_L1);
555         CASE(NORM_L2);
556         CASE(NORM_L2SQR);
557         CASE(NORM_HAMMING);
558         CASE(NORM_HAMMING2);
559         CASE(NORM_RELATIVE);
560         CASE(NORM_MINMAX);
561         default: GAPI_Assert(false && "unknown NormTypes value");
562     }
563 #undef CASE
564     return os;
565 }
566 }  // namespace cv
567
568 #endif //OPENCV_GAPI_TESTS_COMMON_HPP