实现功能:
视频图像采集
图像预处理
车道线检测与识别
实现的效果:
实现思路:
视频采集部分:摄像头采集分为单目采集与多目(双目),双目采集采用立体视觉方法,虽然对于恢复物体的深度信息比较容易,但是图像共轭像点的匹配问题,却在很大程度上限制了它的应用。本系统采用单目视觉方法,即通过一个摄像机来采集图像。虽然,这种方法得到的图像不包含物体的深度信息,但是,如果把时间看作第三轴线,我们便可以从连续的视频图像中得到准三维图像
图像预处理部分:包含图像灰度化,增强图像对比度,图像中值滤波,图像边缘增强,边缘检测信息与区域增长信息融合几部分。
车道线检测识别:有多种方法,如最小二乘法,Hough变换,Radon变换等,本系统使用opencv自带直线检测库霍夫变换。
实现代码:
读取视频检测其中车道线部分核心代码;
用到的结构体声明以及变量初始化:
IplImage* pCutFrame = NULL;
IplImage* pCutFrImg = NULL;
IplImage* pCutBkImg = NULL;
CvMat* pCutFrameMat = NULL;
CvMat* pCutFrMat = NULL;
CvMat* pCutBkMat = NULL;
// CvCapture* pCapture = NULL;
CvMemStorage* storage = cvCreateMemStorage();
CvSeq* lines = NULL;
int nFrmNum = 0;
int CutHeight = 250;
打开已有视频(或摄像头),按帧读取视频
if (!(pCapture = cvCaptureFromFile("//home//wengkl//Downloads//car//3.mov"))){
fprintf(stderr, "Can not open video file\n");
return -2;
}
//每次读取一桢的视频
while (pFrame = cvQueryFrame(pCapture)){
...
}
设置感兴趣区域:
cvSetImageROI(pFrame, cvRect(0, CutHeight, pFrame->width, pFrame->height - CutHeight));
如果是第一帧,分配内存空间
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);
cvCvtColor(pCutFrame, pCutBkImg, CV_BGR2GRAY);
cvCvtColor(pCutFrame, pCutFrImg, CV_BGR2GRAY);
cvConvert(pCutFrImg, pCutFrameMat);
cvConvert(pCutFrImg, pCutFrMat);
cvConvert(pCutFrImg, pCutBkMat);
}
如果不是第一帧,进行各类检测如下:
获得剪切图
cvCopy(pFrame, pCutFrame, 0);
前景图转换为灰度图
cvCvtColor(pCutFrame, pCutFrImg, CV_BGR2GRAY);
cvConvert(pCutFrImg, pCutFrameMat);
图像平滑处理,计算两幅图像差
cvSmooth(pCutFrameMat, pCutFrameMat, CV_GAUSSIAN, 3, 0, 0.0);
cvAbsDiff(pCutFrameMat, pCutBkMat, pCutFrMat);
二值化前景图
cvThreshold(pCutFrMat, pCutFrImg, 35, 255.0, CV_THRESH_BINARY);
形态学滤波
cvErode(pCutFrImg, pCutFrImg, 0, 1);
cvDilate(pCutFrImg, pCutFrImg, 0, 1);
cvRunningAvg(pCutFrameMat, pCutBkMat, 0.003, 0);
cvConvert(pCutBkMat, pCutBkImg);
canny变换
cvCanny(pCutFrImg, pCutFrImg, 50, 100);
霍夫变换直线检测,并在图像上标记出来,打印出当前帧数与直线斜率
lines = cvHoughLines2(pCutFrImg, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180, 100, 30, 15);
printf("line = %d\n",lines->total);
for (int i = 0; itotal; i++){
CvPoint* line = (CvPoint* )cvGetSeqElem(lines, i);
// cvLine(pCutFrame, line[0], line[1], CV_RGB(255, 0, 0), 6, CV_AA);
double k = ((line[0].y - line[1].y)*1.0 / (line[0].x - line[1].x));
cout<<"nFrmNum "< cvReleaseImage(&pCutFrImg);
cvReleaseImage(&pCutBkImg);
cvReleaseImage(&pCutFrame);
cvReleaseMat(&pCutFrameMat);
cvReleaseMat(&pCutFrMat);
cvReleaseMat(&pCutBkMat);
由于本系统是移植到FriendlyARM上使用的,并没有移植GUI的库,不能直接用
CvCapture* pCapture = cvCreateCameraCapture(-1);
int grappicture()
{
int grab;
BITMAPFILEHEADER bf;
BITMAPINFOHEADER bi;
FILE * fp1,* fp2;
fp1 = fopen(BMP, "wb");
fp2 = fopen(YUV, "wb");
if(!fp1)
{
printf("open "BMP"error\n");
return(FALSE);
}
if(!fp2)
{
printf("open "YUV"error\n");
return(FALSE);
}
//Set BITMAPINFOHEADER
bi.biSize = 40;
bi.biWidth = IMAGEWIDTH;
bi.biHeight = IMAGEHEIGHT;
bi.biPlanes = 1;
bi.biBitCount = 24;
bi.biCompression = 0;
bi.biSizeImage = IMAGEWIDTH*IMAGEHEIGHT*3;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
//Set BITMAPFILEHEADER
bf.bfType = 0x4d42;
bf.bfSize = 54 + bi.biSizeImage;
bf.bfReserved = 0;
bf.bfOffBits = 54;
grab=v4l2_grab();
// printf("GRAB is %d\n",grab);
printf("grab ok\n");
fwrite(buffers[0].start, IMAGEHEIGHT*IMAGEWIDTH*2,1, fp2);
printf("save "YUV"OK\n");
yuyv_2_rgb888();
fwrite(&bf, 14, 1, fp1);
fwrite(&bi, 40, 1, fp1);
fwrite(frame_buffer, bi.biSizeImage, 1, fp1);
printf("save "BMP"OK\n");
close_v4l2();
return(TRUE);
}
if(!initcamera())
{
printf("init failure");
}
pFrame = cvQueryFrame(pCapture)
int grapp=grappicture();
if(grapp==0)
{
cout<<"grapcamera failue !"<
移植问题与总结:
在PC下跑这部分代码是很流畅的,但是一旦移植到友善之臂下,摄像头每次保存图片并解析的速度就会降低;加上摄像头的分辨率比较低,导致在ARM上车道线的识别会有误差
另外,目前代码检测的车道线均为直线或类似直线,当车速过快或者转弯角度过大时,检测出的斜率会混乱。