车道检测
来源:互联网 发布:VPN网络 编辑:程序博客网 时间:2024/04/27 14:07
http://www.voidcn.com/blog/qq535033459/article/p-1939538.html
车道线检测是辅助驾驶和自动驾驶的重要研究内容,相关的算法研究已经延续了20多年,本系列文章旨在帮助初学者在阅读文献之余快速上手构建自己的项目。OpenCV极大地方便了机器视觉应用的编写,为了能在刚起步时就看得远些,我们需要站在OpenCV巨人的肩膀上。
先看一个比较简单的程序,Github地址
框架
class LaneDetect
封装核心算法void makeFromVid(string path)
根据视频文件目录读入,对视频中的图像帧进行处理- 主函数 调用makeFromVid
核心算法
整个算法的核心在blobRemoval函数中:
- findContours函数提取轮廓
- 对找到的轮廓进行筛选:
- contourArea轮廓足够大(高于设定的阈值minSize)
- minAreaRect拟合矩形的有足够长的边(高于设定的阈值longLane )
- 根据矩形的偏角和位置再筛选
- 绘制满足条件的轮廓
这个算法非常简单,效果较差。属于利用车道线的基本几何特征和位置的算法。
完整源程序
/*TODO * improve edge linking * remove blobs whose axis direction doesnt point towards vanishing pt * Parallelisation * lane prediction */#include <opencv2/core/core.hpp>#include "opencv2/imgproc/imgproc.hpp"#include <opencv2/highgui/highgui.hpp>#include <iostream>#include <vector>#include <algorithm>#include <math.h>#include <time.h>using namespace std;using namespace cv;clock_t start, stop;class LaneDetect{public: Mat currFrame; //stores the upcoming frame Mat temp; //stores intermediate results Mat temp2; //stores the final lane segments int diff, diffL, diffR; int laneWidth; int diffThreshTop; int diffThreshLow; int ROIrows; int vertical_left; int vertical_right; int vertical_top; int smallLaneArea; int longLane; int vanishingPt; float maxLaneWidth; //to store various blob properties Mat binary_image; //used for blob removal int minSize; int ratio; float contour_area; float blob_angle_deg; float bounding_width; float bounding_length; Size2f sz; vector< vector<Point> > contours; vector<Vec4i> hierarchy; RotatedRect rotated_rect; LaneDetect(Mat startFrame) { //currFrame = startFrame; //if image has to be processed at original size currFrame = Mat(320,480,CV_8UC1,0.0); //initialised the image size to 320x480 resize(startFrame, currFrame, currFrame.size()); // resize the input to required size temp = Mat(currFrame.rows, currFrame.cols, CV_8UC1,0.0);//stores possible lane markings temp2 = Mat(currFrame.rows, currFrame.cols, CV_8UC1,0.0);//stores finally selected lane marks vanishingPt = currFrame.rows/2; //for simplicity right now ROIrows = currFrame.rows - vanishingPt; //rows in region of interest minSize = 0.00015 * (currFrame.cols*currFrame.rows); //min size of any region to be selected as lane maxLaneWidth = 0.025 * currFrame.cols; //approximate max lane width based on image size smallLaneArea = 7 * minSize; longLane = 0.3 * currFrame.rows; ratio = 4; //these mark the possible ROI for vertical lane segments and to filter vehicle glare vertical_left = 2*currFrame.cols/5; vertical_right = 3*currFrame.cols/5; vertical_top = 2*currFrame.rows/3; namedWindow("lane",2); namedWindow("midstep", 2); namedWindow("currframe", 2); namedWindow("laneBlobs",2); getLane(); } void updateSensitivity() { int total=0, average =0; for(int i= vanishingPt; i<currFrame.rows; i++) for(int j= 0 ; j<currFrame.cols; j++) total += currFrame.at<uchar>(i,j); average = total/(ROIrows*currFrame.cols); cout<<"average : "<<average<<endl; } void getLane() { //medianBlur(currFrame, currFrame,5 ); // updateSensitivity(); //ROI = bottom half for(int i=vanishingPt; i<currFrame.rows; i++) for(int j=0; j<currFrame.cols; j++) { temp.at<uchar>(i,j) = 0; temp2.at<uchar>(i,j) = 0; } imshow("currframe", currFrame); blobRemoval(); } void markLane() { for(int i=vanishingPt; i<currFrame.rows; i++) { //IF COLOUR IMAGE IS GIVEN then additional check can be done // lane markings RGB values will be nearly same to each other(i.e without any hue) //min lane width is taken to be 5 laneWidth =5+ maxLaneWidth*(i-vanishingPt)/ROIrows; for(int j=laneWidth; j<currFrame.cols- laneWidth; j++) { diffL = currFrame.at<uchar>(i,j) - currFrame.at<uchar>(i,j-laneWidth); diffR = currFrame.at<uchar>(i,j) - currFrame.at<uchar>(i,j+laneWidth); diff = diffL + diffR - abs(diffL-diffR); //1 right bit shifts to make it 0.5 times diffThreshLow = currFrame.at<uchar>(i,j)>>1; //diffThreshTop = 1.2*currFrame.at<uchar>(i,j); //both left and right differences can be made to contribute //at least by certain threshold (which is >0 right now) //total minimum Diff should be atleast more than 5 to avoid noise if (diffL>0 && diffR >0 && diff>5) if(diff>=diffThreshLow /*&& diff<= diffThreshTop*/ ) temp.at<uchar>(i,j)=255; } } } void blobRemoval() { markLane(); // find all contours in the binary image temp.copyTo(binary_image); findContours(binary_image, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); // for removing invalid blobs if (!contours.empty()) { for (size_t i=0; i<contours.size(); ++i) { //====conditions for removing contours====// contour_area = contourArea(contours[i]) ; //blob size should not be less than lower threshold if(contour_area > minSize) { rotated_rect = minAreaRect(contours[i]); sz = rotated_rect.size; bounding_width = sz.width; bounding_length = sz.height; //openCV selects length and width based on their orientation //so angle needs to be adjusted accordingly blob_angle_deg = rotated_rect.angle; if (bounding_width < bounding_length) blob_angle_deg = 90 + blob_angle_deg; //if such big line has been detected then it has to be a (curved or a normal)lane if(bounding_length>longLane || bounding_width >longLane) { drawContours(currFrame, contours,i, Scalar(255), CV_FILLED, 8); drawContours(temp2, contours,i, Scalar(255), CV_FILLED, 8); } //angle of orientation of blob should not be near horizontal or vertical //vertical blobs are allowed only near center-bottom region, where centre lane mark is present //length:width >= ratio for valid line segments //if area is very small then ratio limits are compensated else if ((blob_angle_deg <-10 || blob_angle_deg >-10 ) && ((blob_angle_deg > -70 && blob_angle_deg < 70 ) || (rotated_rect.center.y > vertical_top && rotated_rect.center.x > vertical_left && rotated_rect.center.x < vertical_right))) { if ((bounding_length/bounding_width)>=ratio || (bounding_width/bounding_length)>=ratio ||(contour_area< smallLaneArea && ((contour_area/(bounding_width*bounding_length)) > .75) && ((bounding_length/bounding_width)>=2 || (bounding_width/bounding_length)>=2))) { drawContours(currFrame, contours,i, Scalar(255), CV_FILLED, 8); drawContours(temp2, contours,i, Scalar(255), CV_FILLED, 8); } } } } } imshow("midstep", temp); imshow("laneBlobs", temp2); imshow("lane",currFrame); } void nextFrame(Mat &nxt) { //currFrame = nxt; //if processing is to be done at original size resize(nxt ,currFrame, currFrame.size()); //resizing the input image for faster processing getLane(); } Mat getResult() { return temp2; }};//end of class LaneDetectvoid makeFromVid(string path){ Mat frame; VideoCapture cap(path); // open the video file for reading if ( !cap.isOpened() ) // if not success, exit program cout << "Cannot open the video file" << endl; //cap.set(CV_CAP_PROP_POS_MSEC, 300); //start the video at 300ms double fps = cap.get(CV_CAP_PROP_FPS); //get the frames per seconds of the video cout << "Input video's Frame per seconds : " << fps << endl; cap.read(frame); LaneDetect detect(frame); while(1) { bool bSuccess = cap.read(frame); // read a new frame from video if (!bSuccess) //if not success, break loop { cout << "Cannot read the frame from video file" << endl; break; } cvtColor(frame, frame, CV_BGR2GRAY); //start = clock(); detect.nextFrame(frame); //stop =clock(); // cout<<"fps : "<<1.0/(((double)(stop-start))/ CLOCKS_PER_SEC)<<endl; if(waitKey(10) == 27) //wait for 'esc' key press for 10 ms. If 'esc' key is pressed, break loop { cout<<"video paused!, press q to quit, any other key to continue"<<endl; if(waitKey(0) == 'q') { cout << "terminated by user" << endl; break; } } }}int main(){ makeFromVid("/home/yash/opencv-2.4.10/programs/output.avi"); // makeFromVid("/home/yash/opencv-2.4.10/programs/road.m4v"); waitKey(0); destroyAllWindows();}
0 0
- 车道检测
- 车道检测模块
- 车道检测与跟踪
- 车道检测模块
- 车道检测模块
- 车道检测数据集
- opencv车道线检测
- opencv车道线检测
- 车道检测与跟踪
- 车道检测问题探究
- 车道检测数据集
- opencv车道线检测
- 车道检测(二)
- 车道检测与跟踪
- ADAS-车道线检测
- 无人驾驶车道检测[C++]
- 车道线检测+车道线跟踪+车道线识别
- halcon车道检测实例注释
- css中的盒子模型
- 【LeetCode】207. Course Schedule (Medium)
- BroadcastReceiver
- std::cerr与std::cout区别
- LINUX下python程序的运行
- 车道检测
- UVa 232 纵横字谜的答案
- Volatile
- MyBatis 最简单的分页,贼几把方便,兄弟,不吹逼
- 不知道大小的图片在盒子中垂直居中
- poj 1256
- Fragment基本使用(三)——与Activity之间传递数据
- 车道检测(二)
- 有关于CSS的面试题和练习