【OpenCV】车道线检测原理与实现

文章目录

    • 车道线检测原理
    • 代码实现

车道线检测原理

采用OpenCV读取视频,进行灰度化处理,然后用canny算子进行边缘检测,分析轮廓,然后进行直线拟合处理,最后对直线添加权重分析,得到最终的车道线检测结果。

代码实现

添加好opencv相关依赖后,写入:

//opencv454学习
#include 
#include 
#include 

using namespace cv;
using namespace std;

/**
**边缘检测+霍夫变换方法
**1、视频读取
**2、二值化
**3、轮廓分析
**4、直线拟合
**5、添加权重
*/

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("test.avi");

	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);	//调用process

		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);

	//canny算子边缘检测
	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]);
		//角度问题:https://blog.csdn.net/weixin_41887615/article/details/91411086

		//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);	//显示fitlines直线拟合后的结果

	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】车道线检测原理与实现_第1张图片

以上。

你可能感兴趣的:(车辆机器人开发,opencv,学习)