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