车道线检测:ultra fast lane detection + 车道保持

车道线检测

ECCV2020年的一篇车道线检测论文,花了两天把这个跑通了。
作者源码地址:https://github.com/cfzd/Ultra-Fast-Lane-Detection
逛B站发现有人把这个做成APP了,免费下载,但许多功能应该是要加作者收费的:https://www.bilibili.com/video/BV1xv411e7zJ?from=search&seid=8046378059587725929

链接:https://pan.baidu.com/s/1D1DFdraWbbvZphkVknNTVQ
提取码:g5rp

错误更新

今天突然来了灵感,在最后一步用车道线拟合的时候用到了函数:fl = np.polyfit(lx, ly, 2)
fr = np.polyfit(rx, ry, 2),这个是用来构建曲线一元二次方程组,也就是拟合出来的车道线,但是图片的坐标原点是在左上角,而我们平常的坐标系的原点是在左下角,所以在拟合的时候要把横纵坐标点换一下变为fl = np.polyfit(ly, lx, 2)fr = np.polyfit(ry, rx, 2) 这样拟合出来的曲线才是以左上角为原点的车道线曲线,这样跑出来的结果就准确多了。

在这里插入图片描述

##############################################################################################################################################

作者提供了两个训练好的模型CULane.pth和Tusimple.pth,大概看了一下,tusimple的模型输入大概为1280x720,比较符合常用的视频大小,所以检测用的模型全部为tusimple模型,可以直接按照源码进行检测。
原码文件感觉太多,我把没用的文件全删了,只留下了检测图片文件demo.py,并额外加了一个视频检测的脚本文件video_demo.py
在这里插入图片描述
检测视频效果感觉一般吧,用别的视频检测,最后拟合的线飘起来了,但勉强够用。
在这里插入图片描述

车道保持

车道线点筛选

上一步检测出车道线的点,并且将其画在原图上,但是做车道保持只需要考虑面前一定区域范围内的车道线就可以了,因此对上一步的结果进行点的筛选,把多余的点去掉,只留下ROI区域的。

def is_in_poly(p, poly):
    """
    对点进行筛选,选出符合ROI特定区域内的点
    :param p: 待判断的点坐标, [x, y]
    :param poly: 多边形顶点,[[x1,y1], [x2,y2], [x3,y3], [x4,y4], ...]
    return: is_in若为True,则说明点在ROI区域,保留,反之则删除。
    """
    px, py = p[0],p[1]
    is_in = False
    for i, corner in enumerate(poly):
        # len(poly) = 4    next_i=(0,1,2,3,0,1,2......)
        next_i = i + 1 if i + 1 < len(poly) else 0
        x1, y1 = corner
        x2, y2 = poly[next_i]
        if (x1 == px and y1 == py) or (x2 == px and y2 == py):  # if point is on vertex
            is_in = True
            break
        if min(y1, y2) < py <= max(y1, y2):  # 判断y是否处于y1与y2之间
            x = x1 + (py - y1) * (x2 - x1) / (y2 - y1)
            if x == px:  # if point is on edge
                is_in = True
                break
            elif x > px:  # if point is on left-side of line
                is_in = True
    return is_in
lane_x=[]
lane_y=[]
is_in = is_in_poly(ppp,poly)
if is_in==True:
	# 将处理后的点坐标添如一个空列表做拟合用
	lane_x.append(ppp[0])
	lane_y.append(ppp[1])
	cv2.circle(frame, ppp, 5, (0, 255, 0), -1)

车道线坐标点排序

上面经过点的筛选之后,其排列是比较混乱的,因此需要根据x坐标将车道线离散点按升序进行排列,并计算其x坐标之间的最大间隔,这样可以分出左右车道线,为后面车道线拟合做准备。

def handle_point(x, y):
    """
    根据x的大小对 x,y 进行排序。再找到最大间隔,并据此把控制点分成两部分。
    return: 返回的是左车道线的x,y坐标以及右车道线x,y的坐标
    """
    lx = [] # 存储左车道线x坐标
    ly = [] # 存储左车道线y坐标
    rx = [] # 存储右车道线x坐标
    ry = [] # 存储右车道线y坐标
    points = zip(x, y)
    # 从小到大排序
    sorted_points = sorted(points)
    x = [point[0] for point in sorted_points]
    y = [point[1] for point in sorted_points]
    # 分割
    Max = 0
    k = 0
    # 找出x坐标最大间隔,分出左车道和右车道
    for i in range(len(x) - 1):
        # 计算欧几里得距离
        d = np.int(math.hypot(x[i + 1] - x[i], y[i + 1] - y[i]))
        if d > Max:
            Max = d
            k = i
    for i in range(len(x)):
        # 坐车道点
        if i < k + 1:
            lx.append(x[i])
            ly.append(y[i])
        # 右车道点
        else:
            rx.append(x[i])
            ry.append(y[i])
    return lx, ly, rx, ry
lx, ly, rx, ry = handle_point(lane_x, lane_y)

拟合车道线+曲率/偏移距离计算

对上面排序好的左右车道点x,y进行二项式拟合,拟合为一条抛物线。通过拟合出的曲线计算其曲线曲率和车辆偏移距离

def poly_fitting(lx, ly, rx, ry):
    """
    分别对两部分控制点进行二次多项式拟合
    """
    lx = np.array(lx)
    ly = np.array(ly)
    rx = np.array(rx)
    ry = np.array(ry)
    fl = np.polyfit(lx, ly, 2)  # 用2次多项式拟合
    fr = np.polyfit(rx, ry, 2)  # 用2次多项式拟合

    ploty = np.linspace(0, 719, 720)
    leftx = fl[0]*ploty**2 + fl[1]*ploty + fl[2]
    rightx = fr[0]*ploty**2 + fr[1]*ploty + fr[2]
    # 定义从像素空间到米的x和y转换
    ym_per_pix = 30/720  # meters per pixel in y dimension
    xm_per_pix = 3.7/700  # meters per pixel in x dimension
    y_eval = np.max(ploty) # 719

    # 将新多项式拟合到世界空间中的x,y
    left_fit_cr = np.polyfit(ploty*ym_per_pix, leftx*xm_per_pix, 2)
    right_fit_cr = np.polyfit(ploty*ym_per_pix, rightx*xm_per_pix, 2)

    # 计算新的曲率半径
    left_curverad = ((1 + (2*left_fit_cr[0]*y_eval*ym_per_pix + left_fit_cr[1])**2)**1.5) / np.absolute(2*left_fit_cr[0])
    right_curverad = ((1 + (2*right_fit_cr[0]*y_eval*ym_per_pix + right_fit_cr[1])**2)**1.5) / np.absolute(2*right_fit_cr[0])
    curvature = ((left_curverad + right_curverad) / 2)  # 曲率

    lane_width = np.absolute(leftx[719] - rightx[719])
    lane_xm_per_pix = 3.7 / lane_width
    # 车辆应该保持偏移的距离
    veh_pos = (((leftx[719] + rightx[719]) * lane_xm_per_pix) / 2.)
    # 当前车辆偏移的距离
    cen_pos = ((cap.get(3) * lane_xm_per_pix) / 2.)
    # 计算车辆偏移距离
    distance_from_center = cen_pos - veh_pos
    return curvature, distance_from_center
def draw_values(img,curvature,distance_from_center):
    """
    将曲率和车道偏移距离里显示在图片上
    """
    font = cv2.FONT_HERSHEY_SIMPLEX
    radius_text = "Radius of Curvature: %sm"%(round(curvature))
    if distance_from_center>0:
        pos_flag = 'right'
    else:
        pos_flag= 'left'
    cv2.putText(img,radius_text,(100,100), font, 1,(255,255,255),2)
    center_text = "Vehicle is %.3fm %s of center"%(abs(distance_from_center),pos_flag)
    cv2.putText(img,center_text,(100,150), font, 1,(255,255,255),2)
    return img
curvature, distance_from_center = poly_fitting(lx, ly, rx, ry)
draw_values(frame,curvature,distance_from_center)

在这里插入图片描述

总结

结果感觉有误差,感觉原因可能如下(还有待验证):
1、摄像头的分辨率不同,安装在车辆位置、高低不同对结果影响不同,在进行视频采集时最好将摄像头固定在某一处,且分辨率相同(1280,720最佳),然后对程序进行特定的修改。
2、在筛选车道线离散点的时候,需要手动建立一个掩膜(矩阵)来删除多余的离散点。掩膜的选取要根据实际情况(不同的输入图像)进行调整,效果更佳。
3、在计算曲率的时候,会有计算像素空间到x/y方向上米/厘米的转换,最好可以进行实际采集,计算每个像素点对应多少米。

参考:
opencv+python 图片中离散点的车道线拟合
python判断平面内一个点是否在多边形内
https://github.com/linghugoogle/CarND-Advanced-Lane-Lines

  • 23
    点赞
  • 135
    收藏
    觉得还不错? 一键收藏
  • 52
    评论
评论 52
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值