Python基于YOLOv8和OpenCV实现车道线和车辆检测

ops/2025/1/12 20:36:51/

使用YOLOv8(You Only Look Once)和OpenCV实现车道线和车辆检测,目标是创建一个可以检测道路上的车道并识别车辆的系统,并估计它们与摄像头的距离。该项目结合了计算机视觉技术和深度学习物体检测。

1、系统主要功能

  • 车道检测:使用边缘检测和霍夫线变换检测道路车道。
  • 汽车检测:使用 YOLOv8 模型识别汽车并在汽车周围绘制边界框。
  • 距离估计:使用边界框大小计算检测到的汽车与摄像头的距离。

2、环境要求

  • OpenCV:用于图像处理和车道检测。
  • Ultralytics YOLOv8:用于车辆检测。
  • NumPy:用于数组操作。
pip install opencv-python-headless numpy ultralytics

opencv-pythonopencv-python-headless 区别是 OpenCV 的 Python 包,主要区别在于是否包含 GUI 相关的功能。

opencvpython_16">opencv-python
  • 包含 GUI 功能:支持窗口显示、鼠标事件等图形界面操作。
  • 依赖:需要 GUI 库(如 GTK、Qt)支持。
  • 适用场景:适用于需要显示图像或与用户交互的环境,如桌面应用。
opencvpythonheadless_21">opencv-python-headless
  • 不包含 GUI 功能:去除了窗口显示和用户交互功能。
  • 依赖:无需 GUI 库,适合无图形界面的环境。
  • 适用场景:适用于服务器或无图形界面的环境,如远程服务器、Docker 容器。
选择建议
  • 如果需要显示图像或与用户交互,选择 opencv-python
  • 如果仅需图像处理且无图形界面需求,选择 opencv-python-headless

3、代码

python">import cv2
import numpy as np
import math
import time
from ultralytics import YOLO  # YOLOv8 module# Function to mask out the region of interest
def region_of_interest(img, vertices):mask = np.zeros_like(img)match_mask_color = 255cv2.fillPoly(mask, vertices, match_mask_color)masked_image = cv2.bitwise_and(img, mask)return masked_image# Function to draw the filled polygon between the lane lines
def draw_lane_lines(img, left_line, right_line, color=[0, 255, 0], thickness=10):line_img = np.zeros_like(img)poly_pts = np.array([[(left_line[0], left_line[1]),(left_line[2], left_line[3]),(right_line[2], right_line[3]),(right_line[0], right_line[1])]], dtype=np.int32)# Fill the polygon between the linescv2.fillPoly(line_img, poly_pts, color)# Overlay the polygon onto the original imageimg = cv2.addWeighted(img, 0.8, line_img, 0.5, 0.0)return img# The lane detection pipeline
def pipeline(image):height = image.shape[0]width = image.shape[1]region_of_interest_vertices = [(0, height),(width / 2, height / 2),(width, height),]# Convert to grayscale and apply Canny edge detectiongray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)cannyed_image = cv2.Canny(gray_image, 100, 200)# Mask out the region of interestcropped_image = region_of_interest(cannyed_image,np.array([region_of_interest_vertices], np.int32))# Perform Hough Line Transformation to detect lineslines = cv2.HoughLinesP(cropped_image,rho=6,theta=np.pi / 60,threshold=160,lines=np.array([]),minLineLength=40,maxLineGap=25)# Separating left and right lines based on slopeleft_line_x = []left_line_y = []right_line_x = []right_line_y = []if lines is None:return imagefor line in lines:for x1, y1, x2, y2 in line:slope = (y2 - y1) / (x2 - x1) if (x2 - x1) != 0 else 0if math.fabs(slope) < 0.5:  # Ignore nearly horizontal linescontinueif slope <= 0:  # Left laneleft_line_x.extend([x1, x2])left_line_y.extend([y1, y2])else:  # Right laneright_line_x.extend([x1, x2])right_line_y.extend([y1, y2])# Fit a linear polynomial to the left and right linesmin_y = int(image.shape[0] * (3 / 5))  # Slightly below the middle of the imagemax_y = image.shape[0]  # Bottom of the imageif left_line_x and left_line_y:poly_left = np.poly1d(np.polyfit(left_line_y, left_line_x, deg=1))left_x_start = int(poly_left(max_y))left_x_end = int(poly_left(min_y))else:left_x_start, left_x_end = 0, 0  # Defaults if no lines detectedif right_line_x and right_line_y:poly_right = np.poly1d(np.polyfit(right_line_y, right_line_x, deg=1))right_x_start = int(poly_right(max_y))right_x_end = int(poly_right(min_y))else:right_x_start, right_x_end = 0, 0  # Defaults if no lines detected# Create the filled polygon between the left and right lane lineslane_image = draw_lane_lines(image,[left_x_start, max_y, left_x_end, min_y],[right_x_start, max_y, right_x_end, min_y])return lane_image# Function to estimate distance based on bounding box size
def estimate_distance(bbox_width, bbox_height):# For simplicity, assume the distance is inversely proportional to the box size# This is a basic estimation, you may use camera calibration for more accuracyfocal_length = 1000  # Example focal length, modify based on camera setupknown_width = 2.0  # Approximate width of the car (in meters)distance = (known_width * focal_length) / bbox_width  # Basic distance estimationreturn distance# Main function to read and process video with YOLOv8
def process_video():# Load the YOLOv8 modelmodel = YOLO('weights/yolov8n.pt')# 或者加载官方模型# model = YOLO("yolov8n.pt")  # load an official model# Open the video filecap = cv2.VideoCapture('video/video.mp4')# Check if video opened successfullyif not cap.isOpened():print("Error: Unable to open video file.")return# Set the desired frame ratetarget_fps = 30frame_time = 1.0 / target_fps  # Time per frame to maintain 30fps# Resize to 720p (1280x720)cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)# Loop through each framewhile cap.isOpened():ret, frame = cap.read()if not ret:break# Resize frame to 720presized_frame = cv2.resize(frame, (1280, 720))# Run the lane detection pipelinelane_frame = pipeline(resized_frame)# Run YOLOv8 to detect cars in the current frameresults = model(resized_frame)# Process the detections from YOLOv8for result in results:boxes = result.boxesfor box in boxes:x1, y1, x2, y2 = map(int, box.xyxy[0])  # Bounding box coordinatesconf = box.conf[0]  # Confidence scorecls = int(box.cls[0])  # Class ID# Only draw bounding boxes for cars with confidence >= 0.5if model.names[cls] == 'car' and conf >= 0.5:label = f'{model.names[cls]} {conf:.2f}'# Draw the bounding boxcv2.rectangle(lane_frame, (x1, y1), (x2, y2), (0, 255, 255), 2)cv2.putText(lane_frame, label, (x1, y1 - 10),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 2)# Estimate the distance of the carbbox_width = x2 - x1bbox_height = y2 - y1distance = estimate_distance(bbox_width, bbox_height)# Display the estimated distancedistance_label = f'Distance: {distance:.2f}m'cv2.putText(lane_frame, distance_label, (x1, y2 + 20),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)# Display the resulting frame with both lane detection and car detectioncv2.imshow('Lane and Car Detection', lane_frame)# Limit the frame rate to 30fpstime.sleep(frame_time)# Break the loop when 'q' is pressedif cv2.waitKey(1) & 0xFF == ord('q'):break# Release video capture and close windowscap.release()cv2.destroyAllWindows()# Run the video processing function
process_video()

4、工作原理

4.1 车道线检测 Pipeline

车道线检测包括一下几个步骤:

Step 1: 屏蔽感兴趣区域(ROI)
只处理图像的下半部分(车道线通常是可见的)。

python">def region_of_interest(img, vertices):mask = np.zeros_like(img)match_mask_color = 255cv2.fillPoly(mask, vertices, match_mask_color)masked_image = cv2.bitwise_and(img, mask)return masked_image

Step 2: 使用Canny进行边缘检测
将图像转换为灰度,并应用Canny边缘检测来突出显示边缘。

python">gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
cannyed_image = cv2.Canny(gray_image, 100, 200)

Step 3: 霍夫线变换
霍夫线变换用于检测当前车道的线段。

python">lines = cv2.HoughLinesP(cropped_image,rho=6,theta=np.pi / 60,threshold=160,lines=np.array([]),minLineLength=40,maxLineGap=25
)

YOLOv8_268">4.2 使用YOLOv8进行车辆检测

Step 1: 加载YOLOv8模型
我们使用预训练的YOLOv8模型来检测每一帧中的汽车(或者使用官方提供的模型)。

python">from ultralytics import YOLO
model = YOLO('weights/yolov8n.pt')
# model = YOLO('yolov8n.pt') #官方提供的模型

Step 2: 绘制边界框
对于每一辆检测到的汽车,绘制边界框,并显示类名(汽车)和置信度分数。

python">for box in boxes:x1, y1, x2, y2 = map(int, box.xyxy[0])conf = box.conf[0]if model.names[cls] == 'car' and conf >= 0.5:label = f'{model.names[cls]} {conf:.2f}'cv2.rectangle(lane_frame, (x1, y1), (x2, y2), (0, 255, 255), 2)cv2.putText(lane_frame, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 2)

Step 3:. 距离估计
根据边界框的大小估计到每辆检测到的汽车的距离。

python">def estimate_distance(bbox_width, bbox_height):focal_length = 1000  # Example focal lengthknown_width = 2.0  # Approximate width of a car (in meters)distance = (known_width * focal_length) / bbox_widthreturn distance

Step 4:. 视频处理 Pipeline
将车道检测、车辆检测和距离估计结合到一个实时视频处理pipeline中。

python">while cap.isOpened():ret, frame = cap.read()if not ret:breaklane_frame = pipeline(resized_frame)results = model(resized_frame)for result in results:# Draw bounding boxes and estimate distancecv2.imshow('Lane and Car Detection', lane_frame)if cv2.waitKey(1) & 0xFF == ord('q'):break

5、结果

在这里插入图片描述

  • 项目源码地址: https://github.com/CityIsBetter/Lane_Detection

http://www.ppmy.cn/ops/149542.html

相关文章

web前端-html

HTML部分 HTML&#xff1a;超文本标记语言。是万维网web编程的基础&#xff0c;web是建立在超文本基础上的。HTML 是万维网的基石 打开www.baidu.com的页面源代码可见 超文本标记超的含义 1.最重要的标签&#xff0c;超链接标签&#xff0c;可跳转页面&#xff0c;关联所有页…

免费网站源码下载指南:如何安全获取并降低开发成本

许多开发者或是需要建立网站的人&#xff0c;可以方便地获取免费网站源码。这样的下载能帮助他们降低开发费用&#xff0c;迅速构建起基本框架。但在此过程中&#xff0c;仍有许多需要注意的事项。 许多开发者或是需要建立网站的人&#xff0c;可以方便地获取免费网站源码。这…

附加共享数据库和共享数据库的区别

**“附加共享数据库”和“共享数据库”**实际上指的是两种不同的概念&#xff0c;尽管它们在一定程度上可能会有交集&#xff0c;下面从两个角度解释它们的区别&#xff1a; 1. 附加共享数据库 这是一个特定操作&#xff0c;主要指的是通过 ATTACH DATABASE 命令&#xff0c;将…

Flutter使用BorderRadiusTween实现由矩形变成圆形的动画

BorderRadiusTween 是插值动画中&#xff0c;用于组件边框半径的类&#xff0c;专门作用于组件边框和半径动化过度。 这个类继承自Tween&#xff0c;用法相似。 下面是示例写法 class BorderRadiusTweenPage extends StatefulWidget {overrideState<StatefulWidget> c…

Rust 1.84.0 发布

Cargo 依赖版本选择改进 稳定了最小支持 Rust 版本&#xff08;MSRV&#xff09;感知的解析器&#xff0c;该解析器会优先选择与项目声明的 MSRV 兼容的依赖版本&#xff0c;减少了维护者支持旧工具链的工作量&#xff0c;无需手动为每个依赖选择旧版本。可以通过.cargo/config…

简单易用的PDF工具箱

软件介绍 PDF24 Creator是一款简单易用的PDF工具箱&#xff0c;而且完全免费&#xff0c;没有任何功能限制。既可以访问官网在线使用各种PDF工具&#xff0c;也可以下载软件离线使用各种PDF工具。 软件功能 1、PDF转换 支持将多种文件格式&#xff08;Word、PowerPoint、Exc…

Linux:进程概念(二.查看进程、父进程与子进程、进程状态详解)

目录 1. 查看进程 1.1 准备工作 1.2 指令&#xff1a;ps—显示当前系统中运行的进程信息 1.3 查看进程属性 1.4 通过 /proc 系统文件夹看进程 2. 父进程与子进程 2.1 介绍 2.2 getpid() \getppid() 2.3 fork()函数—通过系统调用创建进程 fork()函数疑问 3. 进程状态…

Web渗透测试之XSS跨站脚本 原理 出现的原因 出现的位置 测试的方法 危害 防御手段 面试题 一篇文章给你说的明明白白

目录 XSS介绍的原理和说明 Cross Site Scripting 钓鱼 XSS攻击原理 XSS漏洞出现的原因: XSS产生的原因分析 XSS出现位置: XSS测试方法 XSS的危害 防御手段: 其它防御 面试题: 备注: XSS介绍的原理和说明 嵌入在客户端脚本 对客户端进行攻击的Owstop ten 十大漏…