python+opencv车道线,实线虚线的检测

最近在做一个基于opencv的无人小车,行车过程中遇到障碍时需要变道,由于实线不能变道,所以要判断车道线。但是找了很多地方却找不到关于车道线的实线虚线检测,于是通过自己的奇思妙想,想到了解决的办法,于是写下此博客,希望能帮到更多的人。

入门版的车道线检测

参考的资料
在此参考代码基础上完成的实线,虚线检测

代码

import cv2 as cv
import numpy as np
import utils

#读取图片
src = cv.imread('test_images/test3.jpg')
#高斯降噪
src1 = cv.GaussianBlur(src,(5,5),0,0)
# cv.imshow('gaosi',src1)
#灰度处理
src2 = cv.cvtColor(src1,cv.COLOR_BGR2GRAY)
# cv.imshow('huidu',src2)
#边缘检测
lthrehlod = 50
hthrehlod =150
src3 = cv.Canny(src2,lthrehlod,hthrehlod)
# cv.imshow('bianyuan',src3)
#ROI划定区间,并将非此区间变成黑色
regin = np.array([[(0,660),(690,440),
(1200,700),(src.shape[1],660)]]) #为啥要两中括号?
mask = np.zeros_like(src3)
mask_color = 255   #src3图像的通道数是1,且是灰度图像,所以颜色值在0-255
cv.fillPoly(mask,regin,mask_color)
src4 = cv.bitwise_and(src3,mask)
# cv.imshow('bianyuan2',src4)

#利用霍夫变换原理找出上图中的像素点组成的直线,然后画出来
rho = 1
theta = np.pi/180
threhold =15
minlength = 40
maxlengthgap = 20
lines = cv.HoughLinesP(src4,rho,theta,threhold,np.array([]),minlength,maxlengthgap)
#画线
linecolor =[0,255,255]
linewidth = 4
src5 = cv.cvtColor(src4,cv.COLOR_GRAY2BGR) #转化为三通道的图像




# 优化处理
def choose_lines(lines, threhold):  # 过滤斜率差别较大的点
    slope = [(y2 - y1) / (x2 - x1) for line in lines for x1, x2, y1, y2 in line]
    while len(lines) > 0:
        mean = np.mean(slope)  # 平均斜率
        diff = [abs(s - mean) for s in slope]
        idx = np.argmax(diff)
        if diff[idx] > threhold:
            slope.pop(idx)
            lines.pop(idx)
        else:
            break
    return lines


lefts =[]
rights =[]
leftlength=[]
rightlength=[]
for line  in lines:
    for x1,y1,x2,y2 in line:
        #cv.line(src5,(x1,y1),(x2,y2),linecolor,linewidth)
        #分左右车道
        k = (y2-y1)/(x2-x1)
        length= ((y2-y1)**2+(x2-x1)**2)**0.5#计算线段长度
        if k<0:
                lefts.append(line)
                leftlength.append(length)
        else:
                rights.append(line)
                rightlength.append(length)

# print(max(leftlength))
# print(max(rightlength))

if max(leftlength)>max(rightlength):
    text="The left-hand side is the solid line"
else:
    text="The right-hand side is the solid line"



def clac_edgepoints(points, ymin, ymax):  # 可以理解成找一条线的端点
    x = [p[0] for p in points]
    y = [p[1] for p in points]

    k = np.polyfit(y, x, 1)
    func = np.poly1d(k)  # 方程是y关于x的函数,因为输入的ymin ymax。要求xmin,xmax

    xmin = int(func(ymin))
    xmax = int(func(ymax))

    return [(xmin, ymin), (xmax, ymax)]


good_leftlines = choose_lines(lefts, 0.1)  # 处理后的点
good_rightlines = choose_lines(rights, 0.1)

leftpoints = [(x1, y1) for left in good_leftlines for x1, y1, x2, y2 in left]
leftpoints = leftpoints + [(x2, y2) for left in good_leftlines for x1, y1, x2, y2 in left]
rightpoints = [(x1, y1) for right in good_rightlines for x1, y1, x2, y2 in right]
rightpoints = rightpoints + [(x2, y2) for right in good_rightlines for x1, y1, x2, y2 in right]

lefttop = clac_edgepoints(leftpoints, 500, src.shape[0])  # 要画左右车道线的端点
righttop = clac_edgepoints(rightpoints, 500, src.shape[0])

src6 = np.zeros_like(src5)

cv.line(src6, lefttop[0], lefttop[1], linecolor, linewidth)
cv.line(src6, righttop[0], righttop[1], linecolor, linewidth)

# cv.imshow('onlylane',src6)

#图像叠加
src7 = cv.addWeighted(src1,0.8,src6,1,0)
font = cv.FONT_HERSHEY_SIMPLEX
cv.putText(src7,text,(100,100), font, 1,(255,255,255),2)
cv.imshow('Finally Image',src7)

cv.waitKey(0)
cv.destroyAllWindows()
~


代码中有几个需要注意到的地方,是车道线检测关键的所在
1、感兴趣区域的划定,会直接影响车道线检测的结果

#ROI划定区间,并将非此区间变成黑色
regin = np.array([[(0,660),(690,440),
(1200,700),(src.shape[1],660)]]) ~

大概意思就是取到的四个点形成的矩形区域,矩形区域需要框定图中的车道线,我所用到的图片大小是1280x720的,如果使用其他大小的图片可能会报错,以及车道线检测结果出现错误。需要根据自己用的实际图片更改自己的区域。

2、实线,虚线检测部分

#利用霍夫变换原理找出上图中的像素点组成的直线,然后画出来
rho = 1
theta = np.pi/180
threhold =15
minlength = 40
maxlengthgap = 20
lines = cv.HoughLinesP(src4,rho,theta,threhold,np.array([]),minlength,maxlengthgap)~

lefts =[]
rights =[]
leftlength=[]
rightlength=[]
for line  in lines:
    for x1,y1,x2,y2 in line:
        #cv.line(src5,(x1,y1),(x2,y2),linecolor,linewidth)
        #分左右车道
        k = (y2-y1)/(x2-x1)
        length= ((y2-y1)**2+(x2-x1)**2)**0.5#计算线段长度
        if k<0:
                lefts.append(line)
                leftlength.append(length)
        else:
                rights.append(line)
                rightlength.append(length)

if max(leftlength)>max(rightlength):
    text="The left-hand side is the solid line"
else:
    text="The right-hand side is the solid line"~

这里就是实线,虚线检测关键所在,本人自己想到的一个解决办法,思路就是根据直线的长度,长的为实线,短的为虚线。首先通过霍夫变换找到所有的直线,再根据找到的直线算出每个直线的长度,取出左右两边最长的直线进行比较,更长的一边就是实线了。代码实现起来非常简单。

附上我使用的图片
python+opencv车道线,实线虚线的检测_第1张图片python+opencv车道线,实线虚线的检测_第2张图片

你可能感兴趣的:(opencv,python)