不写一行代码,把 COCO-SSD 拖上画布:Webcam 拍一张、tensorflowCoco 认一遍、Debug 报结果——80 类物体随手点名。
14-1 讲了 TF.js 是什么、14-2 把四件套装好并验证了消息格式;本节把它们拼成第一个完整实验。它和 11-5 的 YOLO 是同一任务的 JS 版:11-5 要写 Python 循环读帧+画框,本节全部工作只是连三根线、调一个阈值——工具换了,任务没换。
一、COCO-SSD 是什么货色
COCO-SSD 是 Google 发布的轻量物体检测模型(TF.js Models 家族成员):
- 认 80 类:人、车、猫、狗、杯子、剪刀、键盘、手机……清单来自 COCO 数据集;
- SSD 结构:Single Shot Detector——网络一口气同时【出框+定类】,不走【先找候选再逐个分类】的两阶段流程,换来端侧友好的速度;
- 离线可用:模型文件随节点装在本地,部署完不联网也能认。
和 11-5 的 YOLO 对位:YOLO 也是单阶段检测器(名 home 里的【you only look once】与【single shot】是同一个思路的两种实现),输入一张图、输出一批 {class, score, bbox}——两个模型输出结构一模一样,只是宿主语言和喂图方式不同。
二、最小可用流:三根线
按 14-2 装好四件套后,在画布上摆三个节点连线:
[Webcam] → [tensorflowCoco] → [Debug]
- Webcam:来自 dashboard 类别。部署后打开 dashboard 页面(13-5 的
/ui,装了新版则是/dashboard),点拍照按钮输出一张 jpeg; - tensorflowCoco:配置里 scoreThreshold 先保持默认 0.5,passthru 选 bbox(把原图连同框一起传下去,方便接 image 节点看图);
- Debug:完整消息模式,看输出数组。
点 Webcam 拍照后,Debug 面板出现:
[{"class":"person","score":0.91,"bbox":[98,30,352,470]},
{"class":"cup","score":0.63,"bbox":[420,390,90,120]}]
想看带框的图,再从 tensorflowCoco 拉一根线到 image 节点(14-2 四件套之一)——框会直接画在图上,验收效果一目了然。
三、阈值调优:0.5 不是圣旨
scoreThreshold 决定【多像才算】:检出太少是漏检(阈值偏高),杂草都认成猫是误检(阈值偏低)。调优口诀:
- 想宁可信其有(安防报警类):降到 0.3~0.4,宁可多报不可漏报;
- 想宁缺毋滥(统计计数类):升到 0.6~0.7,只留有把握的;
- 换场景就重调:室内调好的阈值到室外逆光环境全部作废。
这些数值没有理论最优,以自己场景的实测为准——每次调完拍同样几张图对比输出数量,比拍脑袋快得多。
四、它是【拍一张认一张】,不是监控视频流
这里要掰正一个从 12-5 带过来的惯性:TFLite 那节是【while 循环读帧、逐帧实时识别】。COCO-SSD 节点在树莓派上的实际节奏是事件驱动——每收到一条消息(一张图)推理一次,单次推理常要一到几秒(tfjs-node 在 ARM 上并不快)。
所以正确用法是【定时拍一张 → 认一次 → 有结果再行动】,而不是幻想 30 FPS 实时监控。想让节点稳定工作:
- 别把拍照频率设到秒级以内(Node-RED 的 Repeat 间隔给 5~10 秒较稳);
- 内存吃紧时先关掉带框图片输出(passthru 和 image 节点都吃资源);
- 模型首次加载要数秒——部署后第一拍报错或卡顿,等它缓过来再试,这是 14-2 说的【加载慢】不是坏了。
五、动手 Demo:人员检测提醒器
把识别结果变成动作——检测到 person 就在 dashboard 报字:
[Webcam] → [tensorflowCoco] → [Switch] ─(person)→ [Change] → [Text(dashboard)]
└────────────────→ [Debug]
配置三处:
- Switch:按 JSONata/消息属性分流,条件取
payload[].class包含 person(用【数值/属性】规则,遍历数组匹配字符串 person); - Change:设置
msg.payload为固定文本【有人在镜头前】; - Text:dashboard 组里建一个 text 元素,部署后 dashboard 页面直接显示。
看到什么算成功:镜头前没人时 Text 为空;有人入镜后一拍内(几秒级)dashboard 跳出【有人在镜头前】,同时 Debug 里的数组出现 class:"person" 的元素。
读结果:Switch 只挑 person 这一类做动作,其余类别走 Debug 观察不触发提醒——【识别】和【对识别结果做业务判断】在画布上是两个节点,各司其职。想接继电器开关灯?把 Text 换成 13-4 以后的 Python 桥(HTTP/MQTT 触发 gpiozero)即可,13 章的老结论【Pi 5 上别用 GPIO 节点】原样有效。
30 秒实验
同一个摄像头画面,把 scoreThreshold 依次改成 0.3 和 0.8(改完要重新部署),各拍一张同样的照片对比 Debug 输出:
- 0.3 时数组条目更多(连似是而非的都报);
- 0.8 时条目明显变少(只留高把握的);
- 数一遍两次的条目数,你就亲手摸到了【召回 vs 精确】的跷跷板。
六、常见误区
- COCO-SSD 能认出我家猫叫什么名字 —— 它只认 80 类里的【cat】这个通用类别;认【是不是你家那只】要靠 14-4 的自训练模型。
- 部署完第一拍没反应是装坏了 —— 模型首次加载要数秒,先等再拍;报错才回头查 14-2 的重编步骤。
- 把 Repeat 设成 0.1 秒就能做实时监控 —— 树莓派上单次推理就是秒级,消息会越积越多把机器压垮;事件驱动的【每 5~10 秒拍一张】才是这台机器的节奏。
- 阈值调好了就一劳永逸 —— 光线、角度、距离一变,阈值全部要重调;它是一次实验参数,不是一个常数。
自测三问(点开对答案)
1. COCO-SSD 的输出数组每个元素长什么样? `{class: 类别名, score: 0~1 置信度, bbox: [x, y, 宽, 高]}`——和 11-5 YOLO 的输出结构同构。 2. 安防报警和人数统计,阈值分别往哪边调? 报警类调低(0.3~0.4,宁多报不漏报);统计类调高(0.6~0.7,只留有把握的)。 3. 检测到人之后想开灯,在树莓派上应该怎么接? 识别节点触发消息后经 HTTP/MQTT 交给 Python+gpiozero 做开关——Pi 5 上 GPIO 节点已随底层库退场(13-4 结论)。- ☐ 下一节(14-4 AIoT 实验范例:Node-RED 与 Teachable Machine)
相关笔记
- 相关 Node-RED 节点的安装与使用 —— 四件套与重编,本节的开工前提
- AI 实验范例:OpenCV+YOLO 物体识别 —— 同一任务的 Python 版,输出结构同构
- AI 实验范例:TensorFlow Lite+Webcam 实时物体识别 —— 【实时循环】与本章【事件驱动】的节奏对照
- 物联网实验范例:Node-RED 仪表板 —— dashboard 元素与 /dashboard 地址
- 🍓 树莓派 · 索引 —— 全课路线图