cuda_test.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. /*M///////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
  4. //
  5. // By downloading, copying, installing or using the software you agree to this license.
  6. // If you do not agree to this license, do not download, install,
  7. // copy or use the software.
  8. //
  9. //
  10. // License Agreement
  11. // For Open Source Computer Vision Library
  12. //
  13. // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
  14. // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
  15. // Third party copyrights are property of their respective owners.
  16. //
  17. // Redistribution and use in source and binary forms, with or without modification,
  18. // are permitted provided that the following conditions are met:
  19. //
  20. // * Redistribution's of source code must retain the above copyright notice,
  21. // this list of conditions and the following disclaimer.
  22. //
  23. // * Redistribution's in binary form must reproduce the above copyright notice,
  24. // this list of conditions and the following disclaimer in the documentation
  25. // and/or other materials provided with the distribution.
  26. //
  27. // * The name of the copyright holders may not be used to endorse or promote products
  28. // derived from this software without specific prior written permission.
  29. //
  30. // This software is provided by the copyright holders and contributors "as is" and
  31. // any express or implied warranties, including, but not limited to, the implied
  32. // warranties of merchantability and fitness for a particular purpose are disclaimed.
  33. // In no event shall the Intel Corporation or contributors be liable for any direct,
  34. // indirect, incidental, special, exemplary, or consequential damages
  35. // (including, but not limited to, procurement of substitute goods or services;
  36. // loss of use, data, or profits; or business interruption) however caused
  37. // and on any theory of liability, whether in contract, strict liability,
  38. // or tort (including negligence or otherwise) arising in any way out of
  39. // the use of this software, even if advised of the possibility of such damage.
  40. //
  41. //M*/
  42. #include "opencv2/ts/cuda_test.hpp"
  43. #include <stdexcept>
  44. using namespace cv;
  45. using namespace cv::cuda;
  46. using namespace cvtest;
  47. using namespace testing;
  48. using namespace testing::internal;
  49. namespace perf
  50. {
  51. void printCudaInfo();
  52. }
  53. namespace cvtest
  54. {
  55. //////////////////////////////////////////////////////////////////////
  56. // random generators
  57. int randomInt(int minVal, int maxVal)
  58. {
  59. RNG& rng = TS::ptr()->get_rng();
  60. return rng.uniform(minVal, maxVal);
  61. }
  62. double randomDouble(double minVal, double maxVal)
  63. {
  64. RNG& rng = TS::ptr()->get_rng();
  65. return rng.uniform(minVal, maxVal);
  66. }
  67. Size randomSize(int minVal, int maxVal)
  68. {
  69. return Size(randomInt(minVal, maxVal), randomInt(minVal, maxVal));
  70. }
  71. Scalar randomScalar(double minVal, double maxVal)
  72. {
  73. return Scalar(randomDouble(minVal, maxVal), randomDouble(minVal, maxVal), randomDouble(minVal, maxVal), randomDouble(minVal, maxVal));
  74. }
  75. Mat randomMat(Size size, int type, double minVal, double maxVal)
  76. {
  77. return randomMat(TS::ptr()->get_rng(), size, type, minVal, maxVal, false);
  78. }
  79. //////////////////////////////////////////////////////////////////////
  80. // GpuMat create
  81. GpuMat createMat(Size size, int type, bool useRoi)
  82. {
  83. Size size0; Point ofs;
  84. return createMat(size, type, size0, ofs, useRoi);
  85. }
  86. GpuMat createMat(Size size, int type, Size& size0, Point& ofs, bool useRoi)
  87. {
  88. size0 = size;
  89. if (useRoi)
  90. {
  91. size0.width += randomInt(5, 15);
  92. size0.height += randomInt(5, 15);
  93. }
  94. GpuMat d_m(size0, type);
  95. if (size0 != size) {
  96. ofs = Point((size0.width - size.width) / 2, (size0.height - size.height) / 2);
  97. d_m = d_m(Rect(ofs, size));
  98. }
  99. return d_m;
  100. }
  101. GpuMat loadMat(const Mat& m, bool useRoi)
  102. {
  103. GpuMat d_m = createMat(m.size(), m.type(), useRoi);
  104. d_m.upload(m);
  105. return d_m;
  106. }
  107. //////////////////////////////////////////////////////////////////////
  108. // Image load
  109. Mat readImage(const std::string& fileName, int flags)
  110. {
  111. return imread(TS::ptr()->get_data_path() + fileName, flags);
  112. }
  113. Mat readImageType(const std::string& fname, int type)
  114. {
  115. Mat src = readImage(fname, CV_MAT_CN(type) == 1 ? IMREAD_GRAYSCALE : IMREAD_COLOR);
  116. if (CV_MAT_CN(type) == 4)
  117. {
  118. Mat temp;
  119. cvtColor(src, temp, COLOR_BGR2BGRA);
  120. swap(src, temp);
  121. }
  122. src.convertTo(src, CV_MAT_DEPTH(type), CV_MAT_DEPTH(type) == CV_32F ? 1.0 / 255.0 : 1.0);
  123. return src;
  124. }
  125. //////////////////////////////////////////////////////////////////////
  126. // Gpu devices
  127. bool supportFeature(const DeviceInfo& info, FeatureSet feature)
  128. {
  129. return TargetArchs::builtWith(feature) && info.supports(feature);
  130. }
  131. DeviceManager& DeviceManager::instance()
  132. {
  133. static DeviceManager obj;
  134. return obj;
  135. }
  136. void DeviceManager::load(int i)
  137. {
  138. devices_.clear();
  139. devices_.reserve(1);
  140. std::ostringstream msg;
  141. if (i < 0 || i >= getCudaEnabledDeviceCount())
  142. {
  143. msg << "Incorrect device number - " << i;
  144. throw std::runtime_error(msg.str());
  145. }
  146. DeviceInfo info(i);
  147. if (!info.isCompatible())
  148. {
  149. msg << "Device " << i << " [" << info.name() << "] is NOT compatible with current CUDA module build";
  150. throw std::runtime_error(msg.str());
  151. }
  152. devices_.push_back(info);
  153. }
  154. void DeviceManager::loadAll()
  155. {
  156. int deviceCount = getCudaEnabledDeviceCount();
  157. devices_.clear();
  158. devices_.reserve(deviceCount);
  159. for (int i = 0; i < deviceCount; ++i)
  160. {
  161. DeviceInfo info(i);
  162. if (info.isCompatible())
  163. {
  164. devices_.push_back(info);
  165. }
  166. }
  167. }
  168. void parseCudaDeviceOptions(int argc, char **argv)
  169. {
  170. cv::CommandLineParser cmd(argc, argv,
  171. "{ cuda_device | -1 | CUDA device on which tests will be executed (-1 means all devices) }"
  172. "{ h help | false | Print help info }"
  173. );
  174. if (cmd.has("help"))
  175. {
  176. std::cout << "\nAvailable options besides google test option: \n";
  177. cmd.printMessage();
  178. }
  179. int device = cmd.get<int>("cuda_device");
  180. if (device < 0)
  181. {
  182. cvtest::DeviceManager::instance().loadAll();
  183. std::cout << "Run tests on all supported CUDA devices \n" << std::endl;
  184. }
  185. else
  186. {
  187. cvtest::DeviceManager::instance().load(device);
  188. cv::cuda::DeviceInfo info(device);
  189. std::cout << "Run tests on CUDA device " << device << " [" << info.name() << "] \n" << std::endl;
  190. }
  191. }
  192. //////////////////////////////////////////////////////////////////////
  193. // Additional assertion
  194. namespace
  195. {
  196. template <typename T, typename OutT> std::string printMatValImpl(const Mat& m, Point p)
  197. {
  198. const int cn = m.channels();
  199. std::ostringstream ostr;
  200. ostr << "(";
  201. p.x /= cn;
  202. ostr << static_cast<OutT>(m.at<T>(p.y, p.x * cn));
  203. for (int c = 1; c < m.channels(); ++c)
  204. {
  205. ostr << ", " << static_cast<OutT>(m.at<T>(p.y, p.x * cn + c));
  206. }
  207. ostr << ")";
  208. return ostr.str();
  209. }
  210. std::string printMatVal(const Mat& m, Point p)
  211. {
  212. typedef std::string (*func_t)(const Mat& m, Point p);
  213. static const func_t funcs[] =
  214. {
  215. printMatValImpl<uchar, int>, printMatValImpl<schar, int>, printMatValImpl<ushort, int>, printMatValImpl<short, int>,
  216. printMatValImpl<int, int>, printMatValImpl<float, float>, printMatValImpl<double, double>
  217. };
  218. return funcs[m.depth()](m, p);
  219. }
  220. }
  221. void minMaxLocGold(const Mat& src, double* minVal_, double* maxVal_, Point* minLoc_, Point* maxLoc_, const Mat& mask)
  222. {
  223. if (src.depth() != CV_8S)
  224. {
  225. minMaxLoc(src, minVal_, maxVal_, minLoc_, maxLoc_, mask);
  226. return;
  227. }
  228. // OpenCV's minMaxLoc doesn't support CV_8S type
  229. double minVal = std::numeric_limits<double>::max();
  230. Point minLoc(-1, -1);
  231. double maxVal = -std::numeric_limits<double>::max();
  232. Point maxLoc(-1, -1);
  233. for (int y = 0; y < src.rows; ++y)
  234. {
  235. const schar* src_row = src.ptr<schar>(y);
  236. const uchar* mask_row = mask.empty() ? 0 : mask.ptr<uchar>(y);
  237. for (int x = 0; x < src.cols; ++x)
  238. {
  239. if (!mask_row || mask_row[x])
  240. {
  241. schar val = src_row[x];
  242. if (val < minVal)
  243. {
  244. minVal = val;
  245. minLoc = cv::Point(x, y);
  246. }
  247. if (val > maxVal)
  248. {
  249. maxVal = val;
  250. maxLoc = cv::Point(x, y);
  251. }
  252. }
  253. }
  254. }
  255. if (minVal_) *minVal_ = minVal;
  256. if (maxVal_) *maxVal_ = maxVal;
  257. if (minLoc_) *minLoc_ = minLoc;
  258. if (maxLoc_) *maxLoc_ = maxLoc;
  259. }
  260. Mat getMat(InputArray arr)
  261. {
  262. if (arr.kind() == _InputArray::CUDA_GPU_MAT)
  263. {
  264. Mat m;
  265. arr.getGpuMat().download(m);
  266. return m;
  267. }
  268. return arr.getMat();
  269. }
  270. AssertionResult assertMatNear(const char* expr1, const char* expr2, const char* eps_expr, InputArray m1_, InputArray m2_, double eps)
  271. {
  272. Mat m1 = getMat(m1_);
  273. Mat m2 = getMat(m2_);
  274. if (m1.size() != m2.size())
  275. {
  276. std::stringstream msg;
  277. msg << "Matrices \"" << expr1 << "\" and \"" << expr2 << "\" have different sizes : \""
  278. << expr1 << "\" [" << PrintToString(m1.size()) << "] vs \""
  279. << expr2 << "\" [" << PrintToString(m2.size()) << "]";
  280. return AssertionFailure() << msg.str();
  281. }
  282. if (m1.type() != m2.type())
  283. {
  284. std::stringstream msg;
  285. msg << "Matrices \"" << expr1 << "\" and \"" << expr2 << "\" have different types : \""
  286. << expr1 << "\" [" << PrintToString(MatType(m1.type())) << "] vs \""
  287. << expr2 << "\" [" << PrintToString(MatType(m2.type())) << "]";
  288. return AssertionFailure() << msg.str();
  289. }
  290. Mat diff;
  291. absdiff(m1.reshape(1), m2.reshape(1), diff);
  292. double maxVal = 0.0;
  293. Point maxLoc;
  294. minMaxLocGold(diff, 0, &maxVal, 0, &maxLoc);
  295. if (maxVal > eps)
  296. {
  297. std::stringstream msg;
  298. msg << "The max difference between matrices \"" << expr1 << "\" and \"" << expr2
  299. << "\" is " << maxVal << " at (" << maxLoc.y << ", " << maxLoc.x / m1.channels() << ")"
  300. << ", which exceeds \"" << eps_expr << "\", where \""
  301. << expr1 << "\" at (" << maxLoc.y << ", " << maxLoc.x / m1.channels() << ") evaluates to " << printMatVal(m1, maxLoc) << ", \""
  302. << expr2 << "\" at (" << maxLoc.y << ", " << maxLoc.x / m1.channels() << ") evaluates to " << printMatVal(m2, maxLoc) << ", \""
  303. << eps_expr << "\" evaluates to " << eps;
  304. return AssertionFailure() << msg.str();
  305. }
  306. return AssertionSuccess();
  307. }
  308. double checkSimilarity(InputArray m1, InputArray m2)
  309. {
  310. Mat diff;
  311. matchTemplate(getMat(m1), getMat(m2), diff, TM_CCORR_NORMED);
  312. return std::abs(diff.at<float>(0, 0) - 1.f);
  313. }
  314. //////////////////////////////////////////////////////////////////////
  315. // Helper structs for value-parameterized tests
  316. vector<MatType> types(int depth_start, int depth_end, int cn_start, int cn_end)
  317. {
  318. vector<MatType> v;
  319. v.reserve((depth_end - depth_start + 1) * (cn_end - cn_start + 1));
  320. for (int depth = depth_start; depth <= depth_end; ++depth)
  321. {
  322. for (int cn = cn_start; cn <= cn_end; ++cn)
  323. {
  324. v.push_back(MatType(CV_MAKE_TYPE(depth, cn)));
  325. }
  326. }
  327. return v;
  328. }
  329. const vector<MatType>& all_types()
  330. {
  331. static vector<MatType> v = types(CV_8U, CV_64F, 1, 4);
  332. return v;
  333. }
  334. void PrintTo(const UseRoi& useRoi, std::ostream* os)
  335. {
  336. if (useRoi)
  337. (*os) << "sub matrix";
  338. else
  339. (*os) << "whole matrix";
  340. }
  341. void PrintTo(const Inverse& inverse, std::ostream* os)
  342. {
  343. if (inverse)
  344. (*os) << "inverse";
  345. else
  346. (*os) << "direct";
  347. }
  348. //////////////////////////////////////////////////////////////////////
  349. // Other
  350. void dumpImage(const std::string& fileName, const Mat& image)
  351. {
  352. imwrite(TS::ptr()->get_data_path() + fileName, image);
  353. }
  354. void showDiff(InputArray gold_, InputArray actual_, double eps)
  355. {
  356. Mat gold = getMat(gold_);
  357. Mat actual = getMat(actual_);
  358. Mat diff;
  359. absdiff(gold, actual, diff);
  360. threshold(diff, diff, eps, 255.0, cv::THRESH_BINARY);
  361. namedWindow("gold", WINDOW_NORMAL);
  362. namedWindow("actual", WINDOW_NORMAL);
  363. namedWindow("diff", WINDOW_NORMAL);
  364. imshow("gold", gold);
  365. imshow("actual", actual);
  366. imshow("diff", diff);
  367. waitKey();
  368. }
  369. namespace
  370. {
  371. bool keyPointsEquals(const cv::KeyPoint& p1, const cv::KeyPoint& p2)
  372. {
  373. const double maxPtDif = 1.0;
  374. const double maxSizeDif = 1.0;
  375. const double maxAngleDif = 2.0;
  376. const double maxResponseDif = 0.1;
  377. double dist = cv::norm(p1.pt - p2.pt);
  378. if (dist < maxPtDif &&
  379. fabs(p1.size - p2.size) < maxSizeDif &&
  380. abs(p1.angle - p2.angle) < maxAngleDif &&
  381. abs(p1.response - p2.response) < maxResponseDif &&
  382. p1.octave == p2.octave &&
  383. p1.class_id == p2.class_id)
  384. {
  385. return true;
  386. }
  387. return false;
  388. }
  389. struct KeyPointLess
  390. {
  391. bool operator()(const cv::KeyPoint& kp1, const cv::KeyPoint& kp2) const
  392. {
  393. return kp1.pt.y < kp2.pt.y || (kp1.pt.y == kp2.pt.y && kp1.pt.x < kp2.pt.x);
  394. }
  395. };
  396. }
  397. testing::AssertionResult assertKeyPointsEquals(const char* gold_expr, const char* actual_expr, std::vector<cv::KeyPoint>& gold, std::vector<cv::KeyPoint>& actual)
  398. {
  399. if (gold.size() != actual.size())
  400. {
  401. std::stringstream msg;
  402. msg << "KeyPoints size mistmach\n"
  403. << "\"" << gold_expr << "\" : " << gold.size() << "\n"
  404. << "\"" << actual_expr << "\" : " << actual.size();
  405. return AssertionFailure() << msg.str();
  406. }
  407. std::sort(actual.begin(), actual.end(), KeyPointLess());
  408. std::sort(gold.begin(), gold.end(), KeyPointLess());
  409. for (size_t i = 0; i < gold.size(); ++i)
  410. {
  411. const cv::KeyPoint& p1 = gold[i];
  412. const cv::KeyPoint& p2 = actual[i];
  413. if (!keyPointsEquals(p1, p2))
  414. {
  415. std::stringstream msg;
  416. msg << "KeyPoints differ at " << i << "\n"
  417. << "\"" << gold_expr << "\" vs \"" << actual_expr << "\" : \n"
  418. << "pt : " << testing::PrintToString(p1.pt) << " vs " << testing::PrintToString(p2.pt) << "\n"
  419. << "size : " << p1.size << " vs " << p2.size << "\n"
  420. << "angle : " << p1.angle << " vs " << p2.angle << "\n"
  421. << "response : " << p1.response << " vs " << p2.response << "\n"
  422. << "octave : " << p1.octave << " vs " << p2.octave << "\n"
  423. << "class_id : " << p1.class_id << " vs " << p2.class_id;
  424. return AssertionFailure() << msg.str();
  425. }
  426. }
  427. return ::testing::AssertionSuccess();
  428. }
  429. int getMatchedPointsCount(std::vector<cv::KeyPoint>& gold, std::vector<cv::KeyPoint>& actual)
  430. {
  431. std::sort(actual.begin(), actual.end(), KeyPointLess());
  432. std::sort(gold.begin(), gold.end(), KeyPointLess());
  433. int validCount = 0;
  434. for (size_t i = 0; i < gold.size(); ++i)
  435. {
  436. const cv::KeyPoint& p1 = gold[i];
  437. const cv::KeyPoint& p2 = actual[i];
  438. if (keyPointsEquals(p1, p2))
  439. ++validCount;
  440. }
  441. return validCount;
  442. }
  443. int getMatchedPointsCount(const std::vector<cv::KeyPoint>& keypoints1, const std::vector<cv::KeyPoint>& keypoints2, const std::vector<cv::DMatch>& matches)
  444. {
  445. int validCount = 0;
  446. for (size_t i = 0; i < matches.size(); ++i)
  447. {
  448. const cv::DMatch& m = matches[i];
  449. const cv::KeyPoint& p1 = keypoints1[m.queryIdx];
  450. const cv::KeyPoint& p2 = keypoints2[m.trainIdx];
  451. if (keyPointsEquals(p1, p2))
  452. ++validCount;
  453. }
  454. return validCount;
  455. }
  456. void printCudaInfo()
  457. {
  458. perf::printCudaInfo();
  459. }
  460. }
  461. void cv::cuda::PrintTo(const DeviceInfo& info, std::ostream* os)
  462. {
  463. (*os) << info.name();
  464. if (info.deviceID())
  465. (*os) << " [ID: " << info.deviceID() << "]";
  466. }