Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

基于树莓派4B的YOLOv5-Lite轻量级目标检测系统部署与迷宫寻宝应用

Tech May 10 2

引言

本文聚焦于在树莓派4B平台部署轻量化目标检测模型YOLOv5-Lite,并将其应用于"迷宫寻宝"智能小车系统。该系统融合计算机视觉、光电传感与路径规划技术,实现对复杂环境的实时感知与自主决策。通过模型压缩与边缘推理优化,使原本依赖高性能GPU的深度学习任务得以在资源受限的嵌入式设备上稳定运行。

模型选型与轻量化设计

YOLOv5-Lite是YOLOv5系列的精简变体,专为边缘设备设计。其核心改进包括:

  • 移除Focuss层,以标准卷积替代,提升ONNX导出兼容性
  • 简化C3模块结构,减少重复Bottleneck堆叠,降低内存占用
  • 采用SPPF(快速空间金字塔池化)替代传统SPP,提升特征提取效率
  • 对FPN+PAN结构实施通道剪枝,统一各层特征通道数为96,优化缓存访问模式
  • 将PAN中的通道拼接(concat)替换为逐元素叠加(add),减少数据搬运开销

上述优化使模型体积缩减约40%,推理速度提升3倍以上,在保持85%以上原始mAP的前提下,实现5 FPS以上的稳定推理,满足嵌入式实时性需求。

训练与模型转换

训练数据通过树莓派摄像头采集,涵盖三类目标:drrug、glue、prime。使用LabelMe进行标注后,通过脚本将JSON格式转换为YOLO标准的TXT格式(归一化中心坐标+宽高)。

训练配置如下:

python train.py \
  --weights v5lite-s.pt \
  --cfg models/v5Lite-s.yaml \
  --data data/mydata.yaml \
  --img-size 320 \
  --batch-size 16 \
  --device cpu

训练完成后,使用官方export脚本将PyTorch权重转换为ONNX格式:

python export.py --weights best.pt --include onnx

生成的best.onnx模型可在树莓派端直接加载,无需依赖PyTorch环境,仅需安装ONNX Runtime:

pip install onnxruntime==1.16.0 numpy>=1.21.0

边缘推理实现

在树莓派端,推理流程分为预处理、推理、后处理三阶段:

1. 图像预处理

def preprocess(img, model_h=320, model_w=320):
    img_resized = cv2.resize(img, (model_w, model_h), interpolation=cv2.INTER_AREA)
    img_rgb = cv2.cvtColor(img_resized, cv2.COLOR_BGR2RGB)
    img_normalized = img_rgb.astype(np.float32) / 255.0
    blob = np.expand_dims(img_normalized.transpose(2, 0, 1), axis=0)
    return blob

2. ONNX推理

session = ort.InferenceSession("best.onnx", providers=['CPUExecutionProvider'])
outputs = session.run(None, {session.get_inputs()[0].name: blob})[0]

3. 输出解码与NMS

模型输出为三维张量,需进行坐标还原与非极大值抑制:

def decode_outputs(outputs, anchors, strides, nl=3, na=3, model_h=320, model_w=320):
    predictions = []
    for i in range(nl):
        h, w = model_h // strides[i], model_w // strides[i]
        grid = np.meshgrid(np.arange(w), np.arange(h))
        grid = np.stack(grid, axis=-1).astype(np.float32).reshape(-1, 2)
        
        # 解码中心坐标与宽高
        xy = (outputs[i, :, :2] * 2 - 0.5 + grid) * strides[i]
        wh = (outputs[i, :, 2:4] * 2) ** 2 * anchors[i]
        
        # 拼接为 [x1, y1, x2, y2, conf, class_probs]
        x1y1 = xy - wh / 2
        x2y2 = xy + wh / 2
        box = np.concatenate([x1y1, x2y2, outputs[i, :, 4:]], axis=1)
        predictions.append(box)
    
    return np.concatenate(predictions, axis=0)

def nms_boxes(boxes, scores, class_ids, conf_thres=0.5, iou_thres=0.4):
    indices = cv2.dnn.NMSBoxes(boxes, scores, conf_thres, iou_thres)
    if len(indices) > 0:
        return boxes[indices], scores[indices], class_ids[indices]
    return [], [], []

4. 实时视频推理主循环

cap = cv2.VideoCapture(0)
while True:
    ret, frame = cap.read()
    if not ret: break
    
    blob = preprocess(frame)
    raw_out = session.run(None, {input_name: blob})[0]
    
    # 解码与NMS
    det = decode_outputs(raw_out, anchors, strides)
    boxes, confs, ids = nms_boxes(det[:, :4], det[:, 4], det[:, 5:].argmax(axis=1))
    
    # 绘制结果
    for box, conf, cls_id in zip(boxes, confs, ids):
        x1, y1, x2, y2 = map(int, box)
        label = f"{labels[cls_id]}: {conf:.2f}"
        cv2.rectangle(frame, (x1, y1), (x2, y2), (255, 0, 0), 2)
        cv2.putText(frame, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 2)
    
    cv2.imshow("Detection", frame)
    if cv2.waitKey(1) == ord('q'): break

在树莓派4B上,该系统可稳定实现4.8–5.3 FPS,满足实时控制需求。

迷宫寻宝系统集成

系统以树莓派4B为核心,集成以下模块:

1. 宝藏地图识别

采用OpenCV实现:

  • 灰度化 + Cenny边缘检测
  • 轮廓筛选(长宽比≈1:1)定位四个角点
  • 透视变换校正图像畸变
  • 二值化 + 轮廓外接圆检测定位8个宝藏点
  • 左下角色块识别(HSV掩膜)确定队伍颜色

识别结果以JSON格式持久化存储:{ "matrix": [[x1,y1],...], "TC": 1, "count": 2 }

2. 自适应路径规划

采用广度优先搜索(BFS)实现最短路径:

  • 将地图建模为0(可通行)/1(障碍)二维数组
  • 从当前位置出发,BFS搜索最近未访问宝藏点
  • 依据对称规则剪枝:若某点为真宝藏,则其对称点及同象限另一点自动排除
  • 路径输出为坐标序列 → 位移向量 → 转向指令序列(直行/左转/右转)

系统最多仅需访问6个点,最少3个点即可完成任务,显著优于全遍历方案。

3. 灰度传感器循迹

采用8路光电传感器阵列,工作原理:

  • 白色地面反射率高 → 传感器输出高电平
  • 黑色胶带吸收光 → 传感器输出低电平
  • 通过读取8通道高低电平组合,计算中心偏移量:offset = (start + end)/2 - 8

引入位置式PID控制:

def pid_control(offset):
    P = 1.2
    I = 0.02
    D = 0.3
    integral += offset
    derivative = offset - last_offset
    output = P * offset + I * integral + D * derivative
    left_speed = base_speed - output
    right_speed = base_speed + output
    set_motor_speed(left_speed, right_speed)

传感器安装高度2cm,实现稳定巡线,抗干扰能力强。

4. 超声波避障与停止

使用HC-SR04模块检测前方障碍物距离:

def measure_distance():
    GPIO.output(TRIG, GPIO.HIGH)
    time.sleep(0.00001)
    GPIO.output(TRIG, GPIO.LOW)
    start = time.time()
    while GPIO.input(ECHO) == 0: start = time.time()
    stop = time.time()
    while GPIO.input(ECHO) == 1: stop = time.time()
    distance = (stop - start) * 34300 / 2
    return distance if distance < 400 else -1

当距离小于15cm时触发停止,用于精准停靠宝藏点。

5. 中断恢复机制

系统重启时自动读取treasure.json,仅对未访问点执行目标检测与路径规划,避免重复识别,提升系统鲁棒性与效率。

系统性能与成果

整套系统在树莓派4B(2GB RAM)上稳定运行,综合性能如下:

  • 地图识别耗时:≤45秒
  • 目标检测帧率:5.1 FPS
  • 路径规划响应:≤100ms
  • 循迹精度:±1.5cm
  • 平均寻宝时间:78秒(8点迷宫)

相较传统全遍历方案(平均180秒),效率提升57%,且具备断点续跑能力,显著提升竞赛实用性。

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.