树莓派4中YOLO 11 多线程实时检测

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()
<think>嗯,用户想要了解如何在树莓派上运行自定义的YOLO模型,并将结果输出到STM32进行通信。首先,我需要整理整个流程,确保每个步骤都正确无误。可能需要分几个大步骤:环境搭建、模型部署、通信设置和整合测试。 首先,环境搭建方面,树莓派需要安装合适的操作系统,通常是Raspberry Pi OS。然后安装必要的依赖库,比如Python、OpenCV、PyTorch或TensorFlow,具体取决于YOLO的版本。用户可能用的是YOLOv5或v8,得确认他们用的是哪个版本,因为不同版本的部署方式可能不同。如果是自定义模型,还需要确保模型已经转换为适合在树莓派上运行的格式,比如ONNX或者TFLite,特别是考虑到树莓派的计算资源有限。 然后是模型部署部分。用户需要将训练好的YOLO模型加载到树莓派上,并编写推理代码。这里需要注意模型的输入输出格式,以及如何处理摄像头或图像输入。可能还需要调整模型的大小或使用量化来优化推理速度,毕竟树莓派的处理能力不如PC。 接下来是通信部分。树莓派和STM32之间通常通过串口、I2C、SPI或者USB进行通信。最常见的是串口通信,因为它简单且易于实现。需要确定使用哪种通信协议,比如UART,然后编写相应的代码在树莓派端发送数据,以及在STM32端接收并解析数据。数据格式可能需要设计成固定的结构,比如发送坐标和类别信息,可能用JSON或者自定义的二进制格式,但考虑到STM32的资源,可能更倾向于简单的字符串或二进制协议。 整合测试阶段需要确保树莓派能够实时处理图像,运行模型,并将结果准确发送到STM32。同时,STM32的程序需要能够正确解析接收到的数据,并执行相应的操作,比如控制电机或LED。可能还需要处理通信中的错误,比如数据丢失或校验失败。 用户可能遇到的问题包括树莓派性能不足导致推理速度慢,通信中的数据传输错误,或者STM32端的解析问题。需要建议优化模型,使用更高效的推理引擎,或者增加校验机制,如CRC校验,确保数据完整性。另外,可能需要指导用户如何调试通信问题,比如使用逻辑分析仪或串口调试工具。 还要考虑电源管理,尤其是在移动应用中,树莓派和STM32的供电是否稳定。以及可能的硬件连接问题,比如GPIO引脚的正确配置和电平匹配。 最后,用户可能需要具体的代码示例,比如Python的串口通信代码和STM32的接收代码。需要确保代码的兼容性,比如树莓派的Python版本和STM32的固件库版本是否匹配。可能还需要指导如何安装必要的Python库,如pyserial,以及STM32端的HAL库配置。</think>以下为树莓派运行自定义YOLO模型并与STM32通信的完整实现教程,分为五个关键步骤: 一、环境搭建与模型部署 1. 树莓派环境配置 ```bash # 安装Python环境 sudo apt-get install python3-opencv python3-serial pip3 install torch torchvision # YOLO依赖库 # 若使用TensorFlow Lite: pip3 install tflite-runtime ``` 2. 模型优化建议 - 使用YOLOv5s/v8n等轻量级模型 - 转换为ONNX/TFLite格式提升推理速度 ```python # 示例YOLOv5模型加载 import torch model = torch.hub.load('ultralytics/yolov5', 'custom', path='best.pt') ``` 二、通信协议设计 1. 推荐使用UART协议(硬件资源占用少) 2. 数据帧格式示例: ``` [StartByte][X坐标][Y坐标][物体类型][校验和][EndByte] ``` 3. 建议波特率:115200(平衡速度与稳定性) 三、树莓派端实现 ```python import serial import cv2 # 初始化串口 ser = serial.Serial('/dev/ttyAMA0', 115200, timeout=1) # YOLO推理与通信 def detect_and_send(): cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() results = model(frame) for obj in results.xyxy[0]: x1, y1, x2, y2, conf, cls = obj center_x = int((x1+x2)/2) center_y = int((y1+y2)/2) # 构造数据包 data = f"<{center_x},{center_y},{int(cls)}>\n" ser.write(data.encode()) detect_and_send() ``` 四、STM32端实现(基于HAL库) ```c // 串口接收处理 uint8_t rx_buffer[32]; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { static uint8_t idx = 0; if(rx_buffer[idx] == '>') { process_data(rx_buffer); idx = 0; } else { idx = (idx + 1) % sizeof(rx_buffer); } HAL_UART_Receive_IT(&huart1, &rx_buffer[idx], 1); } // 数据解析示例 void process_data(uint8_t* data) { int x, y, cls; sscanf((char*)data, "<%d,%d,%d>", &x, &y, &cls); // 触发控制逻辑 if(cls == 0) { // 检测到特定类别 control_motor(x, y); } } ``` 五、系统优化建议 1. 性能提升方案 - 使用多线程:分离图像采集、推理、通信线程 - 开启GPU加速:通过USB Coral TPU提升推理速度 ```bash # 安装Edge TPU运行时 curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list sudo apt-get update sudo apt-get install edgetpu-compiler ``` 2. 通信可靠性保障 - 添加CRC校验 - 实现ACK应答机制 - 使用软件流控(XON/XOFF) 3. 典型问题排查 - 使用`minicom`调试串口通信 - 通过`htop`监控CPU负载 - 添加LED指示灯进行状态反馈 进阶方案: 1. 使用Modbus协议实现工业级通信 2. 通过ROS建立分布式系统 3. 结合LoRa/WiFi实现无线通信 开发注意事项: 1. 电平匹配:树莓派(3.3V)与STM32(5V)需电平转换 2. 电源隔离:建议单独供电并做好滤波处理 3. 接地处理:确保共地连接可靠 完整项目框架建议: ``` ├── raspberry/ │ ├── inference/ # 模型文件 │ ├── comm/ # 通信协议实现 │ └── main.py # 主程序 ├── stm32/ │ ├── Core/ # 硬件驱动 │ └── App/ # 应用逻辑 └── docs/ # 接口文档 ``` 可通过以下方式验证系统有效性: 1. 使用逻辑分析仪抓取通信波形 2. 通过OpenCV实时显示检测结果 3. 添加串口打印调试信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

MC数据局

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

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

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

打赏作者

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

抵扣说明:

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

余额充值