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