本文目录导读:

- 方法1:使用 Python + Librosa + Matplotlib
- 方法2:使用 SoX 命令行工具
- 方法3:使用 FFmpeg + Python
- 方法4:完整的高级版本(带参数控制)
- 使用方法
- 推荐的目录结构
方法1:使用 Python + Librosa + Matplotlib
import os
import librosa
import librosa.display
import matplotlib.pyplot as plt
import numpy as np
from pathlib import Path
def create_spectrogram(audio_path, output_path, sr=22050):
"""
生成单个音频文件的频谱图
"""
# 加载音频文件
y, sr = librosa.load(audio_path, sr=sr)
# 生成频谱图
plt.figure(figsize=(12, 8))
# 方法1:Mel频谱图
D = librosa.amplitude_to_db(np.abs(librosa.stft(y)), ref=np.max)
librosa.display.specshow(D, sr=sr, x_axis='time', y_axis='hz')
plt.colorbar(format='%+2.0f dB')
# 方法2:或者使用梅尔频谱
# mel_spec = librosa.feature.melspectrogram(y=y, sr=sr)
# mel_db = librosa.amplitude_to_db(mel_spec, ref=np.max)
# librosa.display.specshow(mel_db, sr=sr, x_axis='time', y_axis='mel')
plt.title(f'Spectrogram - {Path(audio_path).stem}')
plt.tight_layout()
# 保存图片
plt.savefig(output_path, dpi=150, bbox_inches='tight')
plt.close()
def batch_process(input_dir, output_dir, file_extensions=['.mp3', '.wav', '.flac']):
"""
批量处理音频文件
"""
# 创建输出目录
Path(output_dir).mkdir(parents=True, exist_ok=True)
# 遍历输入目录
audio_files = []
for ext in file_extensions:
audio_files.extend(list(Path(input_dir).glob(f'**/*{ext}')))
print(f"找到 {len(audio_files)} 个音频文件")
# 批量处理
for i, audio_path in enumerate(audio_files, 1):
try:
output_path = Path(output_dir) / f"{audio_path.stem}_spectrogram.png"
create_spectrogram(str(audio_path), str(output_path))
print(f"[{i}/{len(audio_files)}] 处理完成: {audio_path.name}")
except Exception as e:
print(f"[{i}/{len(audio_files)}] 处理失败: {audio_path.name} - {e}")
# 使用示例
if __name__ == "__main__":
input_directory = "input_audio" # 输入音频目录
output_directory = "output_spectrograms" # 输出图片目录
batch_process(input_directory, output_directory)
方法2:使用 SoX 命令行工具
#!/bin/bash
# batch_spectrogram.sh
INPUT_DIR="input_audio"
OUTPUT_DIR="output_spectrograms"
mkdir -p "$OUTPUT_DIR"
# 批量处理所有.wav文件
for file in "$INPUT_DIR"/*.wav; do
if [ -f "$file" ]; then
filename=$(basename "$file" .wav)
echo "处理文件: $filename"
sox "$file" -n spectrogram -o "$OUTPUT_DIR/${filename}_spectrogram.png"
fi
done
# 处理其他格式(需要先转换)
for file in "$INPUT_DIR"/*.mp3; do
if [ -f "$file" ]; then
filename=$(basename "$file" .mp3)
echo "处理文件: $filename"
# 先转换为WAV,然后生成频谱
sox "$file" -t wav - | sox - -n spectrogram -o "$OUTPUT_DIR/${filename}_spectrogram.png"
fi
done
echo "批量处理完成!"
方法3:使用 FFmpeg + Python
import subprocess
import os
from pathlib import Path
def generate_spectrogram_ffmpeg(input_file, output_file, width=1920, height=1080):
"""
使用FFmpeg生成频谱图
"""
cmd = [
'ffmpeg',
'-i', input_file,
'-lavfi', f'spectrogram=s={width}x{height}:mode=combined:color=rainbow',
'-frames:v', '1',
output_file,
'-y' # 覆盖已存在的文件
]
try:
subprocess.run(cmd, check=True, capture_output=True)
return True
except subprocess.CalledProcessError as e:
print(f"FFmpeg处理失败: {e.stderr.decode()}")
return False
def batch_process_ffmpeg(input_dir, output_dir):
"""
使用FFmpeg批量处理
"""
Path(output_dir).mkdir(parents=True, exist_ok=True)
audio_formats = ['.mp3', '.wav', '.flac', '.m4a', '.ogg']
files_processed = 0
for ext in audio_formats:
for audio_file in Path(input_dir).glob(f'*{ext}'):
output_file = Path(output_dir) / f"{audio_file.stem}_spectrogram.png"
if generate_spectrogram_ffmpeg(str(audio_file), str(output_file)):
files_processed += 1
print(f"处理完成: {audio_file.name}")
else:
print(f"处理失败: {audio_file.name}")
return files_processed
# 使用示例
if __name__ == "__main__":
input_dir = "input_audio"
output_dir = "output_spectrograms"
count = batch_process_ffmpeg(input_dir, output_dir)
print(f"成功处理 {count} 个文件")
方法4:完整的高级版本(带参数控制)
import os
import librosa
import librosa.display
import matplotlib.pyplot as plt
import numpy as np
from pathlib import Path
import argparse
from concurrent.futures import ThreadPoolExecutor
class SpectrogramGenerator:
def __init__(self, input_dir, output_dir,
spectrogram_type='mel', # 'mel', 'stft', 'chroma'
size=(12, 8), dpi=150,
colormap='viridis', max_workers=4):
self.input_dir = Path(input_dir)
self.output_dir = Path(output_dir)
self.spectrogram_type = spectrogram_type
self.size = size
self.dpi = dpi
self.colormap = colormap
self.max_workers = max_workers
# 确保输出目录存在
self.output_dir.mkdir(parents=True, exist_ok=True)
def generate_spectrogram(self, audio_path):
"""生成单个频谱图"""
try:
y, sr = librosa.load(str(audio_path), sr=None)
plt.figure(figsize=self.size)
if self.spectrogram_type == 'mel':
# 梅尔频谱
mel_spec = librosa.feature.melspectrogram(y=y, sr=sr)
mel_db = librosa.amplitude_to_db(mel_spec, ref=np.max)
librosa.display.specshow(mel_db, sr=sr, x_axis='time',
y_axis='mel', cmap=self.colormap)
elif self.spectrogram_type == 'stft':
# STFT频谱
D = librosa.amplitude_to_db(np.abs(librosa.stft(y)), ref=np.max)
librosa.display.specshow(D, sr=sr, x_axis='time',
y_axis='hz', cmap=self.colormap)
elif self.spectrogram_type == 'chroma':
# 色度频谱
chroma = librosa.feature.chroma_stft(y=y, sr=sr)
librosa.display.specshow(chroma, sr=sr, x_axis='time',
y_axis='chroma', cmap=self.colormap)
plt.colorbar(format='%+2.0f dB')
plt.title(f'{self.spectrogram_type.upper()} Spectrogram - {audio_path.stem}')
plt.tight_layout()
output_path = self.output_dir / f"{audio_path.stem}_{self.spectrogram_type}_spectrogram.png"
plt.savefig(str(output_path), dpi=self.dpi, bbox_inches='tight')
plt.close()
return True, audio_path.name
except Exception as e:
return False, f"{audio_path.name}: {str(e)}"
def batch_process(self):
"""批量处理所有音频文件"""
audio_extensions = ['.mp3', '.wav', '.flac', '.m4a', '.ogg', '.wma']
audio_files = []
for ext in audio_extensions:
audio_files.extend(list(self.input_dir.glob(f'*{ext}')))
print(f"找到 {len(audio_files)} 个音频文件")
# 使用线程池并行处理
with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
results = list(executor.map(self.generate_spectrogram, audio_files))
# 统计结果
success = sum(1 for r in results if r[0])
failed = len(results) - success
print(f"处理完成:成功 {success} 个,失败 {failed} 个")
# 显示失败的文件
if failed > 0:
print("失败的文件:")
for result in results:
if not result[0]:
print(f" - {result[1]}")
def main():
parser = argparse.ArgumentParser(description='批量生成音频频谱图')
parser.add_argument('input_dir', help='输入音频目录')
parser.add_argument('output_dir', help='输出图片目录')
parser.add_argument('--type', choices=['mel', 'stft', 'chroma'],
default='mel', help='频谱图类型')
parser.add_argument('--width', type=int, default=12, help='图片宽度(英寸)')
parser.add_argument('--height', type=int, default=8, help='图片高度(英寸)')
parser.add_argument('--dpi', type=int, default=150, help='图片分辨率')
parser.add_argument('--colormap', default='viridis', help='颜色映射')
parser.add_argument('--workers', type=int, default=4, help='并行处理线程数')
args = parser.parse_args()
generator = SpectrogramGenerator(
input_dir=args.input_dir,
output_dir=args.output_dir,
spectrogram_type=args.type,
size=(args.width, args.height),
dpi=args.dpi,
colormap=args.colormap,
max_workers=args.workers
)
generator.batch_process()
if __name__ == "__main__":
main()
使用方法
安装依赖
# 安装Python依赖 pip install librosa matplotlib numpy # 或者安装FFmpeg # Ubuntu/Debian sudo apt-get install ffmpeg # macOS brew install ffmpeg # Windows # 下载FFmpeg并添加到PATH
运行脚本
# 使用高级版(推荐) python spectrogram_generator.py input_audio output_spectrograms --type mel --workers 8 # 使用基本版 python batch_spectrogram.py
推荐的目录结构
project/
├── input_audio/ # 存放音频文件
│ ├── song1.mp3
│ ├── song2.wav
│ └── song3.flac
├── output_spectrograms/ # 输出频谱图
│ ├── song1_mel_spectrogram.png
│ ├── song2_mel_spectrogram.png
│ └── song3_mel_spectrogram.png
├── batch_spectrogram.py # 脚本文件
└── requirements.txt # 依赖文件
这些脚本可以根据需求进行调整,比如修改频谱图样式、输出格式、并行处理数量等。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播