欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

基于opencv实现车道线检测

程序员文章站 2022-05-22 14:26:04
基于opencv的车道线检测,供大家参考,具体内容如下原理:算法基本思想说明:传统的车道线检测,多数是基于霍夫直线检测,其实这个里面有个很大的误区,霍夫直线拟合容易受到各种噪声干扰,直接运用有时候效果...

基于opencv的车道线检测,供大家参考,具体内容如下

原理:

算法基本思想说明:

传统的车道线检测,多数是基于霍夫直线检测,其实这个里面有个很大的误区,霍夫直线拟合容易受到各种噪声干扰,直接运用有时候效果不好,更多的时候通过霍夫直线检测进行初步的筛选,然后再有针对性的进行直线拟合,根据拟合的直线四个点坐标,绘制出车道线,这种方式可以有效避免霍夫直线拟合不良后果,是一种更加稳定的车道线检测方法,在实际项目中,可以选择两种方法并行,在计算出结果后进行叠加或者对比提取,今天分享的案例主要是绕开了霍夫直线检测,通过对二值图像进行轮廓分析与几何分析,提取到相关的车道线信息、然后进行特定区域的像素扫描,拟合生成直线方程,确定四个点绘制出车道线,对连续的视频来说,如果某一帧无法正常检测,就可以通过缓存来替代绘制,从而实现在视频车道线检测中实时可靠。

原理图:

基于opencv实现车道线检测

代码:

#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;
}

结果图片:

基于opencv实现车道线检测

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

相关标签: opencv 检测