Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3 | PointedEar | 1 | /*------------------------------------------------------------------------------------------*\ |
2 | This file contains material supporting chapter 7 of the cookbook: |
||
3 | Computer Vision Programming using the OpenCV Library. |
||
4 | by Robert Laganiere, Packt Publishing, 2011. |
||
5 | |||
6 | This program is free software; permission is hereby granted to use, copy, modify, |
||
7 | and distribute this source code, or portions thereof, for any purpose, without fee, |
||
8 | subject to the restriction that the copyright notice may not be removed |
||
9 | or altered from any source or altered source distribution. |
||
10 | The software is released on an as-is basis and without any warranties of any kind. |
||
11 | In particular, the software is not guaranteed to be fault-tolerant or free from failure. |
||
12 | The author disclaims all warranties with regard to this software, any use, |
||
13 | and any consequent failure, is purely the responsibility of the user. |
||
14 | |||
15 | Copyright (C) 2010-2011 Robert Laganiere, www.laganiere.name |
||
16 | \*------------------------------------------------------------------------------------------*/ |
||
17 | |||
18 | #include <iostream> |
||
19 | #include <vector> |
||
20 | #include <opencv2/core/core.hpp> |
||
21 | #include <opencv2/imgproc/imgproc.hpp> |
||
22 | #include <opencv2/highgui/highgui.hpp> |
||
23 | |||
24 | #include "linefinder.h" |
||
25 | #include "edgedetector.h" |
||
26 | |||
27 | #define PI 3.1415926 |
||
28 | |||
29 | int main() |
||
30 | { |
||
31 | // Read input image |
||
32 | cv::Mat image= cv::imread("../road.jpg",0); |
||
33 | if (!image.data) |
||
34 | return 0; |
||
35 | |||
36 | // Display the image |
||
37 | cv::namedWindow("Original Image"); |
||
38 | cv::imshow("Original Image",image); |
||
39 | |||
40 | // Compute Sobel |
||
41 | EdgeDetector ed; |
||
42 | ed.computeSobel(image); |
||
43 | |||
44 | // Display the Sobel orientation |
||
45 | cv::namedWindow("Sobel (orientation)"); |
||
46 | cv::imshow("Sobel (orientation)",ed.getSobelOrientationImage()); |
||
47 | cv::imwrite("ori.bmp",ed.getSobelOrientationImage()); |
||
48 | |||
49 | // Display the Sobel low threshold |
||
50 | cv::namedWindow("Sobel (low threshold)"); |
||
51 | cv::imshow("Sobel (low threshold)",ed.getBinaryMap(125)); |
||
52 | |||
53 | // Display the Sobel high threshold |
||
54 | cv::namedWindow("Sobel (high threshold)"); |
||
55 | cv::imshow("Sobel (high threshold)",ed.getBinaryMap(350)); |
||
56 | |||
57 | // Apply Canny algorithm |
||
58 | cv::Mat contours; |
||
59 | cv::Canny(image,contours,125,350); |
||
60 | cv::Mat contoursInv; |
||
61 | cv::threshold(contours,contoursInv,128,255,cv::THRESH_BINARY_INV); |
||
62 | |||
63 | // Display the image of contours |
||
64 | cv::namedWindow("Canny Contours"); |
||
65 | cv::imshow("Canny Contours",contoursInv); |
||
66 | |||
67 | // Create a test image |
||
68 | cv::Mat test(200,200,CV_8U,cv::Scalar(0)); |
||
69 | cv::line(test,cv::Point(100,0),cv::Point(200,200),cv::Scalar(255)); |
||
70 | cv::line(test,cv::Point(0,50),cv::Point(200,200),cv::Scalar(255)); |
||
71 | cv::line(test,cv::Point(0,200),cv::Point(200,0),cv::Scalar(255)); |
||
72 | cv::line(test,cv::Point(200,0),cv::Point(0,200),cv::Scalar(255)); |
||
73 | cv::line(test,cv::Point(100,0),cv::Point(100,200),cv::Scalar(255)); |
||
74 | cv::line(test,cv::Point(0,100),cv::Point(200,100),cv::Scalar(255)); |
||
75 | |||
76 | // Display the test image |
||
77 | cv::namedWindow("Test Image"); |
||
78 | cv::imshow("Test Image",test); |
||
79 | cv::imwrite("test.bmp",test); |
||
80 | |||
81 | // Hough tranform for line detection |
||
82 | std::vector<cv::Vec2f> lines; |
||
83 | cv::HoughLines(contours,lines,1,PI/180,60); |
||
84 | |||
85 | // Draw the lines |
||
86 | cv::Mat result(contours.rows,contours.cols,CV_8U,cv::Scalar(255)); |
||
87 | image.copyTo(result); |
||
88 | |||
89 | std::cout << "Lines detected: " << lines.size() << std::endl; |
||
90 | |||
91 | std::vector<cv::Vec2f>::const_iterator it= lines.begin(); |
||
92 | while (it!=lines.end()) { |
||
93 | |||
94 | float rho= (*it)[0]; // first element is distance rho |
||
95 | float theta= (*it)[1]; // second element is angle theta |
||
96 | |||
97 | if (theta < PI/4. || theta > 3.*PI/4.) { // ~vertical line |
||
98 | |||
99 | // point of intersection of the line with first row |
||
100 | cv::Point pt1(rho/cos(theta),0); |
||
101 | // point of intersection of the line with last row |
||
102 | cv::Point pt2((rho-result.rows*sin(theta))/cos(theta),result.rows); |
||
103 | // draw a white line |
||
104 | cv::line( result, pt1, pt2, cv::Scalar(255), 1); |
||
105 | |||
106 | } else { // ~horizontal line |
||
107 | |||
108 | // point of intersection of the line with first column |
||
109 | cv::Point pt1(0,rho/sin(theta)); |
||
110 | // point of intersection of the line with last column |
||
111 | cv::Point pt2(result.cols,(rho-result.cols*cos(theta))/sin(theta)); |
||
112 | // draw a white line |
||
113 | cv::line( result, pt1, pt2, cv::Scalar(255), 1); |
||
114 | } |
||
115 | |||
116 | std::cout << "line: (" << rho << "," << theta << ")\n"; |
||
117 | |||
118 | ++it; |
||
119 | } |
||
120 | |||
121 | // Display the detected line image |
||
122 | cv::namedWindow("Detected Lines with Hough"); |
||
123 | cv::imshow("Detected Lines with Hough",result); |
||
124 | |||
125 | // Create LineFinder instance |
||
126 | LineFinder ld; |
||
127 | |||
128 | // Set probabilistic Hough parameters |
||
129 | ld.setLineLengthAndGap(100,20); |
||
130 | ld.setMinVote(80); |
||
131 | |||
132 | // Detect lines |
||
133 | std::vector<cv::Vec4i> li= ld.findLines(contours); |
||
134 | ld.drawDetectedLines(image); |
||
135 | cv::namedWindow("Detected Lines with HoughP"); |
||
136 | cv::imshow("Detected Lines with HoughP",image); |
||
137 | |||
138 | std::vector<cv::Vec4i>::const_iterator it2= li.begin(); |
||
139 | while (it2!=li.end()) { |
||
140 | |||
141 | std::cout << "(" << (*it2)[0] << ","<< (*it2)[1]<< ")-(" |
||
142 | << (*it2)[2]<< "," << (*it2)[3] << ")" <<std::endl; |
||
143 | |||
144 | ++it2; |
||
145 | } |
||
146 | |||
147 | // Display one line |
||
148 | image= cv::imread("../road.jpg",0); |
||
149 | int n=0; |
||
150 | cv::line(image, cv::Point(li[n][0],li[n][1]),cv::Point(li[n][2],li[n][3]),cv::Scalar(255),5); |
||
151 | cv::namedWindow("One line of the Image"); |
||
152 | cv::imshow("One line of the Image",image); |
||
153 | |||
154 | // Extract the contour pixels of the first detected line |
||
155 | cv::Mat oneline(image.size(),CV_8U,cv::Scalar(0)); |
||
156 | cv::line(oneline, cv::Point(li[n][0],li[n][1]),cv::Point(li[n][2],li[n][3]),cv::Scalar(255),5); |
||
157 | cv::bitwise_and(contours,oneline,oneline); |
||
158 | cv::Mat onelineInv; |
||
159 | cv::threshold(oneline,onelineInv,128,255,cv::THRESH_BINARY_INV); |
||
160 | cv::namedWindow("One line"); |
||
161 | cv::imshow("One line",onelineInv); |
||
162 | |||
163 | std::vector<cv::Point> points; |
||
164 | |||
165 | // Iterate over the pixels to obtain all point positions |
||
166 | for( int y = 0; y < oneline.rows; y++ ) { |
||
167 | |||
168 | uchar* rowPtr = oneline.ptr<uchar>(y); |
||
169 | |||
170 | for( int x = 0; x < oneline.cols; x++ ) { |
||
171 | |||
172 | // if on a contour |
||
173 | if (rowPtr[x]) { |
||
174 | |||
175 | points.push_back(cv::Point(x,y)); |
||
176 | } |
||
177 | } |
||
178 | } |
||
179 | |||
180 | // find the best fitting line |
||
181 | cv::Vec4f line; |
||
182 | cv::fitLine(cv::Mat(points),line,CV_DIST_L2,0,0.01,0.01); |
||
183 | |||
184 | std::cout << "line: (" << line[0] << "," << line[1] << ")(" << line[2] << "," << line[3] << ")\n"; |
||
185 | |||
186 | int x0= line[2]; |
||
187 | int y0= line[3]; |
||
188 | int x1= x0-200*line[0]; |
||
189 | int y1= y0-200*line[1]; |
||
190 | image= cv::imread("../road.jpg",0); |
||
191 | cv::line(image,cv::Point(x0,y0),cv::Point(x1,y1),cv::Scalar(0),3); |
||
192 | cv::namedWindow("Estimated line"); |
||
193 | cv::imshow("Estimated line",image); |
||
194 | |||
195 | // eliminate inconsistent lines |
||
196 | ld.removeLinesOfInconsistentOrientations(ed.getOrientation(),0.4,0.1); |
||
197 | |||
198 | // Display the detected line image |
||
199 | image= cv::imread("../road.jpg",0); |
||
200 | ld.drawDetectedLines(image); |
||
201 | cv::namedWindow("Detected Lines (2)"); |
||
202 | cv::imshow("Detected Lines (2)",image); |
||
203 | |||
204 | // Create a Hough accumulator |
||
205 | cv::Mat acc(200,180,CV_8U,cv::Scalar(0)); |
||
206 | |||
207 | // Choose a point |
||
208 | int x=50, y=30; |
||
209 | |||
210 | // loop over all angles |
||
211 | for (int i=0; i<180; i++) { |
||
212 | |||
213 | double theta= i*PI/180.; |
||
214 | |||
215 | // find corresponding rho value |
||
216 | double rho= x*cos(theta)+y*sin(theta); |
||
217 | int j= static_cast<int>(rho+100.5); |
||
218 | |||
219 | std::cout << i << "," << j << std::endl; |
||
220 | |||
221 | // increment accumulator |
||
222 | acc.at<uchar>(j,i)++; |
||
223 | } |
||
224 | |||
225 | cv::imwrite("hough1.bmp",acc*100); |
||
226 | |||
227 | // Choose a second point |
||
228 | x=30, y=10; |
||
229 | |||
230 | // loop over all angles |
||
231 | for (int i=0; i<180; i++) { |
||
232 | |||
233 | double theta= i*PI/180.; |
||
234 | double rho= x*cos(theta)+y*sin(theta); |
||
235 | int j= static_cast<int>(rho+100.5); |
||
236 | |||
237 | acc.at<uchar>(j,i)++; |
||
238 | } |
||
239 | |||
240 | cv::namedWindow("Hough Accumulator"); |
||
241 | cv::imshow("Hough Accumulator",acc*100); |
||
242 | cv::imwrite("hough2.bmp",acc*100); |
||
243 | |||
244 | // Detect circles |
||
245 | image= cv::imread("../chariot.jpg",0); |
||
246 | cv::GaussianBlur(image,image,cv::Size(5,5),1.5); |
||
247 | std::vector<cv::Vec3f> circles; |
||
248 | cv::HoughCircles(image, circles, CV_HOUGH_GRADIENT, |
||
249 | 2, // accumulator resolution (size of the image / 2) |
||
250 | 50, // minimum distance between two circles |
||
251 | 200, // Canny high threshold |
||
252 | 100, // minimum number of votes |
||
253 | 25, 100); // min and max radius |
||
254 | |||
255 | std::cout << "Circles: " << circles.size() << std::endl; |
||
256 | |||
257 | // Draw the circles |
||
258 | image= cv::imread("../chariot.jpg",0); |
||
259 | std::vector<cv::Vec3f>::const_iterator itc= circles.begin(); |
||
260 | |||
261 | while (itc!=circles.end()) { |
||
262 | |||
263 | cv::circle(image, |
||
264 | cv::Point((*itc)[0], (*itc)[1]), // circle centre |
||
265 | (*itc)[2], // circle radius |
||
266 | cv::Scalar(255), // color |
||
267 | 2); // thickness |
||
268 | |||
269 | ++itc; |
||
270 | } |
||
271 | |||
272 | cv::namedWindow("Detected Circles"); |
||
273 | cv::imshow("Detected Circles",image); |
||
274 | |||
275 | cv::waitKey(); |
||
276 | return 0; |
||
277 | } |