b3608f534e
- 新增 analysis/ 模块:MOG2活动检测、YOLO人物跟踪、MediaPipe摔倒检测、Ollama活动打标、缩略图抽取 - 新增 webapp/:Flask事件浏览界面,按需HEVC→H264转码缓存 - 新增 analyze.py:7阶段状态机流水线(scan→backfill→motion→person→fall→activity→thumbnail) - 新增 cleanup_orphans.py:清理文件已删除的数据库孤儿记录 - 修复:motion/person/activity三阶段加单视频异常兜底,避免批次中断 - 修复:ollama_client加健康检查和3次重试,num_ctx从8192降到2048 - 修复:transcode_cache加fcntl文件锁,防止并发转码同一视频 - 修复:SQLite开WAL模式+busy_timeout,支持读写并发 - 修复:sync.py ffmpeg路径改为shutil.which查找,删除automate.py死代码PYTHON - 修复:thumbnail失败加3次重试上限,避免无限重试损坏文件 - 新增:requirements.lock锁定版本、README文档 - 更新:.gitignore排除.playwright-mcp、截图、备份文件
171 lines
8.0 KiB
Markdown
171 lines
8.0 KiB
Markdown
# ezviz-sync — 萤石摄像头录像同步与智能分析
|
||
|
||
从萤石(EZVIZ)摄像头同步 SD 卡报警录像到本地,对录像做 AI 分析(人物检测、摔倒检测、活动语义打标),并提供 Web 界面浏览和回放。
|
||
|
||
目标设备:萤石 CB60,序列号 `BH5455783`。
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
ezviz-sync/
|
||
├── automate.py # 主力下载脚本:ADB 自动化模拟器内萤石 App 批量下载
|
||
├── sync.py # [已废弃] 开放平台 API 下载方案,保留作备选
|
||
├── probe.py # API 探测调试脚本
|
||
├── analyze.py # 视频分析主入口(7 阶段流水线)
|
||
├── config.py # 萤石开放平台配置(密钥,已 gitignore)
|
||
├── config.example.py # 配置模板
|
||
├── requirements.txt # 直接依赖
|
||
├── requirements.lock # 锁定版本的完整依赖(pip freeze)
|
||
├── recordings/ # 下载的录像,按 设备号/日期/ 归档
|
||
├── analysis.db # SQLite 元数据库(运行时生成)
|
||
├── thumbnails/ # 事件缩略图(运行时生成)
|
||
├── transcoded/ # Web 播放转码缓存(运行时生成)
|
||
├── analysis/ # 分析模块
|
||
│ ├── db.py # SQLite 建表与 CRUD
|
||
│ ├── config.py # 分析参数配置(阈值、模型名、路径)
|
||
│ ├── video_scanner.py # 扫描录像文件入库 + MD5 查重
|
||
│ ├── motion_filter.py # MOG2 背景建模检测活动窗口
|
||
│ ├── person_tracker.py # YOLO11 + ByteTrack 人物跟踪
|
||
│ ├── fall_detector.py # MediaPipe Pose 摔倒检测
|
||
│ ├── activity_tagger.py # Ollama VLM 活动语义打标
|
||
│ ├── thumbnail.py # 事件缩略图抽取
|
||
│ ├── timestamp_reader.py # OSD 时间戳水印识别(模板匹配)
|
||
│ ├── backfill_start_time.py # 精确时间戳回填
|
||
│ ├── dedup_finder.py # 重复视频检测(生成报告)
|
||
│ ├── dedup_cleanup.py # 重复视频清理(默认 dry-run)
|
||
│ ├── cleanup_orphans.py # 清理文件已删除的数据库孤儿记录
|
||
│ ├── hashing.py # MD5 计算
|
||
│ ├── ollama_client.py # Ollama VLM 调用封装
|
||
│ ├── frida_spawn.py # Frida SSL pinning 绕过(抓包用)
|
||
│ ├── unpin.js # Frida 脱壳脚本
|
||
│ ├── models/ # MediaPipe pose 模型权重
|
||
│ └── templates/ # OSD 数字识别模板库
|
||
├── webapp/ # Flask Web 界面
|
||
│ ├── app.py # 路由:事件列表、统计、视频流、缩略图
|
||
│ ├── transcode_cache.py # 按需转码缓存(HEVC→H264)
|
||
│ ├── templates/index.html
|
||
│ └── static/ # app.js, style.css
|
||
└── yolo11n.pt # YOLO11 目标检测权重(首次运行自动下载)
|
||
```
|
||
|
||
## 环境依赖
|
||
|
||
| 工具 | 用途 | 安装 |
|
||
|---|---|---|
|
||
| Python 3.12 | 运行环境 | `pyenv install 3.12` 或系统包管理器 |
|
||
| ffmpeg / ffprobe | 视频处理、抽帧、转码 | `brew install ffmpeg` |
|
||
| ImageMagick (`magick`) | 截图像素分析(automate.py 蓝勾/行检测) | `brew install imagemagick` |
|
||
| Android SDK + ADB | 模拟器控制 | `brew install --cask android-platform-tools` |
|
||
| Android 模拟器 | 运行萤石 App | Android Studio AVD 或第三方模拟器 |
|
||
| Ollama | 本地 VLM 推理(活动打标) | `brew install ollama && ollama pull qwen2.5vl:7b` |
|
||
|
||
## 安装
|
||
|
||
```bash
|
||
# 1. 克隆项目
|
||
git clone <repo> && cd ezviz-sync
|
||
|
||
# 2. 创建虚拟环境
|
||
python3.12 -m venv .venv
|
||
source .venv/bin/activate
|
||
|
||
# 3. 安装依赖(用 lock 文件保证版本一致)
|
||
pip install -r requirements.lock
|
||
|
||
# 4. 配置萤石开放平台
|
||
cp config.example.py config.py
|
||
# 编辑 config.py 填入 AppKey / AppSecret / 设备序列号 / 验证码
|
||
|
||
# 5. 初始化数据库(首次运行 analyze.py 自动建表)
|
||
python analyze.py --only-stage scan
|
||
```
|
||
|
||
## 使用方法
|
||
|
||
### 1. 下载录像
|
||
|
||
```bash
|
||
# 下载昨天的录像(默认)
|
||
python automate.py
|
||
|
||
# 下载最近 7 天的录像
|
||
python automate.py 7
|
||
```
|
||
|
||
下载流程:启动模拟器内萤石 App → 导航到指定日期 → 批量下载 → adb pull 到本地 `recordings/设备号/日期/`。
|
||
|
||
### 2. 分析录像
|
||
|
||
```bash
|
||
# 跑完整流水线(scan → backfill → motion → person → fall → activity → thumbnail)
|
||
python analyze.py
|
||
|
||
# 只跑某个阶段
|
||
python analyze.py --only-stage motion
|
||
|
||
# 小批量测试
|
||
python analyze.py --only-stage person --limit 10
|
||
|
||
# 强制重跑某个阶段(回退已完成的视频状态)
|
||
python analyze.py --only-stage activity --force
|
||
```
|
||
|
||
流水线状态机:`pending → motion_done → person_done → fall_done → activity_done`,每个阶段只处理上一阶段完成的视频,重复运行幂等。
|
||
|
||
### 3. 启动 Web 界面
|
||
|
||
```bash
|
||
python -m webapp.app
|
||
# 打开 http://127.0.0.1:5050
|
||
```
|
||
|
||
功能:按事件类型/日期筛选、点击事件跳转播放对应时间点、转码缓存管理。
|
||
|
||
### 4. 维护工具
|
||
|
||
```bash
|
||
# 检测重复视频(只生成报告,不删除)
|
||
python -m analysis.dedup_finder
|
||
|
||
# 清理重复视频(先预览,确认后加 --execute)
|
||
python -m analysis.dedup_cleanup
|
||
python -m analysis.dedup_cleanup --execute
|
||
|
||
# 清理数据库中文件已不存在的孤儿记录
|
||
python -m analysis.cleanup_orphans # dry-run
|
||
python -m analysis.cleanup_orphans --execute
|
||
```
|
||
|
||
## 分析流水线详解
|
||
|
||
| 阶段 | 输入状态 | 输出状态 | 方法 | 说明 |
|
||
|---|---|---|---|---|
|
||
| scan | — | pending/corrupt/duplicate | ffprobe + MD5 | 扫描 recordings/ 入库,按 MD5 标记重复 |
|
||
| backfill | pending | pending(不变) | 模板匹配 OCR | 读取画面 OSD 时间戳,回填精确 start_time |
|
||
| motion | pending | motion_done | MOG2 背景建模 | 检测有活动的时间窗口,空场景跳过后续重模型 |
|
||
| person | motion_done | person_done | YOLO11n + ByteTrack | 只在活动窗口内跑人物检测跟踪 |
|
||
| fall | person_done | fall_done | MediaPipe Pose | 只在有人的时间段跑姿态估计,规则引擎判摔倒 |
|
||
| activity | fall_done | activity_done | Ollama Qwen2.5-VL | 活动窗口抽帧,VLM 分类为 走动/进食/坐下/站立/离开/其他 |
|
||
| thumbnail | — | — | ffmpeg 抽帧 | 给每条事件生成缩略图 |
|
||
|
||
## 关键设计决策
|
||
|
||
- **下载用 ADB 自动化而非开放平台 API**:开放平台 API 的 FLV 回放流把 24 小时录像拼接成一个文件,丢失了分段信息和精确时间戳;ADB 方案直接下载 App 内的分段报警录像,文件名含时间戳。
|
||
- **分析流水线分层过滤**:先用轻量 MOG2 预筛活动窗口,再在窗口内跑 YOLO,有人的时间段才跑姿态估计和 VLM,避免对空场景浪费算力。
|
||
- **摔倒检测用规则引擎而非 VLM**:安全信号需要可解释、可调阈值、宁可多报不漏报,MediaPipe 关键点 + "直立骤变横躺并持续"规则比模型黑盒更可靠。
|
||
- **Web 播放按需转码**:源文件是 HEVC 编码且 mp4 容器 sample entry 标签缺失,浏览器无法直接播放;第一次播放时用 VideoToolbox 硬件转码为 H264 并缓存,之后复用。
|
||
|
||
## 常见问题
|
||
|
||
**Q: automate.py 报错 `magick: command not found`**
|
||
A: 没装 ImageMagick。`brew install imagemagick`。automate.py 的蓝勾检测和卡片行定位都依赖 `magick` 命令。
|
||
|
||
**Q: analyze.py 跑 activity 阶段很慢/卡住**
|
||
A: 检查 Ollama 是否在运行:`ollama ps`。模型 `qwen2.5vl:7b` 需要约 6GB 显存/内存。
|
||
|
||
**Q: Web 端视频播放不了**
|
||
A: 首次播放会触发转码(HEVC→H264),大文件可能需要几十秒。转码缓存在 `transcoded/`,可在 Web 界面清空。
|
||
|
||
**Q: 数据库里有很多 duplicate 记录**
|
||
A: automate.py 早期版本有重复下载问题(已修复),同一段录像被下载成多份。scan 阶段按 MD5 自动标记 duplicate 并跳过分析。可用 `dedup_cleanup.py` 清理多余文件。
|