2. 使用OpenCV和Intel Neural Compute Stick 2进行实
任务目标
在树莓派4B(4GB及以上版本)上,使用OpenCV读取摄像头或视频帧,通过OpenVINO工具包将SSD MobileNet V2目标检测模型部署到Intel Neural Compute Stick 2(NCS2)上,对每一帧执行推理,并在图像上绘制检测到的目标边界框与类别标签,实现实时检测效果。
环境与依赖
- 硬件:树莓派4B、Intel NCS2、USB摄像头(或使用测试视频文件)
- 系统:Raspberry Pi OS(64位,Bullseye或更新版本)
- 软件:OpenVINO Toolkit 2022.3 LTS(或兼容版本)、OpenCV(随OpenVINO环境自带)、Python 3.7+
- 模型文件:
ssd_mobilenet_v2_coco.xml与ssd_mobilenet_v2_coco.bin(可从OpenVINO模型库下载,或使用以下命令转换)
# 安装OpenVINO(已安装可跳过)
pip install openvino==2022.3.0
# 下载预转换模型(若网络受限,可手动下载后放置到模型目录)
wget https://storage.openvinotoolkit.org/repositories/open_model_zoo/2022.3/models_bin/2/ssd_mobilenet_v2_coco/FP16/ssd_mobilenet_v2_coco.xml
wget https://storage.openvinotoolkit.org/repositories/open_model_zoo/2022.3/models_bin/2/ssd_mobilenet_v2_coco/FP16/ssd_mobilenet_v2_coco.bin
完整实现代码
以下代码从摄像头读取视频帧,使用NCS2进行推理,并绘制检测结果。若没有摄像头,可将VideoCapture(0)替换为视频文件路径。
import cv2
import numpy as np
from openvino.runtime import Core, PartialShape
# ---------- 1. 初始化OpenVINO与NCS2 ----------
core = Core()
# 指定NCS2作为推理设备(若未插入会报错,可改为"CPU"调试)
device = "MYRIAD" # MYRIAD即NCS2
# 加载模型
model_path = "ssd_mobilenet_v2_coco.xml"
model = core.read_model(model_path)
# 设置输入为动态形状,兼容不同分辨率输入
model.reshape({model.input(0): PartialShape([1, 3, 300, 300])})
compiled_model = core.compile_model(model, device)
# 获取输入输出节点
input_layer = compiled_model.input(0)
output_layer = compiled_model.output(0)
# COCO数据集类别名称(仅列出模型支持的80类中的常用部分,完整列表可扩展)
CLASSES = ["background", "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", "kite",
"baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket"]
# ---------- 2. 打开摄像头 ----------
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("错误:无法打开摄像头")
exit(1)
# 设置采集分辨率(NCS2输入为300x300,但摄像头可采集更高分辨率以提升显示效果)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
print("开始实时检测,按 'q' 键退出...")
while True:
ret, frame = cap.read()
if not ret:
print("无法读取视频帧")
break
# ---------- 3. 预处理 ----------
# 调整到模型输入尺寸
resized = cv2.resize(frame, (300, 300))
# HWC -> CHW,并归一化到[0,1]
input_data = np.transpose(resized, (2, 0, 1)).astype(np.float32) / 255.0
input_data = np.expand_dims(input_data, axis=0)
# ---------- 4. 推理 ----------
result = compiled_model([input_data])[output_layer] # shape: [1, 1, N, 7]
detections = result[0][0] # 去除batch和num维度
# ---------- 5. 解析并绘制结果 ----------
h, w = frame.shape[:2]
for detection in detections:
confidence = detection[2]
if confidence > 0.5: # 置信度阈值
class_id = int(detection[1])
x1 = int(detection[3] * w)
y1 = int(detection[4] * h)
x2 = int(detection[5] * w)
y2 = int(detection[6] * h)
# 确保坐标在图像范围内
x1, y1 = max(0, x1), max(0, y1)
x2, y2 = min(w, x2), min(h, y2)
# 绘制边界框与标签
label = CLASSES[class_id] if class_id < len(CLASSES) else f"ID:{class_id}"
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.putText(frame, f"{label}:{confidence:.2f}", (x1, y1 - 5),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
# ---------- 6. 显示结果 ----------
cv2.imshow("NCS2 Object Detection", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 清理资源
cap.release()
cv2.destroyAllWindows()
运行与验证
- 将上述代码保存为
ncs2_detection.py,并确保ssd_mobilenet_v2_coco.xml和.bin文件位于同一目录。 - 插入NCS2设备,执行:
python3 ncs2_detection.py - 观察窗口是否显示摄像头画面,且画面中的人、车等目标被绿色框标记并带有类别标签。
- 将目标移出画面再移入,确认边界框能实时跟随。
通过条件:程序能持续运行且画面流畅(无明显卡顿),检测框能正确框住常见物体(如人、杯子、手机等),类别标签与置信度显示正常。按 q 键可正常退出。
常见问题排查
- NCS2未被识别:执行
lsusb应看到Intel Movidius MyriadX设备。若未出现,检查USB连接或重新插拔。 - MYRIAD设备初始化失败:确认已安装OpenVINO的USB规则:
sudo usermod -a -G users "$USER"并重新登录。 - 帧率过低:可将摄像头分辨率降至320x240,或将置信度阈值提高到0.6以减少绘制开销。
- 模型加载报错:确认XML与BIN文件为FP16精度(NCS2不支持FP32),且两个文件在同一目录。