基于传统方法的车道线检测

1.canny边缘检测

基本原理:检测亮度的急剧变化(大梯度 比如从白色到黑色)在给定阈值下定义为边

预处理:转换灰度图

Canny:
  • 降噪:噪声容易导致误检,用 5*5 的高斯滤波器(正太分布核)对图像做卷积(平滑图像) [Canny自带]
  • 求亮度梯度:在平滑的图像上用 Sobel/Roberts/Prewitt 核沿 x 轴和 y 轴检测边缘是水平/垂直/对角线
  • 非极大值抑制:细化边缘。检查每个像素值在先前计算的梯度方向上是否为局部最大值(相比B,C如果A是局部最大则在下一个点上检查非极大值抑制否则将 A 的像素值设置为 0 并抑制A
  • hysteresis thresholding:非极大值抑制后可以确认强像素在最终边缘映射中。但还要对弱像素进行进一步分析确定它是边缘还是噪声。 a) 梯度> maxVal 的是边缘 b) < minVal 的不是边缘并将其删除 c) 梯度在[minVal, maxVal] 的像素只有在和梯度高于 maxVal 的像素相连时才是边缘
def do_canny(frame):
    gray = cv.cvtColor(frame, cv.COLOR_RGB2GRAY)
    blur = cv.GaussianBlur(gray, (5,5),0)
    canny = cv.Canny(blur,50,150)
    return canny

2.手动分割路面区域、

手动指定一个三角形来分割出路面区域,去除其他干扰边缘

def do_segment(frame):
    height = frame.shape[0]
    polygons = np.array([
    [(0,height), (800,height),(380,290)]
    ])//对应三个点
    mask = np.zeros_like(frame)//生成一张图片,只不过所有值都是0
    cv.fillPoly(mask, polygons, 255) //将三个点围城区域填充为255,其余还是0 ,实际就是掩码
    segment = cv.bitwise_and(frame,mask)//比特位的与操作 255实际就是8比特位为1然后与原像素进行比特位的与操作,就会保留原来像素的值
    return segment

3.霍夫变换得到车道线

hough = cv.HoughLinesP(segment, 2, np.pi / 180,100, np.array([]), minLineLength = 100, maxLineGap = 50)

霍夫变换如何帮助我们找到线?

  • 将笛卡尔坐标系中一系列可能被连成线的点 -> 该点在霍夫空间中对应的线

  • 找到霍夫空间中的交点(m,b)就是那条线的方程

  • 特殊情况:线垂直时梯度无穷大,无法在霍夫空间中表示出来。为了解决这个问题,我们在笛卡尔坐标系中用极坐标法表示直线。对应到霍夫空间也做对应变化。


  • 霍夫空间中相交的曲线越多,交点表示的线在笛卡尔坐标系对应的点越多。我们在霍夫空间中定义交点的最小阈值来检测线。霍夫变换跟踪了帧中的每个点的霍夫空间交点。如果交点数量超过了阈值就确定一条对应参数 θ 和 d的线。


4.获取车道线并叠加到原始图像中

综合所有线,求得两条车道线的平均斜率和截距

def calculate_line(frame, lines):
    left = []
    right = []
    for line in lines:
        x1,y1,x2,y2 = line.reshape(4) # reshape line from 2d to 1d
        parameters = np.polyfit((x1,x2),(y1,y2),1) # 拟合一条直线返回系数
        slope = parameters[0] #斜率
        y_intercept = parameters[1]
        if slope < 0:
            left.append((slope,y_intercept))
        else:
            right.append((slope,y_intercept))

    left_avg = np.average(left,axis = 0)
    right_avg = np.average(right, axis = 0)
    left_line = calculate_coordinates(frame,left_avg)
    right_line = calculate_coordinates(frame,right_avg)
    return np.array([left_line, right_line])
运行程序
cap = cv.VideoCapture("input.mp4")
while (cap.isOpened()):
    # ret = a boolean return value from getting the frame, frame = the current frame being projected in the video
    ret, frame = cap.read()
    canny = do_canny(frame) #canny边缘检测
    cv.imshow("canny", canny)
    # plt.imshow(frame)
    # plt.show()
    segment = do_segment(canny)  #手工分割
    hough = cv.HoughLinesP(segment, 2, np.pi / 180, 100, np.array([]), minLineLength = 100, maxLineGap = 50) #霍夫变换,确定车道线
    # Averages multiple detected lines from hough into one line for left border of lane and one line for right border of lane
    lines = calculate_lines(frame, hough) 
    # Visualizes the lines
    lines_visualize = visualize_lines(frame, lines) #显示车道线
    cv.imshow("hough", lines_visualize)
    # Overlays lines on frame by taking their weighted sums and adding an arbitrary scalar value of 1 as the gamma argument
    output = cv.addWeighted(frame, 0.9, lines_visualize, 1, 1) #车道和原始图片叠加
    # Opens a new window and displays the output frame
    cv.imshow("output", output)
    # Frames are read by intervals of 10 milliseconds. The programs breaks out of the while loop when the user presses the 'q' key
    if cv.waitKey(10) & 0xFF == ord('q'):
        break
# The following frees up resources and closes all windows
cap.release()
cv.destroyAllWindows()

效果图如下



你可能感兴趣的:(基于传统方法的车道线检测)