Arduino UNO Q赋能边缘AI视觉:基于YOLOv5n的轻量化物体识别实战指南
在物联网与人工智能深度融合的今天,将强大的AI视觉能力部署到资源受限的边缘设备上,已成为智能安防、工业质检、智能零售等领域的关键需求。传统的云端AI方案存在延迟高、隐私泄露和网络依赖等问题,而边缘AI则能直接在设备端进行实时推理,完美解决了这些痛点。本文将深入探讨如何利用Arduino UNO Q这款高性能开发板,结合OpenCV与轻量级YOLOv5n模型,构建一套完整的边缘侧物体识别解决方案。这不仅是一次技术实践,更是理解深度学习模型在嵌入式平台部署的绝佳案例。
一、项目概述与核心优势:为何选择Arduino UNO Q与YOLOv5n?
本项目旨在实现一个在Arduino UNO Q开发板上运行的实时物体识别系统。Arduino UNO Q基于瑞芯微RK3588S芯片,拥有强大的CPU和NPU(神经网络处理单元),为边缘AI应用提供了充足的算力。我们选择YOLOv5n(nano)版本,是因为它是YOLO系列中最轻量级的模型之一,在精度和速度之间取得了极佳的平衡,非常适合嵌入式部署。通过ONNX(Open Neural Network Exchange)格式的模型,我们可以利用OpenCV的DNN模块进行高效的推理,无需依赖复杂的深度学习框架,极大简化了部署流程。相较于传统的单片机方案,本方案能处理更复杂的机器学习任务,为产品快速原型开发提供了强大支持。[AFFILIATE_SLOT_1]
二、环境搭建与准备工作:从零开始配置开发环境
成功的项目始于稳定的环境。首先,我们需要完成硬件连接。由于Arduino UNO Q运行完整的Linux系统,我们可以通过SSH进行远程开发,只需一根Type-C线缆同时完成供电和网络连接,非常便捷。

连接成功后,第一步是更新系统软件包,确保拥有最新的库和安全性补丁。在终端中执行以下命令:
sudo apt update
sudo apt upgrade
接下来是核心环节——安装OpenCV。OpenCV是计算机视觉的基石,我们不仅需要安装主库,最好也安装`opencv-data`以获取一些预置的Haar级联分类器数据(虽然本项目未使用,但对其他视觉任务有益)。
sudo apt install python3-opencv
sudo apt install opencv-data
安装完成后,务必进行验证,以确保OpenCV已正确安装并可以导入。执行一个简单的Python脚本或命令来检查版本:
python3 -c "import cv2,sys;print(cv2.__version__,sys.version)"
如果终端成功打印出版本号(如下图所示),则说明环境配置成功。

三、模型部署与推理实战:YOLOv5n ONNX模型的应用
环境就绪后,我们进入神经网络模型部署阶段。首先,需要获取预训练的YOLOv5n模型。为了便于在OpenCV中使用,我们下载其ONNX格式。ONNX是一个开放的模型格式,支持在不同框架间转换和运行,是实现AI模型跨平台部署的关键。
wget https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n.onnx
wget https://github.com/pjreddie/darknet/blob/master/data/coco.names
下载模型后,便是编写推理代码的核心部分。其工作流程可以概括为以下几个关键步骤:
- 1. 加载模型:使用OpenCV的`cv2.dnn.readNetFromONNX()`函数读取ONNX模型文件。
- 2. 图像预处理:将输入图像缩放至模型要求的尺寸(如640x640),并进行归一化、颜色通道转换(BGR转RGB)等操作,转换为blob格式。
- 3. 前向传播(推理):将blob数据输入网络,得到原始的输出张量。
- 4. 后处理:这是最关键且容易出错的一步。需要解析模型的输出,应用置信度阈值和非极大值抑制(NMS)来过滤冗余的检测框,最终得到可信的物体类别、位置和置信度。
- 5. 可视化:将检测到的边界框和类别标签绘制到原图上,并显示结果。
接下来,我们创建一个新的Python文件,并将以下核心代码写入其中。代码中包含了详细的注释,帮助你理解每一步的操作:
#!/usr/bin/env python3
import cv2
import numpy as np
import argparse
# input image path
parser = argparse.ArgumentParser()
parser.add_argument('--image_path', default='./img/desktop.jpg', help='输入指令 python3 or_yolo.py --image_path ./img/desktop.jpg')
args = parser.parse_args()
# ========== Parameters ==========
INPUT_WIDTH = 640
INPUT_HEIGHT = 640
SCORE_THRESHOLD = 0.5
NMS_THRESHOLD = 0.45
CONFIDENCE_THRESHOLD = 0.45
FONT_FACE = cv2.FONT_HERSHEY_SIMPLEX
FONT_SCALE = 0.7
THICKNESS = 1
BLACK = (0,0,0) # BGR
BLUE = (255,178,50)
YELLOW = (0,255,255)
RED = (0,0,255)
GREEN = (0,255,0)
# ======================================
def draw_label(im, label, left, top):
"""绿色填充标签 + 黑色文字"""
(tw, th), _ = cv2.getTextSize(label, FONT_FACE, FONT_SCALE, THICKNESS)
cv2.rectangle(im, (left, top - th - 6), (left + tw + 4, top), GREEN, cv2.FILLED)
cv2.putText(im, label, (left + 2, top - 2), FONT_FACE, FONT_SCALE, BLACK, THICKNESS, cv2.LINE_AA)
def pre_process(im, net):
blob = cv2.dnn.blobFromImage(im, 1/255., (INPUT_WIDTH, INPUT_HEIGHT), (0,0,0), swapRB=True, crop=False)
net.setInput(blob)
out_layers = net.getUnconnectedOutLayersNames()
return net.forward(out_layers)
def post_process(im, outs):
class_ids, confidences, boxes = [], [], []
rows = outs[0].shape[1]
x_factor = im.shape[1] / INPUT_WIDTH
y_factor = im.shape[0] / INPUT_HEIGHT
for r in range(rows):
row = outs[0][0][r]
conf = row[4]
if conf < CONFIDENCE_THRESHOLD: continue
classes_scores = row[5:]
class_id = int(np.argmax(classes_scores))
if classes_scores[class_id] < SCORE_THRESHOLD: continue
cx, cy, w, h = row[0], row[1], row[2], row[3]
left = int((cx - w/2) * x_factor)
top = int((cy - h/2) * y_factor)
width = int(w * x_factor)
height = int(h * y_factor)
boxes.append([left, top, width, height])
confidences.append(float(conf))
class_ids.append(class_id)
indices = cv2.dnn.NMSBoxes(boxes, confidences, CONFIDENCE_THRESHOLD, NMS_THRESHOLD)
for i in indices:
b = boxes[i]
left, top, w, h = b[0], b[1], b[2], b[3]
cv2.rectangle(im, (left, top), (left + w, top + h), GREEN, 2*THICKNESS)
label = f"{classes[class_ids[i]]}:{confidences[i]:.2f}"
draw_label(im, label, left, top - 2)
print(f"{label} | bbox=({left},{top},{w},{h})")
return im
# ================= main =================
classes = open("./model/coco.names").read().strip().split('\n')
net = cv2.dnn.readNet("./model/yolov5n.onnx")
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)
frame = cv2.imread(args.image_path)
assert frame is not None, "目标不存在,请检查图片路径"
outs = pre_process(frame, net)
result = post_process(frame, outs)
# 效率信息
t, _ = net.getPerfProfile()
label = f"Inference: {t*1000/cv2.getTickFrequency():.2f} ms"
cv2.putText(result, label, (20, 40), FONT_FACE, FONT_SCALE, RED, THICKNESS, cv2.LINE_AA)
print(label)
cv2.namedWindow('YOLOv5n', cv2.WINDOW_NORMAL)
cv2.imshow("YOLOv5n", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
保存代码文件后,就可以通过终端运行我们的物体识别程序了。使用如下命令,并指定模型路径和待检测的图片:
python3 or_yolo.py --image_path ./img/desktop.jpg四、效果展示、优化思路与总结
运行程序后,终端会打印出推理过程的信息,包括加载的模型、检测到的物体类别及其置信度。

同时,会弹出一个图像窗口,直观地展示检测结果。你可以看到YOLOv5n准确地在图片中框出了“人”、“杯子”、“笔记本电脑”等物体,并标出了置信度。按任意键即可关闭窗口。








性能优化与扩展思考:
1. 模型量化:可以尝试将FP32的ONNX模型量化为INT8格式,能显著提升在NPU上的推理速度并降低功耗。
2. 多线程处理:利用Arduino UNO Q的多核优势,将图像采集、预处理、推理和后处理分配到不同线程,实现流水线作业,提升帧率。
3. 视频流处理:将本项目的静态图片输入改为摄像头视频流输入,即可实现实时视频物体识别。
4. 模型微调:如果识别特定物体(如某种工业零件),可以在PC上使用自定义数据集对YOLOv5n进行微调,再部署到边缘端,提升专业场景的准确率。[AFFILIATE_SLOT_2]
✅ 总结
本文详细演示了在Arduino UNO Q边缘计算平台上部署YOLOv5n物体识别模型的完整流程。从环境搭建、模型获取,到利用OpenCV DNN模块进行推理和结果可视化,我们一步步实现了将先进的深度学习能力赋予嵌入式设备。这套方案具有轻量化、低延迟、高隐私性的特点,为开发者提供了一个强大的边缘AI视觉开发参考框架,极大地加速了智能硬件产品从概念到原型的进程。随着机器学习和边缘计算技术的不断演进,此类方案的潜力将更加不可限量。
浙公网安备 33010602011771号