Likhita-17/SoundStrike

GitHub: Likhita-17/SoundStrike

基于经典机器学习的枪声检测与到达方向(DOA)估计系统,提供 FastAPI 后端和 Streamlit 前端的完整端到端音频分析方案。

Stars: 0 | Forks: 0

# 🔊 枪声检测 + 到达方向估计系统 这是一个实时音频分析系统,能够检测上传的 WAV 文件中的枪声,并使用两阶段的机器学习 pipeline 评估其**方位到达方向 (DOA)**,通过 FastAPI 后端和 Streamlit Web 界面提供服务。 ## 📌 概述 | 属性 | 值 | |---|---| | 任务 | 二元音频分类 + 圆周回归 | | 检测模型 | 支持向量机 (SVM,RBF 核) | | DOA 模型 | 双重 Random Forest 回归器 (sin/cos 目标) | | 检测数据集 | UrbanSound8K — 类别 6 (枪声),748 个片段 | | DOA 数据集 | STARSS23 (DCASE 2023 挑战赛),600 个场景,35.4 万个标注帧 | | DOA 准确度 | MAE ≈ 17° · 中值误差 ≈ 6° · 68.7% 的帧误差在 10° 以内 | | 界面 | Streamlit + FastAPI | ## 🎯 动机 枪声检测和定位在以下领域具有关键应用: - **公共安全** — 城市环境中的快速事件响应 - **野生动物保护** — 检测非法偷猎活动 - **军事/边境安全** — 实时定位威胁 - **法医学** — 事件发生后的射击方向重建 大多数已部署的系统依赖于昂贵的多麦克风硬件阵列。本项目旨在探索一种**基于学习的单设备方法**,利用双耳线索和频谱特征,是否可以从标准的 FOA 录音中得出有用的方向估计。 ## ✨ 功能 - 🎙️ 支持 WAV 文件上传,并在浏览器内进行音频预览 - 🔫 枪声检测,提供概率置信度得分 - 🧭 方位角估计(−180° 到 +180°),带有可靠性标签 - 📊 交互式极坐标罗盘可视化 - ⚡ 通过滑动窗口特征提取实现快速批量推理 - 🗂️ 特征缓存,避免在重新训练时重复提取 - 🌐 提供 REST API (`/predict`, `/health`),便于集成到其他系统 ## 🏗️ 架构 ``` ┌─────────────────────────────────────────────────────┐ │ Streamlit UI (app.py) │ │ Upload WAV → Audio Preview → Analyse → Compass Plot │ └─────────────────────┬───────────────────────────────┘ │ HTTP POST /predict (multipart WAV) ▼ ┌─────────────────────────────────────────────────────┐ │ FastAPI Backend (main.py) │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ Stage 1 — Gunshot Detection │ │ │ │ librosa.load (sr=22050, stereo) │ │ │ │ → MFCC(40) mean+std [80 dims] │ │ │ │ → ITD + ILD + GCC [3 dims] │ │ │ │ → StandardScaler → SVM (RBF) │ │ │ │ → {detected: bool, confidence: float} │ │ │ └──────────────┬───────────────────────────────┘ │ │ │ if detected == True │ │ ┌──────────────▼───────────────────────────────┐ │ │ │ Stage 2 — DOA Estimation │ │ │ │ librosa.load (sr=24000, stereo) │ │ │ │ → Sliding window (1 s frame, 0.1 s hop) │ │ │ │ → MFCC + ITD + ILD + GCC per frame │ │ │ │ → StandardScaler → RF_sin + RF_cos │ │ │ │ → normalize → arctan2 → azimuth per frame │ │ │ │ → Energy filter (top 15% frames) │ │ │ │ → Confidence² weighted circular mean │ │ │ │ → {azimuth_deg, reliability, frames_used} │ │ │ └──────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────┘ │ JSON response ▼ ┌─────────────────────────────────────────────────────┐ │ Results Display (Streamlit) │ │ Detection badge · Confidence metric │ │ Polar compass plot · Direction interpretation │ └─────────────────────────────────────────────────────┘ ``` ## 📂 仓库结构 ``` metadata_dev1/ ├── app.py # Streamlit frontend ├── main.py # FastAPI backend ├── requirements.txt # Pinned dependencies ├── test.py # Quick audio format sanity check │ ├── scripts/ │ ├── train_svm.py # Train gunshot SVM classifier │ ├── train_angle_model.py # Train RF DOA regressors │ ├── predict_angle.py # DOA inference (used by main.py) │ └── evaluate_angle.py # Offline DOA evaluation │ ├── models/ │ ├── svm_gunshot_model.pkl # Trained SVM (112 KB) │ ├── svm_scaler.pkl # SVM StandardScaler │ └── models_angle/ │ ├── rf_sin.pkl # RF → sin(azimuth) (~127 MB) │ ├── rf_cos.pkl # RF → cos(azimuth) (~129 MB) │ └── angle_scaler.pkl # DOA StandardScaler │ ├── data/ │ ├── master_metadata.csv # Merged STARSS23 labels (354 K rows) │ ├── foa_dev1/ # 600 First-Order Ambisonics WAV scenes │ ├── gunshots/ # 374 UrbanSound8K gunshot clips │ ├── non_gunshots/ # 374 non-gunshot clips (balanced) │ └── metadata_dev2/ # Per-scene CSV label files │ ├── cache/ # Cached numpy feature arrays ├── outputs/ # Evaluation CSVs and prediction logs └── notebooks/ ├── angle_evaluation_debug.ipynb # Evaluation results with plots └── s.ipynb # Dataset exploration / CSV merge ``` ## 📊 数据集 ### STARSS23 (DOA 训练) - **全称:** Sony-TAu Realistic Spatial Soundscapes 2023 - **来源:** [DCASE 2023 挑战赛任务 3](https://dcase.community/challenge2023/task3) - **内容:** 跨越多个房间的 600 个一阶 Ambisonics (FOA) 场景录音,包含最多 3 个同时发生的声音事件的逐帧方位角 + 仰角真实标签 - **使用的标签:** 帧索引、类别 ID、方位角(−180° 到 +180°) - **使用的训练样本:** 从 354,298 个可用帧中随机抽取的 10,000 个帧 ### UrbanSound8K (检测训练) - **来源:** [UrbanSound8K](https://urbansounddataset.weebly.com/urbansound8k.html) - **内容:** 10 种城市声音类别;类别 6 = 枪声 - **使用的片段:** 374 个枪声 + 374 个非枪声(完美平衡,总计 748 个) ## 🧠 机器学习 Pipeline ### 特征工程(83 维) | 特征 | 维度 | 原理 | |---|---|---| | MFCC 均值(40 个系数) | 40 | 捕捉声音事件的频谱包络/音色 | | MFCC 标准差(40 个系数) | 40 | 捕捉帧内频谱的时间变化 | | ITD — 双耳时间差 | 1 | 物理线索:左右声道之间的时间延迟编码了水平方向 | | ILD — 双耳声级差 | 1 | 物理线索:双耳之间的声级不对称性用于定位声音的左右方位 | | GCC — 广义互相关峰值 | 1 | 衡量声道间相关性峰值的尖锐度;作为 SNR 的代理指标 | **为什么使用 sin/cos 回归?** 方位角是一个圆周数值 — 直接对角度(以度为单位)进行回归会在 ±180° 处引入不连续性。分别预测 `sin(θ)` 和 `cos(θ)` 可以避免这个问题;最终的角度可以通过 `arctan2(sin_pred, cos_pred)` 恢复。这是圆周回归中的一种标准技术。 ### 模型 **阶段 1 — 枪声检测器** - 算法:`SVC(kernel='rbf', probability=True)` - 训练:80/20 分层划分;`StandardScaler` 仅在训练集上拟合 - 推理:`predict_proba` → 类别 1 的概率作为置信度 **阶段 2 — DOA 估计器** - 算法:两个 `RandomForestRegressor(n_estimators=200)` 模型 - 目标:`sin(azimuth_rad)` 和 `cos(azimuth_rad)` - 后处理:能量过滤(按 RMS 取前 15% 的帧)+ 加权置信度²的圆周平均值聚合 - 置信度:将 (sin, cos) 预测向量的长度归一化到单位圆;长度越大 = 预测越确定 ## 📈 结果 ### 枪声检测 | 指标 | 值 | |---|---| | 数据集 | 748 个片段(374 个枪声 / 374 个非枪声) | | 测试集划分 | 20% (150 个片段) | | 模型 | SVM RBF | | 训练 | 分层 80/20 划分 | *详细的分类报告会在训练期间打印 (`scripts/train_svm.py`)。* ### DOA 估计(5,000 帧评估 — `notebooks/angle_evaluation_debug.ipynb`) | 指标 | 值 | |---|---| | MAE | 17.00° | | 中值误差 | 6.03° | | 误差在 10° 以内的帧 | 68.66% | | 误差在 20° 以内的帧 | 83.08% | | 误差在 30° 以内的帧 | 86.26% | | 180° 翻转误差 | 1.32% | | 平均置信度 | 0.636 | ## 🚀 安装说明 ### 1. 克隆/下载仓库 ``` cd metadata_dev1 ``` ### 2. 创建虚拟环境 ``` python -m venv venv venv\Scripts\activate # Windows # source venv/bin/activate # macOS / Linux ``` ### 3. 安装依赖项 ``` pip install -r requirements.txt ``` ## ▶️ 使用说明 ### 启动 FastAPI 后端 ``` python main.py ``` 服务器启动于 `http://127.0.0.1:8000`。 Swagger 文档:`http://127.0.0.1:8000/docs` ### 启动 Streamlit 前端(在单独的终端中) ``` streamlit run app.py ``` 开启于 `http://localhost:8501`。 ### 工作流程 1. 在浏览器中打开 `http://localhost:8501` 2. 上传 `.wav` 文件 3. 点击 **Analyse Audio** 4. 查看检测结果和罗盘可视化 ### 直接使用 API ``` curl -X POST "http://127.0.0.1:8000/predict" \ -F "file=@path/to/audio.wav" ``` **响应(检测到枪声):** ``` { "gunshot_detected": true, "gunshot_confidence": 0.923, "final_azimuth_deg": -47.3, "reliability": "HIGH", "frames_used": 12, "frames_total": 58, "avg_confidence": 0.741, "max_confidence": 0.891 } ``` **响应(未检测到枪声):** ``` { "gunshot_detected": false, "gunshot_confidence": 0.112, "message": "No gunshot detected. DOA not computed." } ``` ## 🔁 重新训练 ### 重新训练枪声 SVM ``` python scripts/train_svm.py ``` 需要填充 `data/gunshots/` 和 `data/non_gunshots/` 目录。 ### 重新训练 DOA Random Forest ``` python scripts/train_angle_model.py ``` 需要 `data/foa_dev1/` (FOA WAV 文件) 和 `data/master_metadata.csv`。 要使用更多的训练数据,请编辑 `train_angle_model.py` 中的 `max_samples`: ``` X, y_sin, y_cos = build_training_data_fast(..., max_samples=100000, ...) ``` ### 运行离线 DOA 评估 ``` python scripts/evaluate_angle.py ``` ## 📸 截图 | 上传与检测 | DOA 罗盘 | |---|---| | *(截图)* | *(截图)* | ## ⚠️ 局限性 1. **仅限 FOA 音频以保证可靠的 DOA** — DOA 模型是在一阶 Ambisonics 录音上训练的。单声道或标准立体声文件将产生不太可靠的方向估计,因为双耳线索 (ITD/ILD) 会变得在物理上毫无意义。 2. **SVM 训练集较小** — 748 个片段(每类 374 个)是一个小数据集。无法保证对全新的声学环境(距离、房间声学、武器类型)的泛化能力。 3. **未充分利用 DOA 训练数据** — 354,298 个可用的标注帧中仅使用了 10,000 个。使用完整数据集进行重新训练可能会显著提高 DOA 准确度。 4. **无仰角估计** — 系统仅估计水平方位角。STARSS23 中存在仰角标签,但目前未使用。 5. **单设备假设** — 未实现多麦克风三角测量。DOA 完全依赖于学习到的声道间特征。 6. **多声源场景** — 在具有多个同时发声源的帧中,模型会预测代表所有声源混合体的单一方向。 ## 🔭 未来改进 - [ ] 使用完整的 35.4 万帧数据集重新训练 DOA 模型,以提高准确度 - [ ] 实现正确的 GCC-PHAT(相位变换白化互相关) - [ ] 添加仰角预测作为第二个输出 - [ ] 使用所有 4 个 FOA 声道(W, X, Y, Z),而不是仅使用声道 0 和 1 - [ ] 用 CRNN / LSTM 替换 Random Forest 以获取时间上下文 - [ ] 在 Streamlit UI 中添加实时麦克风录音支持 - [ ] 实施适当的交叉验证和单折评估表 - [ ] Docker 部署配置 - [ ] 基准比较(GCC-PHAT、SRP-PHAT、MUSIC 算法) ## 📁 技术栈 | 层级 | 技术 | |---|---| | 机器学习 | scikit-learn (SVM, Random Forest) | | 音频 | librosa, soundfile, scipy | | 后端 | FastAPI, uvicorn | | 前端 | Streamlit, matplotlib | | 数据 | STARSS23, UrbanSound8K | | 语言 | Python 3.10+ | ## 📄 许可证 本项目使用了 [STARSS23 数据集](https://zenodo.org/record/7880637) (知识共享署名 4.0) 和 [UrbanSound8K](https://urbansounddataset.weebly.com/urbansound8k.html)。在重新分发之前,请查阅它们各自的许可证。
标签:Apex, AV绕过, FastAPI, Kubernetes, Streamlit, 公共安全, 声源定位, 机器学习, 枪声检测, 访问控制, 逆向工具, 音频智能