基于opencv實(shí)現(xiàn)車(chē)道線檢測(cè)
基于opencv的車(chē)道線檢測(cè),供大家參考,具體內(nèi)容如下
原理:
算法基本思想說(shuō)明:
傳統(tǒng)的車(chē)道線檢測(cè),多數(shù)是基于霍夫直線檢測(cè),其實(shí)這個(gè)里面有個(gè)很大的誤區(qū),霍夫直線擬合容易受到各種噪聲干擾,直接運(yùn)用有時(shí)候效果不好,更多的時(shí)候通過(guò)霍夫直線檢測(cè)進(jìn)行初步的篩選,然后再有針對(duì)性的進(jìn)行直線擬合,根據(jù)擬合的直線四個(gè)點(diǎn)坐標(biāo),繪制出車(chē)道線,這種方式可以有效避免霍夫直線擬合不良后果,是一種更加穩(wěn)定的車(chē)道線檢測(cè)方法,在實(shí)際項(xiàng)目中,可以選擇兩種方法并行,在計(jì)算出結(jié)果后進(jìn)行疊加或者對(duì)比提取,今天分享的案例主要是繞開(kāi)了霍夫直線檢測(cè),通過(guò)對(duì)二值圖像進(jìn)行輪廓分析與幾何分析,提取到相關(guān)的車(chē)道線信息、然后進(jìn)行特定區(qū)域的像素掃描,擬合生成直線方程,確定四個(gè)點(diǎn)繪制出車(chē)道線,對(duì)連續(xù)的視頻來(lái)說(shuō),如果某一幀無(wú)法正常檢測(cè),就可以通過(guò)緩存來(lái)替代繪制,從而實(shí)現(xiàn)在視頻車(chē)道線檢測(cè)中實(shí)時(shí)可靠。
原理圖:
代碼:
#include <opencv2/opencv.hpp> #include <iostream> #include <cmath> using namespace cv; using namespace std; /** **1、讀取視頻 **2、二值化 **3、輪廓發(fā)現(xiàn) **4、輪廓分析、面積就算,角度分析 **5、直線擬合 **6、畫(huà)出直線 ** */ 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; //循環(huán)讀取視頻 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, ); //邊緣檢測(cè) 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++) { //計(jì)算面積與周長(zhǎng) double length = arcLength(contours[i], true); double area = contourArea(contours[i]); //cout << "周長(zhǎng) 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 << "開(kāi)始繪制:" << 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; }
結(jié)果圖片:
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- opencv車(chē)道線檢測(cè)的實(shí)現(xiàn)方法
- 基于OpenCV實(shí)現(xiàn)車(chē)道線檢測(cè)(自動(dòng)駕駛 機(jī)器視覺(jué))
- python+opencv實(shí)現(xiàn)車(chē)道線檢測(cè)
- C++ opencv實(shí)現(xiàn)車(chē)道線識(shí)別
- 使用opencv實(shí)現(xiàn)車(chē)道線檢測(cè)實(shí)戰(zhàn)代碼
- OpenCV利用霍夫變換實(shí)現(xiàn)交通車(chē)道線檢測(cè)
- OpenCV實(shí)戰(zhàn)案例之車(chē)道線識(shí)別詳解
相關(guān)文章
Visual Studio 如何創(chuàng)建C/C++項(xiàng)目問(wèn)題
這篇文章主要介紹了Visual Studio 如何創(chuàng)建C/C++項(xiàng)目問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易通訊錄完整流程
這篇文章主要為大家介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易通訊錄的完整流程,每個(gè)環(huán)節(jié)都有完整代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-02-02C++ LeetCode1775通過(guò)最少操作次數(shù)使數(shù)組和相等
這篇文章主要為大家介紹了C++ LeetCode1775通過(guò)最少操作次數(shù)使數(shù)組和相等,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12用c語(yǔ)言實(shí)現(xiàn)和平精英的完整代碼
這篇文章主要介紹了用c語(yǔ)言實(shí)現(xiàn)和平精英的完整代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04c#中實(shí)現(xiàn)退出程序后自動(dòng)重新啟動(dòng)程序的方法
下面小編就為大家?guī)?lái)一篇c#中實(shí)現(xiàn)退出程序后自動(dòng)重新啟動(dòng)程序的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之判斷循環(huán)鏈表空與滿(mǎn)
這篇文章主要介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之判斷循環(huán)鏈表空與滿(mǎn)的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家掌握這部分內(nèi)容,需要的朋友可以參考下2017-10-10OpenSSL動(dòng)態(tài)鏈接庫(kù)源碼安裝教程
Openssl 是一個(gè)開(kāi)放源代碼的SSL協(xié)議的產(chǎn)品實(shí)現(xiàn),它采用C語(yǔ)言作為開(kāi)發(fā)語(yǔ)言,具備了跨系統(tǒng)的性能。這篇文章主要介紹了OpenSSL動(dòng)態(tài)鏈接庫(kù)源碼安裝,需要的朋友可以參考下2021-11-11淺談C++中的string 類(lèi)型占幾個(gè)字節(jié)
本篇文章小編并不是為大家講解string類(lèi)型的用法,而是講解我個(gè)人比較好奇的問(wèn)題,就是string 類(lèi)型占幾個(gè)字節(jié)2013-08-08