背景
宠物猫出现头部震颤和共济失调(走路摇晃),住院期间由医院每日拍摄视频。 治疗需要客观疗效指标,于是有了这个项目:用计算机视觉量化震颤的频率与强度,监测治疗是否起效。
看似简单,实际踩了五个坑。本文记录完整的方法论演进和验证过程。
问题定义
目标:从一段手机视频中,输出猫头部震颤的频率(Hz)和强度。 约束:视频质量不一(暗光、笼子遮挡、飞书压缩)、猫会动、可能手抖、没有标注数据。
方法论演进:五个版本,五个教训
v1:抽帧看静态画面 —— 完全失败
第一反应是抽帧给视觉大模型看。结果:每一帧看起来都很正常。
教训 1:震颤是高频小幅运动(4-6Hz,亚像素级),静态帧里根本不存在这个信息。看视频不能只看帧,要看时序。
v2:全画面光流 —— 被进食动作污染
用 Farneback 光流计算全画面平均位移,FFT 找主频。结果水平主频从 5.2Hz “降到” 2.2Hz, 一度以为治疗起效——实际上是因为猫在吃东西,低频咀嚼动作主导了频谱。
教训 2:运动信号是多成分叠加的。主动运动(低频大幅)会淹没震颤(高频小幅), 必须做频域分离。
v3:静态框 + 剔除手抖段 —— 框漂移
视觉大模型标第一帧头部框,固定框分析,手抖段剔除。两个问题: 静态框跟丢移动的猫头;“剔除”丢数据,不如”补偿”。
教训 3:固定 ROI 在活体目标上必然漂移;能补偿就别剔除。
v4:YOLO 预训练检测 —— 0/258 帧检出
用 COCO 预训练的 YOLOv8n 检测猫头。结果:暗光+笼子遮挡场景下 0/258 帧检出, 甚至把猫误判为狗。
教训 4:预训练检测器不等于万能。对域外分布(暗光、遮挡、低角度), 基于纹理的追踪器(CSRT)比基于类别的检测器更鲁棒。
v5/v6:CSRT 追踪 + 运动补偿 + 抗泄漏 —— 收敛
最终方案:
- 第一帧:视觉大模型标头部框
- 全程:CSRT 追踪器跟随(1144/1144 帧,100% 成功)
- 逐帧:Farneback 光流提取头部区域位移
- 补偿:背景区域光流(中位数)估计全局运动(手抖),从头部信号中减去
- 滤波:高通 >4Hz,切掉呼吸/低频身体运动
- 频谱:Welch PSD + 相对峰值比(峰强度/邻域基线),抗频谱泄漏
def welch_psd(sig, fps=30, nperseg=64):
sig = np.asarray(sig, dtype=float) - np.asarray(sig, dtype=float).mean()
n = len(sig)
step = nperseg // 2
nseg = max(1, (n - nperseg) // step + 1)
psd = np.zeros(nperseg // 2 + 1)
for i in range(nseg):
seg = sig[i*step:i*step+nperseg]
fft = np.fft.rfft(seg * np.hanning(len(seg)))
psd += np.abs(fft) ** 2
psd /= nseg
return np.fft.rfftfreq(nperseg, d=1/fps), psd
关键设计:抗频谱泄漏的峰值检测
直接”3-15Hz 找最大峰”在低频泄漏时会误报。完整频谱检查发现 0.5-2.5Hz 的能量远大于 5Hz 频段——高通滤波不够干净时, 低频泄漏会污染主频判断(半频强度一度高于主峰,疑似谐波)。
修正方案:报告相对峰值比 = 峰强度 / 频段中位数 × 100%:
-
300%:高置信震颤峰
- 200-300%:中等
- <200%:不显著
病猫实测 400-1200%,健康对照(合成)低于 200%——阈值有效分离两类。
验证:鲁棒性与泛化性
鲁棒性(参数扰动)
| 测试 | 结果 |
|---|---|
| 高通 cutoff 3.0-4.5Hz | 主频稳定 5.16Hz |
| 初始框 ±20px 扰动 | 4.69-5.62Hz 波动(中敏感) |
| 时间分段(前/中/后) | 5.2-6.5Hz(生理波动) |
结论:频率量级鲁棒,精确值有 ±1Hz 波动——报”约5Hz”比报”5.16Hz”诚实。
泛化性(合成信号)
- 4-12Hz 全频段检出:峰值比 5461%-10505%
- 抗噪:噪声 0.05→1.0,仍能检出(215%+)
- 假阳性:阈值 200% 时健康信号会误报,提高到 300% 后解决
结果
| 日期 | 条件 | 主频 | 峰/基线比 |
|---|---|---|---|
| 8/10 | 站立 | 5.16Hz | 936% |
| 8/11 | 趴着 | 5.16Hz | 408% |
| 8/12 | 趴着 | 4.69Hz | 206% |
震颤频率落在 4-6Hz 典型频段;强度逐日下降(936%→206%)与临床症状好转 (退热、食欲恢复、血小板回升)一致。
工程总结
- 运动分析的本质是时序信号处理,不是帧的分类
- 误差分析决定可信度:逐秒背景对照才能发现手抖污染;完整频谱检查才能发现谐波
- 预训练模型的边界:域外分布下,简单纹理追踪器完胜 YOLO
- 诚实报告:报范围+置信度,不报伪精确的单点值