perf_math.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. #include "perf_precomp.hpp"
  2. namespace opencv_test
  3. {
  4. using namespace perf;
  5. namespace {
  6. typedef perf::TestBaseWithParam<size_t> VectorLength;
  7. PERF_TEST_P(VectorLength, phase32f, testing::Values(128, 1000, 128*1024, 512*1024, 1024*1024))
  8. {
  9. size_t length = GetParam();
  10. vector<float> X(length);
  11. vector<float> Y(length);
  12. vector<float> angle(length);
  13. declare.in(X, Y, WARMUP_RNG).out(angle);
  14. TEST_CYCLE_N(200) cv::phase(X, Y, angle, true);
  15. SANITY_CHECK(angle, 5e-5);
  16. }
  17. PERF_TEST_P(VectorLength, phase64f, testing::Values(128, 1000, 128*1024, 512*1024, 1024*1024))
  18. {
  19. size_t length = GetParam();
  20. vector<double> X(length);
  21. vector<double> Y(length);
  22. vector<double> angle(length);
  23. declare.in(X, Y, WARMUP_RNG).out(angle);
  24. TEST_CYCLE_N(200) cv::phase(X, Y, angle, true);
  25. SANITY_CHECK(angle, 5e-5);
  26. }
  27. ///////////// Magnitude /////////////
  28. typedef Size_MatType MagnitudeFixture;
  29. PERF_TEST_P(MagnitudeFixture, Magnitude,
  30. testing::Combine(testing::Values(TYPICAL_MAT_SIZES), testing::Values(CV_32F, CV_64F)))
  31. {
  32. cv::Size size = std::get<0>(GetParam());
  33. int type = std::get<1>(GetParam());
  34. cv::Mat x(size, type);
  35. cv::Mat y(size, type);
  36. cv::Mat magnitude(size, type);
  37. declare.in(x, y, WARMUP_RNG).out(magnitude);
  38. TEST_CYCLE() cv::magnitude(x, y, magnitude);
  39. SANITY_CHECK_NOTHING();
  40. }
  41. ///////////// Cart to Polar /////////////
  42. typedef Size_MatType CartToPolarFixture;
  43. PERF_TEST_P(CartToPolarFixture, CartToPolar,
  44. testing::Combine(testing::Values(TYPICAL_MAT_SIZES), testing::Values(CV_32F, CV_64F)))
  45. {
  46. cv::Size size = std::get<0>(GetParam());
  47. int type = std::get<1>(GetParam());
  48. cv::Mat x(size, type);
  49. cv::Mat y(size, type);
  50. cv::Mat magnitude(size, type);
  51. cv::Mat angle(size, type);
  52. declare.in(x, y, WARMUP_RNG).out(magnitude, angle);
  53. TEST_CYCLE() cv::cartToPolar(x, y, magnitude, angle);
  54. SANITY_CHECK_NOTHING();
  55. }
  56. ///////////// Polar to Cart /////////////
  57. typedef Size_MatType PolarToCartFixture;
  58. PERF_TEST_P(PolarToCartFixture, PolarToCart,
  59. testing::Combine(testing::Values(TYPICAL_MAT_SIZES), testing::Values(CV_32F, CV_64F)))
  60. {
  61. cv::Size size = std::get<0>(GetParam());
  62. int type = std::get<1>(GetParam());
  63. cv::Mat magnitude(size, type);
  64. cv::Mat angle(size, type);
  65. cv::Mat x(size, type);
  66. cv::Mat y(size, type);
  67. declare.in(magnitude, angle, WARMUP_RNG).out(x, y);
  68. TEST_CYCLE() cv::polarToCart(magnitude, angle, x, y);
  69. SANITY_CHECK_NOTHING();
  70. }
  71. // generates random vectors, performs Gram-Schmidt orthogonalization on them
  72. Mat randomOrtho(int rows, int ftype, RNG& rng)
  73. {
  74. Mat result(rows, rows, ftype);
  75. rng.fill(result, RNG::UNIFORM, cv::Scalar(-1), cv::Scalar(1));
  76. for (int i = 0; i < rows; i++)
  77. {
  78. Mat v = result.row(i);
  79. for (int j = 0; j < i; j++)
  80. {
  81. Mat p = result.row(j);
  82. v -= p.dot(v) * p;
  83. }
  84. v = v * (1. / cv::norm(v));
  85. }
  86. return result;
  87. }
  88. template<typename FType>
  89. Mat buildRandomMat(int rows, int cols, RNG& rng, int rank, bool symmetrical)
  90. {
  91. int mtype = cv::traits::Depth<FType>::value;
  92. Mat u = randomOrtho(rows, mtype, rng);
  93. Mat v = randomOrtho(cols, mtype, rng);
  94. Mat s(rows, cols, mtype, Scalar(0));
  95. std::vector<FType> singVals(rank);
  96. rng.fill(singVals, RNG::UNIFORM, Scalar(0), Scalar(10));
  97. std::sort(singVals.begin(), singVals.end());
  98. auto singIter = singVals.rbegin();
  99. for (int i = 0; i < rank; i++)
  100. {
  101. s.at<FType>(i, i) = *singIter++;
  102. }
  103. if (symmetrical)
  104. return u * s * u.t();
  105. else
  106. return u * s * v.t();
  107. }
  108. Mat buildRandomMat(int rows, int cols, int mtype, RNG& rng, int rank, bool symmetrical)
  109. {
  110. if (mtype == CV_32F)
  111. {
  112. return buildRandomMat<float>(rows, cols, rng, rank, symmetrical);
  113. }
  114. else if (mtype == CV_64F)
  115. {
  116. return buildRandomMat<double>(rows, cols, rng, rank, symmetrical);
  117. }
  118. else
  119. {
  120. CV_Error(cv::Error::StsBadArg, "This type is not supported");
  121. }
  122. }
  123. CV_ENUM(SolveDecompEnum, DECOMP_LU, DECOMP_SVD, DECOMP_EIG, DECOMP_CHOLESKY, DECOMP_QR)
  124. enum RankMatrixOptions
  125. {
  126. RANK_HALF, RANK_MINUS_1, RANK_FULL
  127. };
  128. CV_ENUM(RankEnum, RANK_HALF, RANK_MINUS_1, RANK_FULL)
  129. enum SolutionsOptions
  130. {
  131. NO_SOLUTIONS, ONE_SOLUTION, MANY_SOLUTIONS
  132. };
  133. CV_ENUM(SolutionsEnum, NO_SOLUTIONS, ONE_SOLUTION, MANY_SOLUTIONS)
  134. typedef perf::TestBaseWithParam<std::tuple<int, RankEnum, MatDepth, SolveDecompEnum, bool, SolutionsEnum>> SolveTest;
  135. PERF_TEST_P(SolveTest, randomMat, ::testing::Combine(
  136. ::testing::Values(31, 64, 100),
  137. ::testing::Values(RANK_HALF, RANK_MINUS_1, RANK_FULL),
  138. ::testing::Values(CV_32F, CV_64F),
  139. ::testing::Values(DECOMP_LU, DECOMP_SVD, DECOMP_EIG, DECOMP_CHOLESKY, DECOMP_QR),
  140. ::testing::Bool(), // normal
  141. ::testing::Values(NO_SOLUTIONS, ONE_SOLUTION, MANY_SOLUTIONS)
  142. ))
  143. {
  144. auto t = GetParam();
  145. int size = std::get<0>(t);
  146. auto rankEnum = std::get<1>(t);
  147. int mtype = std::get<2>(t);
  148. int method = std::get<3>(t);
  149. bool normal = std::get<4>(t);
  150. auto solutions = std::get<5>(t);
  151. bool symmetrical = (method == DECOMP_CHOLESKY || method == DECOMP_LU);
  152. if (normal)
  153. {
  154. method |= DECOMP_NORMAL;
  155. }
  156. int rank = size;
  157. switch (rankEnum)
  158. {
  159. case RANK_HALF: rank /= 2; break;
  160. case RANK_MINUS_1: rank -= 1; break;
  161. default: break;
  162. }
  163. RNG& rng = theRNG();
  164. Mat A = buildRandomMat(size, size, mtype, rng, rank, symmetrical);
  165. Mat x(size, 1, mtype);
  166. Mat b(size, 1, mtype);
  167. switch (solutions)
  168. {
  169. // no solutions, let's make b random
  170. case NO_SOLUTIONS:
  171. {
  172. rng.fill(b, RNG::UNIFORM, Scalar(-1), Scalar(1));
  173. }
  174. break;
  175. // exactly 1 solution, let's combine b from A and x
  176. case ONE_SOLUTION:
  177. {
  178. rng.fill(x, RNG::UNIFORM, Scalar(-10), Scalar(10));
  179. b = A * x;
  180. }
  181. break;
  182. // infinitely many solutions, let's make b zero
  183. default:
  184. {
  185. b = 0;
  186. }
  187. break;
  188. }
  189. TEST_CYCLE() cv::solve(A, b, x, method);
  190. SANITY_CHECK_NOTHING();
  191. }
  192. typedef perf::TestBaseWithParam<std::tuple<std::tuple<int, int>, RankEnum, MatDepth, bool, bool>> SvdTest;
  193. PERF_TEST_P(SvdTest, decompose, ::testing::Combine(
  194. ::testing::Values(std::make_tuple(5, 15), std::make_tuple(32, 32), std::make_tuple(100, 100)),
  195. ::testing::Values(RANK_HALF, RANK_MINUS_1, RANK_FULL),
  196. ::testing::Values(CV_32F, CV_64F),
  197. ::testing::Bool(), // symmetrical
  198. ::testing::Bool() // needUV
  199. ))
  200. {
  201. auto t = GetParam();
  202. auto rc = std::get<0>(t);
  203. auto rankEnum = std::get<1>(t);
  204. int mtype = std::get<2>(t);
  205. bool symmetrical = std::get<3>(t);
  206. bool needUV = std::get<4>(t);
  207. int rows = std::get<0>(rc);
  208. int cols = std::get<1>(rc);
  209. if (symmetrical)
  210. {
  211. rows = max(rows, cols);
  212. cols = rows;
  213. }
  214. int rank = std::min(rows, cols);
  215. switch (rankEnum)
  216. {
  217. case RANK_HALF: rank /= 2; break;
  218. case RANK_MINUS_1: rank -= 1; break;
  219. default: break;
  220. }
  221. int flags = needUV ? 0 : SVD::NO_UV;
  222. RNG& rng = theRNG();
  223. Mat A = buildRandomMat(rows, cols, mtype, rng, rank, symmetrical);
  224. TEST_CYCLE() cv::SVD svd(A, flags);
  225. SANITY_CHECK_NOTHING();
  226. }
  227. PERF_TEST_P(SvdTest, backSubst, ::testing::Combine(
  228. ::testing::Values(std::make_tuple(5, 15), std::make_tuple(32, 32), std::make_tuple(100, 100)),
  229. ::testing::Values(RANK_HALF, RANK_MINUS_1, RANK_FULL),
  230. ::testing::Values(CV_32F, CV_64F),
  231. // back substitution works the same regardless of source matrix properties
  232. ::testing::Values(true),
  233. // back substitution has no sense without u and v
  234. ::testing::Values(true) // needUV
  235. ))
  236. {
  237. auto t = GetParam();
  238. auto rc = std::get<0>(t);
  239. auto rankEnum = std::get<1>(t);
  240. int mtype = std::get<2>(t);
  241. int rows = std::get<0>(rc);
  242. int cols = std::get<1>(rc);
  243. int rank = std::min(rows, cols);
  244. switch (rankEnum)
  245. {
  246. case RANK_HALF: rank /= 2; break;
  247. case RANK_MINUS_1: rank -= 1; break;
  248. default: break;
  249. }
  250. RNG& rng = theRNG();
  251. Mat A = buildRandomMat(rows, cols, mtype, rng, rank, /* symmetrical */ false);
  252. cv::SVD svd(A);
  253. // preallocate to not spend time on it during backSubst()
  254. Mat dst(cols, 1, mtype);
  255. Mat rhs(rows, 1, mtype);
  256. rng.fill(rhs, RNG::UNIFORM, Scalar(-10), Scalar(10));
  257. TEST_CYCLE() svd.backSubst(rhs, dst);
  258. SANITY_CHECK_NOTHING();
  259. }
  260. typedef perf::TestBaseWithParam< testing::tuple<int, int, int> > KMeans;
  261. PERF_TEST_P_(KMeans, single_iter)
  262. {
  263. RNG& rng = theRNG();
  264. const int K = testing::get<0>(GetParam());
  265. const int dims = testing::get<1>(GetParam());
  266. const int N = testing::get<2>(GetParam());
  267. const int attempts = 5;
  268. Mat data(N, dims, CV_32F);
  269. rng.fill(data, RNG::UNIFORM, -0.1, 0.1);
  270. const int N0 = K;
  271. Mat data0(N0, dims, CV_32F);
  272. rng.fill(data0, RNG::UNIFORM, -1, 1);
  273. for (int i = 0; i < N; i++)
  274. {
  275. int base = rng.uniform(0, N0);
  276. cv::add(data0.row(base), data.row(i), data.row(i));
  277. }
  278. declare.in(data);
  279. Mat labels, centers;
  280. TEST_CYCLE()
  281. {
  282. kmeans(data, K, labels, TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 1, 0),
  283. attempts, KMEANS_PP_CENTERS, centers);
  284. }
  285. SANITY_CHECK_NOTHING();
  286. }
  287. PERF_TEST_P_(KMeans, good)
  288. {
  289. RNG& rng = theRNG();
  290. const int K = testing::get<0>(GetParam());
  291. const int dims = testing::get<1>(GetParam());
  292. const int N = testing::get<2>(GetParam());
  293. const int attempts = 5;
  294. Mat data(N, dims, CV_32F);
  295. rng.fill(data, RNG::UNIFORM, -0.1, 0.1);
  296. const int N0 = K;
  297. Mat data0(N0, dims, CV_32F);
  298. rng.fill(data0, RNG::UNIFORM, -1, 1);
  299. for (int i = 0; i < N; i++)
  300. {
  301. int base = rng.uniform(0, N0);
  302. cv::add(data0.row(base), data.row(i), data.row(i));
  303. }
  304. declare.in(data);
  305. Mat labels, centers;
  306. TEST_CYCLE()
  307. {
  308. kmeans(data, K, labels, TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 0),
  309. attempts, KMEANS_PP_CENTERS, centers);
  310. }
  311. SANITY_CHECK_NOTHING();
  312. }
  313. PERF_TEST_P_(KMeans, with_duplicates)
  314. {
  315. RNG& rng = theRNG();
  316. const int K = testing::get<0>(GetParam());
  317. const int dims = testing::get<1>(GetParam());
  318. const int N = testing::get<2>(GetParam());
  319. const int attempts = 5;
  320. Mat data(N, dims, CV_32F, Scalar::all(0));
  321. const int N0 = std::max(2, K * 2 / 3);
  322. Mat data0(N0, dims, CV_32F);
  323. rng.fill(data0, RNG::UNIFORM, -1, 1);
  324. for (int i = 0; i < N; i++)
  325. {
  326. int base = rng.uniform(0, N0);
  327. data0.row(base).copyTo(data.row(i));
  328. }
  329. declare.in(data);
  330. Mat labels, centers;
  331. TEST_CYCLE()
  332. {
  333. kmeans(data, K, labels, TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 0),
  334. attempts, KMEANS_PP_CENTERS, centers);
  335. }
  336. SANITY_CHECK_NOTHING();
  337. }
  338. INSTANTIATE_TEST_CASE_P(/*nothing*/ , KMeans,
  339. testing::Values(
  340. // K clusters, dims, N points
  341. testing::make_tuple(2, 3, 100000),
  342. testing::make_tuple(4, 3, 500),
  343. testing::make_tuple(4, 3, 1000),
  344. testing::make_tuple(4, 3, 10000),
  345. testing::make_tuple(8, 3, 1000),
  346. testing::make_tuple(8, 16, 1000),
  347. testing::make_tuple(8, 64, 1000),
  348. testing::make_tuple(16, 16, 1000),
  349. testing::make_tuple(16, 32, 1000),
  350. testing::make_tuple(32, 16, 1000),
  351. testing::make_tuple(32, 32, 1000),
  352. testing::make_tuple(100, 2, 1000)
  353. )
  354. );
  355. }
  356. } // namespace