报警要连着攒够两分钟,几帧噪声就让它永远攒不满
问题
我在做一个转动监测,判定结果分几档:在转、停了、看不清。其中「停了」不能直接报警,得连续持续够一段时间(默认两分钟)才升级成异常,为的是躲开偶尔一晃而过的抖动误报。
现象
拿一段有标准答案的视频回放:前 64 秒在正常转,之后停了,一直到片尾。尾段明明一直没动,报警却始终不响。
把时间线打出来看,停转那一段里有大约 20~25% 的帧被判成了「在转」。不是一直判错,就是隔一会儿冒出来一帧两帧。剩下的帧都判「停了」。
信号本来就弱,检测框在停住之后还有一点极慢的残余漂移,偶尔算出来的速率就冒过了门限,判成「在转」了。
怎么解决
原来的写法是个连续计数器:判「停了」就往里累加时间,一旦判「在转」,立刻把整个计时清零,从头再来。
问题就在这个清零上。两分钟的门槛,只要中间任何一帧被判成「在转」,前面攒的全部作废。弱信号下这种零星误判躲不掉,隔几十秒来一帧,计数器就永远攒不满 120 秒。报警链路本身没写错,是它对噪声一点容忍都没有。
换成看占比就好了:
- 开一个滑动窗口,每帧往里放一个标记:判「停了」记 1,判「在转」记 0;
- 「看不清」「没看到管子」这两种不记进去,等于把计时暂停,既不算正也不算反;
- 升级报警的条件从「连续停够 120 秒」改成「窗口里停的比例不低于 80%,而且窗口得基本填满」。
这样零星几帧误判只把比例拉低一点点,不会把之前攒的全抹掉。
几个边界也顺手处理了:
- 管子中途转出画面,会把窗口里最旧的记录挤出去,窗口填不满,覆盖不够 → 不误报;
- 持续旋转的时候停的比例是 0 → 不报;
- 短暂停转(比如 49 秒)还是不报——这是对的,占比窗口要求持续看得见差不多一整圈,短停本来就不该响。
验证用了合成和真实各几组:真停加 18% 噪声误判,新逻辑报、旧逻辑不报;200 秒纯停,新旧都报;持续转,两者都不报;真实固定机位回放,改动没引入新误报。
结论
「必须连续 N 帧都成立」是个特别脆的条件。只要中间允许任何一帧不满足就清零,偶发噪声就能让真实发生的事永远攒不满,而且现象很隐蔽——日志里看不出报错,只是报警不响,你甚至会以为是阈值调太高了。
改成「窗口内占比达标 + 窗口填满」稳得多,噪声被平均掉,同时「没看清」单独处理成暂停,不会被算成反证。
再往前一步,那次改动里还有个更根本的教训:一开始我用的判据要求「速率跟 0 区分不开」才算停,结果停转后框有 0.2~0.5 像素每秒的残余慢漂移,速率永远显著不等于 0,整个停转段被死死卡在「看不清」。后来改成看置信区间——只要速率的上界低于正常转速的下限,就算「没在以正常转速转」。跟自己测出来的噪声比,比跟一个理想中的绝对零比,靠谱得多。