Python将图片写到音频频谱
用到的库:pillow、numpy、matplotlib
源码GitHub
# -*- coding: utf-8 -*-
import wave
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
from matplotlib.mlab import window_none
def img2wav(img_path, wav_path, fft_size=1024):
"""
把图片写到音频频域
:param img_path: 输入图片路径
:param wav_path: 输出音频路径
:param fft_size: 图片每列代表的音频长度,也是频域长度的两倍
"""
# 读取图片,转为灰度图
img = Image.open(img_path).convert("L")
# 缩放到高度 = fft_size / 2 (令负频率全为0)
img = img.resize((img.width * fft_size // 2 // img.height, fft_size // 2),
Image.BICUBIC)
# 转为numpy数组
img = np.array(img, "float")
# 变换到-100~0分贝
img = img * (100 / 255) - 100
# 单位从分贝转成1,此时取值为0~1
# amp_dB = 20 * ln(amp) / ln(10)
# amp = exp(amp_dB / 20 * ln(10))
img = np.exp(img * (np.log(10) / 20))
# 翻转(索引小的频率小)然后转置(要迭代列)
img = img[::-1].T
# 防溢出,每列总振幅不能超过1
max_sum = max(col.sum() for col in img)
if max_sum > 1:
img /= max_sum
with wave.open(wav_path, "wb") as f:
# (nchannels, sampwidth, framerate, nframes, comptype, compname)
f.setparams((1, 2, 44100, len(img) * fft_size, "NONE", ""))
for col in img:
# 傅里叶反变换
data = np.fft.ifft(col * fft_size, fft_size).real * 32767
# 最后一次防溢出,限制范围在-32768~32767
for index in np.where(data < -32768):
data[index] = -32768
for index in np.where(data > 32767):
data[index] = 32767
# 写到wav文件
data = data.astype("short")
f.writeframesraw(data)
def draw_spectrum(wav_path, fft_size=1024):
"""
画音频频谱图
:param wav_path: 输入音频路径
:param fft_size: 傅里叶变换用的长度
"""
# 读wav
with wave.open(wav_path, "rb") as f:
n_samples = f.getnframes()
data = f.readframes(n_samples)
n_channels = f.getnchannels()
sample_rate = f.getframerate()
# 转为numpy数组
data = np.fromstring(data, "short")
# 取第一个声道
data.shape = (n_samples, n_channels)
data = data.T[0]
# 画频谱,无加窗和重叠
plt.specgram(data / 32767, fft_size, sample_rate, window=window_none,
noverlap=0, scale="dB")
plt.show()
if __name__ == "__main__":
img2wav("test.jpg", "test.wav")
draw_spectrum("test.wav")
测试图片:
自己画的频谱效果
AU的频谱效果,因为AU有加窗和重叠所以和自己画的有点不一样
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。