Merge pull request #7610 from terfendail:ovx_sobel
[platform/upstream/opencv.git] / modules / ts / include / opencv2 / ts / ts_perf.hpp
1 #ifndef OPENCV_TS_PERF_HPP
2 #define OPENCV_TS_PERF_HPP
3
4 #include "opencv2/core.hpp"
5 #include "ts_gtest.h"
6 #include "ts_ext.hpp"
7
8 #include <functional>
9
10 #if !(defined(LOGD) || defined(LOGI) || defined(LOGW) || defined(LOGE))
11 # if defined(ANDROID) && defined(USE_ANDROID_LOGGING)
12 #  include <android/log.h>
13
14 #  define PERF_TESTS_LOG_TAG "OpenCV_perf"
15 #  define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, PERF_TESTS_LOG_TAG, __VA_ARGS__))
16 #  define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, PERF_TESTS_LOG_TAG, __VA_ARGS__))
17 #  define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, PERF_TESTS_LOG_TAG, __VA_ARGS__))
18 #  define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, PERF_TESTS_LOG_TAG, __VA_ARGS__))
19 # else
20 #  define LOGD(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
21 #  define LOGI(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
22 #  define LOGW(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
23 #  define LOGE(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
24 # endif
25 #endif
26
27 // declare major namespaces to avoid errors on unknown namespace
28 namespace cv { namespace cuda {} namespace ocl {} }
29
30 namespace perf
31 {
32 class TestBase;
33
34 /*****************************************************************************************\
35 *                Predefined typical frame sizes and typical test parameters               *
36 \*****************************************************************************************/
37 const cv::Size szQVGA = cv::Size(320, 240);
38 const cv::Size szVGA = cv::Size(640, 480);
39 const cv::Size szSVGA = cv::Size(800, 600);
40 const cv::Size szXGA = cv::Size(1024, 768);
41 const cv::Size szSXGA = cv::Size(1280, 1024);
42 const cv::Size szWQHD = cv::Size(2560, 1440);
43
44 const cv::Size sznHD = cv::Size(640, 360);
45 const cv::Size szqHD = cv::Size(960, 540);
46 const cv::Size sz240p = szQVGA;
47 const cv::Size sz720p = cv::Size(1280, 720);
48 const cv::Size sz1080p = cv::Size(1920, 1080);
49 const cv::Size sz1440p = szWQHD;
50 const cv::Size sz2160p = cv::Size(3840, 2160);//UHDTV1 4K
51 const cv::Size sz4320p = cv::Size(7680, 4320);//UHDTV2 8K
52
53 const cv::Size sz3MP = cv::Size(2048, 1536);
54 const cv::Size sz5MP = cv::Size(2592, 1944);
55 const cv::Size sz2K = cv::Size(2048, 2048);
56
57 const cv::Size szODD = cv::Size(127, 61);
58
59 const cv::Size szSmall24 = cv::Size(24, 24);
60 const cv::Size szSmall32 = cv::Size(32, 32);
61 const cv::Size szSmall64 = cv::Size(64, 64);
62 const cv::Size szSmall128 = cv::Size(128, 128);
63
64 #define SZ_ALL_VGA ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA)
65 #define SZ_ALL_GA  ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA, ::perf::szXGA, ::perf::szSXGA)
66 #define SZ_ALL_HD  ::testing::Values(::perf::sznHD, ::perf::szqHD, ::perf::sz720p, ::perf::sz1080p)
67 #define SZ_ALL_SMALL ::testing::Values(::perf::szSmall24, ::perf::szSmall32, ::perf::szSmall64, ::perf::szSmall128)
68 #define SZ_ALL  ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA, ::perf::szXGA, ::perf::szSXGA, ::perf::sznHD, ::perf::szqHD, ::perf::sz720p, ::perf::sz1080p)
69 #define SZ_TYPICAL  ::testing::Values(::perf::szVGA, ::perf::szqHD, ::perf::sz720p, ::perf::szODD)
70
71
72 #define TYPICAL_MAT_SIZES ::perf::szVGA, ::perf::sz720p, ::perf::sz1080p, ::perf::szODD
73 #define TYPICAL_MAT_TYPES CV_8UC1, CV_8UC4, CV_32FC1
74 #define TYPICAL_MATS testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( TYPICAL_MAT_TYPES ) )
75 #define TYPICAL_MATS_C1 testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( CV_8UC1, CV_32FC1 ) )
76 #define TYPICAL_MATS_C4 testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( CV_8UC4 ) )
77
78
79 /*****************************************************************************************\
80 *                MatType - printable wrapper over integer 'type' of Mat                   *
81 \*****************************************************************************************/
82 class MatType
83 {
84 public:
85     MatType(int val=0) : _type(val) {}
86     operator int() const {return _type;}
87
88 private:
89     int _type;
90 };
91
92 /*****************************************************************************************\
93 *     CV_ENUM and CV_FLAGS - macro to create printable wrappers for defines and enums     *
94 \*****************************************************************************************/
95
96 #define CV_ENUM(class_name, ...)                                                        \
97     namespace {                                                                         \
98     using namespace cv;using namespace cv::cuda; using namespace cv::ocl;               \
99     struct class_name {                                                                 \
100         class_name(int val = 0) : val_(val) {}                                          \
101         operator int() const { return val_; }                                           \
102         void PrintTo(std::ostream* os) const {                                          \
103             const int vals[] = { __VA_ARGS__ };                                         \
104             const char* svals = #__VA_ARGS__;                                           \
105             for(int i = 0, pos = 0; i < (int)(sizeof(vals)/sizeof(int)); ++i) {         \
106                 while(isspace(svals[pos]) || svals[pos] == ',') ++pos;                  \
107                 int start = pos;                                                        \
108                 while(!(isspace(svals[pos]) || svals[pos] == ',' || svals[pos] == 0))   \
109                     ++pos;                                                              \
110                 if (val_ == vals[i]) {                                                  \
111                     *os << std::string(svals + start, svals + pos);                     \
112                     return;                                                             \
113                 }                                                                       \
114             }                                                                           \
115             *os << "UNKNOWN";                                                           \
116         }                                                                               \
117         static ::testing::internal::ParamGenerator<class_name> all() {                  \
118             const class_name vals[] = { __VA_ARGS__ };                                  \
119             return ::testing::ValuesIn(vals);                                           \
120         }                                                                               \
121     private: int val_;                                                                  \
122     };                                                                                  \
123     static inline void PrintTo(const class_name& t, std::ostream* os) { t.PrintTo(os); } }
124
125 #define CV_FLAGS(class_name, ...)                                                       \
126     namespace {                                                                         \
127     struct class_name {                                                                 \
128         class_name(int val = 0) : val_(val) {}                                          \
129         operator int() const { return val_; }                                           \
130         void PrintTo(std::ostream* os) const {                                          \
131             using namespace cv;using namespace cv::cuda; using namespace cv::ocl;        \
132             const int vals[] = { __VA_ARGS__ };                                         \
133             const char* svals = #__VA_ARGS__;                                           \
134             int value = val_;                                                           \
135             bool first = true;                                                          \
136             for(int i = 0, pos = 0; i < (int)(sizeof(vals)/sizeof(int)); ++i) {         \
137                 while(isspace(svals[pos]) || svals[pos] == ',') ++pos;                  \
138                 int start = pos;                                                        \
139                 while(!(isspace(svals[pos]) || svals[pos] == ',' || svals[pos] == 0))   \
140                     ++pos;                                                              \
141                 if ((value & vals[i]) == vals[i]) {                                     \
142                     value &= ~vals[i];                                                  \
143                     if (first) first = false; else *os << "|";                          \
144                     *os << std::string(svals + start, svals + pos);                     \
145                     if (!value) return;                                                 \
146                 }                                                                       \
147             }                                                                           \
148             if (first) *os << "UNKNOWN";                                                \
149         }                                                                               \
150     private: int val_;                                                                  \
151     };                                                                                  \
152     static inline void PrintTo(const class_name& t, std::ostream* os) { t.PrintTo(os); } }
153
154 CV_ENUM(MatDepth, CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F, CV_USRTYPE1)
155
156 /*****************************************************************************************\
157 *                 Regression control utility for performance testing                      *
158 \*****************************************************************************************/
159 enum ERROR_TYPE
160 {
161     ERROR_ABSOLUTE = 0,
162     ERROR_RELATIVE = 1
163 };
164
165 class CV_EXPORTS Regression
166 {
167 public:
168     static Regression& add(TestBase* test, const std::string& name, cv::InputArray array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
169     static Regression& addMoments(TestBase* test, const std::string& name, const cv::Moments & array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
170     static Regression& addKeypoints(TestBase* test, const std::string& name, const std::vector<cv::KeyPoint>& array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
171     static Regression& addMatches(TestBase* test, const std::string& name, const std::vector<cv::DMatch>& array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
172     static void Init(const std::string& testSuitName, const std::string& ext = ".xml");
173
174     Regression& operator() (const std::string& name, cv::InputArray array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
175
176 private:
177     static Regression& instance();
178     Regression();
179     ~Regression();
180
181     Regression(const Regression&);
182     Regression& operator=(const Regression&);
183
184     cv::RNG regRNG;//own random numbers generator to make collection and verification work identical
185     std::string storageInPath;
186     std::string storageOutPath;
187     cv::FileStorage storageIn;
188     cv::FileStorage storageOut;
189     cv::FileNode rootIn;
190     std::string currentTestNodeName;
191     std::string suiteName;
192
193     cv::FileStorage& write();
194
195     static std::string getCurrentTestNodeName();
196     static bool isVector(cv::InputArray a);
197     static double getElem(cv::Mat& m, int x, int y, int cn = 0);
198
199     void init(const std::string& testSuitName, const std::string& ext);
200     void write(cv::InputArray array);
201     void write(cv::Mat m);
202     void verify(cv::FileNode node, cv::InputArray array, double eps, ERROR_TYPE err);
203     void verify(cv::FileNode node, cv::Mat actual, double eps, std::string argname, ERROR_TYPE err);
204 };
205
206 #define SANITY_CHECK(array, ...) ::perf::Regression::add(this, #array, array , ## __VA_ARGS__)
207 #define SANITY_CHECK_MOMENTS(array, ...) ::perf::Regression::addMoments(this, #array, array , ## __VA_ARGS__)
208 #define SANITY_CHECK_KEYPOINTS(array, ...) ::perf::Regression::addKeypoints(this, #array, array , ## __VA_ARGS__)
209 #define SANITY_CHECK_MATCHES(array, ...) ::perf::Regression::addMatches(this, #array, array , ## __VA_ARGS__)
210 #define SANITY_CHECK_NOTHING() this->setVerified()
211
212 class CV_EXPORTS GpuPerf
213 {
214 public:
215   static bool targetDevice();
216 };
217
218 #define PERF_RUN_CUDA()  ::perf::GpuPerf::targetDevice()
219
220 /*****************************************************************************************\
221 *                            Container for performance metrics                            *
222 \*****************************************************************************************/
223 typedef struct CV_EXPORTS performance_metrics
224 {
225     size_t bytesIn;
226     size_t bytesOut;
227     unsigned int samples;
228     unsigned int outliers;
229     double gmean;
230     double gstddev;//stddev for log(time)
231     double mean;
232     double stddev;
233     double median;
234     double min;
235     double frequency;
236     int terminationReason;
237
238     enum
239     {
240         TERM_ITERATIONS = 0,
241         TERM_TIME = 1,
242         TERM_INTERRUPT = 2,
243         TERM_EXCEPTION = 3,
244         TERM_SKIP_TEST = 4, // there are some limitations and test should be skipped
245         TERM_UNKNOWN = -1
246     };
247
248     performance_metrics();
249     void clear();
250 } performance_metrics;
251
252
253 /*****************************************************************************************\
254 *                           Strategy for performance measuring                            *
255 \*****************************************************************************************/
256 enum PERF_STRATEGY
257 {
258     PERF_STRATEGY_DEFAULT = -1,
259     PERF_STRATEGY_BASE = 0,
260     PERF_STRATEGY_SIMPLE = 1
261 };
262
263
264 /*****************************************************************************************\
265 *                           Base fixture for performance tests                            *
266 \*****************************************************************************************/
267 #ifdef CV_COLLECT_IMPL_DATA
268 // Implementation collection processing class.
269 // Accumulates and shapes implementation data.
270 typedef struct ImplData
271 {
272     bool ipp;
273     bool icv;
274     bool ipp_mt;
275     bool ocl;
276     bool plain;
277     std::vector<int> implCode;
278     std::vector<cv::String> funName;
279
280     ImplData()
281     {
282         Reset();
283     }
284
285     void Reset()
286     {
287         cv::setImpl(0);
288         ipp = icv = ocl = ipp_mt = false;
289         implCode.clear();
290         funName.clear();
291     }
292
293     void GetImpl()
294     {
295         flagsToVars(cv::getImpl(implCode, funName));
296     }
297
298     std::vector<cv::String> GetCallsForImpl(int impl)
299     {
300         std::vector<cv::String> out;
301
302         for(int i = 0; i < (int)implCode.size(); i++)
303         {
304             if(impl == implCode[i])
305                 out.push_back(funName[i]);
306         }
307         return out;
308     }
309
310     // Remove duplicate entries
311     void ShapeUp()
312     {
313         std::vector<int> savedCode;
314         std::vector<cv::String> savedName;
315
316         for(int i = 0; i < (int)implCode.size(); i++)
317         {
318             bool match = false;
319             for(int j = 0; j < (int)savedCode.size(); j++)
320             {
321                 if(implCode[i] == savedCode[j] && !funName[i].compare(savedName[j]))
322                 {
323                     match = true;
324                     break;
325                 }
326             }
327             if(!match)
328             {
329                 savedCode.push_back(implCode[i]);
330                 savedName.push_back(funName[i]);
331             }
332         }
333
334         implCode = savedCode;
335         funName = savedName;
336     }
337
338     // convert flags register to more handy variables
339     void flagsToVars(int flags)
340     {
341 #if defined(HAVE_IPP_ICV_ONLY)
342         ipp    = 0;
343         icv    = ((flags&CV_IMPL_IPP) > 0);
344 #else
345         ipp    = ((flags&CV_IMPL_IPP) > 0);
346         icv    = 0;
347 #endif
348         ipp_mt = ((flags&CV_IMPL_MT) > 0);
349         ocl    = ((flags&CV_IMPL_OCL) > 0);
350         plain  = (flags == 0);
351     }
352
353 } ImplData;
354 #endif
355
356 #ifdef ENABLE_INSTRUMENTATION
357 class InstumentData
358 {
359 public:
360     static ::cv::String treeToString();
361     static void         printTree();
362 };
363 #endif
364
365 class CV_EXPORTS TestBase: public ::testing::Test
366 {
367 public:
368     TestBase();
369
370     static void Init(int argc, const char* const argv[]);
371     static void Init(const std::vector<std::string> & availableImpls,
372                      int argc, const char* const argv[]);
373     static void RecordRunParameters();
374     static std::string getDataPath(const std::string& relativePath);
375     static std::string getSelectedImpl();
376
377     static enum PERF_STRATEGY getCurrentModulePerformanceStrategy();
378     static enum PERF_STRATEGY setModulePerformanceStrategy(enum PERF_STRATEGY strategy);
379
380     class PerfSkipTestException: public cv::Exception
381     {
382     public:
383         int dummy; // workaround for MacOSX Xcode 7.3 bug (don't make class "empty")
384         PerfSkipTestException() : dummy(0) {}
385     };
386
387 protected:
388     virtual void PerfTestBody() = 0;
389
390     virtual void SetUp();
391     virtual void TearDown();
392
393     bool startTimer(); // bool is dummy for conditional loop
394     void stopTimer();
395     bool next();
396
397     PERF_STRATEGY getCurrentPerformanceStrategy() const;
398
399     enum WarmUpType
400     {
401         WARMUP_READ,
402         WARMUP_WRITE,
403         WARMUP_RNG,
404         WARMUP_NONE
405     };
406
407     void reportMetrics(bool toJUnitXML = false);
408     static void warmup(cv::InputOutputArray a, WarmUpType wtype = WARMUP_READ);
409
410     performance_metrics& calcMetrics();
411
412     void RunPerfTestBody();
413
414 #ifdef CV_COLLECT_IMPL_DATA
415     ImplData implConf;
416 #endif
417 #ifdef ENABLE_INSTRUMENTATION
418     InstumentData instrConf;
419 #endif
420
421 private:
422     typedef std::vector<std::pair<int, cv::Size> > SizeVector;
423     typedef std::vector<int64> TimeVector;
424
425     SizeVector inputData;
426     SizeVector outputData;
427     unsigned int getTotalInputSize() const;
428     unsigned int getTotalOutputSize() const;
429
430     enum PERF_STRATEGY testStrategy;
431
432     TimeVector times;
433     int64 lastTime;
434     int64 totalTime;
435     int64 timeLimit;
436     static int64 timeLimitDefault;
437     static unsigned int iterationsLimitDefault;
438
439     unsigned int minIters;
440     unsigned int nIters;
441     unsigned int currentIter;
442     unsigned int runsPerIteration;
443     unsigned int perfValidationStage;
444
445     performance_metrics metrics;
446     void validateMetrics();
447
448     static int64 _timeadjustment;
449     static int64 _calibrate();
450
451     static void warmup_impl(cv::Mat m, WarmUpType wtype);
452     static int getSizeInBytes(cv::InputArray a);
453     static cv::Size getSize(cv::InputArray a);
454     static void declareArray(SizeVector& sizes, cv::InputOutputArray a, WarmUpType wtype);
455
456     class CV_EXPORTS _declareHelper
457     {
458     public:
459         _declareHelper& in(cv::InputOutputArray a1, WarmUpType wtype = WARMUP_READ);
460         _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, WarmUpType wtype = WARMUP_READ);
461         _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, WarmUpType wtype = WARMUP_READ);
462         _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, cv::InputOutputArray a4, WarmUpType wtype = WARMUP_READ);
463
464         _declareHelper& out(cv::InputOutputArray a1, WarmUpType wtype = WARMUP_WRITE);
465         _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, WarmUpType wtype = WARMUP_WRITE);
466         _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, WarmUpType wtype = WARMUP_WRITE);
467         _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, cv::InputOutputArray a4, WarmUpType wtype = WARMUP_WRITE);
468
469         _declareHelper& iterations(unsigned int n);
470         _declareHelper& time(double timeLimitSecs);
471         _declareHelper& tbb_threads(int n = -1);
472         _declareHelper& runs(unsigned int runsNumber);
473
474         _declareHelper& strategy(enum PERF_STRATEGY s);
475     private:
476         TestBase* test;
477         _declareHelper(TestBase* t);
478         _declareHelper(const _declareHelper&);
479         _declareHelper& operator=(const _declareHelper&);
480         friend class TestBase;
481     };
482     friend class _declareHelper;
483
484     bool verified;
485
486 public:
487     _declareHelper declare;
488
489     void setVerified() { this->verified = true; }
490 };
491
492 template<typename T> class TestBaseWithParam: public TestBase, public ::testing::WithParamInterface<T> {};
493
494 typedef std::tr1::tuple<cv::Size, MatType> Size_MatType_t;
495 typedef TestBaseWithParam<Size_MatType_t> Size_MatType;
496
497 /*****************************************************************************************\
498 *                              Print functions for googletest                             *
499 \*****************************************************************************************/
500 CV_EXPORTS void PrintTo(const MatType& t, std::ostream* os);
501
502 } //namespace perf
503
504 namespace cv
505 {
506
507 CV_EXPORTS void PrintTo(const String& str, ::std::ostream* os);
508 CV_EXPORTS void PrintTo(const Size& sz, ::std::ostream* os);
509
510 } //namespace cv
511
512
513 /*****************************************************************************************\
514 *                        Macro definitions for performance tests                          *
515 \*****************************************************************************************/
516 #define PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name) \
517   test_case_name##_##test_name##_perf_namespace_proxy
518
519 // Defines a performance test.
520 //
521 // The first parameter is the name of the test case, and the second
522 // parameter is the name of the test within the test case.
523 //
524 // The user should put his test code between braces after using this
525 // macro.  Example:
526 //
527 //   PERF_TEST(FooTest, InitializesCorrectly) {
528 //     Foo foo;
529 //     EXPECT_TRUE(foo.StatusIsOK());
530 //   }
531 #define PERF_TEST(test_case_name, test_name)\
532     namespace PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name) {\
533      class TestBase {/*compile error for this class means that you are trying to use perf::TestBase as a fixture*/};\
534      class test_case_name : public ::perf::TestBase {\
535       public:\
536        test_case_name() {}\
537       protected:\
538        virtual void PerfTestBody();\
539      };\
540      TEST_F(test_case_name, test_name){ RunPerfTestBody(); }\
541     }\
542     void PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name)::test_case_name::PerfTestBody()
543
544 // Defines a performance test that uses a test fixture.
545 //
546 // The first parameter is the name of the test fixture class, which
547 // also doubles as the test case name.  The second parameter is the
548 // name of the test within the test case.
549 //
550 // A test fixture class must be declared earlier.  The user should put
551 // his test code between braces after using this macro.  Example:
552 //
553 //   class FooTest : public ::perf::TestBase {
554 //    protected:
555 //     virtual void SetUp() { TestBase::SetUp(); b_.AddElement(3); }
556 //
557 //     Foo a_;
558 //     Foo b_;
559 //   };
560 //
561 //   PERF_TEST_F(FooTest, InitializesCorrectly) {
562 //     EXPECT_TRUE(a_.StatusIsOK());
563 //   }
564 //
565 //   PERF_TEST_F(FooTest, ReturnsElementCountCorrectly) {
566 //     EXPECT_EQ(0, a_.size());
567 //     EXPECT_EQ(1, b_.size());
568 //   }
569 #define PERF_TEST_F(fixture, testname) \
570     namespace PERF_PROXY_NAMESPACE_NAME_(fixture, testname) {\
571      class TestBase {/*compile error for this class means that you are trying to use perf::TestBase as a fixture*/};\
572      class fixture : public ::fixture {\
573       public:\
574        fixture() {}\
575       protected:\
576        virtual void PerfTestBody();\
577      };\
578      TEST_F(fixture, testname){ RunPerfTestBody(); }\
579     }\
580     void PERF_PROXY_NAMESPACE_NAME_(fixture, testname)::fixture::PerfTestBody()
581
582 // Defines a parametrized performance test.
583 //
584 // The first parameter is the name of the test fixture class, which
585 // also doubles as the test case name.  The second parameter is the
586 // name of the test within the test case.
587 //
588 // The user should put his test code between braces after using this
589 // macro.  Example:
590 //
591 //   typedef ::perf::TestBaseWithParam<cv::Size> FooTest;
592 //
593 //   PERF_TEST_P(FooTest, DoTestingRight, ::testing::Values(::perf::szVGA, ::perf::sz720p) {
594 //     cv::Mat b(GetParam(), CV_8U, cv::Scalar(10));
595 //     cv::Mat a(GetParam(), CV_8U, cv::Scalar(20));
596 //     cv::Mat c(GetParam(), CV_8U, cv::Scalar(0));
597 //
598 //     declare.in(a, b).out(c).time(0.5);
599 //
600 //     TEST_CYCLE() cv::add(a, b, c);
601 //
602 //     SANITY_CHECK(c);
603 //   }
604 #define PERF_TEST_P(fixture, name, params)  \
605     class fixture##_##name : public fixture {\
606      public:\
607       fixture##_##name() {}\
608      protected:\
609       virtual void PerfTestBody();\
610     };\
611     TEST_P(fixture##_##name, name /*perf*/){ RunPerfTestBody(); }\
612     INSTANTIATE_TEST_CASE_P(/*none*/, fixture##_##name, params);\
613     void fixture##_##name::PerfTestBody()
614
615 #ifndef __CV_TEST_EXEC_ARGS
616 #if defined(_MSC_VER) && (_MSC_VER <= 1400)
617 #define __CV_TEST_EXEC_ARGS(...)    \
618     while (++argc >= (--argc,-1)) {__VA_ARGS__; break;} /*this ugly construction is needed for VS 2005*/
619 #else
620 #define __CV_TEST_EXEC_ARGS(...)    \
621     __VA_ARGS__;
622 #endif
623 #endif
624
625 #ifdef HAVE_OPENCL
626 namespace cvtest { namespace ocl {
627 void dumpOpenCLDevice();
628 }}
629 #define TEST_DUMP_OCL_INFO cvtest::ocl::dumpOpenCLDevice();
630 #else
631 #define TEST_DUMP_OCL_INFO
632 #endif
633
634 #define CV_PERF_TEST_MAIN_INTERNALS(modulename, impls, ...)     \
635     ::perf::Regression::Init(#modulename); \
636     ::perf::TestBase::Init(std::vector<std::string>(impls, impls + sizeof impls / sizeof *impls), \
637                            argc, argv); \
638     ::testing::InitGoogleTest(&argc, argv); \
639     cvtest::printVersionInfo(); \
640     ::testing::Test::RecordProperty("cv_module_name", #modulename); \
641     ::perf::TestBase::RecordRunParameters(); \
642     __CV_TEST_EXEC_ARGS(__VA_ARGS__) \
643     TEST_DUMP_OCL_INFO \
644     return RUN_ALL_TESTS();
645
646 // impls must be an array, not a pointer; "plain" should always be one of the implementations
647 #define CV_PERF_TEST_MAIN_WITH_IMPLS(modulename, impls, ...) \
648 int main(int argc, char **argv)\
649 {\
650     CV_PERF_TEST_MAIN_INTERNALS(modulename, impls, __VA_ARGS__)\
651 }
652
653 #define CV_PERF_TEST_MAIN(modulename, ...) \
654 int main(int argc, char **argv)\
655 {\
656     const char * plain_only[] = { "plain" };\
657     CV_PERF_TEST_MAIN_INTERNALS(modulename, plain_only, __VA_ARGS__)\
658 }
659
660 #define TEST_CYCLE_N(n) for(declare.iterations(n); next() && startTimer(); stopTimer())
661 #define TEST_CYCLE() for(; next() && startTimer(); stopTimer())
662 #define TEST_CYCLE_MULTIRUN(runsNum) for(declare.runs(runsNum); next() && startTimer(); stopTimer()) for(int r = 0; r < runsNum; ++r)
663
664 namespace perf
665 {
666 namespace comparators
667 {
668
669 template<typename T>
670 struct CV_EXPORTS RectLess_ :
671         public std::binary_function<cv::Rect_<T>, cv::Rect_<T>, bool>
672 {
673   bool operator()(const cv::Rect_<T>& r1, const cv::Rect_<T>& r2) const
674   {
675     return r1.x < r2.x ||
676             (r1.x == r2.x && r1.y < r2.y) ||
677             (r1.x == r2.x && r1.y == r2.y && r1.width < r2.width) ||
678             (r1.x == r2.x && r1.y == r2.y && r1.width == r2.width && r1.height < r2.height);
679   }
680 };
681
682 typedef RectLess_<int> RectLess;
683
684 struct CV_EXPORTS KeypointGreater :
685         public std::binary_function<cv::KeyPoint, cv::KeyPoint, bool>
686 {
687     bool operator()(const cv::KeyPoint& kp1, const cv::KeyPoint& kp2) const
688     {
689         if (kp1.response > kp2.response) return true;
690         if (kp1.response < kp2.response) return false;
691         if (kp1.size > kp2.size) return true;
692         if (kp1.size < kp2.size) return false;
693         if (kp1.octave > kp2.octave) return true;
694         if (kp1.octave < kp2.octave) return false;
695         if (kp1.pt.y < kp2.pt.y) return false;
696         if (kp1.pt.y > kp2.pt.y) return true;
697         return kp1.pt.x < kp2.pt.x;
698     }
699 };
700
701 } //namespace comparators
702
703 void CV_EXPORTS sort(std::vector<cv::KeyPoint>& pts, cv::InputOutputArray descriptors);
704 } //namespace perf
705
706 #endif //OPENCV_TS_PERF_HPP