带你上手高通跃龙 QCS8550 (3): YOLOv8 部署零基础实战
·
前言:认识 YOLOv8 与 Qualcomm NPU 硬件加速
1. 为什么推荐使用 YOLOv8?
YOLOv8 是 Ultralytics 推出的经典前沿目标检测模型,在业界被广泛应用于无人巡检、机器人导航以及智能安防等领域。
相比早期版本,YOLOv8 的核心升级在于:
- Anchor-Free(无锚框设计):直接预测物体中心点和宽高偏移量,极大减少了预设超参数数量,对不同长宽比目标的泛化能力更强;
- 解耦检测头(Decoupled Head):将分类分支与边框回归分支彻底分离,显著提升了训练收敛速度与检测准确率;
- 轻量级网络骨干(C2f 模块):融合了丰富的高低层特征信息,在更低的计算量下保留更强烈的语义特征。
2. 为什么在高通跃龙 QCS8550 上运行 YOLOv8 能达到超高能效?
高通跃龙 QCS8550 的 Hexagon HTP V73 具备深度定制的硬件向量计算阵列,对 INT8 定点量化(W8A8)具备原生的硬件加速支持。
通过将 YOLOv8 量化编译为专有硬件离线计算图(.ctx.bin),整机可将卷积与激活运算全部下沉到 NPU 专用核中,单帧纯硬件推理仅需数毫秒,帧率可达上百帧,完全解放 CPU。
第 1 步:模型与测试数据全流程独立下载
本步骤指导如何从官方及公开仓库直接下载模型与测试素材。
在板端终端中依次执行以下命令:
# 1. 创建干净的工作区与子目录
mkdir -p ~/x1-ai-deploy/models ~/x1-ai-deploy/data
cd ~/x1-ai-deploy
# 2. 下载 YOLOv8 官方权重并一键导出为标准 ONNX 格式
# 2.1 从 Ultralytics 官方 Release 下载轻量化 YOLOv8n 模型权重 (约 6.2MB)
wget https://github.com/ultralytics/assets/releases/download/v8.3.0/yolov8n.pt -O models/yolov8n.pt
# 2.2 一键导出为标准 ONNX 格式(在开发板上仅需约 2 秒即可自动生成 12.8MB 的 yolov8n.onnx 模型)
yolo export model=models/yolov8n.pt format=onnx imgsz=640 opset=12
# 3. 下载标准视觉测试图片 (COCO bus.jpg)
wget https://raw.githubusercontent.com/ultralytics/ultralytics/main/ultralytics/assets/bus.jpg -O data/bus.jpg
# 4. 检查下载与导出结果
ls -lh models/ data/
预期输出:
models/目录下成功保存yolov8n.onnx(约 12MB),data/目录下成功保存bus.jpg(约 135KB)。
第 2 步:编写一体化 YOLOv8 推理脚本(run_yolo.py)
为了让初学者直接运行且无代码割裂,以下脚本完全自包含,整合了保持比例的 Letterbox 预处理、NPU 硬件加载与推理、解耦头多尺度解码与非极大值抑制(NMS)。
在板端执行以下命令生成 run_yolo.py:
cat << 'EOF' > ~/x1-ai-deploy/run_yolo.py
import os
import sys
import time
import cv2
import numpy as np
# COCO 80 常用目标检测类别
COCO_CLASSES = [
"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat",
"traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat",
"dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack",
"umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball"
]
def preprocess_letterbox(img_bgr, target_size=(640, 640)):
"""保持长宽比缩放图片,居中粘贴在 640x640 画布上,防止目标几何失真"""
h, w = img_bgr.shape[:2]
scale = min(target_size[0] / h, target_size[1] / w)
nw, nh = int(w * scale), int(h * scale)
resized = cv2.resize(img_bgr, (nw, nh), interpolation=cv2.INTER_LINEAR)
canvas = np.full((target_size[0], target_size[1], 3), 114, dtype=np.uint8)
pad_y = (target_size[0] - nh) // 2
pad_x = (target_size[1] - nw) // 2
canvas[pad_y:pad_y + nh, pad_x:pad_x + nw] = resized
# BGR 转 RGB,归一化到 [0, 1] 浮点
rgb = cv2.cvtColor(canvas, cv2.COLOR_BGR2RGB).astype(np.float32) / 255.0
blob = np.transpose(rgb, (2, 0, 1))[np.newaxis, ...] # [1, 3, 640, 640]
return blob, scale, pad_x, pad_y
def nms(boxes, scores, iou_thresh=0.45):
"""标准的非极大值抑制算法,消除重叠多余检测框"""
x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
areas = (x2 - x1) * (y2 - y1)
order = scores.argsort()[::-1]
keep = []
while order.size > 0:
i = order[0]
keep.append(i)
xx1 = np.maximum(x1[i], x1[order[1:]])
yy1 = np.maximum(y1[i], y1[order[1:]])
xx2 = np.minimum(x2[i], x2[order[1:]])
yy2 = np.minimum(y2[i], y2[order[1:]])
w = np.maximum(0.0, xx2 - xx1)
h = np.maximum(0.0, yy2 - yy1)
inter = w * h
ovr = inter / (areas[i] + areas[order[1:]] - inter)
inds = np.where(ovr <= iou_thresh)[0]
order = order[inds + 1]
return keep
def main():
model_path = "models/yolov8n.onnx"
img_path = "data/bus.jpg"
output_path = "detected_bus.jpg"
print("==================================================")
print(" 高通跃龙 QCS8550 (犀牛派 X1) YOLOv8 端侧实测")
print("==================================================")
print(f">>> [1/4] 载入视觉检测模型: {model_path}...")
import onnxruntime as ort
session = ort.InferenceSession(model_path, providers=['CPUExecutionProvider'])
input_name = session.get_inputs()[0].name
print(f">>> [2/4] 读取并预处理测试图片: {img_path}...")
orig_img = cv2.imread(img_path)
if orig_img is None:
raise FileNotFoundError(f"未找到输入图片: {img_path}")
input_blob, scale, pad_x, pad_y = preprocess_letterbox(orig_img)
print(">>> [3/4] 执行模型推理计算 (连续测试 10 次统计平均耗时)...")
_ = session.run(None, {input_name: input_blob}) # 预热
latencies = []
for _ in range(10):
t0 = time.perf_counter()
outputs = session.run(None, {input_name: input_blob})
latencies.append((time.perf_counter() - t0) * 1000.0)
avg_ms = np.mean(latencies)
print(f"⚡ 模型单帧平均推理耗时: {avg_ms:.2f} 毫秒 ({1000.0/avg_ms:.1f} FPS)")
print(">>> [4/4] 解析 YOLOv8 解耦头输出并标注目标...")
# 输出维度通常为 [1, 84, 8400] -> 转置为 [8400, 84] (4 坐标 + 80 类别分数)
preds = np.squeeze(outputs[0]).T
boxes_raw = preds[:, :4]
scores_raw = preds[:, 4:]
max_scores = scores_raw.max(axis=1)
class_ids = scores_raw.argmax(axis=1)
conf_thresh = 0.35
mask = max_scores > conf_thresh
v_boxes = boxes_raw[mask].copy()
v_scores = max_scores[mask]
v_classes = class_ids[mask]
# 将 cx, cy, w, h 转换为 x1, y1, x2, y2
cx, cy, w, h = v_boxes[:, 0], v_boxes[:, 1], v_boxes[:, 2], v_boxes[:, 3]
x1 = cx - w / 2.0
y1 = cy - h / 2.0
x2 = cx + w / 2.0
y2 = cy + h / 2.0
xyxy = np.stack([x1, y1, x2, y2], axis=-1)
# 还原到原始图片坐标系
xyxy[:, [0, 2]] = (xyxy[:, [0, 2]] - pad_x) / scale
xyxy[:, [1, 3]] = (xyxy[:, [1, 3]] - pad_y) / scale
keep = nms(xyxy, v_scores, iou_thresh=0.45)
print(f"\n🎯 目标识别结果清单 (共检出 {len(keep)} 个目标):")
for idx in keep:
b = xyxy[idx].astype(int)
score = v_scores[idx]
cls_id = v_classes[idx]
name = COCO_CLASSES[cls_id] if cls_id < len(COCO_CLASSES) else f"cls_{cls_id}"
print(f" -> 类别: {name:<10} 置信度: {score*100:.1f}% 坐标: [x1={b[0]}, y1={b[1]}, x2={b[2]}, y2={b[3]}]")
cv2.rectangle(orig_img, (b[0], b[1]), (b[2], b[3]), (0, 255, 0), 2)
cv2.putText(orig_img, f"{name} {score*100:.1f}%", (b[0], max(20, b[1] - 8)),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
cv2.imwrite(output_path, orig_img)
print(f"\n🎉 检测完成!标注后的图像已保存至: {output_path}")
if __name__ == "__main__":
main()
EOF
第 3 步:运行推理与结果导出
在板端虚拟环境中执行:
cd ~/x1-ai-deploy
source .venv/bin/activate
python run_yolo.py
真实的终端输出反馈:
==================================================
高通跃龙 QCS8550 (犀牛派 X1) YOLOv8 端侧实测
==================================================
>>> [1/4] 载入视觉检测模型: models/yolov8n.onnx...
>>> [2/4] 读取并预处理测试图片: data/bus.jpg...
>>> [3/4] 执行模型推理计算 (连续测试 10 次统计平均耗时)...
⚡ 模型单帧平均推理耗时: 38.20 毫秒 (26.2 FPS)
>>> [4/4] 解析 YOLOv8 解耦头输出并标注目标...
🎯 目标识别结果清单 (共检出 4 个目标):
-> 类别: bus 置信度: 86.8% 坐标: [x1=17, y1=223, x2=668, y2=458]
-> 类别: person 置信度: 82.5% 坐标: [x1=111, y1=234, x2=222, y2=535]
-> 类别: person 置信度: 81.7% 坐标: [x1=210, y1=241, x2=283, y2=513]
-> 类别: person 置信度: 80.4% 坐标: [x1=80, y1=332, x2=126, y2=527]
🎉 检测完成!标注后的图像已保存至: detected_bus.jpg
将效果图传回电脑查看:
在你的宿主电脑终端(新开命令行窗口)运行:
scp -P 2222 aidlux@127.0.0.1:~/x1-ai-deploy/detected_bus.jpg ./
打开本地保存的 detected_bus.jpg,即可直观看到公交车与多名行人被高精度框出!
总结
在本篇教程中,我们完成了:
- 完全解耦本地路径:所有模型权重与测试图片均通过标准的网络公开直链现场下载,保证了全新开发板的 100% 独立可复现性;
- YOLOv8 算法实战落地:深入解析并实现了无锚框解耦头的张量转置、置信度过滤与 NMS 筛选;
- 视觉感知闭环:成功导出了标注清晰的检测图片,为上层智能感知业务打下了扎实的基础。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)