00001 #ifndef __OPENCV_TS_PERF_HPP__
00002 #define __OPENCV_TS_PERF_HPP__
00003
00004 #include "opencv2/core/core.hpp"
00005 #include "opencv2/features2d/features2d.hpp"
00006 #include "ts_gtest.h"
00007
00008 #ifdef HAVE_TBB
00009 #include "tbb/task_scheduler_init.h"
00010 #endif
00011
00012 #if !(defined(LOGD) || defined(LOGI) || defined(LOGW) || defined(LOGE))
00013 # if defined(ANDROID) && defined(USE_ANDROID_LOGGING)
00014 # include <android/log.h>
00015
00016 # define PERF_TESTS_LOG_TAG "OpenCV_perf"
00017 # define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, PERF_TESTS_LOG_TAG, __VA_ARGS__))
00018 # define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, PERF_TESTS_LOG_TAG, __VA_ARGS__))
00019 # define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, PERF_TESTS_LOG_TAG, __VA_ARGS__))
00020 # define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, PERF_TESTS_LOG_TAG, __VA_ARGS__))
00021 # else
00022 # define LOGD(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
00023 # define LOGI(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
00024 # define LOGW(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
00025 # define LOGE(_str, ...) do{printf(_str , ## __VA_ARGS__); printf("\n");fflush(stdout);} while(0)
00026 # endif
00027 #endif
00028
00029 namespace perf
00030 {
00031 class TestBase;
00032
00033
00034
00035
00036 const cv::Size szQVGA = cv::Size(320, 240);
00037 const cv::Size szVGA = cv::Size(640, 480);
00038 const cv::Size szSVGA = cv::Size(800, 600);
00039 const cv::Size szXGA = cv::Size(1024, 768);
00040 const cv::Size szSXGA = cv::Size(1280, 1024);
00041 const cv::Size szWQHD = cv::Size(2560, 1440);
00042
00043 const cv::Size sznHD = cv::Size(640, 360);
00044 const cv::Size szqHD = cv::Size(960, 540);
00045 const cv::Size sz240p = szQVGA;
00046 const cv::Size sz720p = cv::Size(1280, 720);
00047 const cv::Size sz1080p = cv::Size(1920, 1080);
00048 const cv::Size sz1440p = szWQHD;
00049 const cv::Size sz2160p = cv::Size(3840, 2160);
00050 const cv::Size sz4320p = cv::Size(7680, 4320);
00051
00052 const cv::Size sz3MP = cv::Size(2048, 1536);
00053 const cv::Size sz5MP = cv::Size(2592, 1944);
00054 const cv::Size sz2K = cv::Size(2048, 2048);
00055
00056 const cv::Size szODD = cv::Size(127, 61);
00057
00058 const cv::Size szSmall24 = cv::Size(24, 24);
00059 const cv::Size szSmall32 = cv::Size(32, 32);
00060 const cv::Size szSmall64 = cv::Size(64, 64);
00061 const cv::Size szSmall128 = cv::Size(128, 128);
00062
00063 #define SZ_ALL_VGA ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA)
00064 #define SZ_ALL_GA ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA, ::perf::szXGA, ::perf::szSXGA)
00065 #define SZ_ALL_HD ::testing::Values(::perf::sznHD, ::perf::szqHD, ::perf::sz720p, ::perf::sz1080p)
00066 #define SZ_ALL_SMALL ::testing::Values(::perf::szSmall24, ::perf::szSmall32, ::perf::szSmall64, ::perf::szSmall128)
00067 #define SZ_ALL ::testing::Values(::perf::szQVGA, ::perf::szVGA, ::perf::szSVGA, ::perf::szXGA, ::perf::szSXGA, ::perf::sznHD, ::perf::szqHD, ::perf::sz720p, ::perf::sz1080p)
00068 #define SZ_TYPICAL ::testing::Values(::perf::szVGA, ::perf::szqHD, ::perf::sz720p, ::perf::szODD)
00069
00070
00071 #define TYPICAL_MAT_SIZES ::perf::szVGA, ::perf::sz720p, ::perf::sz1080p, ::perf::szODD
00072 #define TYPICAL_MAT_TYPES CV_8UC1, CV_8UC4, CV_32FC1
00073 #define TYPICAL_MATS testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( TYPICAL_MAT_TYPES ) )
00074 #define TYPICAL_MATS_C1 testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( CV_8UC1, CV_32FC1 ) )
00075 #define TYPICAL_MATS_C4 testing::Combine( testing::Values( TYPICAL_MAT_SIZES ), testing::Values( CV_8UC4 ) )
00076
00077
00078
00079
00080
00081 class MatType
00082 {
00083 public:
00084 MatType(int val=0) : _type(val) {}
00085 operator int() const {return _type;}
00086
00087 private:
00088 int _type;
00089 };
00090
00091
00092
00093
00094
00095 #define CV_ENUM(class_name, ...) \
00096 namespace { class CV_EXPORTS class_name {\
00097 public:\
00098 class_name(int val = 0) : _val(val) {}\
00099 operator int() const {return _val;}\
00100 void PrintTo(std::ostream* os) const {\
00101 const int vals[] = {__VA_ARGS__};\
00102 const char* svals = #__VA_ARGS__;\
00103 for(int i = 0, pos = 0; i < (int)(sizeof(vals)/sizeof(int)); ++i){\
00104 while(isspace(svals[pos]) || svals[pos] == ',') ++pos;\
00105 int start = pos;\
00106 while(!(isspace(svals[pos]) || svals[pos] == ',' || svals[pos] == 0)) ++pos;\
00107 if (_val == vals[i]) {\
00108 *os << std::string(svals + start, svals + pos);\
00109 return;\
00110 }\
00111 }\
00112 *os << "UNKNOWN";\
00113 }\
00114 struct Container{\
00115 typedef class_name value_type;\
00116 Container(class_name* first, size_t len): _begin(first), _end(first+len){}\
00117 const class_name* begin() const {return _begin;}\
00118 const class_name* end() const {return _end;}\
00119 private: class_name *_begin, *_end;\
00120 };\
00121 static Container all(){\
00122 static int vals[] = {__VA_ARGS__};\
00123 return Container((class_name*)vals, sizeof(vals)/sizeof(vals[0]));\
00124 }\
00125 private: int _val;\
00126 };\
00127 inline void PrintTo(const class_name& t, std::ostream* os) { t.PrintTo(os); } }
00128
00129 #define CV_FLAGS(class_name, ...) \
00130 class CV_EXPORTS class_name {\
00131 public:\
00132 class_name(int val = 0) : _val(val) {}\
00133 operator int() const {return _val;}\
00134 void PrintTo(std::ostream* os) const {\
00135 const int vals[] = {__VA_ARGS__};\
00136 const char* svals = #__VA_ARGS__;\
00137 int value = _val;\
00138 bool first = true;\
00139 for(int i = 0, pos = 0; i < (int)(sizeof(vals)/sizeof(int)); ++i){\
00140 while(isspace(svals[pos]) || svals[pos] == ',') ++pos;\
00141 int start = pos;\
00142 while(!(isspace(svals[pos]) || svals[pos] == ',' || svals[pos] == 0)) ++pos;\
00143 if ((value & vals[i]) == vals[i]) {\
00144 value &= ~vals[i]; \
00145 if (first) first = false; else *os << "|"; \
00146 *os << std::string(svals + start, svals + pos);\
00147 if (!value) return;\
00148 }\
00149 }\
00150 if (first) *os << "UNKNOWN";\
00151 }\
00152 private: int _val;\
00153 };\
00154 inline void PrintTo(const class_name& t, std::ostream* os) { t.PrintTo(os); }
00155
00156 CV_ENUM(MatDepth, CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F, CV_USRTYPE1)
00157
00158
00159
00160
00161 enum ERROR_TYPE
00162 {
00163 ERROR_ABSOLUTE = 0,
00164 ERROR_RELATIVE = 1
00165 };
00166
00167 class CV_EXPORTS Regression
00168 {
00169 public:
00170 static Regression& add(TestBase* test, const std::string& name, cv::InputArray array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
00171 static Regression& addKeypoints(TestBase* test, const std::string& name, const std::vector<cv::KeyPoint>& array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
00172 static Regression& addMatches(TestBase* test, const std::string& name, const std::vector<cv::DMatch>& array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
00173 static void Init(const std::string& testSuitName, const std::string& ext = ".xml");
00174
00175 Regression& operator() (const std::string& name, cv::InputArray array, double eps = DBL_EPSILON, ERROR_TYPE err = ERROR_ABSOLUTE);
00176
00177 private:
00178 static Regression& instance();
00179 Regression();
00180 ~Regression();
00181
00182 Regression(const Regression&);
00183 Regression& operator=(const Regression&);
00184
00185 cv::RNG regRNG;
00186 std::string storageInPath;
00187 std::string storageOutPath;
00188 cv::FileStorage storageIn;
00189 cv::FileStorage storageOut;
00190 cv::FileNode rootIn;
00191 std::string currentTestNodeName;
00192 std::string suiteName;
00193
00194 cv::FileStorage& write();
00195
00196 static std::string getCurrentTestNodeName();
00197 static bool isVector(cv::InputArray a);
00198 static double getElem(cv::Mat& m, int x, int y, int cn = 0);
00199
00200 void init(const std::string& testSuitName, const std::string& ext);
00201 void write(cv::InputArray array);
00202 void write(cv::Mat m);
00203 void verify(cv::FileNode node, cv::InputArray array, double eps, ERROR_TYPE err);
00204 void verify(cv::FileNode node, cv::Mat actual, double eps, std::string argname, ERROR_TYPE err);
00205 };
00206
00207 #define SANITY_CHECK(array, ...) ::perf::Regression::add(this, #array, array , ## __VA_ARGS__)
00208 #define SANITY_CHECK_KEYPOINTS(array, ...) ::perf::Regression::addKeypoints(this, #array, array , ## __VA_ARGS__)
00209 #define SANITY_CHECK_MATCHES(array, ...) ::perf::Regression::addMatches(this, #array, array , ## __VA_ARGS__)
00210
00211 #ifdef HAVE_CUDA
00212 class CV_EXPORTS GpuPerf
00213 {
00214 public:
00215 static bool targetDevice();
00216 };
00217
00218 # define PERF_RUN_GPU() ::perf::GpuPerf::targetDevice()
00219 #else
00220 # define PERF_RUN_GPU() false
00221 #endif
00222
00223
00224
00225
00226
00227 typedef struct CV_EXPORTS performance_metrics
00228 {
00229 size_t bytesIn;
00230 size_t bytesOut;
00231 unsigned int samples;
00232 unsigned int outliers;
00233 double gmean;
00234 double gstddev;
00235 double mean;
00236 double stddev;
00237 double median;
00238 double min;
00239 double frequency;
00240 int terminationReason;
00241
00242 enum
00243 {
00244 TERM_ITERATIONS = 0,
00245 TERM_TIME = 1,
00246 TERM_INTERRUPT = 2,
00247 TERM_EXCEPTION = 3,
00248 TERM_UNKNOWN = -1
00249 };
00250
00251 performance_metrics();
00252 } performance_metrics;
00253
00254
00255
00256
00257
00258 class CV_EXPORTS TestBase: public ::testing::Test
00259 {
00260 public:
00261 TestBase();
00262
00263 static void Init(int argc, const char* const argv[]);
00264 static std::string getDataPath(const std::string& relativePath);
00265
00266 protected:
00267 virtual void PerfTestBody() = 0;
00268
00269 virtual void SetUp();
00270 virtual void TearDown();
00271
00272 void startTimer();
00273 void stopTimer();
00274 bool next();
00275
00276
00277
00278 enum
00279 {
00280 WARMUP_READ,
00281 WARMUP_WRITE,
00282 WARMUP_RNG,
00283 WARMUP_NONE
00284 };
00285
00286 void reportMetrics(bool toJUnitXML = false);
00287 static void warmup(cv::InputOutputArray a, int wtype = WARMUP_READ);
00288
00289 performance_metrics& calcMetrics();
00290 void RunPerfTestBody();
00291 private:
00292 typedef std::vector<std::pair<int, cv::Size> > SizeVector;
00293 typedef std::vector<int64> TimeVector;
00294
00295 SizeVector inputData;
00296 SizeVector outputData;
00297 unsigned int getTotalInputSize() const;
00298 unsigned int getTotalOutputSize() const;
00299
00300 TimeVector times;
00301 int64 lastTime;
00302 int64 totalTime;
00303 int64 timeLimit;
00304 static int64 timeLimitDefault;
00305 static unsigned int iterationsLimitDefault;
00306
00307 unsigned int nIters;
00308 unsigned int currentIter;
00309 unsigned int runsPerIteration;
00310
00311 performance_metrics metrics;
00312 void validateMetrics();
00313
00314 static int64 _timeadjustment;
00315 static int64 _calibrate();
00316
00317 static void warmup_impl(cv::Mat m, int wtype);
00318 static int getSizeInBytes(cv::InputArray a);
00319 static cv::Size getSize(cv::InputArray a);
00320 static void declareArray(SizeVector& sizes, cv::InputOutputArray a, int wtype = 0);
00321
00322 class CV_EXPORTS _declareHelper
00323 {
00324 public:
00325 _declareHelper& in(cv::InputOutputArray a1, int wtype = WARMUP_READ);
00326 _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, int wtype = WARMUP_READ);
00327 _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, int wtype = WARMUP_READ);
00328 _declareHelper& in(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, cv::InputOutputArray a4, int wtype = WARMUP_READ);
00329
00330 _declareHelper& out(cv::InputOutputArray a1, int wtype = WARMUP_WRITE);
00331 _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, int wtype = WARMUP_WRITE);
00332 _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, int wtype = WARMUP_WRITE);
00333 _declareHelper& out(cv::InputOutputArray a1, cv::InputOutputArray a2, cv::InputOutputArray a3, cv::InputOutputArray a4, int wtype = WARMUP_WRITE);
00334
00335 _declareHelper& iterations(unsigned int n);
00336 _declareHelper& time(double timeLimitSecs);
00337 _declareHelper& tbb_threads(int n = -1);
00338 _declareHelper& runs(unsigned int runsNumber);
00339 private:
00340 TestBase* test;
00341 _declareHelper(TestBase* t);
00342 _declareHelper(const _declareHelper&);
00343 _declareHelper& operator=(const _declareHelper&);
00344 friend class TestBase;
00345 };
00346 friend class _declareHelper;
00347 friend class Regression;
00348
00349 bool verified;
00350
00351 public:
00352 _declareHelper declare;
00353 };
00354
00355 template<typename T> class TestBaseWithParam: public TestBase, public ::testing::WithParamInterface<T> {};
00356
00357 typedef std::tr1::tuple<cv::Size, MatType> Size_MatType_t;
00358 typedef TestBaseWithParam<Size_MatType_t> Size_MatType;
00359
00360
00361
00362
00363 CV_EXPORTS void PrintTo(const MatType& t, std::ostream* os);
00364
00365 }
00366
00367 namespace cv
00368 {
00369
00370 CV_EXPORTS void PrintTo(const Size& sz, ::std::ostream* os);
00371
00372 }
00373
00374
00375
00376
00377
00378 #define PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name) \
00379 test_case_name##_##test_name##_perf_namespace_proxy
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393 #define PERF_TEST(test_case_name, test_name)\
00394 namespace PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name) {\
00395 class TestBase {};\
00396 class test_case_name : public ::perf::TestBase {\
00397 public:\
00398 test_case_name() {}\
00399 protected:\
00400 virtual void PerfTestBody();\
00401 };\
00402 TEST_F(test_case_name, test_name){ RunPerfTestBody(); }\
00403 }\
00404 void PERF_PROXY_NAMESPACE_NAME_(test_case_name, test_name)::test_case_name::PerfTestBody()
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431 #define PERF_TEST_F(fixture, testname) \
00432 namespace PERF_PROXY_NAMESPACE_NAME_(fixture, testname) {\
00433 class TestBase {};\
00434 class fixture : public ::fixture {\
00435 public:\
00436 fixture() {}\
00437 protected:\
00438 virtual void PerfTestBody();\
00439 };\
00440 TEST_F(fixture, testname){ RunPerfTestBody(); }\
00441 }\
00442 void PERF_PROXY_NAMESPACE_NAME_(fixture, testname)::fixture::PerfTestBody()
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466 #define PERF_TEST_P(fixture, name, params) \
00467 class fixture##_##name : public fixture {\
00468 public:\
00469 fixture##_##name() {}\
00470 protected:\
00471 virtual void PerfTestBody();\
00472 };\
00473 TEST_P(fixture##_##name, name ){ RunPerfTestBody(); }\
00474 INSTANTIATE_TEST_CASE_P(, fixture##_##name, params);\
00475 void fixture##_##name::PerfTestBody()
00476
00477
00478 #define CV_PERF_TEST_MAIN(testsuitname, ...) \
00479 int main(int argc, char **argv)\
00480 {\
00481 while (++argc >= (--argc,-1)) {__VA_ARGS__; break;} \
00482 ::perf::Regression::Init(#testsuitname);\
00483 ::perf::TestBase::Init(argc, argv);\
00484 ::testing::InitGoogleTest(&argc, argv);\
00485 return RUN_ALL_TESTS();\
00486 }
00487
00488 #define TEST_CYCLE_N(n) for(declare.iterations(n); startTimer(), next(); stopTimer())
00489 #define TEST_CYCLE() for(; startTimer(), next(); stopTimer())
00490 #define TEST_CYCLE_MULTIRUN(runsNum) for(declare.runs(runsNum); startTimer(), next(); stopTimer()) for(int r = 0; r < runsNum; ++r)
00491
00492 namespace perf
00493 {
00494 namespace comparators
00495 {
00496
00497 template<typename T>
00498 struct CV_EXPORTS RectLess_
00499 {
00500 bool operator()(const cv::Rect_<T>& r1, const cv::Rect_<T>& r2) const
00501 {
00502 return r1.x < r2.x
00503 || (r1.x == r2.x && r1.y < r2.y)
00504 || (r1.x == r2.x && r1.y == r2.y && r1.width < r2.width)
00505 || (r1.x == r2.x && r1.y == r2.y && r1.width == r2.width && r1.height < r2.height);
00506 }
00507 };
00508
00509 typedef RectLess_<int> RectLess;
00510
00511 struct CV_EXPORTS KeypointGreater
00512 {
00513 bool operator()(const cv::KeyPoint& kp1, const cv::KeyPoint& kp2) const
00514 {
00515 if(kp1.response > kp2.response) return true;
00516 if(kp1.response < kp2.response) return false;
00517 if(kp1.size > kp2.size) return true;
00518 if(kp1.size < kp2.size) return false;
00519 if(kp1.octave > kp2.octave) return true;
00520 if(kp1.octave < kp2.octave) return false;
00521 if(kp1.pt.y < kp2.pt.y) return false;
00522 if(kp1.pt.y > kp2.pt.y) return true;
00523 return kp1.pt.x < kp2.pt.x;
00524 }
00525 };
00526
00527 }
00528
00529 void CV_EXPORTS sort(std::vector<cv::KeyPoint>& pts, cv::InputOutputArray descriptors);
00530 }
00531
00532 #endif //__OPENCV_TS_PERF_HPP__