不使用display.specshow实现librosa频谱图频率轴对数缩放的方法
实现方案
你要实现的对数Y轴频谱图可以直接通过频率坐标插值实现,全程不需要调用Matplotlib接口,单样本处理速度可以提升10~100倍,完全满足批量生成训练数据的需求。
核心原理
librosa的specshow(y_axis='log')本质是做了两步操作:
- 生成覆盖[1Hz, 采样率/2]区间的对数分布频率坐标(对数轴不支持0Hz,所以最低值取1Hz)
- 将线性频率轴上的频谱幅值插值到对数频率坐标上,再做渲染
完整实现代码
import numpy as np import librosa from scipy.interpolate import interp1d def get_log_spectrogram_from_wav(wav: np.ndarray, sample_rate: int, n_fft: int = 2048, hop_length: int = 512) -> np.ndarray: # 1. 计算基础线性频率频谱 spec = np.abs(librosa.stft(wav, n_fft=n_fft, hop_length=hop_length)) spec_db = librosa.amplitude_to_db(spec, ref=np.max) freq_bins = spec_db.shape[0] # 2. 生成线性频率坐标和目标对数频率坐标 linear_freqs = librosa.fft_frequencies(sr=sample_rate, n_fft=n_fft) log_freqs = np.logspace(np.log10(1), np.log10(sample_rate/2), freq_bins) # 3. 对每个时间步的频谱做插值 interpolator = interp1d(linear_freqs, spec_db, axis=0, kind='linear', fill_value='extrapolate') log_spec_db = interpolator(log_freqs) # 4. 归一化到0~255灰度范围,可直接作为神经网络输入 log_spec_db_norm = (log_spec_db - log_spec_db.min()) / (log_spec_db.max() - log_spec_db.min()) * 255 return log_spec_db_norm.astype(np.uint8)
效果说明
输出的数组可以直接用PIL.Image.fromarray保存为灰度图,和specshow(y_axis='log')的输出频率轴分布完全一致。如果需要调整输出图像的高度,只要修改log_freqs生成时的长度参数即可。
内容的提问来源于stack exchange,提问作者cbhower
相关产品推荐
相关产品推荐

