把 12-3 的裸接口推理装进摄像头循环:USB 摄像头取帧 → 缩到 300×300 → LiteRT 推理 → 画框贴标签——树莓派的实时物体识别由此闭环;并且首次落地【隔帧检测】:推理慢一拍没关系,取流照常全速跑。
这是本章也是 AI 篇的收官实验:12-3 的四步舞(载模型/分配/填入/读出)提供脑子,10-6 的 V4L2 摄像头提供眼睛,11-3 的画框函数提供嘴,11-5 的【检测不必每帧都做】提供腿。四个旧知识点在此合流——本课所有 AI 实验的骨架到这一篇全部对齐。
一、实时版的结构:取流与推理解耦
12-3 一张图推理 35ms(Pi 5),看着很快,但摄像头 30 FPS 意味着每帧只有 33ms 预算——加上取帧、缩放、画框,单帧全链路必超。老教程在这里集体翻车:把推理塞进取流循环,帧率掉到 5 FPS 还卡顿。
解法不是更快的模型(也可以),而是先解耦:
取流线程(全速):摄像头 → 保存最新一帧
推理循环:取最新帧 → 推理 → 画框显示
Python 里最轻的做法不必上多线程——隔帧检测:每 N 帧才推理一次,其余帧直接复用上一次的结果画框。11-5 的第一生存法则原样适用。
二、动手 Demo:USB 摄像头实时物体识别
模型文件沿用 12-3 下载的 detect.tflite 与 coco_labels.txt:
# demo12_5_live.py —— TFLite + Webcam 实时物体识别
import time, cv2, numpy as np
from tflite_runtime.interpreter import Interpreter
interpreter = Interpreter(model_path="detect.tflite")
interpreter.allocate_tensors()
inp = interpreter.get_input_details()[0]
_, ih, iw, _ = inp["shape"]
labels = [l.strip() for l in open("coco_labels.txt", encoding="utf-8")]
cap = cv2.VideoCapture(0)
cap.set(3, 640); cap.set(4, 480)
frame_id, last_results = 0, []
while True:
ok, img = cap.read()
if not ok:
break
# 每 3 帧推理一次(隔帧检测),其余帧复用结果
if frame_id % 3 == 0:
small = cv2.resize(cv2.cvtColor(img, cv2.COLOR_BGR2RGB), (iw, ih))
data = np.expand_dims(small, 0).astype(inp["dtype"])
interpreter.set_tensor(inp["index"], data)
interpreter.invoke()
boxes = interpreter.get_tensor(interpreter.get_output_details()[0]["index"])[0]
classes = interpreter.get_tensor(interpreter.get_output_details()[1]["index"])[0]
scores = interpreter.get_tensor(interpreter.get_output_details()[2]["index"])[0]
last_results = []
for i in range(len(scores)):
if scores[i] > 0.5:
ymin, xmin, ymax, xmax = boxes[i]
last_results.append((
int(xmin * 640), int(ymin * 480),
int(xmax * 640), int(ymax * 480),
labels[int(classes[i]) + 1], float(scores[i])))
for x1, y1, x2, y2, name, score in last_results:
cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
tag = f"{name} {score:.2f}"
cv2.putText(img, tag, (x1, y1 - 8),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
cv2.imshow("Live", img)
frame_id += 1
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cap.release(); cv2.destroyAllWindows()
看到什么算成功:镜头前举起一个水杯,绿色框稳稳套住并标 cup 0.8x;框每 3 帧刷新一次位置——物体快速移动时框会短暂落后,这是隔帧检测的正常代价,不是故障。整体画面流畅度明显高于【每帧都推理】的版本。
读结果:注意框坐标的换算链——模型输出的是 300×300 输入图上的归一化坐标(12-3),乘回 640×480 才是显示图上的像素(11-3 的比例→像素思维与 12-1 的坐标换算在此第三次出现,这是视觉代码的通用功课)。
三、30 秒实验:给推理掐块秒表
在推理分支里加三行,量化【隔帧到底省了多少】:
t0 = time.perf_counter()
interpreter.invoke()
infer_ms = (time.perf_counter() - t0) * 1000
print(f"inference: {infer_ms:.0f} ms")
看到什么算成功:Pi 5 约 30-40ms、Pi 4 约 100-150ms。心算对账:Pi 5 上 1000ms / (40ms×3帧间隔) ≈ 8 次推理/秒,但显示帧率仍是取流帧率(不受推理拖累)——这就是解耦的意义。数字和你机器差一倍以上时,先查散热(CPU 降频是推理变慢的头号原因)。
四、本章防坑段:老教程的实时版哪里会翻车
- 每帧都推理——老教程的循环里没有
frame_id % 3这类判断,Pi 4 上直接卡成幻灯片;隔帧检测是实时视觉的第一课。 - 拿
cv2.VideoCapture(0)却接的是 CSI 相机——CSI 走 libcamera 栈,OpenCV 默认够不着(10-4 用 picamera2 的原因);本节标题里的 Webcam 特指 USB 摄像头(V4L2 栈),两种设备的取流路完全不同。 - 推理与显示用同一分辨率——推理吃 300×300,显示给 640×480,两套尺寸各自为政、靠换算衔接;老教程常把 resize 写丢,模型静默出错。
- 置信度阈值写死 0.9——太高的阈值让画面常年没框,新手误以为模型坏了;0.5 起步,按误报情况微调(与 11-5 同一条经验)。
五、常见误区
- 以为实时版要换更强的模型才算升级——先做结构优化(隔帧、喂小图、解耦),再谈换模型;结构不改,换什么模型都卡。
- 把框画在 300×300 的小图上再放大——框会糊成马赛克;正确顺序是【在原图坐标上画】,模型坐标只当数据源。
- 推理结果落进
last_results却忘了清空——物体移出画面后旧框还残留;每次推理前先重置列表。 - 误把掉帧当识别错——框的位置落后、标签闪烁都是隔帧机制的正常表现;实时视觉永远在【流畅】与【准确】间做交换,没有两头全占。
自测三问(点开对答案)
1. 为什么实时版要隔帧检测?——单帧全链路超预算(推理 35ms+取帧缩放画框),隔帧让显示保持取流帧率、推理结果复用,流畅度大幅提升。 2. 框坐标从模型到屏幕要经过几步换算?——两步:模型归一化坐标(0~1,y 在前)先乘输入尺寸再映射回显示分辨率(640×480)。 3. 本节摄像头为什么不能用 CSI 相机模块?——CSI 走 libcamera 栈 OpenCV 的 VideoCapture 够不着,需用 picamera2(10-4);Webcam 走 V4L2 才归 VideoCapture 管。12-1 认发动机(MediaPipe:Tasks 新代 API+NumPy 2 坑)→ 12-2 装积木(CVZone:三行出骨架)→ 12-3 下地库(LiteRT 裸接口四步舞)→ 12-4 第一仗(剪刀石头布:检测靠模型、判断靠规则)→ 12-5 收官(实时检测:隔帧+解耦)。 AI 两章合起来是一条完整的路:11 章学会【通用认物】(YOLO),12 章学会【专精认手】(MediaPipe)与【裸机推理】(LiteRT)——树莓派从【能看】(第十章)走到【看懂】,再走到【看得实时】。 带着走的一句话:封装层(CVZone/ultralytics)让你跑得快,裸接口(Interpreter 四步舞)让你走得远——两层都见过,以后拿到任何 .tflite 都不慌。 下一章按教材顺序,等波仔报标题。
- ☑ 第十二章 完结 —— 教材这一章已读完五节:认识了 MediaPipe 的两代 API 与 NumPy 冲突坑、把 CVZone 的积木层玩熟、下到 LiteRT 裸接口走通四步舞、用规则判断完成第一个手势实验,最后以隔帧检测的实时识别收官——树莓派【看世界】这门功课,到此 both【认得出】与【跟得上】都齐了
- ☑ 第十三章 IoT 实验范例:温湿度监控与 Node-RED —— 已完结:物联网实验范例:Node-RED 仪表板(IoT 收官:Flask 点灯、DHT22 上云、Node-RED 仪表板——采集上云展示三条路全通)
相关笔记
- TensorFlow Lite 物体识别 —— 上一节:四步舞与模型文件在这里
- AI 实验范例:识别剪刀、石头和布的手势 —— 隔帧与解耦思路的规则版先例
- 使用 Python 操作相机模块 —— CSI 相机版实时取流(picamera2 之路)
- AI 实验范例:OpenCV+YOLO 物体识别 —— AI 篇的上半场:YOLO 全托管版实时检测
- 认识 IoT 物联网 —— 下一章起点:本章的【看得实时】成为 IoT 链路的边缘智能层
- 物联网实验范例:Node-RED 仪表板 —— 章末收官:与本节同款的【取流/推理解耦】思想换装成【采集/展示解耦】
- 🍓 树莓派 · 索引 —— 全课路线图