目录1.分离音频CLAP文本 - 音频对比模型 推荐### YAMNet首选### PANNs羽毛球击球检测1.分离音频ffmpeg -i yu_0922.mp4 -vn -acodec pcm_s16le output.wavCLAP文本 - 音频对比模型 推荐- 文本 - 音频对比模型HuggingFace 直接加载- 用法输入文字描述羽毛球击球声、球拍打框声、运动鞋摩擦地面、人声模型输出音频和这些文本的相似度打分- 优点**不需要标注数据**录几段球场音频就能测试能不能区分击球支持短脉冲声音- 缺点推理开销偏大不太适合嵌入式实时跑## 2. 轻量模型适合本地 / 手机 / 嵌入式实时检测推荐工程落地### YAMNet首选Google 开源AudioSet 预训练输出 521 类环境音频同时输出音频 embedding 向量TensorFlow- 模型很小十几 MB可转 TFLite低延迟适合流式持续检测击球事件- 使用方式**提取 embedding再接一个简单分类头少量击球录音微调**就能识别击球 / 打杆 / 噪音- 输入16kHz 单声道 wav正好匹配击球短时脉冲音频- 16kHz 单声道十几 MB可转 TFLite 跑手机 / 嵌入式支持流式逐帧检测拿到每次拍球的时间戳- 直接跑就能识别**篮球拍地弹跳**不用训练- 局限原生分不清「篮网进球声、打板、打铁」球场嘈杂人声、球鞋摩擦会带来误报想区分### PANNs音频事件检测常用 CNN 模型支持定位**事件发生时间点**哪一秒击球HuggingFace、PaddlePaddle 都有实现适合不仅要判断 “是不是击球”还要拿到击球发生的时间戳## 3. 高精度音频 Transformer有标注数据集时用### ASTAudio Spectrogram TransformerMIT 开源音频 TransformerAudioSet 训练音频分类精度高适合你收集几十上百条标注好的击球、打框、吊球、杀球音频做精细分类区分不同击球类型缺点显存、算力开销大于 YAMNet## 4. 额外备选- SenseVoiceFunASR主打语音识别但附带音频事件检测适合球场同时有人声的混合音频场景- HuBERT / Wav2Vec2语音预训练模型可以提取波形特征做迁移学习对冲击音表现一般不优先推荐### 4. AST如果你收集了一批球场音频想精细区分运球 / 打板 / 进球唰声 / 打铁就用 AST 微调分类精度最高羽毛球击球检测最好还是音频分类识别击球import os import librosa import numpy as np from scipy.signal import find_peaks import soundfile as sf def extract_hit_audio_segments(wav_path, out_prefixhit_segment): 提取击球音频峰值切割出每一段击球音频 :param wav_path: 输入wav文件路径 :param out_prefix: 输出片段文件名前缀 :return: 峰值时间列表 [(start_sec, end_sec), ...] # 加载音频统一采样率22050 y, sr librosa.load(wav_path, sr22050) # 计算RMS能量包络 frame_length 512 hop_length 256 rms librosa.feature.rms(yy, frame_lengthframe_length, hop_lengthhop_length)[0] # 找能量峰值击球尖峰 peaks_idx, peak_props find_peaks( rms, height0.1, # 最小能量阈值根据你的音频调 distance70 # 帧间隔防止同一击球识别多个峰 ) # 帧转秒 frame_time hop_length / sr peak_times peaks_idx * frame_time print(f检测到击球峰值时间(秒): {peak_times.round(3)}) # 【核心】以峰值为中心截取片段峰值前0.15s ~ 峰值后0.35s pre 0.15 post 0.35 segments [] for i, t_peak in enumerate(peak_times): t_start t_peak - pre t_end t_peak post # 边界保护不能小于0不能超过音频总长 t_start max(0.0, t_start) t_end min(y.shape[0]/sr, t_end) # 时间转采样点 start_sample int(t_start * sr) end_sample int(t_end * sr) seg_audio y[start_sample:end_sample] segments.append((t_start, t_end)) # 保存单个击球片段 out_name faaa/{out_prefix}_{i:02d}.wav os.makedirs(os.path.dirname(out_name), exist_okTrue) sf.write(out_name, seg_audio, sr) print(f保存片段{i}: {t_start:.3f} ~ {t_end:.3f} - {out_name}) return segments if __name__ __main__: segs extract_hit_audio_segments(rE:\data\yumao\yu_0922.mp4)