fast_hough_transform.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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) 2015, Smart Engines Ltd, all rights reserved.
  14. // Copyright (C) 2015, Institute for Information Transmission Problems of the Russian Academy of Sciences (Kharkevich Institute), all rights reserved.
  15. // Copyright (C) 2015, Dmitry Nikolaev, Simon Karpenko, Michail Aliev, Elena Kuznetsova, 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 <opencv2/imgproc.hpp>
  44. #include <opencv2/highgui.hpp>
  45. #include <opencv2/core/utility.hpp>
  46. #include <opencv2/ximgproc.hpp>
  47. #include <iostream>
  48. #include <iomanip>
  49. #include <cstdio>
  50. #include <ctime>
  51. #include <vector>
  52. using namespace cv;
  53. using namespace cv::ximgproc;
  54. using namespace std;
  55. static void help()
  56. {
  57. cout << "\nThis program demonstrates line finding with the Fast Hough transform.\n"
  58. "Usage:\n"
  59. "./fasthoughtransform\n"
  60. "<image_name>, default is '../../../samples/data/building.jpg'\n"
  61. "<fht_image_depth>, default is " << CV_32S << "\n"
  62. "<fht_angle_range>, default is " << 6 << " (@see cv::AngleRangeOption)\n"
  63. "<fht_operator>, default is " << 2 << " (@see cv::HoughOp)\n"
  64. "<fht_makeskew>, default is " << 1 << "(@see cv::HoughDeskewOption)" << endl;
  65. }
  66. static bool parseArgs(int argc, const char **argv,
  67. Mat &img,
  68. int &houghDepth,
  69. int &houghAngleRange,
  70. int &houghOperator,
  71. int &houghSkew)
  72. {
  73. if (argc > 6)
  74. {
  75. cout << "Too many arguments" << endl;
  76. return false;
  77. }
  78. const char *filename = argc >= 2 ? argv[1]
  79. : "../../../samples/data/building.jpg";
  80. img = imread(filename, 0);
  81. if (img.empty())
  82. {
  83. cout << "Failed to load image from '" << filename << "'" << endl;
  84. return false;
  85. }
  86. houghDepth = argc >= 3 ? atoi(argv[2]) : CV_32S;
  87. houghAngleRange = argc >= 4 ? atoi(argv[3]) : 6;//ARO_315_135
  88. houghOperator = argc >= 5 ? atoi(argv[4]) : 2;//FHT_ADD
  89. houghSkew = argc >= 6 ? atoi(argv[5]) : 1;//HDO_DESKEW
  90. return true;
  91. }
  92. static bool getEdges(const Mat &src, Mat &dst)
  93. {
  94. Mat ucharSingleSrc;
  95. src.convertTo(ucharSingleSrc, CV_8UC1);
  96. Canny(ucharSingleSrc, dst, 50, 200, 3);
  97. return true;
  98. }
  99. static bool fht(const Mat &src, Mat &dst,
  100. int dstDepth, int angleRange, int op, int skew)
  101. {
  102. clock_t clocks = clock();
  103. FastHoughTransform(src, dst, dstDepth, angleRange, op, skew);
  104. clocks = clock() - clocks;
  105. double secs = (double)clocks / CLOCKS_PER_SEC;
  106. cout << std::setprecision(2) << "FastHoughTransform finished in " << secs
  107. << " seconds" << endl;
  108. return true;
  109. }
  110. template<typename T>
  111. bool rel(pair<T, Point> const &a, pair<T, Point> const &b)
  112. {
  113. return a.first > b.first;
  114. }
  115. template<typename T>
  116. bool incIfGreater(const T& a, const T& b, int *value)
  117. {
  118. if (!value || a < b)
  119. return false;
  120. if (a > b)
  121. ++(*value);
  122. return true;
  123. }
  124. static const int MAX_LEN = 10000;
  125. template<typename T>
  126. bool getLocalExtr(vector<Vec4i> &lines,
  127. const Mat &src,
  128. const Mat &fht,
  129. float minWeight,
  130. int maxCount)
  131. {
  132. vector<pair<T, Point> > weightedPoints;
  133. for (int y = 0; y < fht.rows; ++y)
  134. {
  135. if (weightedPoints.size() > MAX_LEN)
  136. break;
  137. T const *pLine = (T *)fht.ptr(max(y - 1, 0));
  138. T const *cLine = (T *)fht.ptr(y);
  139. T const *nLine = (T *)fht.ptr(min(y + 1, fht.rows - 1));
  140. for (int x = 0; x < fht.cols; ++x)
  141. {
  142. if (weightedPoints.size() > MAX_LEN)
  143. break;
  144. T const value = cLine[x];
  145. if (value >= minWeight)
  146. {
  147. int isLocalMax = 0;
  148. for (int xx = max(x - 1, 0);
  149. xx <= min(x + 1, fht.cols - 1);
  150. ++xx)
  151. {
  152. if (!incIfGreater(value, pLine[xx], &isLocalMax) ||
  153. !incIfGreater(value, cLine[xx], &isLocalMax) ||
  154. !incIfGreater(value, nLine[xx], &isLocalMax))
  155. {
  156. isLocalMax = 0;
  157. break;
  158. }
  159. }
  160. if (isLocalMax > 0)
  161. weightedPoints.push_back(make_pair(value, Point(x, y)));
  162. }
  163. }
  164. }
  165. if (weightedPoints.empty())
  166. return true;
  167. sort(weightedPoints.begin(), weightedPoints.end(), &rel<T>);
  168. weightedPoints.resize(min(static_cast<int>(weightedPoints.size()),
  169. maxCount));
  170. for (size_t i = 0; i < weightedPoints.size(); ++i)
  171. {
  172. lines.push_back(HoughPoint2Line(weightedPoints[i].second, src));
  173. }
  174. return true;
  175. }
  176. static bool getLocalExtr(vector<Vec4i> &lines,
  177. const Mat &src,
  178. const Mat &fht,
  179. float minWeight,
  180. int maxCount)
  181. {
  182. int const depth = CV_MAT_DEPTH(fht.type());
  183. switch (depth)
  184. {
  185. case 0:
  186. return getLocalExtr<uchar>(lines, src, fht, minWeight, maxCount);
  187. case 1:
  188. return getLocalExtr<schar>(lines, src, fht, minWeight, maxCount);
  189. case 2:
  190. return getLocalExtr<ushort>(lines, src, fht, minWeight, maxCount);
  191. case 3:
  192. return getLocalExtr<short>(lines, src, fht, minWeight, maxCount);
  193. case 4:
  194. return getLocalExtr<int>(lines, src, fht, minWeight, maxCount);
  195. case 5:
  196. return getLocalExtr<float>(lines, src, fht, minWeight, maxCount);
  197. case 6:
  198. return getLocalExtr<double>(lines, src, fht, minWeight, maxCount);
  199. default:
  200. return false;
  201. }
  202. }
  203. static void rescale(Mat const &src, Mat &dst,
  204. int const maxHeight=500,
  205. int const maxWidth = 1000)
  206. {
  207. double scale = min(min(static_cast<double>(maxWidth) / src.cols,
  208. static_cast<double>(maxHeight) / src.rows), 1.0);
  209. resize(src, dst, Size(), scale, scale, INTER_LINEAR_EXACT);
  210. }
  211. static void showHumanReadableImg(string const &name, Mat const &img)
  212. {
  213. Mat ucharImg;
  214. img.convertTo(ucharImg, CV_MAKETYPE(CV_8U, img.channels()));
  215. rescale(ucharImg, ucharImg);
  216. imshow(name, ucharImg);
  217. }
  218. static void showFht(Mat const &fht)
  219. {
  220. double minv(0), maxv(0);
  221. minMaxLoc(fht, &minv, &maxv);
  222. Mat ucharFht;
  223. fht.convertTo(ucharFht, CV_MAKETYPE(CV_8U, fht.channels()),
  224. 255.0 / (maxv + minv), minv / (maxv + minv));
  225. rescale(ucharFht, ucharFht);
  226. imshow("fast hough transform", ucharFht);
  227. }
  228. static void showLines(Mat const &src, vector<Vec4i> const &lines)
  229. {
  230. Mat bgrSrc;
  231. cvtColor(src, bgrSrc, COLOR_GRAY2BGR);
  232. for (size_t i = 0; i < lines.size(); ++i)
  233. {
  234. Vec4i const &l = lines[i];
  235. line(bgrSrc, Point(l[0], l[1]), Point(l[2], l[3]),
  236. Scalar(0, 0, 255), 1, LINE_AA);
  237. }
  238. rescale(bgrSrc, bgrSrc);
  239. imshow("lines", bgrSrc);
  240. }
  241. int main(int argc, const char **argv)
  242. {
  243. Mat src;
  244. int depth(0);
  245. int angleRange(0);
  246. int op(0);
  247. int skew(0);
  248. if (!parseArgs(argc, argv, src, depth, angleRange, op, skew))
  249. {
  250. help();
  251. return -1;
  252. }
  253. showHumanReadableImg("src", src);
  254. Mat canny;
  255. if (!getEdges(src, canny))
  256. {
  257. cout << "Failed to select canny edges";
  258. return -2;
  259. }
  260. showHumanReadableImg("canny", canny);
  261. Mat hough;
  262. if (!fht(canny, hough, depth, angleRange, op, skew))
  263. {
  264. cout << "Failed to compute Fast Hough Transform";
  265. return -2;
  266. }
  267. showFht(hough);
  268. vector<Vec4i> lines;
  269. if (!getLocalExtr(lines, canny, hough,
  270. static_cast<float>(255 * 0.3 * min(src.rows, src.cols)),
  271. 50))
  272. {
  273. cout << "Failed to find local maximums on FHT image";
  274. return -2;
  275. }
  276. showLines(canny, lines);
  277. waitKey();
  278. return 0;
  279. }