C++ opencv实现车道线识别

本文实例为大家分享了C++ opencv实现车道线识别的具体代码,供大家参考,具体内容如下

先上图

1、

2、

(一)目前国内外广泛使用的车道线检测方法主要分为两大类:

(1) 基于道路特征的车道线检测;

(2) 基于道路模型的车道线检测。

基于道路特征的车道线检测作为主流检测方法之一,主要是利用车道线与道路环境的物理特征差异进行后续图像的分割与处理,从而突出车道线特征,以实现车道线的检测。该方法复杂度较低,实时性较高,但容易受到道路环境干扰。
基于道路模型的车道线检测主要是基于不同的二维或三维道路图像模型(如直线型、抛物线型、样条曲线型、组合模型等) ,采用相应方法确定各模型参数,然后进行车道线拟合。该方法对特定道路的检测具有较高的准确度,但局限性强、运算量大、实时性较差。

(二)在这我介绍一种车道线检测方法,效果在高速上还可以,对于破损道路,光照变化太大等道路效果不佳,后续继续改进(直方图均衡以及多特征融合等等),这里有个基础版本的接口,大致步骤如下

(1)图像灰度化
(2)图像高斯滤波
(3)边缘检测
(4)获取掩膜,获取感兴趣区域
(5)霍夫变换检测直线
(6)将检测到的车道线分类,设置阈值,以图像中线分为左右两边的车道线,存入一个vector
(7)回归两条直线,即左右分别两个点,且求出斜率方程
(8)确定车道线的转弯与否

下面我贴出代码

(1)头文件(LaneDetector.h)

class LaneDetector
{
private:
 double img_size;
 double img_center;
 bool left_flag = false; // Tells us if there's left boundary of lane detected
 bool right_flag = false; // Tells us if there's right boundary of lane detected
 cv::Point right_b; // Members of both line equations of the lane boundaries:
 double right_m; // y = m*x + b
 cv::Point left_b; //
 double left_m; //

public:
 cv::Mat deNoise(cv::Mat inputImage); // Apply Gaussian blurring to the input Image
 cv::Mat edgeDetector(cv::Mat img_noise); // Filter the image to obtain only edges
 cv::Mat mask(cv::Mat img_edges); // Mask the edges image to only care about ROI
 std::vector<cv::Vec4i> houghLines(cv::Mat img_mask); // Detect Hough lines in masked edges image
 std::vector<std::vector<cv::Vec4i> > lineSeparation(std::vector<cv::Vec4i> lines, cv::Mat img_edges); // Sprt detected lines by their slope into right and left lines
 std::vector<cv::Point> regression(std::vector<std::vector<cv::Vec4i> > left_right_lines, cv::Mat inputImage); // Get only one line for each side of the lane
 std::string predictTurn(); // Determine if the lane is turning or not by calculating the position of the vanishing point
 int plotLane(cv::Mat inputImage, std::vector<cv::Point> lane, std::string turn); // Plot the resultant lane and turn prediction in the frame.
};

源文件LaneDetector.cpp

*@file LaneDetector.cpp
*@author Miguel Maestre Trueba
*@brief Definition of all the function that form part of the LaneDetector class.
*@brief The class will take RGB images as inputs and will output the same RGB image but
*@brief with the plot of the detected lanes and the turn prediction.
*/
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include "LaneDetector.h"

// IMAGE BLURRING
/**
*@brief Apply gaussian filter to the input image to denoise it
*@param inputImage is the frame of a video in which the
*@param lane is going to be detected
*@return Blurred and denoised image
*/
cv::Mat LaneDetector::deNoise(cv::Mat inputImage) {
 cv::Mat output;

 cv::GaussianBlur(inputImage, output, cv::Size(3, 3), 0, 0);

 return output;
}

// EDGE DETECTION
/**
*@brief Detect all the edges in the blurred frame by filtering the image
*@param img_noise is the previously blurred frame
*@return Binary image with only the edges represented in white
*/
cv::Mat LaneDetector::edgeDetector(cv::Mat img_noise) {
 cv::Mat output;
 cv::Mat kernel;
 cv::Point anchor;

 // Convert image from RGB to gray
 cv::cvtColor(img_noise, output, cv::COLOR_RGB2GRAY);
 // Binarize gray image
 cv::threshold(output, output, 140, 255, cv::THRESH_BINARY);

 // Create the kernel [-1 0 1]
 // This kernel is based on the one found in the
 // Lane Departure Warning System by Mathworks
 anchor = cv::Point(-1, -1);
 kernel = cv::Mat(1, 3, CV_32F);
 kernel.at<float>(0, 0) = -1;
 kernel.at<float>(0, 1) = 0;
 kernel.at<float>(0, 2) = 1;

 // Filter the binary image to obtain the edges
 cv::filter2D(output, output, -1, kernel, anchor, 0, cv::BORDER_DEFAULT);
 cv::imshow("output", output);
 return output;
}

// MASK THE EDGE IMAGE
/**
*@brief Mask the image so that only the edges that form part of the lane are detected
*@param img_edges is the edges image from the previous function
*@return Binary image with only the desired edges being represented
*/
cv::Mat LaneDetector::mask(cv::Mat img_edges) {
 cv::Mat output;
 cv::Mat mask = cv::Mat::zeros(img_edges.size(), img_edges.type());
 cv::Point pts[4] = {
 cv::Point(210, 720),
 cv::Point(550, 450),
 cv::Point(717, 450),
 cv::Point(1280, 720)
 };

 // Create a binary polygon mask
 cv::fillConvexPoly(mask, pts, 4, cv::Scalar(255, 0, 0));
 // Multiply the edges image and the mask to get the output
 cv::bitwise_and(img_edges, mask, output);

 return output;
}

// HOUGH LINES
/**
*@brief Obtain all the line segments in the masked images which are going to be part of the lane boundaries
*@param img_mask is the masked binary image from the previous function
*@return Vector that contains all the detected lines in the image
*/
std::vector<cv::Vec4i> LaneDetector::houghLines(cv::Mat img_mask) {
 std::vector<cv::Vec4i> line;

 // rho and theta are selected by trial and error
 HoughLinesP(img_mask, line, 1, CV_PI / 180, 20, 20, 30);

 return line;
}

// SORT RIGHT AND LEFT LINES
/**
*@brief Sort all the detected Hough lines by slope.
*@brief The lines are classified into right or left depending
*@brief on the sign of their slope and their approximate location
*@param lines is the vector that contains all the detected lines
*@param img_edges is used for determining the image center
*@return The output is a vector(2) that contains all the classified lines
*/
std::vector<std::vector<cv::Vec4i> > LaneDetector::lineSeparation(std::vector<cv::Vec4i> lines, cv::Mat img_edges) {
 std::vector<std::vector<cv::Vec4i> > output(2);
 size_t j = 0;
 cv::Point ini;
 cv::Point fini;
 double slope_thresh = 0.3;
 std::vector<double> slopes;
 std::vector<cv::Vec4i> selected_lines;
 std::vector<cv::Vec4i> right_lines, left_lines;

 // Calculate the slope of all the detected lines
 for (auto i : lines) {
 ini = cv::Point(i[0], i[1]);
 fini = cv::Point(i[2], i[3]);

 // Basic algebra: slope = (y1 - y0)/(x1 - x0)
 double slope = (static_cast<double>(fini.y) - static_cast<double>(ini.y)) / (static_cast<double>(fini.x) - static_cast<double>(ini.x) + 0.00001);

 // If the slope is too horizontal, discard the line
 // If not, save them and their respective slope
 if (std::abs(slope) > slope_thresh) {
 slopes.push_back(slope);
 selected_lines.push_back(i);
 }
 }

 // Split the lines into right and left lines
 img_center = static_cast<double>((img_edges.cols / 2));
 while (j < selected_lines.size()) {
 ini = cv::Point(selected_lines[j][0], selected_lines[j][1]);
 fini = cv::Point(selected_lines[j][2], selected_lines[j][3]);

 // Condition to classify line as left side or right side
 if (slopes[j] > 0 && fini.x > img_center && ini.x > img_center) {
 right_lines.push_back(selected_lines[j]);
 right_flag = true;
 }
 else if (slopes[j] < 0 && fini.x < img_center && ini.x < img_center) {
 left_lines.push_back(selected_lines[j]);
 left_flag = true;
 }
 j++;
 }

 output[0] = right_lines;
 output[1] = left_lines;

 return output;
}

// REGRESSION FOR LEFT AND RIGHT LINES
/**
*@brief Regression takes all the classified line segments initial and final points and fits a new lines out of them using the method of least squares.
*@brief This is done for both sides, left and right.
*@param left_right_lines is the output of the lineSeparation function
*@param inputImage is used to select where do the lines will end
*@return output contains the initial and final points of both lane boundary lines
*/
std::vector<cv::Point> LaneDetector::regression(std::vector<std::vector<cv::Vec4i> > left_right_lines, cv::Mat inputImage) {
 std::vector<cv::Point> output(4);
 cv::Point ini;
 cv::Point fini;
 cv::Point ini2;
 cv::Point fini2;
 cv::Vec4d right_line;
 cv::Vec4d left_line;
 std::vector<cv::Point> right_pts;
 std::vector<cv::Point> left_pts;

 // If right lines are being detected, fit a line using all the init and final points of the lines
 if (right_flag == true) {
 for (auto i : left_right_lines[0]) {
 ini = cv::Point(i[0], i[1]);
 fini = cv::Point(i[2], i[3]);

 right_pts.push_back(ini);
 right_pts.push_back(fini);
 }

 if (right_pts.size() > 0) {
 // The right line is formed here
 cv::fitLine(right_pts, right_line, CV_DIST_L2, 0, 0.01, 0.01);
 right_m = right_line[1] / right_line[0];
 right_b = cv::Point(right_line[2], right_line[3]);
 }
 }

 // If left lines are being detected, fit a line using all the init and final points of the lines
 if (left_flag == true) {
 for (auto j : left_right_lines[1]) {
 ini2 = cv::Point(j[0], j[1]);
 fini2 = cv::Point(j[2], j[3]);

 left_pts.push_back(ini2);
 left_pts.push_back(fini2);
 }

 if (left_pts.size() > 0) {
 // The left line is formed here
 cv::fitLine(left_pts, left_line, CV_DIST_L2, 0, 0.01, 0.01);
 left_m = left_line[1] / left_line[0];
 left_b = cv::Point(left_line[2], left_line[3]);
 }
 }

 // One the slope and offset points have been obtained, apply the line equation to obtain the line points
 int ini_y = inputImage.rows;
 int fin_y = 470;

 double right_ini_x = ((ini_y - right_b.y) / right_m) + right_b.x;
 double right_fin_x = ((fin_y - right_b.y) / right_m) + right_b.x;

 double left_ini_x = ((ini_y - left_b.y) / left_m) + left_b.x;
 double left_fin_x = ((fin_y - left_b.y) / left_m) + left_b.x;

 output[0] = cv::Point(right_ini_x, ini_y);
 output[1] = cv::Point(right_fin_x, fin_y);
 output[2] = cv::Point(left_ini_x, ini_y);
 output[3] = cv::Point(left_fin_x, fin_y);

 return output;
}

// TURN PREDICTION
/**
*@brief Predict if the lane is turning left, right or if it is going straight
*@brief It is done by seeing where the vanishing point is with respect to the center of the image
*@return String that says if there is left or right turn or if the road is straight
*/
std::string LaneDetector::predictTurn() {
 std::string output;
 double vanish_x;
 double thr_vp = 10;

 // The vanishing point is the point where both lane boundary lines intersect
 vanish_x = static_cast<double>(((right_m*right_b.x) - (left_m*left_b.x) - right_b.y + left_b.y) / (right_m - left_m));

 // The vanishing points location determines where is the road turning
 if (vanish_x < (img_center - thr_vp))
 output = "Left Turn";
 else if (vanish_x >(img_center + thr_vp))
 output = "Right Turn";
 else if (vanish_x >= (img_center - thr_vp) && vanish_x <= (img_center + thr_vp))
 output = "Straight";

 return output;
}

// PLOT RESULTS
/**
*@brief This function plots both sides of the lane, the turn prediction message and a transparent polygon that covers the area inside the lane boundaries
*@param inputImage is the original captured frame
*@param lane is the vector containing the information of both lines
*@param turn is the output string containing the turn information
*@return The function returns a 0
*/
int LaneDetector::plotLane(cv::Mat inputImage, std::vector<cv::Point> lane, std::string turn) {
 std::vector<cv::Point> poly_points;
 cv::Mat output;

 // Create the transparent polygon for a better visualization of the lane
 inputImage.copyTo(output);
 poly_points.push_back(lane[2]);
 poly_points.push_back(lane[0]);
 poly_points.push_back(lane[1]);
 poly_points.push_back(lane[3]);
 cv::fillConvexPoly(output, poly_points, cv::Scalar(0, 0, 255), CV_AA, 0);
 cv::addWeighted(output, 0.3, inputImage, 1.0 - 0.3, 0, inputImage);

 // Plot both lines of the lane boundary
 cv::line(inputImage, lane[0], lane[1], cv::Scalar(0, 255, 255), 5, CV_AA);
 cv::line(inputImage, lane[2], lane[3], cv::Scalar(0, 255, 255), 5, CV_AA);

 // Plot the turn message
 cv::putText(inputImage, turn, cv::Point(50, 90), cv::FONT_HERSHEY_COMPLEX_SMALL, 3, cvScalar(0, 255, 0), 1, CV_AA);

 // Show the final output image
 cv::namedWindow("Lane", CV_WINDOW_AUTOSIZE);
 cv::imshow("Lane", inputImage);
 return 0;
}

main函数

#include <iostream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include "LaneDetector.h"
//#include "LaneDetector.cpp"

/**
*@brief Function main that runs the main algorithm of the lane detection.
*@brief It will read a video of a car in the highway and it will output the
*@brief same video but with the plotted detected lane
*@param argv[] is a string to the full path of the demo video
*@return flag_plot tells if the demo has sucessfully finished
*/
int main() {

 // The input argument is the location of the video
 cv::VideoCapture cap("challenge_video.mp4");
 if (!cap.isOpened())
 return -1;

 LaneDetector lanedetector; // Create the class object
 cv::Mat frame;
 cv::Mat img_denoise;
 cv::Mat img_edges;
 cv::Mat img_mask;
 cv::Mat img_lines;
 std::vector<cv::Vec4i> lines;
 std::vector<std::vector<cv::Vec4i> > left_right_lines;
 std::vector<cv::Point> lane;
 std::string turn;
 int flag_plot = -1;
 int i = 0;

 // Main algorithm starts. Iterate through every frame of the video
 while (i < 540) {
 // Capture frame
 if (!cap.read(frame))
 break;

 // Denoise the image using a Gaussian filter
 img_denoise = lanedetector.deNoise(frame);

 // Detect edges in the image
 img_edges = lanedetector.edgeDetector(img_denoise);

 // Mask the image so that we only get the ROI
 img_mask = lanedetector.mask(img_edges);

 // Obtain Hough lines in the cropped image
 lines = lanedetector.houghLines(img_mask);

 if (!lines.empty())
 {
 // Separate lines into left and right lines
 left_right_lines = lanedetector.lineSeparation(lines, img_edges);

 // Apply regression to obtain only one line for each side of the lane
 lane = lanedetector.regression(left_right_lines, frame);

 // Predict the turn by determining the vanishing point of the the lines
 turn = lanedetector.predictTurn();

 // Plot lane detection
 flag_plot = lanedetector.plotLane(frame, lane, turn);

 i += 1;
 cv::waitKey(25);
 }
 else {
 flag_plot = -1;
 }
 }
 return flag_plot;
}

最后再晒一张结果图吧

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

(0)

相关推荐

  • opencv3/C++ 平面对象识别&透视变换方式

    findHomography( ) 函数findHomography( )找到两个平面之间的透视变换H. 参数说明: Mat findHomography( InputArray srcPoints, //原始平面中点的坐标 InputArray dstPoints, //目标平面中点的坐标 int method = 0, //用于计算单应性矩阵的方法 double ransacReprojThreshold = 3, OutputArray mask=noArray(), //通过鲁棒法(RA

  • opencv实现简单人脸识别

    对于opencv 它提供了许多已经练习好的模型可供使用,我们需要通过他们来进行人脸识别 参考了网上许多资料 假设你已经配好了开发环境 ,在我之前的博客中由开发环境的配置. 项目代码结构: dataSet : 存储训练用的图片,他由data_gen生成,当然也可以修改代码由其他方式生成 haarcascade_frontalface_alt.xml  . haarcascade_frontalface_default.xml: 用于人脸检测的haar分类器,网上普遍说第一个效果更好,第二个运行速度

  • 基于Opencv实现颜色识别

    彩色模型   数字图像处理中常用的采用模型是RGB(红,绿,蓝)模型和HSV(色调,饱和度,亮度),RGB广泛应用于彩色监视器和彩色视频摄像机,我们平时的图片一般都是RGB模型.而HSV模型更符合人描述和解释颜色的方式,HSV的彩色描述对人来说是自然且非常直观的. HSV模型 HSV模型中颜色的参数分别是:色调(H:hue),饱和度(S:saturation),亮度(V:value).由A. R. Smith在1978年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model). (1

  • opencv摄像头捕获识别颜色

    本文实例为大家分享了opencv摄像头捕获识别颜色的具体代码,供大家参考,具体内容如下 #include "highgui.h" #include "iostream" using namespace std; int main() { CvCapture* pCap = cvCreateCameraCapture(1 );//这里-1也可以,不过我的电脑装的有CyberLink YouCam软件, int flag=0; //OpenCV会默认调用该摄像头,而不调

  • C++ opencv实现车道线识别

    本文实例为大家分享了C++ opencv实现车道线识别的具体代码,供大家参考,具体内容如下 先上图 1. 2. (一)目前国内外广泛使用的车道线检测方法主要分为两大类: (1) 基于道路特征的车道线检测: (2) 基于道路模型的车道线检测. 基于道路特征的车道线检测作为主流检测方法之一,主要是利用车道线与道路环境的物理特征差异进行后续图像的分割与处理,从而突出车道线特征,以实现车道线的检测.该方法复杂度较低,实时性较高,但容易受到道路环境干扰. 基于道路模型的车道线检测主要是基于不同的二维或三维

  • 基于OpenCV实现车道线检测(自动驾驶 机器视觉)

    目录 0 前言 1 车道线检测 2 目标 3 检测思路 4 代码实现 4.1 视频图像加载 4.2 车道线区域 4.3 区域 4.4 canny 边缘检测 4.5 霍夫变换(Hough transform) 4.6 HoughLinesP 检测原理 0 前言 无人驾驶技术是机器学习为主的一门前沿领域,在无人驾驶领域中机器学习的各种算法随处可见,今天学长给大家介绍无人驾驶技术中的车道线检测. 1 车道线检测 在无人驾驶领域每一个任务都是相当复杂,看上去无从下手.那么面对这样极其复杂问题,我们解决问

  • 基于opencv实现车道线检测

    基于opencv的车道线检测,供大家参考,具体内容如下 原理: 算法基本思想说明: 传统的车道线检测,多数是基于霍夫直线检测,其实这个里面有个很大的误区,霍夫直线拟合容易受到各种噪声干扰,直接运用有时候效果不好,更多的时候通过霍夫直线检测进行初步的筛选,然后再有针对性的进行直线拟合,根据拟合的直线四个点坐标,绘制出车道线,这种方式可以有效避免霍夫直线拟合不良后果,是一种更加稳定的车道线检测方法,在实际项目中,可以选择两种方法并行,在计算出结果后进行叠加或者对比提取,今天分享的案例主要是绕开了霍夫

  • python+opencv实现车道线检测

    python+opencv车道线检测(简易实现),供大家参考,具体内容如下 技术栈:python+opencv 实现思路: 1.canny边缘检测获取图中的边缘信息: 2.霍夫变换寻找图中直线: 3.绘制梯形感兴趣区域获得车前范围: 4.得到并绘制车道线: 效果展示: 代码实现: import cv2 import numpy as np def canny(): gray = cv2.cvtColor(lane_image, cv2.COLOR_RGB2GRAY) #高斯滤波 blur = c

  • 使用opencv实现车道线检测实战代码

    效果 void lane_detection(cv::Mat &src, cv::Mat &dst) { dst = cv::Mat::zeros(src.size(),src.type()); cv::Mat grid =cv::Mat::zeros(src.size(),src.type()); int iStep = 25; int iNUmsX = src.cols / iStep; int inUmsY = src.rows / iStep; for(int i = 1; i &

  • opencv车道线检测的实现方法

    车道线检测,需要完成以下功能: 图像裁剪:通过设定图像ROI区域,拷贝图像获得裁剪图像 反透视变换:用的是室外采集到的视频,没有对应的变换矩阵.所以建立二维坐标,通过四点映射的方法计算矩阵,进行反透视变化.后因ROI区域的设置易造成变换矩阵获取困难和插值得到的透视图效果不理想,故没应用 二值化:先变化为灰度图,然后设定阈值直接变成二值化图像. 形态学滤波:对二值化图像进行腐蚀,去除噪点,然后对图像进行膨胀,弥补对车道线的腐蚀. 边缘检测:canny变化.sobel变化和laplacian变化中选

  • Python道路车道线检测的实现

    车道线检测是自动驾驶汽车以及一般计算机视觉的关键组件.这个概念用于描述自动驾驶汽车的路径并避免进入另一条车道的风险. 在本文中,我们将构建一个机器学习项目来实时检测车道线.我们将使用 OpenCV 库使用计算机视觉的概念来做到这一点.为了检测车道,我们必须检测车道两侧的白色标记. 使用 Python 和 OpenCV 进行道路车道线检测 使用 Python 中的计算机视觉技术,我们将识别自动驾驶汽车必须行驶的道路车道线.这将是自动驾驶汽车的关键部分,因为自动驾驶汽车不应该越过它的车道,也不应该进

  • 使用OpenCV对车道进行实时检测的实现示例代码

    项目介绍 下图中的两条线即为车道: 我们的任务就是通过 OpenCV 在一段视频(或摄像头)中实时检测出车道并将其标记出来.其效果如下图所示: 这里使用的代码来源于磐怼怼大神,此文章旨在对其代码进行解释. 实现步骤 1.将视频的所有帧读取为图片: 2.创建掩码并应用到这些图片上: 3.图像阈值化: 4.用霍夫线变换检测车道: 5.将车道画到每张图片上: 6.将所有图片合并为视频. 代码实现 1.导入需要的库 import os import re import cv2 import numpy

  • python+opencv实现动态物体识别

    注意:这种方法十分受光线变化影响 自己在家拿着手机瞎晃的成果图: 源代码: # -*- coding: utf-8 -*- """ Created on Wed Sep 27 15:47:54 2017 @author: tina """ import cv2 import numpy as np camera = cv2.VideoCapture(0) # 参数0表示第一个摄像头 # 判断视频是否打开 if (camera.isOpened()

  • OpenCV Java实现人脸识别和裁剪功能

    本文实例为大家分享了OpenCV Java实现人脸识别和裁剪的具体代码,供大家参考,具体内容如下 安装及配置 1.首先安装OpenCV,地址 这里我下载的是Windows版的3.4.5 然后安装即可-- 2.Eclipse配置OpenCV Window->Preferences->Java->User Libraries New输入你的Libraries名 这里我的安装目录是D:\OpenCV,所以是: 然后引入dll,我是64位机子,所以是: Ok,下面创建Java项目做Java与Op

随机推荐