OpenCV中音频的表示机制及提取音频dB值的方法咨询
问题描述
我写了一个试图读取视频帧关联音频信号的函数:
import cv2 def read_audio_frames(file_path): # Open the video file video = cv2.VideoCapture(file_path) # Get audio properties frame_rate = video.get(cv2.CAP_PROP_FPS) num_frames = int(video.get(cv2.CAP_PROP_FRAME_COUNT)) # Read the audio frames audio_frames = [] for _ in range(num_frames): ret, frame = video.read() if not ret: break audio_frames.append(frame) # Release the video object video.release() return audio_frames
调用后执行以下代码:
# Read audio frames audio_frames = read_audio_frames(file_path) audio_frames[0] # 每个分离的音频帧 len( audio_frames[0][0] ) #= 1080,搞不懂为什么和采样率44100有关 audio_frames[0][0][0]
得到结果:
array([3, 1, 1], dtype=uint8)
我有几个疑惑:
- 目标音频是立体声,但结果返回三个值而非两个通道对应的值;而且uint8的0-255范围不符合音频常用的16bit、24bit、32bit位深。
- 维度对应关系存疑:
audio_frames[0]对应视频帧,但audio_frames[0][0]并没有对应采样率44100的音频采样点。 - 不同MP4文件的维度结果不同:
len(audio_frames[0])=300 len(audio_frames[0][0])=1920 len(audio_frames[0][0][0])=3
len(audio_frames[0][0])和音频采样数不匹配。
请问OpenCV中音频是如何表示的?我该如何编写函数提取音频的dBs值?
解答
OpenCV的音频处理误区
你完全搞错了——OpenCV根本不支持读取视频中的音频数据。你写的函数里,video.read()返回的frame是视频的图像帧,不是音频帧:
- 你看到的
array([3,1,1], dtype=uint8)是图像像素的BGR三个通道值(OpenCV默认用BGR格式存储图像),和音频没有任何关系。 - 维度
len(audio_frames[0])是图像的高度,len(audio_frames[0][0])是图像的宽度,第三个维度是BGR通道数,不同MP4的维度差异其实是视频分辨率不同导致的,和音频完全无关。
正确提取音频并计算dB值的方法
要处理视频中的音频,得用专门的音视频处理库,比如ffmpeg-python结合librosa来实现:
步骤1:安装依赖
pip install ffmpeg-python librosa numpy
步骤2:提取音频并计算dB值的函数
import ffmpeg import librosa import numpy as np def get_audio_dbs(file_path): # 用ffmpeg从视频中提取音频,转为PCM格式 out, _ = ( ffmpeg .input(file_path) .output('pipe:', format='s16le', acodec='pcm_s16le', ac=2, ar='44100') .run(capture_stdout=True) ) # 将二进制数据转为int16格式的numpy数组 audio_data = np.frombuffer(out, dtype=np.int16) # 分离立体声通道 audio_data = audio_data.reshape(-1, 2) # 将音频数据转为-1到1的浮点数范围,用于计算dB audio_float = audio_data / np.iinfo(np.int16).max # 计算每个采样点的dBFS值(加1e-10避免log(0)报错) dbs = 20 * np.log10(np.abs(audio_float) + 1e-10) return dbs, audio_float.shape[0], 44100 # 返回dB数组、总采样数、采样率
调用示例
dbs, sample_count, sample_rate = get_audio_dbs("your_video.mp4") print(f"采样率: {sample_rate},总采样数: {sample_count}") print(f"第一个采样点左声道dB值: {dbs[0][0]:.2f},右声道dB值: {dbs[0][1]:.2f}")
补充:计算时间段平均dB
如果需要计算某段时间内的平均音量,可以对dB数组做滑动窗口平均:
# 计算每100ms的平均dB window_size = int(sample_rate * 0.1) avg_dbs = np.array([ np.mean(dbs[i:i+window_size], axis=0) for i in range(0, sample_count - window_size, window_size) ])
内容的提问来源于stack exchange,提问作者ShoutOutAndCalculate
相关产品推荐
相关产品推荐

