test_houghlines.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  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. // Copyright (C) 2014, Itseez, Inc, all rights reserved.
  16. // Third party copyrights are property of their respective owners.
  17. //
  18. // Redistribution and use in source and binary forms, with or without modification,
  19. // are permitted provided that the following conditions are met:
  20. //
  21. // * Redistribution's of source code must retain the above copyright notice,
  22. // this list of conditions and the following disclaimer.
  23. //
  24. // * Redistribution's in binary form must reproduce the above copyright notice,
  25. // this list of conditions and the following disclaimer in the documentation
  26. // and/or other materials provided with the distribution.
  27. //
  28. // * The name of the copyright holders may not be used to endorse or promote products
  29. // derived from this software without specific prior written permission.
  30. //
  31. // This software is provided by the copyright holders and contributors "as is" and
  32. // any express or implied warranties, including, but not limited to, the implied
  33. // warranties of merchantability and fitness for a particular purpose are disclaimed.
  34. // In no event shall the Intel Corporation or contributors be liable for any direct,
  35. // indirect, incidental, special, exemplary, or consequential damages
  36. // (including, but not limited to, procurement of substitute goods or services;
  37. // loss of use, data, or profits; or business interruption) however caused
  38. // and on any theory of liability, whether in contract, strict liability,
  39. // or tort (including negligence or otherwise) arising in any way out of
  40. // the use of this software, even if advised of the possibility of such damage.
  41. //
  42. //M*/
  43. #include "test_precomp.hpp"
  44. //#define GENERATE_DATA // generate data in debug mode via CPU code path (without IPP / OpenCL and other accelerators)
  45. namespace opencv_test { namespace {
  46. template<typename T>
  47. struct SimilarWith
  48. {
  49. T value;
  50. float theta_eps;
  51. float rho_eps;
  52. SimilarWith<T>(T val, float e, float r_e): value(val), theta_eps(e), rho_eps(r_e) { };
  53. bool operator()(const T& other);
  54. };
  55. template<>
  56. bool SimilarWith<Vec2f>::operator()(const Vec2f& other)
  57. {
  58. return std::abs(other[0] - value[0]) < rho_eps && std::abs(other[1] - value[1]) < theta_eps;
  59. }
  60. template<>
  61. bool SimilarWith<Vec3f>::operator()(const Vec3f& other)
  62. {
  63. return std::abs(other[0] - value[0]) < rho_eps && std::abs(other[1] - value[1]) < theta_eps;
  64. }
  65. template<>
  66. bool SimilarWith<Vec4i>::operator()(const Vec4i& other)
  67. {
  68. return cv::norm(value, other) < theta_eps;
  69. }
  70. template <typename T>
  71. int countMatIntersection(const Mat& expect, const Mat& actual, float eps, float rho_eps)
  72. {
  73. int count = 0;
  74. if (!expect.empty() && !actual.empty())
  75. {
  76. for (MatConstIterator_<T> it=expect.begin<T>(); it!=expect.end<T>(); it++)
  77. {
  78. MatConstIterator_<T> f = std::find_if(actual.begin<T>(), actual.end<T>(), SimilarWith<T>(*it, eps, rho_eps));
  79. if (f != actual.end<T>())
  80. count++;
  81. }
  82. }
  83. return count;
  84. }
  85. String getTestCaseName(String filename)
  86. {
  87. string temp(filename);
  88. size_t pos = temp.find_first_of("\\/.");
  89. while ( pos != string::npos ) {
  90. temp.replace( pos, 1, "_" );
  91. pos = temp.find_first_of("\\/.");
  92. }
  93. return String(temp);
  94. }
  95. class BaseHoughLineTest
  96. {
  97. public:
  98. enum {STANDART = 0, PROBABILISTIC};
  99. protected:
  100. template<typename LinesType, typename LineType>
  101. void run_test(int type, const char* xml_name);
  102. string picture_name;
  103. double rhoStep;
  104. double thetaStep;
  105. int threshold;
  106. int minLineLength;
  107. int maxGap;
  108. };
  109. typedef tuple<string, double, double, int> Image_RhoStep_ThetaStep_Threshold_t;
  110. class StandartHoughLinesTest : public BaseHoughLineTest, public testing::TestWithParam<Image_RhoStep_ThetaStep_Threshold_t>
  111. {
  112. public:
  113. StandartHoughLinesTest()
  114. {
  115. picture_name = get<0>(GetParam());
  116. rhoStep = get<1>(GetParam());
  117. thetaStep = get<2>(GetParam());
  118. threshold = get<3>(GetParam());
  119. minLineLength = 0;
  120. maxGap = 0;
  121. }
  122. };
  123. typedef tuple<string, double, double, int, int, int> Image_RhoStep_ThetaStep_Threshold_MinLine_MaxGap_t;
  124. class ProbabilisticHoughLinesTest : public BaseHoughLineTest, public testing::TestWithParam<Image_RhoStep_ThetaStep_Threshold_MinLine_MaxGap_t>
  125. {
  126. public:
  127. ProbabilisticHoughLinesTest()
  128. {
  129. picture_name = get<0>(GetParam());
  130. rhoStep = get<1>(GetParam());
  131. thetaStep = get<2>(GetParam());
  132. threshold = get<3>(GetParam());
  133. minLineLength = get<4>(GetParam());
  134. maxGap = get<5>(GetParam());
  135. }
  136. };
  137. typedef tuple<double, double, double, double> HoughLinesPointSetInput_t;
  138. class HoughLinesPointSetTest : public testing::TestWithParam<HoughLinesPointSetInput_t>
  139. {
  140. protected:
  141. void run_test();
  142. double Rho;
  143. double Theta;
  144. double rhoMin, rhoMax, rhoStep;
  145. double thetaMin, thetaMax, thetaStep;
  146. public:
  147. HoughLinesPointSetTest()
  148. {
  149. rhoMin = get<0>(GetParam());
  150. rhoMax = get<1>(GetParam());
  151. rhoStep = (rhoMax - rhoMin) / 360.0f;
  152. thetaMin = get<2>(GetParam());
  153. thetaMax = get<3>(GetParam());
  154. thetaStep = CV_PI / 180.0f;
  155. Rho = 320.00000;
  156. Theta = 1.04719;
  157. }
  158. };
  159. template<typename LinesType, typename LineType>
  160. void BaseHoughLineTest::run_test(int type, const char* xml_name)
  161. {
  162. string filename = cvtest::TS::ptr()->get_data_path() + picture_name;
  163. Mat src = imread(filename, IMREAD_GRAYSCALE);
  164. ASSERT_FALSE(src.empty()) << "Invalid test image: " << filename;
  165. string xml = string(cvtest::TS::ptr()->get_data_path()) + "imgproc/" + xml_name;
  166. Mat dst;
  167. Canny(src, dst, 100, 150, 3);
  168. ASSERT_FALSE(dst.empty()) << "Failed Canny edge detector";
  169. LinesType lines;
  170. if (type == STANDART)
  171. HoughLines(dst, lines, rhoStep, thetaStep, threshold, 0, 0);
  172. else if (type == PROBABILISTIC)
  173. HoughLinesP(dst, lines, rhoStep, thetaStep, threshold, minLineLength, maxGap);
  174. String test_case_name = format("lines_%s_%.0f_%.2f_%d_%d_%d", picture_name.c_str(), rhoStep, thetaStep,
  175. threshold, minLineLength, maxGap);
  176. test_case_name = getTestCaseName(test_case_name);
  177. #ifdef GENERATE_DATA
  178. {
  179. FileStorage fs(xml, FileStorage::READ);
  180. ASSERT_TRUE(!fs.isOpened() || fs[test_case_name].empty());
  181. }
  182. {
  183. FileStorage fs(xml, FileStorage::APPEND);
  184. EXPECT_TRUE(fs.isOpened()) << "Cannot open sanity data file: " << xml;
  185. fs << test_case_name << Mat(lines);
  186. }
  187. #else
  188. FileStorage fs(xml, FileStorage::READ);
  189. FileNode node = fs[test_case_name];
  190. ASSERT_FALSE(node.empty()) << "Missing test data: " << test_case_name << std::endl << "XML: " << xml;
  191. Mat exp_lines_;
  192. read(fs[test_case_name], exp_lines_, Mat());
  193. fs.release();
  194. LinesType exp_lines;
  195. exp_lines_.copyTo(exp_lines);
  196. int count = -1;
  197. if (type == STANDART)
  198. count = countMatIntersection<LineType>(Mat(exp_lines), Mat(lines), (float) thetaStep + FLT_EPSILON, (float) rhoStep + FLT_EPSILON);
  199. else if (type == PROBABILISTIC)
  200. count = countMatIntersection<LineType>(Mat(exp_lines), Mat(lines), 1e-4f, 0.f);
  201. #if defined HAVE_IPP && IPP_VERSION_X100 >= 810 && !IPP_DISABLE_HOUGH
  202. EXPECT_LE(std::abs((double)count - Mat(exp_lines).total()), Mat(exp_lines).total() * 0.25)
  203. << "count=" << count << " expected=" << Mat(exp_lines).total();
  204. #else
  205. EXPECT_EQ(count, (int)Mat(exp_lines).total());
  206. #endif
  207. #endif // GENERATE_DATA
  208. }
  209. void HoughLinesPointSetTest::run_test(void)
  210. {
  211. Mat lines_f, lines_i;
  212. vector<Point2f> pointf;
  213. vector<Point2i> pointi;
  214. vector<Vec3d> line_polar_f, line_polar_i;
  215. const float Points[20][2] = {
  216. { 0.0f, 369.0f }, { 10.0f, 364.0f }, { 20.0f, 358.0f }, { 30.0f, 352.0f },
  217. { 40.0f, 346.0f }, { 50.0f, 341.0f }, { 60.0f, 335.0f }, { 70.0f, 329.0f },
  218. { 80.0f, 323.0f }, { 90.0f, 318.0f }, { 100.0f, 312.0f }, { 110.0f, 306.0f },
  219. { 120.0f, 300.0f }, { 130.0f, 295.0f }, { 140.0f, 289.0f }, { 150.0f, 284.0f },
  220. { 160.0f, 277.0f }, { 170.0f, 271.0f }, { 180.0f, 266.0f }, { 190.0f, 260.0f }
  221. };
  222. // Float
  223. for (int i = 0; i < 20; i++)
  224. {
  225. pointf.push_back(Point2f(Points[i][0],Points[i][1]));
  226. }
  227. HoughLinesPointSet(pointf, lines_f, 20, 1,
  228. rhoMin, rhoMax, rhoStep,
  229. thetaMin, thetaMax, thetaStep);
  230. lines_f.copyTo( line_polar_f );
  231. // Integer
  232. for( int i = 0; i < 20; i++ )
  233. {
  234. pointi.push_back( Point2i( (int)Points[i][0], (int)Points[i][1] ) );
  235. }
  236. HoughLinesPointSet( pointi, lines_i, 20, 1,
  237. rhoMin, rhoMax, rhoStep,
  238. thetaMin, thetaMax, thetaStep );
  239. lines_i.copyTo( line_polar_i );
  240. EXPECT_EQ((int)(line_polar_f.at(0).val[1] * 100000.0f), (int)(Rho * 100000.0f));
  241. EXPECT_EQ((int)(line_polar_f.at(0).val[2] * 100000.0f), (int)(Theta * 100000.0f));
  242. EXPECT_EQ((int)(line_polar_i.at(0).val[1] * 100000.0f), (int)(Rho * 100000.0f));
  243. EXPECT_EQ((int)(line_polar_i.at(0).val[2] * 100000.0f), (int)(Theta * 100000.0f));
  244. }
  245. TEST_P(StandartHoughLinesTest, regression)
  246. {
  247. run_test<Mat, Vec2f>(STANDART, "HoughLines.xml");
  248. }
  249. TEST_P(ProbabilisticHoughLinesTest, regression)
  250. {
  251. run_test<Mat, Vec4i>(PROBABILISTIC, "HoughLinesP.xml");
  252. }
  253. TEST_P(StandartHoughLinesTest, regression_Vec2f)
  254. {
  255. run_test<std::vector<Vec2f>, Vec2f>(STANDART, "HoughLines2f.xml");
  256. }
  257. TEST_P(StandartHoughLinesTest, regression_Vec3f)
  258. {
  259. run_test<std::vector<Vec3f>, Vec3f>(STANDART, "HoughLines3f.xml");
  260. }
  261. TEST_P(HoughLinesPointSetTest, regression)
  262. {
  263. run_test();
  264. }
  265. TEST(HoughLinesPointSet, regression_21029)
  266. {
  267. std::vector<Point2f> points;
  268. points.push_back(Point2f(100, 100));
  269. points.push_back(Point2f(1000, 1000));
  270. points.push_back(Point2f(10000, 10000));
  271. points.push_back(Point2f(100000, 100000));
  272. double rhoMin = 0;
  273. double rhoMax = 10;
  274. double rhoStep = 0.1;
  275. double thetaMin = 85 * CV_PI / 180.0;
  276. double thetaMax = 95 * CV_PI / 180.0;
  277. double thetaStep = 1 * CV_PI / 180.0;
  278. int lines_max = 5;
  279. int threshold = 100;
  280. Mat lines;
  281. HoughLinesPointSet(points, lines,
  282. lines_max, threshold,
  283. rhoMin, rhoMax, rhoStep,
  284. thetaMin, thetaMax, thetaStep
  285. );
  286. EXPECT_TRUE(lines.empty());
  287. }
  288. INSTANTIATE_TEST_CASE_P( ImgProc, StandartHoughLinesTest, testing::Combine(testing::Values( "shared/pic5.png", "../stitching/a1.png" ),
  289. testing::Values( 1, 10 ),
  290. testing::Values( 0.05, 0.1 ),
  291. testing::Values( 80, 150 )
  292. ));
  293. INSTANTIATE_TEST_CASE_P( ImgProc, ProbabilisticHoughLinesTest, testing::Combine(testing::Values( "shared/pic5.png", "shared/pic1.png" ),
  294. testing::Values( 5, 10 ),
  295. testing::Values( 0.05, 0.1 ),
  296. testing::Values( 75, 150 ),
  297. testing::Values( 0, 10 ),
  298. testing::Values( 0, 4 )
  299. ));
  300. INSTANTIATE_TEST_CASE_P( Imgproc, HoughLinesPointSetTest, testing::Combine(testing::Values( 0.0f, 120.0f ),
  301. testing::Values( 360.0f, 480.0f ),
  302. testing::Values( 0.0f, (CV_PI / 18.0f) ),
  303. testing::Values( (CV_PI / 2.0f), (CV_PI * 5.0f / 12.0f) )
  304. ));
  305. }} // namespace