OpenCV+ moviepy + tkinter 视频车道线智能识别项目源码

项目完整源代码,使用 OpenCV 的Hough 直线检测算法,提取出道路车道线并绘制出来。通过tkinter 提供GUI界面展示效果。

1、导入相关模块

py 复制代码
import matplotlib.pyplot as plt
import numpy as np
import cv2
import os
import matplotlib.image as mpimg
from moviepy.editor import VideoFileClip
import math

2. 用掩码获取ROI区域

python 复制代码
def interested_region(img, vertices):
    if len(img.shape) > 2: 
        mask_color_ignore = (255,) * img.shape[2]
    else:
        mask_color_ignore = 255
        
    cv2.fillPoly(np.zeros_like(img), vertices, mask_color_ignore)
    return cv2.bitwise_and(img, np.zeros_like(img))

3、Hough变换空间, 转换像素到直线

py 复制代码
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)
    line_img = np.zeros((img.shape[0], img.shape[1], 3), dtype=np.uint8)
    lines_drawn(line_img,lines)
    return line_img

4、在Hough变换后,每帧增加两条线

py 复制代码
def lines_drawn(img, lines, color=[255, 0, 0], thickness=6):
    global cache
    global first_frame
    slope_l, slope_r = [],[]
    lane_l,lane_r = [],[]

    α =0.2        # 希腊字母阿尔法
    for line in lines:
        for x1,y1,x2,y2 in line:
            slope = (y2-y1)/(x2-x1)
            if slope > 0.4:
                slope_r.append(slope)
                lane_r.append(line)
            elif slope < -0.4:
                slope_l.append(slope)
                lane_l.append(line)
        img.shape[0] = min(y1,y2,img.shape[0])
    if((len(lane_l) == 0) or (len(lane_r) == 0)):
        print ('no lane detected')
        return 1
    slope_mean_l = np.mean(slope_l,axis =0)
    slope_mean_r = np.mean(slope_r,axis =0)
    mean_l = np.mean(np.array(lane_l),axis=0)
    mean_r = np.mean(np.array(lane_r),axis=0)
    
    if ((slope_mean_r == 0) or (slope_mean_l == 0 )):
        print('dividing by zero')
        return 1
    
    x1_l = int((img.shape[0] - mean_l[0][1] - (slope_mean_l * mean_l[0][0]))/slope_mean_l) 
    x2_l = int((img.shape[0] - mean_l[0][1] - (slope_mean_l * mean_l[0][0]))/slope_mean_l)   
    x1_r = int((img.shape[0] - mean_r[0][1] - (slope_mean_r * mean_r[0][0]))/slope_mean_r)
    x2_r = int((img.shape[0] - mean_r[0][1] - (slope_mean_r * mean_r[0][0]))/slope_mean_r)
    
   
    if x1_l > x1_r:
        x1_l = int((x1_l+x1_r)/2)
        x1_r = x1_l
        y1_l = int((slope_mean_l * x1_l ) + mean_l[0][1] - (slope_mean_l * mean_l[0][0]))
        y1_r = int((slope_mean_r * x1_r ) + mean_r[0][1] - (slope_mean_r * mean_r[0][0]))
        y2_l = int((slope_mean_l * x2_l ) + mean_l[0][1] - (slope_mean_l * mean_l[0][0]))
        y2_r = int((slope_mean_r * x2_r ) + mean_r[0][1] - (slope_mean_r * mean_r[0][0]))
    else:
        y1_l = img.shape[0]
        y2_l = img.shape[0]
        y1_r = img.shape[0]
        y2_r = img.shape[0]
      
    present_frame = np.array([x1_l,y1_l,x2_l,y2_l,x1_r,y1_r,x2_r,y2_r],dtype ="float32")
    
    if first_frame == 1:
        next_frame = present_frame        
        first_frame = 0        
    else :
        prev_frame = cache
        next_frame = (1-α)*prev_frame+α*present_frame
             
    cv2.line(img, (int(next_frame[0]), int(next_frame[1])), (int(next_frame[2]),int(next_frame[3])), color, thickness)
    cv2.line(img, (int(next_frame[4]), int(next_frame[5])), (int(next_frame[6]),int(next_frame[7])), color, thickness)
    
    cache = next_frame
    

5、处理每帧画面

python 复制代码
def weighted_img(img, initial_img, α=0.8, β=1., λ=0.):
    return cv2.addWeighted(initial_img, α, img, β, λ)


def process_image(image):

    global first_frame

    gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    img_hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)


    lower_yellow = np.array([20, 100, 100], dtype = "uint8")
    upper_yellow = np.array([30, 255, 255], dtype="uint8")

    mask_yellow = cv2.inRange(img_hsv, lower_yellow, upper_yellow)
    mask_white = cv2.inRange(gray_image, 200, 255)
    mask_yw = cv2.bitwise_or(mask_white, mask_yellow)
    mask_yw_image = cv2.bitwise_and(gray_image, mask_yw)
	# gause blue 
    gauss_gray= cv2.GaussianBlur(mask_yw_image, (5, 5), 0)
	# detect edge
    canny_edges=cv2.Canny(gauss_gray, 50, 150,apertureSize=3)

    imshape = image.shape
    lower_left = [imshape[1]/9,imshape[0]]
    lower_right = [imshape[1]-imshape[1]/9,imshape[0]]
    top_left = [imshape[1]/2-imshape[1]/8,imshape[0]/2+imshape[0]/10]
    top_right = [imshape[1]/2+imshape[1]/8,imshape[0]/2+imshape[0]/10]
    vertices = [np.array([lower_left,top_left,top_right,lower_right],dtype=np.int32)]
    roi_image = interested_region(canny_edges, vertices)

    theta = np.pi/180

    line_image = hough_lines(roi_image, 4, theta, 30, 100, 180)
    result = weighted_img(line_image, image, α=0.8, β=1., λ=0.)
    return result

:

6、用moviepy的videofileClip 读出视频,调用process_image方法处理后保存至文件

py 复制代码
first_frame = 1
white_output = '__path_to_output_file__'
clip1 = VideoFileClip("__path_to_input_file__")
new_clip = clip1.fl_image(process_image)
new_clip.write_videofile(white_output, audio=False)  

7、用tkinter编写车道线检测项目的GUI图形界面

py 复制代码
import tkinter as tk
from tkinter import *
import cv2
from PIL import Image, ImageTk
import os
import numpy as np

global last_frame1                                   
last_frame1 = np.zeros((480, 640, 3), dtype=np.uint8)
global last_frame2                                      
last_frame2 = np.zeros((480, 640, 3), dtype=np.uint8)
global cap1
global cap2
cap_input = cv2.VideoCapture("path_to_input_test_video")
cap_drawlane = cv2.VideoCapture("path_to_resultant_lane_detected_video")

def show_input_video():                                       
    if not cap_input.isOpened():                             
        print("无法打开原始视频")
    flag1, frame1 = cap_input.read()
    frame1 = cv2.resize(frame1,(400,500))
    if flag1 is None:
        print ("原视频读帧错误")
    elif flag1:
        global last_frame1
        last_frame1 = frame1.copy()
        pic = cv2.cvtColor(last_frame1, cv2.COLOR_BGR2RGB)     
        img = Image.fromarray(pic)
        imgtk = ImageTk.PhotoImage(image=img)
        lmain.imgtk = imgtk
        lmain.configure(image=imgtk)
        lmain.after(10, show_input_video)


def show_drawlane_video():
    if not cap_drawlane.isOpened():                             
        print("无法打开车道线视频")
    flag2, frame2 = cap_drawlane.read()
    frame2 = cv2.resize(frame2,(400,500))
    if flag2 is None:
        print ("车道线视频读帧错误")
    elif flag2:
        global last_frame2
        last_frame2 = frame2.copy()
        pic2 = cv2.cvtColor(last_frame2, cv2.COLOR_BGR2RGB)
        img2 = Image.fromarray(pic2)
        img2tk = ImageTk.PhotoImage(image=img2)
        lmain2.img2tk = img2tk
        lmain2.configure(image=img2tk)
        lmain2.after(10, show_drawlane_video)

if __name__ == '__main__':
    root=tk.Tk()                                     
    lmain = tk.Label(master=root)
    lmain2 = tk.Label(master=root)

    lmain.pack(side = LEFT)
    lmain2.pack(side = RIGHT)
    root.title("车道线检测")            
    root.geometry("900x700+100+10") 
    exitbutton = Button(root, text='退出',fg="red",command=   root.destroy).pack(side = BOTTOM,)
    show_input_video()
    show_drawlane_video()
    root.mainloop()                                  
    cap.release()
相关推荐
金銀銅鐵4 分钟前
[Python] 基于欧几里得算法,实现分数约分计算器
python·数学
冬奇Lab2 小时前
Workflow 系列(03):状态管理——持久化、幂等性与版本绑定
人工智能·工作流引擎
Lyn_Li2 小时前
Kaggle Top 5 | 198只股票、200条数据的金融预测——BattleFin高分方案从零复现
python·kaggle·比赛复盘·金融预测
冬奇Lab2 小时前
每日一个开源项目(第146篇):openpilot - 开源自动驾驶辅助系统,曾在 Consumer Reports 评测中超过特斯拉 Autopilot
人工智能·开源·自动驾驶
吴佳浩3 小时前
AI 工程师知识地图:模型格式、框架、部署工具一次讲明白
人工智能·aigc·ai编程
IT_陈寒4 小时前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
码农胖大海4 小时前
AI额度不够用的解决方案
人工智能
后端小肥肠4 小时前
小红书虚拟商品怎么做?我先用 Skill 跑通了壁纸品类
人工智能·aigc·agent
feiyu_gao4 小时前
从零搭建个人 AI 工作台:一个管理者的 3 个月实验
人工智能·aigc·团队管理