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

该文介绍了使用YOLOv5进行目标检测,包括车辆、行人检测,并通过Hough变换进行车道线检测的项目。作者提供了Canny阈值调整和ROI标定的辅助工具,以及整个检测流程的Python代码,包括视频帧处理、目标检测和车道线提取,最终可将结果合并成视频输出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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实现车道线检测 #### 准备工作 在开始之前,确保安装了必要的依赖库。这通常包括PyTorch、OpenCV其他一些辅助工具。对于YOLOv5来说,还需要下载预训练权重文件以及配置文件。 ```bash pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113 pip install opencv-python matplotlib numpy git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt ``` #### 数据集准备 为了使YOLOv5适应特定的任务——即车道线检测,需要收集并标注相应的数据集。这些图像应该覆盖不同天气条件光照环境下的各类道路场景[^1]。 #### 模型调整与训练 由于标准版YOLOv5主要用于通用物体识别而非专门针对车道标记,因此可能需要对网络结构做一些修改来更好地捕捉车道特征。可以考虑增加额外的卷积层或改变锚框尺寸以提高对细长形状(如线条)的敏感度。此外,在训练过程中加入适当的数据增强手段有助于提升泛化能力[^3]。 #### 推理过程中的处理技巧 当利用训练好的模型执行推理时,除了常规的目标边界框预测外,还可以采用后处理方法进一步优化输出质量: - **非极大值抑制 (NMS)**:去除重叠过多的候选区域; - **霍夫变换**:用于从二值化的边缘图中提取直线段,从而更精确地描绘出完整的车道轮廓[^2]; ```python import cv2 from pathlib import Path import torch from models.experimental import attempt_load from utils.general import non_max_suppression, scale_coords from utils.datasets import letterbox def detect_lane(image_path): weights = 'best.pt' # 替换成自己的最佳模型路径 imgsz = 640 # 输入图片大小 device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu') model = attempt_load(weights, map_location=device) # 加载模型 stride = int(model.stride.max()) # 获取步幅 names = model.module.names if hasattr(model, 'module') else model.names im0 = cv2.imread(str(Path(image_path))) # 读取原始图片 img = letterbox(im0, new_shape=imgsz)[0] # 调整输入尺寸 img = img[:, :, ::-1].transpose(2, 0, 1).copy() img = torch.from_numpy(img).to(device) img = img.float() / 255.0 # 归一化像素值到[0,1] if img.ndimension() == 3: img = img.unsqueeze(0) pred = model(img)[0] # 执行前向传播获取预测结果 det = non_max_suppression(pred, conf_thres=0.25, iou_thres=0.45)[-1] if len(det): # 如果存在有效检测 det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() for *xyxy, conf, cls in reversed(det): label = f'{names[int(cls)]} {conf:.2f}' plot_one_box(xyxy, im0, label=label, color=(0, 255, 0), line_thickness=3) def plot_one_box(x, img, color=None, label=None, line_thickness=None): tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA) tf = max(tl - 1, 1) t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA) cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA) ```
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fr0mdeepsea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值