文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

怎么在C++中使用opencv实现一个车道线识别功能

2023-06-06 10:30

关注

本篇文章为大家展示了怎么在C++中使用opencv实现一个车道线识别功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

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

(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 BLURRINGcv::Mat LaneDetector::deNoise(cv::Mat inputImage) { cv::Mat output; cv::GaussianBlur(inputImage, output, cv::Size(3, 3), 0, 0); return output;}// EDGE DETECTIONcv::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 IMAGEcv::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 LINESstd::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 LINESstd::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 LINESstd::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 PREDICTIONstd::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 RESULTSint 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"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;}

上述内容就是怎么在C++中使用opencv实现一个车道线识别功能,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯