YOLO 多线程实时检测代码
本脚本展示了如何使用多线程+队列实现 基于YOLO模型的实时目标检测,适用于树莓派等资源有限的设备。
主要特点
- 多线程分离:采集线程仅负责摄像头取帧,推理与显示在主线程进行,两者通过队列解耦,提升处理效率。
- 支持帧队列:最新帧实时送入队列,保证推理始终是最新画面,避免延迟。
- 可配置性能参数:模型路径、分辨率、推理帧率、队列长度都可灵活调整。
- Picamera2:用于树莓派摄像头高速取帧。
- Ultralytics YOLO:推理目标检测。
- OpenCV:绘制检测结果和显示FPS。
核心参数
MODEL_WEIGHTS = "yolo11l.pt" # 模型权重路径,可换为yolov8n.pt等更小模型
FRAME_SIZE = (416, 416) # 图像分辨率,调小可提速
INFER_FPS = 10 # 推理最大帧率,减小可减轻负载
QUEUE_SIZE = 2 # 队列长度,保证实时性
主要模块
1. 摄像头采集线程
负责不断采集最新帧,并将其放入队列(如果队列未满)。
class CameraStream:
def __init__(self, size=(416, 416)):
self.picam2 = Picamera2()
self.picam2.preview_configuration.main.size = size
self.picam2.preview_configuration.main.format = "RGB888"
self.picam2.preview_configuration.align()
self.picam2.configure("preview")
self.picam2.start()
self.stopped = False
def capture_loop(self, queue):
while not self.stopped:
frame = self.picam2.capture_array()
if not queue.full():
queue.put(frame)
def stop(self):
self.stopped = True
self.picam2.stop()
2. 推理与显示主循环
不断从队列中取出最新帧,进行YOLO推理,绘制检测结果与FPS,并实时显示。
def inference_loop(queue, model):
last_infer = 0
annotated_frame = None
while True:
try:
frame = queue.get(timeout=1)
except:
continue
now = time.time()
if now - last_infer >= 1.0 / INFER_FPS:
results = model(frame)
annotated_frame = results[0].plot()
inference_time = results[0].speed['inference']
fps = 1000 / inference_time if inference_time > 0 else 0
text = f'FPS: {fps:.1f}'
font = cv2.FONT_HERSHEY_SIMPLEX
text_size = cv2.getTextSize(text, font, 1, 2)[0]
text_x = annotated_frame.shape[1] - text_size[0] - 10
text_y = text_size[1] + 10
cv2.putText(annotated_frame, text, (text_x, text_y), font, 1, (255, 255, 255), 2, cv2.LINE_AA)
last_infer = now
cv2.imshow("YOLO RealTime", annotated_frame)
if cv2.waitKey(1) == ord("q"):
break
3. 主程序入口
- 初始化队列、摄像头与模型
- 启动采集线程
- 启动推理显示主循环
- 程序退出时资源释放
if __name__ == "__main__":
frame_queue = Queue(maxsize=QUEUE_SIZE)
cam = CameraStream(size=FRAME_SIZE)
model = YOLO(MODEL_WEIGHTS)
t_capture = threading.Thread(target=cam.capture_loop, args=(frame_queue,), daemon=True)
t_capture.start()
try:
inference_loop(frame_queue, model)
finally:
cam.stop()
cv2.destroyAllWindows()
性能优化建议
- 模型越小越快:建议用
yolov8n.pt
等nano模型替换大模型。 - 降低分辨率:
(320,320)
或更低分辨率可以显著提升速度,精度略有损失。 - 降低推理帧率:如
INFER_FPS=5
,可减少CPU/GPU占用。 - 关闭显示:如只需数据,不需要窗口,注释掉
cv2.imshow
可再提速。 - 丢弃积压帧:队列长度保持1-2,保证永远处理最新帧。
适用场景
适合在树莓派等边缘计算设备上部署实时目标检测任务,兼顾速度和精度,适用于智能监控、工业检测、机器人等场景。
# YOLO 多线程实时检测代码(中文说明)
本脚本展示了如何使用多线程+队列实现 **基于YOLO模型的实时目标检测**,适用于树莓派等资源有限的设备。
## 主要特点
- **多线程分离**:采集线程仅负责摄像头取帧,推理与显示在主线程进行,两者通过队列解耦,提升处理效率。
- **支持帧队列**:最新帧实时送入队列,保证推理始终是最新画面,避免延迟。
- **可配置性能参数**:模型路径、分辨率、推理帧率、队列长度都可灵活调整。
- **Picamera2**:用于树莓派摄像头高速取帧。
- **Ultralytics YOLO**:推理目标检测。
- **OpenCV**:绘制检测结果和显示FPS。
---
## 核心参数
```python
MODEL_WEIGHTS = "yolo11l.pt" # 模型权重路径,可换为yolov8n.pt等更小模型
FRAME_SIZE = (416, 416) # 图像分辨率,调小可提速
INFER_FPS = 10 # 推理最大帧率,减小可减轻负载
QUEUE_SIZE = 2 # 队列长度,保证实时性
主要模块
1. 摄像头采集线程
负责不断采集最新帧,并将其放入队列(如果队列未满)。
class CameraStream:
def __init__(self, size=(416, 416)):
self.picam2 = Picamera2()
self.picam2.preview_configuration.main.size = size
self.picam2.preview_configuration.main.format = "RGB888"
self.picam2.preview_configuration.align()
self.picam2.configure("preview")
self.picam2.start()
self.stopped = False
def capture_loop(self, queue):
while not self.stopped:
frame = self.picam2.capture_array()
if not queue.full():
queue.put(frame)
def stop(self):
self.stopped = True
self.picam2.stop()
2. 推理与显示主循环
不断从队列中取出最新帧,进行YOLO推理,绘制检测结果与FPS,并实时显示。
def inference_loop(queue, model):
last_infer = 0
annotated_frame = None
while True:
try:
frame = queue.get(timeout=1)
except:
continue
now = time.time()
if now - last_infer >= 1.0 / INFER_FPS:
results = model(frame)
annotated_frame = results[0].plot()
inference_time = results[0].speed['inference']
fps = 1000 / inference_time if inference_time > 0 else 0
text = f'FPS: {fps:.1f}'
font = cv2.FONT_HERSHEY_SIMPLEX
text_size = cv2.getTextSize(text, font, 1, 2)[0]
text_x = annotated_frame.shape[1] - text_size[0] - 10
text_y = text_size[1] + 10
cv2.putText(annotated_frame, text, (text_x, text_y), font, 1, (255, 255, 255), 2, cv2.LINE_AA)
last_infer = now
cv2.imshow("YOLO RealTime", annotated_frame)
if cv2.waitKey(1) == ord("q"):
break
3. 主程序入口
- 初始化队列、摄像头与模型
- 启动采集线程
- 启动推理显示主循环
- 程序退出时资源释放
if __name__ == "__main__":
frame_queue = Queue(maxsize=QUEUE_SIZE)
cam = CameraStream(size=FRAME_SIZE)
model = YOLO(MODEL_WEIGHTS)
t_capture = threading.Thread(target=cam.capture_loop, args=(frame_queue,), daemon=True)
t_capture.start()
try:
inference_loop(frame_queue, model)
finally:
cam.stop()
cv2.destroyAllWindows()
性能优化建议
- 模型越小越快:建议用
yolov8n.pt
等nano模型替换大模型。 - 降低分辨率:
(320,320)
或更低分辨率可以显著提升速度,精度略有损失。 - 降低推理帧率:如
INFER_FPS=5
,可减少CPU/GPU占用。 - 关闭显示:如只需数据,不需要窗口,注释掉
cv2.imshow
可再提速。 - 丢弃积压帧:队列长度保持1-2,保证永远处理最新帧。
适用场景
适合在树莓派等边缘计算设备上部署实时目标检测任务,兼顾速度和精度,适用于智能监控、工业检测、机器人等场景。
主要代码
import threading
import time
import cv2
from queue import Queue
from picamera2 import Picamera2
from ultralytics import YOLO
MODEL_WEIGHTS = "yolo11l.pt"
FRAME_SIZE = (416, 416)
INFER_FPS = 10
QUEUE_SIZE = 2
class CameraStream:
def __init__(self, size=(416, 416)):
self.picam2 = Picamera2()
self.picam2.preview_configuration.main.size = size
self.picam2.preview_configuration.main.format = "RGB888"
self.picam2.preview_configuration.align()
self.picam2.configure("preview")
self.picam2.start()
self.stopped = False
def capture_loop(self, queue):
while not self.stopped:
frame = self.picam2.capture_array()
if not queue.full():
queue.put(frame)
def stop(self):
self.stopped = True
self.picam2.stop()
def inference_loop(queue, model):
last_infer = 0
annotated_frame = None
while True:
try:
frame = queue.get(timeout=1)
except:
continue
now = time.time()
if now - last_infer >= 1.0 / INFER_FPS:
results = model(frame)
annotated_frame = results[0].plot()
inference_time = results[0].speed['inference']
fps = 1000 / inference_time if inference_time > 0 else 0
text = f'FPS: {fps:.1f}'
font = cv2.FONT_HERSHEY_SIMPLEX
text_size = cv2.getTextSize(text, font, 1, 2)[0]
text_x = annotated_frame.shape[1] - text_size[0] - 10
text_y = text_size[1] + 10
cv2.putText(annotated_frame, text, (text_x, text_y), font, 1, (255, 255, 255), 2, cv2.LINE_AA)
last_infer = now
cv2.imshow("YOLO RealTime", annotated_frame)
if cv2.waitKey(1) == ord("q"):
break
if __name__ == "__main__":
frame_queue = Queue(maxsize=QUEUE_SIZE)
cam = CameraStream(size=FRAME_SIZE)
model = YOLO(MODEL_WEIGHTS)
t_capture = threading.Thread(target=cam.capture_loop, args=(frame_queue,), daemon=True)
t_capture.start()
try:
inference_loop(frame_queue, model)
finally:
cam.stop()
cv2.destroyAllWindows()