Python基于YOLOv8和OpenCV實現(xiàn)車道線和車輛檢測功能
使用YOLOv8(You Only Look Once)和OpenCV實現(xiàn)車道線和車輛檢測,目標(biāo)是創(chuàng)建一個可以檢測道路上的車道并識別車輛的系統(tǒng),并估計它們與攝像頭的距離。該項目結(jié)合了計算機視覺技術(shù)和深度學(xué)習(xí)物體檢測。
1、系統(tǒng)主要功能
- 車道檢測:使用邊緣檢測和霍夫線變換檢測道路車道。
- 汽車檢測:使用 YOLOv8 模型識別汽車并在汽車周圍繪制邊界框。
- 距離估計:使用邊界框大小計算檢測到的汽車與攝像頭的距離。
2、環(huán)境要求
- OpenCV:用于圖像處理和車道檢測。
- Ultralytics YOLOv8:用于車輛檢測。
- NumPy:用于數(shù)組操作。
pip install opencv-python-headless numpy ultralytics
opencv-python
和 opencv-python-headless
區(qū)別是 OpenCV 的 Python 包,主要區(qū)別在于是否包含 GUI 相關(guān)的功能。
opencv-python
- 包含 GUI 功能:支持窗口顯示、鼠標(biāo)事件等圖形界面操作。
- 依賴:需要 GUI 庫(如 GTK、Qt)支持。
- 適用場景:適用于需要顯示圖像或與用戶交互的環(huán)境,如桌面應(yīng)用。
opencv-python-headless
- 不包含 GUI 功能:去除了窗口顯示和用戶交互功能。
- 依賴:無需 GUI 庫,適合無圖形界面的環(huán)境。
- 適用場景:適用于服務(wù)器或無圖形界面的環(huán)境,如遠(yuǎn)程服務(wù)器、Docker 容器。
3、代碼
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 = 255 cv2.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 lines cv2.fillPoly(line_img, poly_pts, color) # Overlay the polygon onto the original image img = 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 detection gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) cannyed_image = cv2.Canny(gray_image, 100, 200) # Mask out the region of interest cropped_image = region_of_interest( cannyed_image, np.array([region_of_interest_vertices], np.int32) ) # Perform Hough Line Transformation to detect lines lines = 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 slope left_line_x = [] left_line_y = [] right_line_x = [] right_line_y = [] if lines is None: return image for line in lines: for x1, y1, x2, y2 in line: slope = (y2 - y1) / (x2 - x1) if (x2 - x1) != 0 else 0 if math.fabs(slope) < 0.5: # Ignore nearly horizontal lines continue if slope <= 0: # Left lane left_line_x.extend([x1, x2]) left_line_y.extend([y1, y2]) else: # Right lane right_line_x.extend([x1, x2]) right_line_y.extend([y1, y2]) # Fit a linear polynomial to the left and right lines min_y = int(image.shape[0] * (3 / 5)) # Slightly below the middle of the image max_y = image.shape[0] # Bottom of the image if 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 detected if 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 lines lane_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 accuracy focal_length = 1000 # Example focal length, modify based on camera setup known_width = 2.0 # Approximate width of the car (in meters) distance = (known_width * focal_length) / bbox_width # Basic distance estimation return distance # Main function to read and process video with YOLOv8 def process_video(): # Load the YOLOv8 model model = YOLO('weights/yolov8n.pt') # 或者加載官方模型 # model = YOLO("yolov8n.pt") # load an official model # Open the video file cap = cv2.VideoCapture('video/video.mp4') # Check if video opened successfully if not cap.isOpened(): print("Error: Unable to open video file.") return # Set the desired frame rate target_fps = 30 frame_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 frame while cap.isOpened(): ret, frame = cap.read() if not ret: break # Resize frame to 720p resized_frame = cv2.resize(frame, (1280, 720)) # Run the lane detection pipeline lane_frame = pipeline(resized_frame) # Run YOLOv8 to detect cars in the current frame results = model(resized_frame) # Process the detections from YOLOv8 for result in results: boxes = result.boxes for box in boxes: x1, y1, x2, y2 = map(int, box.xyxy[0]) # Bounding box coordinates conf = box.conf[0] # Confidence score cls = int(box.cls[0]) # Class ID # Only draw bounding boxes for cars with confidence >= 0.5 if model.names[cls] == 'car' and conf >= 0.5: label = f'{model.names[cls]} {conf:.2f}' # Draw the bounding box 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) # Estimate the distance of the car bbox_width = x2 - x1 bbox_height = y2 - y1 distance = estimate_distance(bbox_width, bbox_height) # Display the estimated distance distance_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 detection cv2.imshow('Lane and Car Detection', lane_frame) # Limit the frame rate to 30fps time.sleep(frame_time) # Break the loop when 'q' is pressed if cv2.waitKey(1) & 0xFF == ord('q'): break # Release video capture and close windows cap.release() cv2.destroyAllWindows() # Run the video processing function process_video()
4、工作原理
4.1 車道線檢測 Pipeline
車道線檢測包括一下幾個步驟:
Step 1: 屏蔽感興趣區(qū)域(ROI)
只處理圖像的下半部分(車道線通常是可見的)。
def region_of_interest(img, vertices): mask = np.zeros_like(img) match_mask_color = 255 cv2.fillPoly(mask, vertices, match_mask_color) masked_image = cv2.bitwise_and(img, mask) return masked_image
Step 2: 使用Canny進(jìn)行邊緣檢測
將圖像轉(zhuǎn)換為灰度,并應(yīng)用Canny邊緣檢測來突出顯示邊緣。
gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) cannyed_image = cv2.Canny(gray_image, 100, 200)
Step 3: 霍夫線變換
霍夫線變換用于檢測當(dāng)前車道的線段。
lines = cv2.HoughLinesP( cropped_image, rho=6, theta=np.pi / 60, threshold=160, lines=np.array([]), minLineLength=40, maxLineGap=25 )
4.2 使用YOLOv8進(jìn)行車輛檢測
Step 1: 加載YOLOv8模型
我們使用預(yù)訓(xùn)練的YOLOv8模型來檢測每一幀中的汽車(或者使用官方提供的模型)。
from ultralytics import YOLO model = YOLO('weights/yolov8n.pt') # model = YOLO('yolov8n.pt') #官方提供的模型
Step 2: 繪制邊界框
對于每一輛檢測到的汽車,繪制邊界框,并顯示類名(汽車)和置信度分?jǐn)?shù)。
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:. 距離估計
根據(jù)邊界框的大小估計到每輛檢測到的汽車的距離。
def estimate_distance(bbox_width, bbox_height): focal_length = 1000 # Example focal length known_width = 2.0 # Approximate width of a car (in meters) distance = (known_width * focal_length) / bbox_width return distance
Step 4:. 視頻處理 Pipeline
將車道檢測、車輛檢測和距離估計結(jié)合到一個實時視頻處理pipeline中。
while cap.isOpened(): ret, frame = cap.read() if not ret: break lane_frame = pipeline(resized_frame) results = model(resized_frame) for result in results: # Draw bounding boxes and estimate distance cv2.imshow('Lane and Car Detection', lane_frame) if cv2.waitKey(1) & 0xFF == ord('q'): break
5、結(jié)果
項目源碼地址: https://github.com/CityIsBetter/Lane_Detection
到此這篇關(guān)于Python基于YOLOv8和OpenCV實現(xiàn)車道線和車輛檢測的文章就介紹到這了,更多相關(guān)Python YOLOv8和OpenCV車道線檢測內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python?turtle.right與turtle.setheading的區(qū)別講述
這篇文章主要介紹了Python?turtle.right與turtle.setheading的區(qū)別,本文以turtle.right為例給大家詳細(xì)介紹,需要的朋友可以參考下2022-03-03基于pdf2docx模塊Python實現(xiàn)批量將PDF轉(zhuǎn)Word文檔的完整代碼教程
這篇文章主要介紹了基于pdf2docx模塊Python實現(xiàn)批量將PDF轉(zhuǎn)Word文檔的完整代碼教程,PDF文件是一種常見的文檔格式,如何轉(zhuǎn)換成word呢,需要的朋友可以參考下2023-04-04Python 生成器,迭代,yield關(guān)鍵字,send()傳參給yield語句操作示例
這篇文章主要介紹了Python 生成器,迭代,yield關(guān)鍵字,send()傳參給yield語句操作,結(jié)合實例形式分析了Python生成器、迭代、yield關(guān)鍵字及異常處理相關(guān)操作技巧,需要的朋友可以參考下2019-10-10Python Matplotlib條形圖之垂直條形圖和水平條形圖詳解
這篇文章主要為大家詳細(xì)介紹了Python Matplotlib條形圖之垂直條形圖和水平條形圖,使用數(shù)據(jù)庫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03Python實現(xiàn)從常規(guī)文檔中提取圖片的方法詳解
這篇文章主要為大家詳細(xì)介紹了如何使用Python實現(xiàn)從常規(guī)文檔(Word,PDF,Excel,HTML)中提取圖片的方法,有需要的小伙伴可以參考一下2025-03-03