新闻详情

新闻详情

首页 / 资讯中心 / 详情

Python语音检索

发布时间:2026/10/2 20:49:12来源:尧图网络
Python语音检索
这是一份音频检索代码根据一段查询语音在本地音频库中快速找出最相似的录音文件。python# -*- coding: utf-8 -*-voice_match.py —— 根据一段语音在本地音频库中检索最相似的音频原理与说话内容无关的通用声学匹配1. 每段音频切成 2s 滑窗每个窗口提取定长声学向量MFCC Δ ΔΔCMN 归一化分段池化2. 所有窗口向量 L2 归一化后堆成矩阵即声学指纹库3. 查询语音同样切窗提特征与库矩阵做余弦相似度4. 按文件聚合每个查询窗口取最佳命中再取 top-n 平均返回 Top-K用法python voice_match.py build ./audios -i ./indexpython voice_match.py search ./query.wav -i ./index -k 5from __future__ import annotationsimport argparseimport jsonfrom pathlib import Pathimport numpy as npimport librosaSR 16000N_MFCC 20N_PARTS 4 # 时间轴分几段池化AUDIO_EXTS {.wav, .mp3, .flac, .m4a, .ogg, .aac, .opus, .wma}# 特征维度 N_MFCC * 3(原ΔΔΔ) * N_PARTS * 2(meanstd) 480FEAT_DIM N_MFCC * 3 * N_PARTS * 2# --------------------------------------------------------------------------# 音频加载 / 切窗# --------------------------------------------------------------------------def load_audio(path: str | Path, sr: int SR) - np.ndarray:读音频 - 单声道 - 重采样 - 去静音 - 峰值归一化y, _ librosa.load(str(path), srsr, monoTrue)if y.size 0:return y.astype(np.float32)y, _ librosa.effects.trim(y, top_db30)peak float(np.abs(y).max())if peak 0:y y / peakreturn y.astype(np.float32)def make_windows(y: np.ndarray, win: float 2.0, hop: float 1.0,sr: int SR) - list[np.ndarray]:滑窗切分保证短音频也能返回至少一个窗口w, h int(win * sr), int(hop * sr)if y.size 0:return []if y.size w:return [y]out [y[s:s w] for s in range(0, y.size - w 1, h)]if (y.size - w) % h: # 补上尾部残留out.append(y[-w:])return out# --------------------------------------------------------------------------# 特征提取可替换为声纹模型见文末说明# --------------------------------------------------------------------------def embed(y: np.ndarray, sr: int SR) - np.ndarray | None:一段语音(建议 1~3s) - L2 归一化的 480 维向量if y.size sr * 0.25: # 太短丢弃return Nonemfcc librosa.feature.mfcc(yy, srsr, n_mfccN_MFCC, n_fft400,hop_length160, n_mels40, fmin20, fmax7600,)# 倒谱均值归一化(CMN)抑制麦克风/信道带来的整体偏移mfcc mfcc - mfcc.mean(axis1, keepdimsTrue)d1 librosa.feature.delta(mfcc)d2 librosa.feature.delta(mfcc, order2)feat np.vstack([mfcc, d1, d2]) # (60, T)# 时间轴均分 N_PARTS 段每段取 mean std保留粗时序信息parts np.array_split(feat, N_PARTS, axis1)pooled np.concatenate([np.concatenate([p.mean(axis1), p.std(axis1)]) for p in parts])norm float(np.linalg.norm(pooled))if norm 1e-9:return Nonereturn (pooled / norm).astype(np.float32)# --------------------------------------------------------------------------# 索引# --------------------------------------------------------------------------class VoiceIndex:def __init__(self, index_dir: str | Path):self.dir Path(index_dir)self.dir.mkdir(parentsTrue, exist_okTrue)self.vec_path self.dir / vectors.npyself.meta_path self.dir / meta.jsonself.vectors: np.ndarray | None Noneself.meta: list[dict] []def save(self) - None:np.save(self.vec_path, self.vectors)self.meta_path.write_text(json.dumps(self.meta, ensure_asciiFalse), encodingutf-8)def load(self) - VoiceIndex:if not self.vec_path.exists() or not self.meta_path.exists():raise FileNotFoundError(f索引不存在{self.dir}请先执行 build)self.vectors np.load(self.vec_path)self.meta json.loads(self.meta_path.read_text(encodingutf-8))return self# --------------------------------------------------------------------------# 建库# --------------------------------------------------------------------------def build(audio_dir: str | Path, index_dir: str | Path,win: float 2.0, hop: float 1.0) - VoiceIndex:audio_dir Path(audio_dir)files sorted(p for p in audio_dir.rglob(*) if p.suffix.lower() in AUDIO_EXTS)if not files:raise SystemExit(f在 {audio_dir} 下没找到音频文件)vecs: list[np.ndarray] []meta: list[dict] []for i, f in enumerate(files, 1):try:y load_audio(f)except Exception as e: # 损坏/不支持的格式print(f[skip] {f.name}: {e})continuekept 0for j, seg in enumerate(make_windows(y, win, hop)):v embed(seg)if v is None:continuevecs.append(v)meta.append({file: str(f), win: j})kept 1print(f[{i}/{len(files)}] {f.name} 窗口{kept})idx VoiceIndex(index_dir)idx.vectors (np.vstack(vecs).astype(np.float32)if vecs else np.zeros((0, FEAT_DIM), np.float32))idx.meta metaidx.save()print(f\n完成{len(files)} 个文件{len(meta)} 个窗口向量 - {index_dir})return idx# --------------------------------------------------------------------------# 检索# --------------------------------------------------------------------------def search(query: str | Path, index_dir: str | Path,top_k: int 5, win: float 2.0, hop: float 1.0) - list[tuple]:idx VoiceIndex(index_dir).load()if idx.vectors is None or idx.vectors.shape[0] 0:raise RuntimeError(索引为空请先 build)y load_audio(query)q_vecs [v for v in (embed(s) for s in make_windows(y, win, hop)) if v is not None]if not q_vecs:raise RuntimeError(查询语音太短或全是静音)Q np.vstack(q_vecs) # (nq, D)S Q idx.vectors.T # (nq, nv) 余弦相似度越大越像files np.array([m[file] for m in idx.meta])results []for f in np.unique(files):sub S[:, files f] # (nq, nf)best np.sort(sub.max(axis1))[::-1] # 每个查询窗口的最佳命中n min(3, best.size)score float(best[:n].mean()) # top-3 平均抗单点噪声hits int((sub 0.8).sum()) # 强命中窗口数参考results.append((f, score, hits))results.sort(keylambda x: -x[1])return results[:top_k]# --------------------------------------------------------------------------# CLI# --------------------------------------------------------------------------def main() - None:ap argparse.ArgumentParser(description基于语音的音频库检索)sub ap.add_subparsers(destcmd, requiredTrue)b sub.add_parser(build, help扫描目录建索引)b.add_argument(audio_dir)b.add_argument(-i, --index, defaultvoice_index)b.add_argument(--win, typefloat, default2.0, help窗口秒数)b.add_argument(--hop, typefloat, default1.0, help滑动步长秒数)s sub.add_parser(search, help用一段语音检索)s.add_argument(query)s.add_argument(-i, --index, defaultvoice_index)s.add_argument(-k, typeint, default5)s.add_argument(--win, typefloat, default2.0)s.add_argument(--hop, typefloat, default1.0)a ap.parse_args()if a.cmd build:build(a.audio_dir, a.index, a.win, a.hop)else:rows search(a.query, a.index, a.k, a.win, a.hop)print(f\n{相似度:8} {强命中:6} 文件)print(- * 60)for f, sc, hits in rows:print(f{sc:8.4f} {hits:6d} {f})if __name__ __main__:main()语音匹配检索的完整流程拆解从建立声学指纹到检索排序整个流程围绕几个关键步骤展开音频加载与预处理统一转为单声道、重采样到16kHz自动去除首尾静音并对音量做归一化让后续特征更稳定。滑窗切分与特征提取默认每2秒切一个窗口用1秒步长滑动。每个窗口提取MFCC及其一阶、二阶差分再做倒谱均值归一化和分段池化最终压缩成480维的L2归一化向量。索引构建与保存把所有音频的窗口向量堆成矩阵连同文件路径信息一起保存到索引目录。查询检索与排序对查询语音做同样的特征提取计算它与库中所有窗口向量的余弦相似度再按文件聚合每个查询窗口取最佳命中再取top-3平均返回相似度最高的结果。---优化建议 当前默认按说话人声学特征匹配若您更关注“同一段录音”的精确查找可以替换为音频指纹方案如pyacoustid并调整相似度计算方式。仅供参考学习用。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

OpenClaw网关1006报错排查:WSL2目录迁移与WebSocket连接修复 2026/10/2 21:34:20

OpenClaw网关1006报错排查:WSL2目录迁移与WebSocket连接修复

先把结论放前面:这个报错我排查了一整天才彻底解决,原因比想象中隐蔽,但解决思路其实就那么几条。如果你正在给 OpenClaw 换运行目录、搬数据盘,或者刚装完 Windows Companion 准备连 WSL 里的网关,突然看到gateway cl…

阅读更多 →
Pixelle-Video 上手指南:一个主题到 AI 短视频成片的完整路径 2026/10/2 21:34:20

Pixelle-Video 上手指南:一个主题到 AI 短视频成片的完整路径

Pixelle-Video 上手指南:一个主题到 AI 短视频成片的完整路径 【免费下载链接】Pixelle-Video 🚀 AI 全自动短视频引擎 | AI Fully Automated Short Video Engine 项目地址: https://gitcode.com/GitHub_Trending/pi/Pixelle-Video Pixelle-Video…

阅读更多 →
SimilarWeb 集成实战指南:在 marketingskills 中用 REST API 与零依赖 CLI 完成竞品流量情报分析 2026/10/2 21:34:19

SimilarWeb 集成实战指南:在 marketingskills 中用 REST API 与零依赖 CLI 完成竞品流量情报分析

AI 技能人工智能 【免费下载链接】marketingskills Marketing skills for Claude Code and AI agents. CRO, copywriting, SEO, analytics, and growth engineering. 项目地址: https://gitcode.com/GitHub_Trending/mar/marketingskills 点击查看 免费下载 本指南…

阅读更多 →
MAS Windows 与 Office 激活工具使用指南:4 条永久激活路线免密钥一次跑通 2026/10/2 21:34:19

MAS Windows 与 Office 激活工具使用指南:4 条永久激活路线免密钥一次跑通

MAS Windows 与 Office 激活工具使用指南:4 条永久激活路线免密钥一次跑通 【免费下载链接】Microsoft-Activation-Scripts Open-source Windows and Office activator featuring HWID, Ohook, TSforge, and Online KMS activation methods, along with advanced tr…

阅读更多 →
Oracle EBS标准成本核算制度:成本要素、差异账户与月末结转实操 2026/10/2 21:34:12

Oracle EBS标准成本核算制度:成本要素、差异账户与月末结转实操

简介:《ORACLE EBS标准成本核算制度.doc》是一份面向ERP实施顾问、成本会计与制造业财务人员的完整制度文档,系统讲解标准成本法在EBS系统中的落地规则。内容涵盖物料、资源、外协资源、制造费用、物料管理费五大成本要素的构成与费率核定,并…

阅读更多 →
【C语言】指针型数组(Finish) 2026/10/2 21:34:11

【C语言】指针型数组(Finish)

malloc 分配出来的 int* 指针&#xff0c;完全能用 [] 下标访问。示例代码#include <stdio.h> #include <stdlib.h>int main() {// 分配能存放5个int的内存int *arr (int *)malloc(5 * sizeof(int));if(arr NULL){perror("malloc fail");return 1…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉