基于opencv的车道线检测,供大家参考,具体内容如下
原理:
算法基本思想说明:
传统的车道线检测,多数是基于霍夫直线检测,其实这个里面有个很大的误区,霍夫直线拟合容易受到各种噪声干扰,直接运用有时候效果不好,更多的时候通过霍夫直线检测进行初步的筛选,然后再有针对性的进行直线拟合,根据拟合的直线四个点坐标,绘制出车道线,这种方式可以有效避免霍夫直线拟合不良后果,是一种更加稳定的车道线检测方法,在实际项目中,可以选择两种方法并行,在计算出结果后进行叠加或者对比提取,今天分享的案例主要是绕开了霍夫直线检测,通过对二值图像进行轮廓分析与几何分析,提取到相关的车道线信息、然后进行特定区域的像素扫描,拟合生成直线方程,确定四个点绘制出车道线,对连续的视频来说,如果某一帧无法正常检测,就可以通过缓存来替代绘制,从而实现在视频车道线检测中实时可靠。
原理图:
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
#include <opencv2/opencv.hpp> #include <iostream> #include <cmath> using namespace cv; using namespace std; /** **1、读取视频 **2、二值化 **3、轮廓发现 **4、轮廓分析、面积就算,角度分析 **5、直线拟合 **6、画出直线 ** */ Point left_line[2]; Point right_line[2]; void process(Mat &frame, Point *left_line, Point *right_line); Mat fitLines(Mat &image, Point *left_line, Point *right_line); int main( int argc, char ** argv) { //读取视频 VideoCapture capture( "E:/opencv/road_line.mp4" ); int height = capture.get(CAP_PROP_FRAME_HEIGHT); int width = capture.get(CAP_PROP_FRAME_WIDTH); int count = capture.get(CAP_PROP_FRAME_COUNT); int fps = capture.get(CAP_PROP_FPS); //初始化 left_line[0] = Point(0,0); left_line[1] = Point(0, 0); right_line[0] = Point(0, 0); right_line[1] = Point(0, 0); cout << height<< " " << width<< " " <<count<< " " <<fps << endl; //循环读取视频 Mat frame; while ( true ) { int ret = capture.read(frame); if (!ret) { break ; } imshow( "input" , frame); process(frame, left_line, right_line); char c = waitKey(5); if (c == 27) { break ; } } } void process(Mat &frame, Point *left_line, Point *right_line ){ Mat gray,binary; /**灰度化*/ cvtColor(frame, gray, COLOR_BGR2GRAY); //threshold(gray, binary, ); //边缘检测 Canny(gray, binary, 150, 300); //imshow("Canny", binary); for ( size_t i = 0; i < (gray.rows/2+40); i++) { for ( size_t j = 0; j < gray.cols; j++) { binary.at<uchar>(i, j) = 0; } } imshow( "binary" , binary); //寻找轮廓 vector<vector<Point>> contours; findContours(binary, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); Mat out_image = Mat::zeros(gray.size(), gray.type()); for ( int i = 0; i < contours.size(); i++) { //计算面积与周长 double length = arcLength(contours[i], true ); double area = contourArea(contours[i]); //cout << "周长 length:" << length << endl; //cout << "面积 area:" << area << endl; //外部矩形边界 Rect rect = boundingRect(contours[i]); int h = gray.rows - 50; //轮廓分析: if (length < 5.0 || area < 10.0) { continue ; } if (rect.y > h) { continue ; } //最小包围矩形 RotatedRect rrt = minAreaRect(contours[i]); //cout << "最小包围矩形 angle:" << rrt.angle << endl; double angle = abs (rrt.angle); //angle < 50.0 || angle>89.0 if (angle < 20.0 || angle>84.0) { continue ; } if (contours[i].size() > 5) { //用椭圆拟合 RotatedRect errt = fitEllipse(contours[i]); //cout << "用椭圆拟合err.angle:" << errt.angle << endl; if ((errt.angle<5.0) || (errt.angle>160.0)) { if (80.0 < errt.angle && errt.angle < 100.0) { continue ; } } } //cout << "开始绘制:" << endl; drawContours(out_image, contours, i, Scalar(255), 2, 8); imshow( "out_image" , out_image); } Mat result = fitLines(out_image, left_line, right_line); imshow( "result" , result); Mat dst; addWeighted(frame, 0.8, result, 0.5,0, dst); imshow( "lane-lines" , dst); } //直线拟合 Mat fitLines(Mat &image, Point *left_line, Point *right_line) { int height = image.rows; int width = image.cols; Mat out = Mat::zeros(image.size(), CV_8UC3); int cx = width / 2; int cy = height / 2; vector<Point> left_pts; vector<Point> right_pts; Vec4f left; for ( int i = 100; i < (cx-10); i++) { for ( int j = cy; j < height; j++) { int pv = image.at<uchar>(j, i); if (pv == 255) { left_pts.push_back(Point(i, j)); } } } for ( int i = cx; i < (width-20); i++) { for ( int j = cy; j < height; j++) { int pv = image.at<uchar>(j, i); if (pv == 255) { right_pts.push_back(Point(i, j)); } } } if (left_pts.size() > 2) { fitLine(left_pts, left, DIST_L1, 0, 0.01, 0.01); double k1 = left[1] / left[0]; double step = left[3] - k1 * left[2]; int x1 = int ((height - step) / k1); int y2 = int ((cx - 25)*k1 + step); Point left_spot_1 = Point(x1, height); Point left_spot_end = Point((cx - 25), y2); line(out, left_spot_1, left_spot_end, Scalar(0, 0, 255), 8, 8, 0); left_line[0] = left_spot_1; left_line[1] = left_spot_end; } else { line(out, left_line[0], left_line[1], Scalar(0, 0, 255), 8, 8, 0); } if (right_pts.size()>2) { Point spot_1 = right_pts[0]; Point spot_end = right_pts[right_pts.size()-1]; int x1 = spot_1.x; int y1 = spot_1.y; int x2 = spot_end.x; int y2 = spot_end.y; line(out, spot_1, spot_end, Scalar(0, 0, 255), 8, 8, 0); right_line[0] = spot_1; right_line[1] = spot_end; } else { line(out, right_line[0], right_line[1], Scalar(0, 0, 255), 8, 8, 0); } return out; } |
结果图片:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/weixin_41887615/article/details/91450495