yolo8+声纹识别(实时字幕)
现在已经完成了人脸识别跟踪 ✅,接下来要:
✅ 加入「声纹识别(说话人识别)」功能,识别谁在讲话,并在视频中“这个人”的名字旁边加上「正在讲话」。
这属于多模态识别(视觉 + 音频):
-
说明实现原理与推荐工具
-
给出整体流程架构
-
推荐稳定的开源工具包
-
展示如何与当前人脸识别结合
✅ 整体目标
希望实现:
-
摄像头中显示所有人的名字(已完成)
-
通过麦克风监听讲话内容
-
根据声纹判断当前是谁在讲话
-
在视频中对这个人显示“正在讲话”
✅ 实现路径(视觉 + 音频)
🔊 声纹识别部分(说话人识别)
目标 | 技术名称 | 推荐工具 |
---|---|---|
声音中识别是谁 | 说话人识别(Speaker Identification) | pyannote-audio不推荐, resemblyzer推荐 |
声音中找谁在说话 | 说话人活动检测(Voice Activity Detection, VAD) | webrtcvad , silero-vad |
声纹注册(采集说话人音频) | Speaker Embedding | resemblyzer , speechbrain |
1. pyannote-audio和resemblyzer区别核心功能对比
特性 | pyannote-audio | resemblyzer |
---|---|---|
主要用途 | 说话人分割(Diarization)、语音活动检测(VAD)、重叠语音检测 | 声纹嵌入(Speaker Embedding)、实时声纹比对 |
模型复杂度 | 高(多模块联合优化,端到端流程) | 低(轻量级,专注声纹向量提取) |
预训练模型 | 提供完整的说话人分割管道(如 speaker-diarization-3.1 ) | 仅提供声纹编码器(如 VoiceEncoder ) |
实时性 | 较慢(适合离线处理) | 快(支持实时流式处理) |
依赖项 | 依赖 PyTorch 和 Hugging Face 模型库 | 仅需 NumPy 和 PyTorch |
典型应用场景 | 会议记录、广播分析、多说话人数据集标注 | 实时声纹验证、说话人聚类 |
2. 技术实现差异
pyannote-audio
-
模块化设计:
包含独立的子模块(如segmentation
、embedding
、clustering
),可灵活组合或替换16。 -
端到端流程:
支持从语音活动检测到说话人聚类的完整流程,适合复杂场景(如重叠语音处理)6。 -
性能优化:
部分版本(如speaker-diarization-3.1
)处理长音频较慢,推荐使用 v2 版本加速12。
resemblyzer
-
轻量级:
仅实现声纹向量提取(512 维嵌入),需自行结合聚类算法(如 K-Means)完成分割5。 -
实时性:
适合流式处理,单次推理速度快(约 0.1 秒/语音片段)5。 -
易用性:
无需复杂配置,适合快速验证声纹相似度
✅ 推荐方案(轻量 + 可行)
🔧 声纹识别用 resemblyzer
,搭配 YOLO 人脸
注意!!!!!!!!!!!!
先安装ffmpeg,resemblyzer会依赖
1. 为什么 resemblyzer
需要 ffmpeg
?
resemblyzer
的核心功能是处理音频文件(如 MP3、WAV 等),但它本身 不直接调用 ffmpeg
,而是通过以下依赖链间接使用:
resemblyzer → librosa(音频加载) → audioread(解码非WAV格式) → ffmpeg(实际解码工具)
-
关键点:
只有处理 非WAV格式(如MP3、MP4) 时才需要ffmpeg
。如果仅使用 WAV 文件,可跳过安装。
✅ 安装【ffmpeg】
https://ffmpeg.org/打开网站下载自己的版本
接下来📦 安装其他依赖:
pip install resemblyzer sounddevice webrtcvad numpy
💡 resemblyzer 是 Facebook 开源的轻量级声纹识别库,能实时从麦克风提取声纹并判断是否是目标用户。
✅ 总体流程图(视觉 + 音频结合):
✅ 示例代码框架(概要)
1、查看在PyCharm里面能不能使用ffmpeg
import subprocesstry:result = subprocess.run(["ffmpeg", "-version"], capture_output=True, text=True)if result.returncode == 0:print("✅ ffmpeg 已安装")else:print("❌ ffmpeg 未安装或异常")
except FileNotFoundError:print("❌ 未找到 ffmpeg 命令")
2、拿两段音频识别
from resemblyzer import VoiceEncoder, preprocess_wav
import numpy as np# 初始化编码器
encoder = VoiceEncoder()# 加载并预处理音频
wav1 = preprocess_wav("/Users/lianying/Desktop/yolo/1.m4a") # 支持 .wav/.mp4 文件
wav2 = preprocess_wav("/Users/lianying/Desktop/yolo/2.m4a")# 提取声纹嵌入(512 维向量)
embed1 = encoder.embed_utterance(wav1)
embed2 = encoder.embed_utterance(wav2)# 计算相似度(余弦相似度)
similarity = np.dot(embed1, embed2)
print(f"声纹相似度: {similarity:.4f}") # 0.0~1.0,>0.8 可视为同一人
已经成功识别声纹了 !!!!!!!
✅ 接下来整合以下功能:
模块 | 状态 |
---|---|
🧠 人脸识别 + 声纹识别 | ✅ 已完成(已有) |
🎙️ Whisper 语音识别 | ✅ 可用(ffmpeg 已安装) |
💬 实时字幕显示 | 🔜 马上整合 |
已经安装好了 ffmpeg
✅,那现在可以 正式接入 Whisper 实现“说话内容转字幕”。
🧠 模型大小选择:使用 Whisper 的哪个版本?(默认推荐 base
)
-
tiny
(最快) /base
(准确+轻)/small
(较高准确)
✅ 安装 Whisper(OpenAI 官方)
pip install -U openai-whisper
✅ Whisper 使用示例(语音转文字)
import whisper
model = whisper.load_model("base") # 也可以用 "tiny", "small", "medium", "large"# 录音 → 保存为 temp.wav
import sounddevice as sd
from scipy.io.wavfile import writefs = 16000
duration = 3
audio = sd.rec(int(duration * fs), samplerate=fs, channels=1)
sd.wait()
write("temp.wav", fs, audio)# 语音识别
result = model.transcribe("temp.wav", language="zh")
print("识别内容:", result["text"])
🎯 目标
基于摄像头视频流,识别谁在讲话,并把“张三(正在讲话):你好啊,我是张三”样式的字幕实时显示在画面上(支持中文)
✅ 内容包含:
模块 | 技术 | 状态 |
---|---|---|
人脸识别 | YOLOv8 + face_recognition | ✅ |
声纹识别 | Resemblyzer | ✅ |
语音转文字 | Whisper(base) | ✅ |
实时录音 | sounddevice | ✅ |
字幕显示 | PIL + 中文字体支持 | ✅ |
✅ 使用前请确认:
如下文件夹结构:
import os
import cv2
import numpy as np
from PIL import ImageFont, ImageDraw, Image
import face_recognition
from resemblyzer import VoiceEncoder, preprocess_wav
import sounddevice as sd
from scipy.io.wavfile import write
import whisper
from ultralytics import YOLO# === 参数设置 ===
VOICE_DB = "voice_db"
FACES_DB = "faces"
FONT_PATH = "font/AlimamaDaoLiTi-Regular.ttf" # 中文黑体字体路径(请确保该字体文件存在)
SAMPLE_RATE = 16000
RECORD_DURATION = 1 # 录音时间(秒)
CONFIDENCE_THRESHOLD = 0.75# === 初始化模型 ===
print("加载 YOLOv8 模型...")
yolo_model = YOLO("/Users/lianying/Desktop/yolo/model_face.pt") # 检测人脸用
print("加载人脸识别数据库...")
known_encodings, known_names = [], []
for name in os.listdir(FACES_DB):for img_file in os.listdir(os.path.join(FACES_DB, name)):img_path = os.path.join(FACES_DB, name, img_file)img = face_recognition.load_image_file(img_path)enc = face_recognition.face_encodings(img)if enc:known_encodings.append(enc[0])known_names.append(name)print("加载声纹识别数据库...")
encoder = VoiceEncoder()
speaker_embeddings = {}
for file in os.listdir(VOICE_DB):if file.endswith(".wav"):name = file.split(".")[0]wav = preprocess_wav(os.path.join(VOICE_DB, file))embed = encoder.embed_utterance(wav)speaker_embeddings[name] = embedprint("加载 Whisper 模型...")
asr_model = whisper.load_model("base")# === 字体 ===
font = ImageFont.truetype(FONT_PATH, 24)# === 摄像头 ===
cap = cv2.VideoCapture(0)
frame_count = 0
interval = int(30 * RECORD_DURATION) # 每 interval 帧识别一次
current_speaker = ""
current_text = ""while True:ret, frame = cap.read()if not ret:breakframe_count += 1# 每 interval 帧录音 + 声纹识别 + Whisperif frame_count % interval == 0:print("\n[INFO] 正在录音并分析说话人...")audio = sd.rec(int(RECORD_DURATION * SAMPLE_RATE), samplerate=SAMPLE_RATE, channels=1)sd.wait()write("temp.wav", SAMPLE_RATE, audio)# 声纹识别wav = preprocess_wav("temp.wav")embed = encoder.embed_utterance(wav)best_name, best_score = "", 0.5for name, ref in speaker_embeddings.items():sim = np.dot(embed, ref)if sim > best_score:best_score = simbest_name = namecurrent_speaker = best_name if best_score > CONFIDENCE_THRESHOLD else ""# Whisper 语音识别result = asr_model.transcribe("temp.wav", language="zh")current_text = result["text"].strip()print(f"[识别] {current_speaker}:{current_text}")# 人脸检测 + 标注results = yolo_model.predict(frame, classes=[0], conf=0.4, verbose=False)for result in results:boxes = result.boxes.xyxy.cpu().numpy().astype(int)for box in boxes:x1, y1, x2, y2 = boxface_crop = frame[y1:y2, x1:x2]rgb_crop = cv2.cvtColor(face_crop, cv2.COLOR_BGR2RGB)encs = face_recognition.face_encodings(rgb_crop)name = "未知"if encs:matches = face_recognition.compare_faces(known_encodings, encs[0])face_distances = face_recognition.face_distance(known_encodings, encs[0])if True in matches:best_match = np.argmin(face_distances)name = known_names[best_match]# 准备显示信息label = nameif name == current_speaker:label += "(正在讲话)"if current_text:label += f":{current_text}"# 绘图(PIL 支持中文)pil_img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))draw = ImageDraw.Draw(pil_img)draw.rectangle([x1, y1, x2, y2], outline="green", width=2)draw.text((x1, y1 - 30), label, font=font, fill=(255, 0, 0))frame = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)cv2.imshow("实时人脸 + 声纹 + 字幕识别", frame)if cv2.waitKey(1) & 0xFF == ord("q"):breakcap.release()
cv2.destroyAllWindows()