車道線檢測,需要完成以下功能:
創(chuàng)新互聯(lián)總部坐落于成都市區(qū),致力網(wǎng)站建設(shè)服務(wù)有成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、網(wǎng)絡(luò)營銷策劃、網(wǎng)頁設(shè)計(jì)、網(wǎng)站維護(hù)、公眾號搭建、重慶小程序開發(fā)、軟件開發(fā)等為企業(yè)提供一整套的信息化建設(shè)解決方案。創(chuàng)造真正意義上的網(wǎng)站建設(shè),為互聯(lián)網(wǎng)品牌在互動行銷領(lǐng)域創(chuàng)造價值而不懈努力!
實(shí)現(xiàn)的效果
在亮度良好道路條件良好的情況下,檢測車前區(qū)域的車道線實(shí)現(xiàn)比較成功,排除掉高速護(hù)欄的影響,而且原圖像還能完整體現(xiàn)。
車子行駛在高速公路大型彎道上,可以在一定角度范圍內(nèi)認(rèn)定車道線仍是直線,檢測出為直線。
車子切換過程中只有一根車道線被識別,但是穩(wěn)定回變換車道后,實(shí)現(xiàn)效果良好。減速線為黃色,二值化是也被過濾,沒造成影響。
剛進(jìn)入隧道時,攝像機(jī)光源基本處于高光狀態(tài),拍攝亮度基本不變,二值化圖像時情況良好,噪聲比較多但是沒產(chǎn)生多大線狀影響;當(dāng)攝像頭自動調(diào)節(jié)亮度,圖像亮度變低,二值化時同一閾值把車道線給過濾掉,造成無法識別車道線的現(xiàn)象。
在道路損壞的情況下,由于閾值一定,基本上檢測不出車道線。
結(jié)論
實(shí)現(xiàn)的功能:實(shí)現(xiàn)了車道線檢測的基本功能,反透視變換矩陣實(shí)現(xiàn)了但效果不太理想,使用自己寫的直線檢測部分,車道線識別抗干擾能力較強(qiáng)。
缺點(diǎn):整個識別系統(tǒng)都是固定的參數(shù),只能在特定的環(huán)境產(chǎn)生良好的效果。
改進(jìn)空間:提取全部關(guān)鍵參數(shù),每次對ROI圖像進(jìn)行快速掃描更新參數(shù),否則使用默認(rèn)參數(shù)。例如,可以選擇每次5間隔取點(diǎn),以像素最高點(diǎn)的85%作為該次二值化的閾值。從而做到動態(tài)車道線識別。
完整代碼
方法一
main.cpp
#include<cv.h>
#include<cxcore.h>
#include<highgui.h>
#include"mylinedetect.h"
#include<cstdio>
#include<iostream>
using namespace std;
int main(){
//聲明IplImage指針
IplImage* pFrame = NULL;
IplImage* pCutFrame = NULL;
IplImage* pCutFrImg = NULL;
//聲明CvCapture指針
CvCapture* pCapture = NULL;
//聲明CvMemStorage和CvSeg指針
CvMemStorage* storage = cvCreateMemStorage();
CvSeq* lines = NULL;
//生成視頻的結(jié)構(gòu)
VideoWriter writer("result.avi", CV_FOURCC('M', 'J', 'P', 'G'), 25.0, Size(856, 480));
//當(dāng)前幀數(shù)
int nFrmNum = 0;
//裁剪的天空高度
int CutHeight = 310;
//窗口命名
cvNamedWindow("video", 1);
cvNamedWindow("BWmode", 1);
//調(diào)整窗口初始位置
cvMoveWindow("video", 300, 0);
cvMoveWindow("BWmode", 300, 520);
//不能打開則退出
if (!(pCapture = cvCaptureFromFile("lane.avi"))){
fprintf(stderr, "Can not open video file\n");
return -2;
}
//每次讀取一楨的視頻
while (pFrame = cvQueryFrame(pCapture)){
//設(shè)置ROI裁剪圖像
cvSetImageROI(pFrame, cvRect(0, CutHeight, pFrame->width, pFrame->height - CutHeight));
nFrmNum++;
//第一次要申請內(nèi)存p
if (nFrmNum == 1){
pCutFrame = cvCreateImage(cvSize(pFrame->width, pFrame->height - CutHeight), pFrame->depth, pFrame->nChannels);
cvCopy(pFrame, pCutFrame, 0);
pCutFrImg = cvCreateImage(cvSize(pCutFrame->width, pCutFrame->height), IPL_DEPTH_8U, 1);
//轉(zhuǎn)化成單通道圖像再處理
cvCvtColor(pCutFrame, pCutFrImg, CV_BGR2GRAY);
}
else{
//獲得剪切圖
cvCopy(pFrame, pCutFrame, 0);
#if 0 //反透視變換
//二維坐標(biāo)下的點(diǎn),類型為浮點(diǎn)
CvPoint2D32f srcTri[4], dstTri[4];
CvMat* warp_mat = cvCreateMat(3, 3, CV_32FC1);
//計(jì)算矩陣反射變換
srcTri[0].x = 10;
srcTri[0].y = 20;
srcTri[1].x = pCutFrame->width - 5;
srcTri[1].y = 0;
srcTri[2].x = 0;
srcTri[2].y = pCutFrame->height - 1;
srcTri[3].x = pCutFrame->width - 1;
srcTri[3].y = pCutFrame->height - 1;
//改變目標(biāo)圖像大小
dstTri[0].x = 0;
dstTri[0].y = 0;
dstTri[1].x = pCutFrImg->width - 1;
dstTri[1].y = 0;
dstTri[2].x = 0;
dstTri[2].y = pCutFrImg->height - 1;
dstTri[3].x = pCutFrImg->width - 1;
dstTri[3].y = pCutFrImg->height - 1;
//獲得矩陣
cvGetPerspectiveTransform(srcTri, dstTri, warp_mat);
//反透視變換
cvWarpPerspective(pCutFrame, pCutFrImg, warp_mat);
#endif
//前景圖轉(zhuǎn)換為灰度圖
cvCvtColor(pCutFrame, pCutFrImg, CV_BGR2GRAY);
//二值化前景圖
cvThreshold(pCutFrImg, pCutFrImg, 80, 255.0, CV_THRESH_BINARY);
//進(jìn)行形態(tài)學(xué)濾波,去掉噪音
cvErode(pCutFrImg, pCutFrImg, 0, 2);
cvDilate(pCutFrImg, pCutFrImg, 0, 2);
//canny變化
cvCanny(pCutFrImg, pCutFrImg, 50, 120);
//sobel變化
//Mat pCutFrMat(pCutFrImg);
//Sobel(pCutFrMat, pCutFrMat, pCutFrMat.depth(), 1, 1);
//laplacian變化
//Laplacian(pCutFrMat, pCutFrMat, pCutFrMat.depth());
#if 1 //0為下面的代碼,1為上面的代碼
#pragma region Hough直線檢測
lines = cvHoughLines2(pCutFrImg, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180, 100, 15, 15);
printf("Lines number: %d\n", lines->total);
//畫出直線
for (int i = 0; i<lines->total; i++){
CvPoint* line = (CvPoint*)cvGetSeqElem(lines, i);
double k = ((line[0].y - line[1].y)*1.0 / (line[0].x - line[1].x));
cout<<"nFrmNum "<<nFrmNum<<" 's k = "<<k<<endl;
if(!(abs(k)<0.1))//去掉水平直線
cvLine(pFrame, line[0], line[1], CV_RGB(255, 0, 0), 6, CV_AA);
}
#pragma endregion
#else
#pragma region mylinedetect
Mat edge(pCutFrImg);
vector<struct line> lines = detectLine(edge, 60);
Mat pFrameMat(pFrame);
drawLines(pFrameMat, lines);
namedWindow("mylinedetect", 1);
imshow("mylinedetect", pFrameMat);
#pragma endregion
#endif
//恢復(fù)ROI區(qū)域
cvResetImageROI(pFrame);
//寫入視頻流
writer << pFrame;
//顯示圖像
cvShowImage("video", pFrame);
cvShowImage("BWmode", pCutFrImg);
//按鍵事件,空格暫停,其他跳出循環(huán)
int temp = cvWaitKey(2);
if (temp == 32){
while (cvWaitKey() == -1);
}
else if (temp >= 0){
break;
}
}
}
//銷毀窗口
cvDestroyWindow("video");
cvDestroyWindow("BWmode");
//釋放圖像
cvReleaseImage(&pCutFrImg);
cvReleaseImage(&pCutFrame);
cvReleaseCapture(&pCapture);
return 0;
}mylinedetect.h
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <vector>
#include <cmath>
using namespace cv;
using namespace std;
const double pi = 3.1415926f;
const double RADIAN = 180.0 / pi;
struct line{
int theta;
int r;
};
vector<struct line> detectLine(Mat &img, int threshold){
vector<struct line> lines;
int diagonal = floor(sqrt(img.rows*img.rows + img.cols*img.cols));
vector< vector<int> >p(360, vector<int>(diagonal));
//統(tǒng)計(jì)數(shù)量
for (int j = 0; j < img.rows; j++) {
for (int i = 0; i < img.cols; i++) {
if (img.at<unsigned char>(j, i) > 0){
for (int theta = 0; theta < 360; theta++){
int r = floor(i*cos(theta / RADIAN) + j*sin(theta / RADIAN));
if (r < 0)
continue;
p[theta][r]++;
}
}
}
}
//獲得最大值
for (int theta = 0; theta < 360; theta++){
for (int r = 0; r < diagonal; r++){
int thetaLeft = max(0, theta - 1);
int thetaRight = min(359, theta + 1);
int rLeft = max(0, r - 1);
int rRight = min(diagonal - 1, r + 1);
int tmp = p[theta][r];
if (tmp > threshold
&& tmp > p[thetaLeft][rLeft] && tmp > p[thetaLeft][r] && tmp > p[thetaLeft][rRight]
&& tmp > p[theta][rLeft] && tmp > p[theta][rRight]
&& tmp > p[thetaRight][rLeft] && tmp > p[thetaRight][r] && tmp > p[thetaRight][rRight]){
struct line newline;
newline.theta = theta;
newline.r = r;
lines.push_back(newline);
}
}
}
return lines;
}
void drawLines(Mat &img, const vector<struct line> &lines){
for (int i = 0; i < lines.size(); i++){
vector<Point> points;
int theta = lines[i].theta;
int r = lines[i].r;
double ct = cos(theta / RADIAN);
double st = sin(theta / RADIAN);
//公式 r = x*ct + y*st
//計(jì)算左邊
int y = int(r / st);
if (y >= 0 && y < img.rows){
Point p(0, y);
points.push_back(p);
}
//計(jì)算右邊
y = int((r - ct*(img.cols - 1)) / st);
if (y >= 0 && y < img.rows){
Point p(img.cols - 1, y);
points.push_back(p);
}
//計(jì)算上邊
int x = int(r / ct);
if (x >= 0 && x < img.cols){
Point p(x, 0);
points.push_back(p);
}
//計(jì)算下邊
x = int((r - st*(img.rows - 1)) / ct);
if (x >= 0 && x < img.cols){
Point p(x, img.rows - 1);
points.push_back(p);
}
//畫線
cv::line(img, points[0], points[1], Scalar(255, 0, 0), 5, CV_AA);
}
}方法二:
#include<cv.h>
#include<cxcore.h>
#include<highgui.h>
#include<cstdio>
#include<iostream>
using namespace std;
int main(){
//聲明IplImage指針
IplImage* pFrame = NULL;
IplImage* pCutFrame = NULL;
IplImage* pCutFrImg = NULL;
IplImage* pCutBkImg = NULL;
//聲明CvMat指針
CvMat* pCutFrameMat = NULL;
CvMat* pCutFrMat = NULL;
CvMat* pCutBkMat = NULL;
//聲明CvCapture指針
CvCapture* pCapture = NULL;
//聲明CvMemStorage和CvSeg指針
CvMemStorage* storage = cvCreateMemStorage();
CvSeq* lines = NULL;
//當(dāng)前幀數(shù)
int nFrmNum = 0;
//裁剪的天空高度
int CutHeight = 250;
//窗口命名
cvNamedWindow("video", 1);
//cvNamedWindow("background", 1);
cvNamedWindow("foreground", 1);
//調(diào)整窗口初始位置
cvMoveWindow("video", 300, 30);
cvMoveWindow("background", 100, 100);
cvMoveWindow("foreground", 300, 370);
//不能打開則退出
if (!(pCapture = cvCaptureFromFile("lane.avi"))){
fprintf(stderr, "Can not open video file\n");
return -2;
}
//每次讀取一楨的視頻
while (pFrame = cvQueryFrame(pCapture)){
//設(shè)置ROI裁剪圖像
cvSetImageROI(pFrame, cvRect(0, CutHeight, pFrame->width, pFrame->height - CutHeight));
nFrmNum++;
//第一次要申請內(nèi)存p
if (nFrmNum == 1){
pCutFrame = cvCreateImage(cvSize(pFrame->width, pFrame->height - CutHeight), pFrame->depth, pFrame->nChannels);
cvCopy(pFrame, pCutFrame, 0);
pCutBkImg = cvCreateImage(cvSize(pCutFrame->width, pCutFrame->height), IPL_DEPTH_8U, 1);
pCutFrImg = cvCreateImage(cvSize(pCutFrame->width, pCutFrame->height), IPL_DEPTH_8U, 1);
pCutBkMat = cvCreateMat(pCutFrame->height, pCutFrame->width, CV_32FC1);
pCutFrMat = cvCreateMat(pCutFrame->height, pCutFrame->width, CV_32FC1);
pCutFrameMat = cvCreateMat(pCutFrame->height, pCutFrame->width, CV_32FC1);
//轉(zhuǎn)化成單通道圖像再處理
cvCvtColor(pCutFrame, pCutBkImg, CV_BGR2GRAY);
cvCvtColor(pCutFrame, pCutFrImg, CV_BGR2GRAY);
//轉(zhuǎn)換成矩陣
cvConvert(pCutFrImg, pCutFrameMat);
cvConvert(pCutFrImg, pCutFrMat);
cvConvert(pCutFrImg, pCutBkMat);
}
else{
//獲得剪切圖
cvCopy(pFrame, pCutFrame, 0);
//前景圖轉(zhuǎn)換為灰度圖
cvCvtColor(pCutFrame, pCutFrImg, CV_BGR2GRAY);
cvConvert(pCutFrImg, pCutFrameMat);
//高斯濾波先,以平滑圖像
cvSmooth(pCutFrameMat, pCutFrameMat, CV_GAUSSIAN, 3, 0, 0.0);
//當(dāng)前幀跟背景圖相減
cvAbsDiff(pCutFrameMat, pCutBkMat, pCutFrMat);
//二值化前景圖
cvThreshold(pCutFrMat, pCutFrImg, 35, 255.0, CV_THRESH_BINARY);
//進(jìn)行形態(tài)學(xué)濾波,去掉噪音
cvErode(pCutFrImg, pCutFrImg, 0, 1);
cvDilate(pCutFrImg, pCutFrImg, 0, 1);
//更新背景
cvRunningAvg(pCutFrameMat, pCutBkMat, 0.003, 0);
//pCutBkMat = cvCloneMat(pCutFrameMat);
//將背景轉(zhuǎn)化為圖像格式,用以顯示
//cvConvert(pCutBkMat, pCutBkImg);
cvCvtColor(pCutFrame, pCutBkImg, CV_BGR2GRAY);
//canny變化
cvCanny(pCutFrImg, pCutFrImg, 50, 100);
#pragma region Hough檢測
lines = cvHoughLines2(pCutFrImg, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180, 100, 30, 15);
printf("Lines number: %d\n", lines->total);
//畫出直線
for (int i = 0; i<lines->total; i++){
CvPoint* line = (CvPoint* )cvGetSeqElem(lines, i);
cvLine(pCutFrame, line[0], line[1], CV_RGB(255, 0, 0), 6, CV_AA);
}
#pragma endregion
//顯示圖像
cvShowImage("video", pCutFrame);
cvShowImage("background", pCutBkImg);
cvShowImage("foreground", pCutFrImg);
//按鍵事件,空格暫停,其他跳出循環(huán)
int temp = cvWaitKey(2);
if (temp == 32){
while (cvWaitKey() == -1);
}
else if (temp >= 0){
break;
}
}
//恢復(fù)ROI區(qū)域(多余可去掉)
cvResetImageROI(pFrame);
}
//銷毀窗口
cvDestroyWindow("video");
cvDestroyWindow("background");
cvDestroyWindow("foreground");
//釋放圖像和矩陣
cvReleaseImage(&pCutFrImg);
cvReleaseImage(&pCutBkImg);
cvReleaseImage(&pCutFrame);
cvReleaseMat(&pCutFrameMat);
cvReleaseMat(&pCutFrMat);
cvReleaseMat(&pCutBkMat);
cvReleaseCapture(&pCapture);
return 0;
}以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。
新聞標(biāo)題:opencv車道線檢測的實(shí)現(xiàn)方法
鏈接分享:http://www.chinadenli.net/article40/peeeeo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化、定制網(wǎng)站、App開發(fā)、做網(wǎng)站、軟件開發(fā)、虛擬主機(jī)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)