jjzjj

基于YOLOv5+Hough变换的目标检测和车道线检测

Fr0mdeepsea 2023-09-22 原文

这学期做的一个大作业,实现了对行驶过程中车辆、行人以及车道线的检测。

1.B站视频演示
2.Github仓库链接

文章目录


一、实现效果

第一个是其他车道线检测里拿的视频素材,第二个是b站中国街景的驾车实拍视频。

主要的检测流程是:

  1. 选择一段你喜欢的路况视频,按帧分解为图片(提供视频帧分解程序mp4tofigure.py
  2. 图片预处理,设定Canny高低阈值以及ROI标定(提供动态调整Canny高低阈值的辅助程序 Canny_check.py,交互式ROI标定的辅助程序roi_setup.py
  3. 送入主程序main.py,进行目标检测和车道线检测。
  4. 检测结果为图片,可以转换成视频(提供导出视频程序figure2video.py


二、环境配置

一个可以运行YOLOv5的python环境,与之前的一篇博客Realsense D435i Yolov5目标检测实时获得目标三维位置信息差不多。
仓库结构

三、基于YOLOv5的目标检测

这部分没啥特别的,就是套YOLOv5框架。不过由于原版的YOLOv5代码过于冗长,为后期与车道线检测的代码相结合,对YOLOv5源代码进行适当的简化封装,将检测过程基于一个封装的函数实现,如下所示。Canvas为返回的图像矩阵,class_id_list为检测到类的id列表,xyxy_list为检测框的角点位置像素坐标,conf_list为置信度列表。

canvas, class_id_list, xyxy_list, conf_list = model.detect(color_image)

选用YOLOv5s权重,其中前八类为为交通相关。
['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light']
效果如下

四、基于Hough变换的车道线检测

基于Hough变换的车道线检测流程为:输入图片——Canny轮廓检测——设定ROI——Hough变换提取直线——结果信息绘制。

4.1 前置工作 Canny阈值设定

首先需要调整一下Canny的阈值,使得轮廓检测出来的车道线连续平滑。
这里提供一个可以动态调整Canny高低阈值的辅助程序 Canny_check.py

import cv2
para=[300,400]
def nothing(*arg):
    pass
cv2.namedWindow('Trackbar')
cv2.resizeWindow('Trackbar', 400, 100)
cv2.createTrackbar('low', 'Trackbar', para[0], 1000, nothing)
cv2.createTrackbar('high', 'Trackbar', para[1], 1000, nothing)

source=cv2.imread("test.jpg")
img=source.copy()
cv2.namedWindow("canny", 0)
while(1):
    img = source.copy()
    low = cv2.getTrackbarPos('low', 'Trackbar')
    high = cv2.getTrackbarPos('high', 'Trackbar')
    img = cv2.Canny(img, low, high)
    cv2.imshow("canny", img)
    cv2.waitKey(20)

4.2 前置工作 ROI标定

接着需要标定出车道线检测范围的ROI
这里提供一个交互式ROI标定的辅助程序roi_setup.py,按顺时针顺序左键进行像素标定,右键完成像素点连接,中键清除所有标记,最终可以导出标定结果。

import cv2
import numpy as np

def mouse(event, x, y, flags, param):
    img1 = img.copy()
    if event == cv2.EVENT_LBUTTONDOWN:

        x_list.append(x)
        y_list.append(y)
        # print(x_list)
        for i in range(len(x_list)):
            xy = "(%d,%d)" % (x_list[i], y_list[i])
            cv2.circle(img1, (x_list[i], y_list[i]), 1, (0, 0, 255), thickness=2)
            cv2.putText(img1, xy, (x_list[i], y_list[i]), cv2.FONT_HERSHEY_PLAIN, 2, (0, 0, 255), thickness=2)
        cv2.imshow("image", img1)  # 显示坐标
    if event == cv2.EVENT_RBUTTONDOWN:
        for i in range(len(x_list)-1):
            cv2.line(img1, [x_list[i],y_list[i]] ,[x_list[i+1],y_list[i+1]],(0,0,255),thickness=2)
        cv2.line(img1, [x_list[-1], y_list[-1]], [x_list[0], y_list[0]], (0, 0, 255), thickness=2)
        cv2.imshow("image", img1)
    if event == cv2.EVENT_MBUTTONDOWN:
        img1 = img.copy()
        cv2.imshow("image", img1)
        x_list.clear()
        y_list.clear()


def get_coordinate_by_click(img_path):
    global img
    img = cv2.imread(img_path)  # 图片路径
    cv2.namedWindow("image", 0)  # 设置窗口标题和大小
    cv2.setMouseCallback("image", mouse)
    cv2.imshow("image", img)
    cv2.waitKey(0)
    print("x坐标:",x_list)
    print("y坐标:",y_list)
    cv2.destroyAllWindows()


if __name__ == '__main__':
    x_list=[]
    y_list=[]
    img_path = r'./figure/2/1.jpg'
    get_coordinate_by_click(img_path)

4.3 Hough变换提取直线

按照之前标定的ROI进行Hough变换,检测到的直线绘制一个绿色的蒙板。

五、核心代码

import numpy as np
import cv2
from myClass import YoloV5
from myFunction import weighted_img, draw_lines, hough_lines


if __name__ == '__main__':
    print("[INFO] 开始YoloV5模型加载")
    # YOLOV5模型配置文件(YAML格式)的路径 yolov5_yaml_path
    model = YoloV5(yolov5_yaml_path='config/yolov5s.yaml')
    print("[INFO] 完成YoloV5模型加载")
    low = 200 #Canny low
    high = 300 #Canny high
    rho = 1  # 霍夫像素单位
    theta = np.pi / 360  # 霍夫角度移动步长
    hof_threshold = 20  # 霍夫平面累加阈值threshold
    min_line_len = 10  # 线段最小长度
    max_line_gap = 20  # 最大允许断裂长度
    index = 0 #图片索引
    while True:
        index = index + 1
        # 一张一张图片进行检测按index进行索引
        path = r"./figure/1/" + str(index) + ".jpg"
        path_output = r"./out/2/" + str(index) + ".jpg"
        color_image = cv2.imread(path)
        lane_img=color_image.copy()
        edges = cv2.Canny(lane_img, low, high)
        mask = np.zeros_like(edges)
        # vertices = np.array( [[(554, 463), (733, 464), (1112, 654), (298, 671)]],dtype=np.int32)#素材2的ROI
        vertices = np.array( [[(757, 800), (1150, 800), (1556, 1064), (314, 1064)]],dtype=np.int32)#素材1的ROI
        cv2.fillPoly(mask, vertices, 255)#绿色蒙板绘制
        masked_edges = cv2.bitwise_and(edges, mask)  # 按位与
        line_image = np.zeros_like(lane_img)
        # 绘制车道线线段
        lines = hough_lines(masked_edges, rho, theta, hof_threshold, min_line_len, max_line_gap)
        draw_lines(line_image, lines, thickness=10)
        # YoloV5 目标检测
        canvas, class_id_list, xyxy_list, conf_list = model.detect(color_image)
        if xyxy_list:
            for i in range(len(xyxy_list)):
                ux = int((xyxy_list[i][0] + xyxy_list[i][2]) / 2)  # 计算像素坐标系的x
                uy = int((xyxy_list[i][1] + xyxy_list[i][3]) / 2)  # 计算像素坐标系的y
                cv2.circle(canvas, (ux, uy), 4, (255, 255, 255), 5)  # 标出中心点
                cv2.putText(canvas, str([ux, uy]), (ux + 20, uy + 10), 0, 1,
                            [225, 255, 255], thickness=2, lineType=cv2.LINE_AA)  # 标出坐标
        canvas=weighted_img(canvas, line_image)
        # 可视化部分
        cv2.namedWindow("raw", 0)
        cv2.imshow('raw',color_image)
        cv2.namedWindow("line", 0)
        cv2.imshow('line',line_image)
        cv2.namedWindow('detection', 0)
        cv2.imshow('detection', canvas)
        # cv2.imwrite(path_output, canvas)#图片保存
        key = cv2.waitKey()
        # Press esc or 'q' to close the image window
        if key & 0xFF == ord('q') or key == 27:
            cv2.destroyAllWindows()
            break

有关基于YOLOv5+Hough变换的目标检测和车道线检测的更多相关文章

  1. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  2. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  3. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  4. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  5. ruby - 检测由 RSpec、Ruby 运行的代码 - 2

    我想知道我的代码是否在rspec下运行。这可能吗?原因是我正在加载一些错误记录器,这些记录器在测试期间会被故意错误(expect{x}.toraise_error)弄得乱七八糟。我查看了我的ENV变量,没有(明显的)测试环境变量的迹象。 最佳答案 在spec_helper.rb的开头添加:ENV['RACK_ENV']='test'现在您可以在代码中检查RACK_ENV是否经过测试。 关于ruby-检测由RSpec、Ruby运行的代码,我们在StackOverflow上找到一个类似的问题

  6. ruby - 使用 Ruby Daemons gem 检测停止 - 2

    我正在使用rubydaemongem。想知道如何向停止操作添加一些额外的步骤?希望我能检测到停止被调用,并向其添加一些额外的代码。任何人都知道我如何才能做到这一点? 最佳答案 查看守护程序gem代码,它似乎没有用于此目的的明显扩展点。但是,我想知道(在守护进程中)您是否可以捕获守护进程在发生“停止”时发送的KILL/TERM信号...?trap("TERM")do#executeyourextracodehereend或者你可以安装一个at_exit钩子(Hook):-at_exitdo#executeyourextracodehe

  7. ruby-on-rails - (Ruby,Rails) 基于角色的身份验证和用户管理...? - 2

    我正在寻找用于Rails的优质管理插件。似乎大多数现有的插件/gem(例如“restful_authentication”、“acts_as_authenticated”)都围绕着self注册等展开。但是,我正在寻找一种功能齐全的基于管理/管理角色的解决方案——但不是简单地附加到另一个非基于角色的解决方案。如果我找不到,我想我会自己动手......只是不想重新发明轮子。 最佳答案 RyanBates最近做了两个关于授权的railscast(注意身份验证和授权之间的区别;身份验证检查用户是否如她所说的那样,授权检查用户是否有权访问资源

  8. ruby - 在 Rakefile 中动态生成 Rake 测试任务(基于现有的测试文件) - 2

    我正在根据Rakefile中的现有测试文件动态生成测试任务。假设您有各种以模式命名的单元测试文件test_.rb.所以我正在做的是创建一个以“测试”命名空间内的文件名命名的任务。使用下面的代码,我可以用raketest:调用所有测试require'rake/testtask'task:default=>'test:all'namespace:testdodesc"Runalltests"Rake::TestTask.new(:all)do|t|t.test_files=FileList['test_*.rb']endFileList['test_*.rb'].eachdo|task|n

  9. ruby - Ruby 脚本如何检测到它正在 irb 中运行? - 2

    我有一个定义类的Ruby脚本。我希望脚本执行语句BoolParser.generate:file_base=>'bool_parser'仅当脚本作为可执行文件被调用时,而不是当它被irbrequire(或通过-r在命令行上传递)时。我可以用什么来包装上面的语句,以防止它在我的Ruby文件加载时执行? 最佳答案 条件$0==__FILE__...!/usr/bin/ruby1.8classBoolParserdefself.generate(args)p['BoolParser.generate',args]endendif$0==_

  10. ruby - 如何使用 Ruby 基于字母数字字符串生成颜色? - 2

    我想要像“嘿那里”这样的东西变成,例如,#316583。我希望将任意长度的字符串“归结”为十六进制颜色。我不知道从哪里开始。我在想,每个字符串的MD5散列都是不同的-但如何将该散列转换为十六进制颜色数字? 最佳答案 你可以只取几位前几位:require'digest/md5'color=Digest::MD5.hexdigest('Mytext')[0..5] 关于ruby-如何使用Ruby基于字母数字字符串生成颜色?,我们在StackOverflow上找到一个类似的问题:

随机推荐