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()
相关推荐
AI Echoes2 分钟前
构建一个LangChain RAG应用
数据库·python·langchain·prompt·agent
玩转单片机与嵌入式7 分钟前
在STM32F103单片机上跑通AI模型:为什么选正弦波作为Hello World?
人工智能·stm32·单片机
闲谈共视16 分钟前
基于去中心化社交与AI智能服务的Web钱包商业开发的可行性
前端·人工智能·去中心化·区块链
老马啸西风22 分钟前
成熟企业级技术平台-10-跳板机 / 堡垒机(Bastion Host)详解
人工智能·深度学习·算法·职场和发展
c#上位机29 分钟前
halcon求区域交集——intersection
图像处理·人工智能·计算机视觉·c#·halcon
派大鑫wink40 分钟前
从零到精通:Python 系统学习指南(附实战与资源)
开发语言·python
c骑着乌龟追兔子43 分钟前
Day 38 官方文档的阅读
python
TengTaiTech1 小时前
单芯片音频二分频新高度:全系列高通QCC平台智能分频方案解析
音视频
中冕—霍格沃兹软件开发测试1 小时前
探索性测试:思维驱动下的高效缺陷狩猎
人工智能·科技·开源·appium·bug
cnfalcon1 小时前
ESP-IDF AI硬件开发技术问题记录
人工智能·esp-idf