Skip to content
Joker.Yun
Go back

猫头部震颤的量化分析:CSRT追踪 + 光流 + FFT 的工程实践

约 6 分钟读完Edit page

背景

宠物猫出现头部震颤和共济失调(走路摇晃),住院期间由医院每日拍摄视频。 治疗需要客观疗效指标,于是有了这个项目:用计算机视觉量化震颤的频率与强度,监测治疗是否起效。

看似简单,实际踩了五个坑。本文记录完整的方法论演进和验证过程。

问题定义

目标:从一段手机视频中,输出猫头部震颤的频率(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 追踪 + 运动补偿 + 抗泄漏 —— 收敛

最终方案:

  1. 第一帧:视觉大模型标头部框
  2. 全程:CSRT 追踪器跟随(1144/1144 帧,100% 成功)
  3. 逐帧:Farneback 光流提取头部区域位移
  4. 补偿:背景区域光流(中位数)估计全局运动(手抖),从头部信号中减去
  5. 滤波:高通 >4Hz,切掉呼吸/低频身体运动
  6. 频谱: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%:

病猫实测 400-1200%,健康对照(合成)低于 200%——阈值有效分离两类。

验证:鲁棒性与泛化性

鲁棒性(参数扰动)

测试结果
高通 cutoff 3.0-4.5Hz主频稳定 5.16Hz
初始框 ±20px 扰动4.69-5.62Hz 波动(中敏感)
时间分段(前/中/后)5.2-6.5Hz(生理波动)

结论:频率量级鲁棒,精确值有 ±1Hz 波动——报”约5Hz”比报”5.16Hz”诚实。

泛化性(合成信号)

结果

日期条件主频峰/基线比
8/10站立5.16Hz936%
8/11趴着5.16Hz408%
8/12趴着4.69Hz206%

震颤频率落在 4-6Hz 典型频段;强度逐日下降(936%→206%)与临床症状好转 (退热、食欲恢复、血小板回升)一致。

工程总结

  1. 运动分析的本质是时序信号处理,不是帧的分类
  2. 误差分析决定可信度:逐秒背景对照才能发现手抖污染;完整频谱检查才能发现谐波
  3. 预训练模型的边界:域外分布下,简单纹理追踪器完胜 YOLO
  4. 诚实报告:报范围+置信度,不报伪精确的单点值

项目开源:github.com/cloud666666666/cat-tremor-analysis


Edit page
Share this post:

Next Post
从 0 到 1 搭建机械臂 VLA 数据采集系统