基于OpenCV Hough变换检测车道线后无法生成车道中心线问题求助
车道中心线检测实现方案
核心原理
直接取坐标中点失效的核心原因是HoughLinesP返回的是多条离散的短线段,不是规整的左右各一条完整车道线,因此需要先对所有检测到的线段做分组拟合,得到左右两条完整的车道线,再计算中心线。
具体实现步骤:
- 按斜率将所有线段分为左右车道线两组:图像坐标系y轴向下,左车道线斜率为负,右车道线斜率为正,同时过滤斜率绝对值过小的水平干扰线段
- 对每组线段的斜率、截距做平均,得到左右车道线的统一线性方程
y = mx + b - 固定车道线的纵向覆盖范围(从图像底部到感兴趣区域上边界),分别计算左右车道线在上下两个y坐标对应的x值,取两个位置的x中点作为中心线的两个端点,绘制中心线
完整修改后代码
import cv2 import numpy as np # 边缘检测函数 def canny(img): gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blur = cv2.GaussianBlur(gray, (5,5), 0) canny = cv2.Canny(blur, 50, 150) return canny # 感兴趣区域提取,顶点可根据视频分辨率自行调整 def region_of_interest(img): height = img.shape[0] width = img.shape[1] polygons = np.array([ [(200, height), (width/2, height/2 + 50), (width-200, height)] ]) mask = np.zeros_like(img) cv2.fillPoly(mask, np.int32([polygons]), 255) masked_img = cv2.bitwise_and(img, mask) return masked_img def houghLines(cropped_canny): return cv2.HoughLinesP(cropped_canny, 2, np.pi/180, 100, np.array([]), minLineLength=70, maxLineGap=5) def addWeighted(frame, line_image): return cv2.addWeighted(frame, 0.8, line_image, 1, 1) # 对检测到的离散线段做拟合,得到左右两条完整车道线 def average_slope_intercept(frame, lines): left_fit = [] right_fit = [] for line in lines: for x1, y1, x2, y2 in line: parameters = np.polyfit((x1, x2), (y1, y2), 1) slope = parameters[0] intercept = parameters[1] # 过滤斜率异常的干扰线段,阈值可根据实际场景调整 if slope < -0.5: left_fit.append((slope, intercept)) elif slope > 0.5: right_fit.append((slope, intercept)) left_fit_avg = np.average(left_fit, axis=0) if len(left_fit) > 0 else None right_fit_avg = np.average(right_fit, axis=0) if len(right_fit) > 0 else None # 将线性方程参数转换为线段端点坐标 def make_coordinates(img, line_params): slope, intercept = line_params y1 = img.shape[0] y2 = int(y1 * 0.6) # 车道线上边界,和ROI范围对齐即可 x1 = int((y1 - intercept)/slope) x2 = int((y2 - intercept)/slope) return np.array([x1, y1, x2, y2]) left_line = make_coordinates(frame, left_fit_avg) if left_fit_avg is not None else None right_line = make_coordinates(frame, right_fit_avg) if right_fit_avg is not None else None return np.array([left_line, right_line]) if left_line is not None and right_line is not None else None def display_lines(img, lines, center_line=None): line_image = np.zeros_like(img) # 绘制红色左右车道线 if lines is not None: for x1, y1, x2, y2 in lines: cv2.line(line_image,(x1,y1),(x2,y2),(0,0,255),5) # 绘制绿色中心线,颜色粗细可自行调整 if center_line is not None: cx1, cy1, cx2, cy2 = center_line cv2.line(line_image, (cx1, cy1), (cx2, cy2), (0,255,0), 5) return line_image cap = cv2.VideoCapture("videoplayback (online-video-cutter.com) (1).mp4") while(cap.isOpened()): ret, frame = cap.read() if not ret: break canny_image = canny(frame) cropped_canny = region_of_interest(canny_image) lines = houghLines(cropped_canny) averaged_lines = average_slope_intercept(frame, lines) center_line = None if averaged_lines is not None: left_line, right_line = averaged_lines # 计算中心线两个端点 cx1 = (left_line[0] + right_line[0]) // 2 cy1 = left_line[1] cx2 = (left_line[2] + right_line[2]) // 2 cy2 = left_line[3] center_line = np.array([cx1, cy1, cx2, cy2]) line_image = display_lines(frame, averaged_lines, center_line) combo_image = addWeighted(frame, line_image) cv2.imshow("result", combo_image) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()
调整说明
如果适配你的视频场景出现偏差,可调整以下参数:
- 斜率过滤阈值
-0.5、0.5,适配不同拍摄角度的车道线倾斜程度 - 感兴趣区域的多边形顶点、车道线上边界系数
0.6,和实际画面中车道的覆盖范围对齐
内容的提问来源于stack exchange,提问作者Awais Ghaffar
相关产品推荐
相关产品推荐

