车道线拟合代码

    科技2022-07-21  109

    代码

    import cv2 import numpy as np def find_line_fit(img, name = "default" ,nwindows=9, margin=100, minpix=50 , minLane = 50): ''' Args: img: 传入的灰度图像 name: 图像的名字,当处理视屏流的时候,有些图像没法拟合可以用异常来报错提示那一帧出了问题 nwindows: 将图像纵向切割的窗口个数 margin: 滑动窗口的宽 minpix: 如果滑动窗口中像素个数大于设定的这个阈值,则将下一次滑动窗口的中心设为这次白色像素的水平方向的均值处 minLane: 如果当前直方图的最大值小于这个阈值,则这次的滑动窗口中心设置成上一次的值 Returns: left_fit:左车道线的二阶函数式系数 right_fit:右车道线的二阶函数式系数 ''' # 拷贝一份为了教学显示,不可直接画在原图上,画的线是白色的会有影响 img2show = img.copy() # 初始化获取图片的中间作为左右分割线,如果处理视屏流可以使用上一次计算的左右车道线的中心赋给这个值 midpoint = np.int(img.shape[1]/2) # 计算窗口的高度 window_height = np.int(img.shape[0]/nwindows) # 获取所有白色像素的位置 nonzero = img.nonzero() nonzeroy = np.array(nonzero[0]) nonzerox = np.array(nonzero[1]) # 用来存左右车道线的列表 left_lane_inds = [] right_lane_inds = [] # 用来存图片长宽 h = [0,img.shape[0]] w = [0,img.shape[1]] # 用来存滑动窗口的位置 leftx_current = w[0] rightx_current = w[1] # 遍历窗口 for window in range(nwindows): # 计算窗口纵向的起始结束位置 start = h[1] - int(h[0] + (h[1] - h[0]) * window / nwindows) end = h[1] - int(h[0] + (h[1] - h[0]) * (window + 1) / nwindows) cv2.line(img2show, (0, start), (w[1], start), (255, 255, 255)) cv2.line(img2show, (0, end), (w[1], end), (255, 255, 255)) # 计算当前窗口的直方图 histogram = np.sum(img[end:start,w[0]:w[1]], axis=0) # 获取中间线左侧的直方图最大值作为滑动窗口的中心 leftx_current = np.argmax(histogram[:midpoint]) if np.argmax(histogram[:midpoint]) > minLane else leftx_current # 获取中间线右侧的直方图最大值作为滑动窗口的中心 rightx_current = np.argmax(histogram[midpoint:]) + midpoint if np.argmax(histogram[midpoint:]) > minLane else rightx_current # 以刚获取的中心创建margin参数为宽的滑动窗口 win_y_low = img.shape[0] - (window+1)*window_height win_y_high = img.shape[0] - window*window_height win_xleft_low = leftx_current - margin win_xleft_high = leftx_current + margin win_xright_low = rightx_current - margin win_xright_high = rightx_current + margin # 绘制滑动窗口 cv2.rectangle(img2show,(win_xleft_low,win_y_low),(win_xleft_high,win_y_high), (255,255,255), 2) cv2.rectangle(img2show,(win_xright_low,win_y_low),(win_xright_high,win_y_high), (255,255,255), 2) cv2.imshow("rec",img2show) cv2.waitKey(2000) # 找到滑动窗口中的白色像素 good_left_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) & (nonzerox >= win_xleft_low) & (nonzerox < win_xleft_high)).nonzero()[0] good_right_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) & (nonzerox >= win_xright_low) & (nonzerox < win_xright_high)).nonzero()[0] # 将这些像素添加到事先准备的列表中 left_lane_inds.append(good_left_inds) right_lane_inds.append(good_right_inds) # 如果像素个数大于设定的阈值,则将下一次滑动窗口的中心设为这次白色像素的水平方向的均值处 if len(good_left_inds) > minpix: leftx_current = np.int(np.mean(nonzerox[good_left_inds])) if len(good_right_inds) > minpix: rightx_current = np.int(np.mean(nonzerox[good_right_inds])) # 连接索引数组,就是把每一层的滑动窗口中读取的白色都存到left_lane_inds中 left_lane_inds = np.concatenate(left_lane_inds) right_lane_inds = np.concatenate(right_lane_inds) # 获取白色的x,y leftx = nonzerox[left_lane_inds] lefty = nonzeroy[left_lane_inds] rightx = nonzerox[right_lane_inds] righty = nonzeroy[right_lane_inds] cv2.imwrite("result.png",img2show) # 用二阶函数式拟合得到公式 try: left_fit = np.polyfit(lefty, leftx, 2) right_fit = np.polyfit(righty, rightx, 2) except: print("error:" + name) return [0,0,0],[0,0,0] return left_fit, right_fit if __name__ == '__main__': imgName = "line.png" img = cv2.imread(imgName) gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) find_line_fit(gray,name = imgName)

    使用的图片

    运行方式

    将图片和代码保存本地,代码命名fitLine.py,图片命名line.png。然后将图片和代码处于同一文件夹下,执行以下命令运行代码:

    python fitLine.py

    运行结果

    Processed: 0.009, SQL: 8