基于python的车道线检测

时间:2025-05-06 08:22:37
from moviepy.editor import VideoFileClip import matplotlib.pyplot as plt import matplotlib.image as mplimg import numpy as np import cv2 blur_ksize = 5 # Gaussian blur kernel size canny_lthreshold = 50 # Canny edge detection low threshold canny_hthreshold = 150 # Canny edge detection high threshold # Hough transform parameters rho = 1#rho的步长,即直线到图像原点(0,0)点的距离 theta = np.pi / 180#theta的范围 threshold = 15#累加器中的值高于它时才认为是一条直线 min_line_length = 40#线的最短长度,比这个短的都被忽略 max_line_gap = 20#两条直线之间的最大间隔,小于此值,认为是一条直线 def roi_mask(img, vertices):#img是输入的图像,verticess是兴趣区的四个点的坐标(三维的数组) mask = np.zeros_like(img)#生成与输入图像相同大小的图像,并使用0填充,图像为黑色 #defining a 3 channel or 1 channel color to fill the mask with depending on the input image if len(img.shape) > 2: channel_count = img.shape[2] # . 3 or 4 depending on your image mask_color = (255,) * channel_count#如果 channel_count=3,则为(255,255,255) else: mask_color = 255 cv2.fillPoly(mask, vertices, mask_color)#使用白色填充多边形,形成蒙板 masked_img = cv2.bitwise_and(img, mask)#img&mask,经过此操作后,兴趣区域以外的部分被蒙住了,只留下兴趣区域的图像 return masked_img def draw_roi(img, vertices): cv2.polylines(img, vertices, True, [255, 0, 0], thickness=2) def draw_lines(img, lines, color=[255, 0, 0], thickness=2): for line in lines: for x1, y1, x2, y2 in line: cv2.line(img, (x1, y1), (x2, y2), color, thickness) def hough_lines(img, rho, theta, threshold, min_line_len, max_line_gap): lines = cv2.HoughLinesP(img, rho, theta, threshold, np.array([]), minLineLength=min_line_len, maxLineGap=max_line_gap)#函数输出的直接就是一组直线点的坐标位置(每条直线用两个点表示[x1,y1],[x2,y2]) line_img = np.zeros((img.shape[0], img.shape[1], 3), dtype=np.uint8)#生成绘制直线的绘图板,黑底 # draw_lines(line_img, lines) draw_lanes(line_img, lines) return line_img def draw_lanes(img, lines, color=[255, 0, 0], thickness=8): left_lines, right_lines = [], []#用于存储左边和右边的直线 for line in lines:#对直线进行分类 for x1, y1, x2, y2 in line: k = (y2 - y1) / (x2 - x1) if k < 0: left_lines.append(line) else: right_lines.append(line) if (len(left_lines) <= 0 or len(right_lines) <= 0): return img clean_lines(left_lines, 0.1)#弹出左侧不满足斜率要求的直线 clean_lines(right_lines, 0.1)#弹出右侧不满足斜率要求的直线 left_points = [(x1, y1) for line in left_lines for x1,y1,x2,y2 in line]#提取左侧直线族中的所有的第一个点 left_points = left_points + [(x2, y2) for line in left_lines for x1,y1,x2,y2 in line]#提取左侧直线族中的所有的第二个点 right_points = [(x1, y1) for line in right_lines for x1,y1,x2,y2 in line]#提取右侧直线族中的所有的第一个点 right_points = right_points + [(x2, y2) for line in right_lines for x1,y1,x2,y2 in line]#提取右侧侧直线族中的所有的第二个点 left_vtx = calc_lane_vertices(left_points, 325, img.shape[0])#拟合点集,生成直线表达式,并计算左侧直线在图像中的两个端点的坐标 right_vtx = calc_lane_vertices(right_points, 325, img.shape[0])#拟合点集,生成直线表达式,并计算右侧直线在图像中的两个端点的坐标 cv2.line(img, left_vtx[0], left_vtx[1], color, thickness)#画出直线 cv2.line(img, right_vtx[0], right_vtx[1], color, thickness)#画出直线 #将不满足斜率要求的直线弹出 def clean_lines(lines, threshold): slope=[] for line in lines: for x1,y1,x2,y2 in line: k=(y2-y1)/(x2-x1) slope.append(k) #slope = [(y2 - y1) / (x2 - x1) for line in lines for x1, y1, x2, 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] > threshold:#将差值大于阈值的直线弹出 slope.pop(idx)#弹出斜率 lines.pop(idx)#弹出直线 else: break #拟合点集,生成直线表达式,并计算直线在图像中的两个端点的坐标 def calc_lane_vertices(point_list, ymin, ymax): x = [p[0] for p in point_list]#提取x y = [p[1] for p in point_list]#提取y fit = np.polyfit(y, x, 1)#用一次多项式x=a*y+b拟合这些点,fit是(a,b) fit_fn = np.poly1d(fit)#生成多项式对象a*y+b xmin = int(fit_fn(ymin))#计算这条直线在图像中最左侧的横坐标 xmax = int(fit_fn(ymax))#计算这条直线在图像中最右侧的横坐标 return [(xmin, ymin), (xmax, ymax)] def process_an_image(img): roi_vtx = np.array([[(0, img.shape[0]), (460, 325), (520, 325), (img.shape[1], img.shape[0])]])#目标区域的四个点坐标,roi_vtx是一个三维的数组 gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)#图像转换为灰度图 blur_gray = cv2.GaussianBlur(gray, (blur_ksize, blur_ksize), 0, 0)#使用高斯模糊去噪声 edges = cv2.Canny(blur_gray, canny_lthreshold, canny_hthreshold)#使用Canny进行边缘检测 roi_edges = roi_mask(edges, roi_vtx)#对边缘检测的图像生成图像蒙板,去掉不感兴趣的区域,保留兴趣区 line_img = hough_lines(roi_edges, rho, theta, threshold, min_line_length, max_line_gap)#使用霍夫直线检测,并且绘制直线 res_img = cv2.addWeighted(img, 0.8, line_img, 1, 0)#将处理后的图像与原图做融合 return res_img img = mplimg.imread("") print("start to process the image....") res_img=process_an_image(img) print("show you the image....") plt.imshow(res_img) plt.show() print("start to process the video....") output = 'video_2_xlt.mp4'#ouput video clip = VideoFileClip("video_2.mp4")#input video out_clip = clip.fl_image(process_an_image)#对视频的每一帧进行处理 out_clip.write_videofile(output, audio=True)#将处理后的视频写入新的视频文件