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