提取音频时出现杂音,是音视频处理中非常常见的问题。无论是从视频中抽取音轨,还是对录音素材进行转码,只要听感上存在嘶嘶声、电流声或环境底噪,都意味着有某个环节出了问题。杂音的产生原因有很多,但最容易被忽略的往往有两个:一个是编码阶段的比特率配置,另一个是信号本身的噪声成分。本文从这两个维度展开,先搞清楚比特率如何影响噪声,再介绍降噪滤波的核心方法,最后给出组合使用的实践路径。

比特率设置:从源头抑制量化噪声
很多人在处理音频时会把比特率等同于文件大小,其实比特率对应的是编码器每秒处理的数据量,它决定了压缩过程中保留多少声音细节。比特率越低,编码器不得不丢掉更多高频信息和动态细节,这些被粗暴丢弃的部分会以量化噪声的形式弥散到整个频谱中,听感上就是一层挥之不去的“沙沙”声。尤其在从视频中提取音频时,如果原始音轨本身是低码率,再经过一次压缩,噪声会被进一步放大。
量化噪声的产生与采样位深密切相关。以16bit采样为例,理论上信噪比约为96dB,而8bit采样只有48dB,显然8bit音频的背景噪声会非常明显。在提取音频时,如果你选择低于128kbps的MP3或AAC编码,中高频的量化噪声就会变得可闻。相比之下,无损编码如FLAC或PCM保留完整数据,虽然不能消除原始录音中的环境噪声,但至少不会因为压缩而“制造”出新的噪声。
在实际操作中,建议遵循“可听音质优先,文件大小靠比特率上限控制”的原则。提取语音旁白或播客节目时,MP3/AAC建议至少192kbps;如果原始素材包含音乐或复杂音效,建议选择256kbps以上,或者直接使用无损格式。位深方面,16bit对绝大多数场景已经足够,后续需要大幅动态范围调整时,可以用24bit进行中间处理,避免截断失真。
降噪滤波:从频谱中剥离底噪
即使比特率设置合理,原始音频中仍然可能包含空调嗡嗡声、电脑风扇声、房间混响等环境噪声。这些噪声在频谱上通常呈现固定频率或较宽频带的能量分布,与语音或音乐的主体信号在时间‑频率域存在差异。降噪滤波的核心任务就是识别并削弱噪声分量,同时尽量保留有效信号。
最简单的滤波方式是传统IIR/FIR滤波器,例如高通滤波器可以去除50Hz以下的电源交流声,带阻滤波器可以削除固定频率的嗡鸣。但环境噪声往往不是单一频率,这时就需要更智能的算法。谱减法是目前最经典的降噪算法,它将带噪信号通过STFT变换到频域,在无语音段估计噪声谱,然后用原始频谱减去噪声谱,最后通过ISTFT重构时域信号。这个过程能有效降低平稳噪声,但处理不当会产生类似“音乐噪声”的残留。
为了避免音乐噪声,许多工具引入了维纳滤波或基于深度学习的降噪模型。维纳滤波通过估计语音和噪声的统计特性,计算一个时变增益函数,对信噪比高的频段保留更多能量,对信噪比低的频段进行压制。下面是一段基于Python的谱减法实现示例,可以帮助你快速理解算法的基本流程:
import numpy as np
from scipy.io import wavfile
from scipy.signal import stft, istft
def spectral_subtraction(input_file, output_file, alpha=1.2, beta=0.01):
sr, data = wavfile.read(input_file)
if data.dtype != np.float32:
data = data.astype(np.float32) / 32768.0
if len(data.shape) > 1:
data = np.mean(data, axis=1)
f, t, Zxx = stft(data, fs=sr, nperseg=2048, noverlap=768)
# 利用前10帧估计噪声
noise_frames = Zxx[:, :10]
noise_amp = np.mean(np.abs(noise_frames), axis=1, keepdims=True)
amp = np.abs(Zxx)
phase = np.angle(Zxx)
# 谱减:对幅度谱进行修正
subtract = alpha * noise_amp
mag = np.maximum(amp - subtract, beta * noise_amp)
Zxx_clean = mag * np.exp(1j * phase)
_, cleaned = istft(Zxx_clean, fs=sr, nperseg=2048, noverlap=768)
cleaned = np.clip(cleaned, -1.0, 1.0)
wavfile.write(output_file, sr, (cleaned * 32767).astype(np.int16))
spectral_subtraction("input.wav", "output.wav")
上面的示例通过前10帧估计噪声谱,然后对每个频点的幅度谱做减法。alpha控制降噪强度,beta用于设置一个最小的底噪下限,避免把声音消成完全静音。如果你只需要对一段录音做快速降噪,也可以直接使用Audacity或Adobe Audition内置的降噪工具,它们已经封装了类似的算法,使用起来更简单。
组合策略:先定比特率,再做滤波
比特率与降噪并非二选一,而是一套流水线上的两道工序。如果直接把带着大量底噪的低码率音频丢给降噪算法,滤波器会把噪声与有效信号一起削弱,结果声音变得沉闷且仍然不干净。正确的顺序是先检查并调整比特率,确保编码过程不引入新的量化噪声,再针对原始噪声做滤波处理。
在命令行环境下,FFmpeg是处理音频的利器。以从视频中提取高质量音轨为例,可以先用无损参数将音频解包为PCM,再做降噪滤波,最后压缩为需要的格式。下面这段命令展示了如何从视频提取48kHz采样率、16bit位深的PCM音轨:
ffmpeg -i input.mp4 -vn -ac 2 -ar 48000 -sample_fmt s16 -acodec pcm_s16le intermediate.wav
拿到中间PCM文件后,可以使用上文提到的Python脚本进行谱减法降噪,也可以使用FFmpeg自带的高通滤波和低通滤波。例如下面这条命令使用高通滤波器去除80Hz以下的风声和电源噪声:
ffmpeg -i intermediate.wav -af "highpass=f=80, lowpass=f=12000" filtered.wav
组合使用这两步,通常就能得到干净、自然的音频。如果原始素材包含瞬态爆音或点击声,还需要加入专门的脉冲噪声抑制步骤。对于语音内容,建议对比降噪前后的波形和频谱,避免过度处理带来的语音失真。
识别杂音类型,避免常见误区
在比特率设置和降噪滤波之外,同样重要的还有对杂音类型的判断。许多人在听到杂音时,第一时间就开启降噪并把强度拉到最大,结果背景噪声消失了,人声也变得像隔着一层棉被。这正是因为不了解噪声的频段特征。判断噪声来源最直观的方式是查看频谱图:交流声呈现为50Hz附近的窄带亮线,白色噪声则均匀分布在整个频带上。
另一个常见误区是盲目提高比特率。对于已经录制完成的音频,提升编码比特率并不会让已有的环境噪声消失,它只能避免在压缩过程中产生新的失真。相反,过高的比特率在一些场景下会浪费存储空间和传输带宽,所以应该根据内容类型选择合理的上限。无损格式虽然保留了全部信息,但对有杂音的素材来说,它只是忠实地还原了杂音。
还有一个容易被忽略的点:降噪滤波的处理顺序会影响最终效果。如果先压缩再滤波,压缩可能已经把噪声和语音混合在一起,滤波难度会成倍增加。推荐的做法是先解包为无损PCM,完成所有滤波和动态处理,最后再根据发布需求进行有损压缩。整套流程可以总结为:解包到PCM → 分析频谱 → 参数设置 → 降噪滤波 → 最终编码。通过这样的流程,大部分提取音频的杂音问题都能得到有效解决。