车道检测源码分析系列(三)

下面看一个出自国外某教授的基于OpenCVSharp的车辆视觉框架,虽然包含车道检测和车辆识别,但源程序仅100行左右,非常精巧。

算法描述

检测部分的步骤很经典,是比较通用的步骤:

  1. 将图像上半部分无关内容截掉,设定ROI
  2. 转为灰度图
  3. Canny算子提取边缘
  4. Hough检测直线
  5. 通过直线角度位置信息筛选出车道线,标记到图上

效果如下图:

源程序

有博客将其中车道检测部分转为了OpenCV2,以下的源码转自该博客。原文链接

另外,国外有基于此程序进行扩展的,后续会介绍。

OpenCVSharp版本

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

using OpenCvSharp;

namespace LaneDetection
{
    class Program
    {
        [STAThread]
        static void Main()
        {
            CvCapture cap = CvCapture.FromFile("test1.mp4");
            CvWindow w = new CvWindow("Lane Detection");
            CvWindow canny = new CvWindow("Canny");
            IplImage src, gray, dstCanny, halfFrame, smallImg;
            CvMemStorage storage = new CvMemStorage();
            CvSeq lines;

            while (CvWindow.WaitKey(10) < 0)
            {
                src = cap.QueryFrame();
                halfFrame = new IplImage(new CvSize(src.Size.Width / 2, src.Size.Height / 2), BitDepth.U8, 3);
                Cv.PyrDown(src, halfFrame, CvFilter.Gaussian5x5);

                gray = new IplImage(src.Size, BitDepth.U8, 1);
                dstCanny = new IplImage(src.Size, BitDepth.U8, 1);
                storage.Clear();

                // Crop off top half of image since we're only interested in the lower portion of the video
                int halfWidth = src.Width / 2;
                int halfHeight = src.Height / 2;
                int startX = halfWidth - (halfWidth / 2);
                src.SetROI(new CvRect(0, halfHeight - 0, src.Width - 1, src.Height - 1));

                gray.SetROI(src.GetROI());
                dstCanny.SetROI(src.GetROI());

                src.CvtColor(gray, ColorConversion.BgrToGray);
                Cv.Smooth(gray, gray, SmoothType.Gaussian, 5, 5);
                Cv.Canny(gray, dstCanny, 50, 200, ApertureSize.Size3);
                canny.Image = dstCanny;
                storage.Clear();
                lines = dstCanny.HoughLines2(storage, HoughLinesMethod.Probabilistic, 1, Math.PI / 180, 50, 50, 100);

                for (int i = 0; i < lines.Total; i++)
                {
                    CvLineSegmentPoint elem = lines.GetSeqElem(i).Value;

                    int dx = elem.P2.X - elem.P1.X;
                    int dy = elem.P2.Y - elem.P1.Y;
                    double angle = Math.Atan2(dy, dx) * 180 / Math.PI;

                    if (Math.Abs(angle) <= 10)
                        continue;

                    if (elem.P1.Y > elem.P2.Y + 50  || elem.P1.Y < elem.P2.Y -50 )
                    {
                        src.Line(elem.P1, elem.P2, CvColor.Red, 2, LineType.AntiAlias, 0);
                    }
                }
                src.ResetROI();
                storage.Clear();
                w.Image = src;
            }
        }
    }
}

OpenCV2版本

#include "stdafx.h"
#include 
#include 
#include 

using namespace cv;
using namespace std;

#define INF 99999999
CvCapture* g_capture = NULL;

int g_slider_pos = 0 ;
int frame_count = 0;
CvSeq* lines;


int main(int argc,char* argv[])
{                  
    cvNamedWindow( "show");      
    g_capture=cvCreateFileCapture( "D:\\road.avi");
    IplImage* frame;
    while(1)
    {  
        CvMemStorage* storage = cvCreateMemStorage();
        frame=cvQueryFrame(g_capture);

        //set the ROI of the original image
        int x = 0,y = frame->height/2;
        int width = frame->width,height = frame->height/2;

        if(!frame) 
            break; 

        cvSetImageROI(frame,cvRect(x,y,width,height));
        IplImage* gray = cvCreateImage(cvGetSize(frame),8,1);
        cvCvtColor(frame,gray,CV_BGR2GRAY);

        cvCanny(gray,gray,50,100);
        cvShowImage("canny",gray);
        cvSmooth(gray,gray,CV_GAUSSIAN,3,1,0);

        //Hough
        lines = cvHoughLines2(gray,storage,CV_HOUGH_PROBABILISTIC,1,CV_PI/180,50,90,50);

        //select approprivate lines acoording to the slope
        for (int i = 0;i < lines->total;i ++)
        {
            double k =INF;
            CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);
            int dx = line[1].x - line[0].x;
            int dy = line[1].x - line[0].y;
            double angle = atan2(dy,dx) * 180 /CV_PI;
            if (abs(angle) <= 10)
                continue;
            if (line[0].y > line[1].y + 50 || line[0].y < line[1].y - 50)
            {
                cvLine(frame,line[0],line[1],CV_RGB(255,0,0),2,CV_AA);
            }
        }
        cvResetImageROI(frame);     
        cvShowImage( "show",frame);
        char c = cvWaitKey(33);            
        if(c==27)
            break;
    } 
    cvReleaseCapture(&g_capture);
    cvDestroyWindow( "show");               
    return 0;
}

参考资料

  • 国外教授的博客-OpenCVSharp版本 【中文翻译】
  • 国内某博客-改写OpenCV2版本

你可能感兴趣的:(computer-vision)