Matplotlib - 绘制wav文件的波形

时间:2014-04-13 14:11:02

标签: python matplotlib

我正在开发一个旨在将用户指定的数据隐藏在wav文件中的程序(隐写程序,但仅限于教育用途,没有什么非常复杂的)。除了进行隐写操作外,我还需要可视化原始和输出wav文件的内容,但是我不知道如何以可行的方式进行操作。

起初,我以为我只是使用来自canvas的{​​{1}}小部件,但它几乎无法使用,因为输入的wav文件可能非常大而且绘制这样的数量是不可行的数据,更不用说我需要处理缩放,滚动等。

我发现tkinter我认为可以解决我的问题。我加载了一个10 MB的wav文件(16位,立体声),将两个通道的样本分开并将它们转换为带符号的16位整数。然后我试图绘制第一个通道的数据,但似乎matplotlib无法处理如此大量的点来绘图 - 首先我可以看到波形图(但仍需要很长时间)但是当我调整窗口大小时(这会导致重绘图),会发生以下异常:

matplotlib

当我尝试加载更大的WAV文件(50 MB)时,即使没有绘制波形,也会发生同样的错误。所以我需要采取不同的方法,但不知道该怎么做。当我首先加载样本时,我可能会绘制输入样本子集的平均值,这对于matplotlib来说应该是可以忍受的。但是当我缩放/滚动绘图时我不知道如何处理情况,这意味着根据实际的缩放级别和实际的视图位置(“窗口”)重新计算平均值,这可能是非常差的性能 - 明智的。

这只是一个样本图,所以我无法想象在没有遇到性能问题甚至是上述失败/异常的情况下,将这一数据量(2个通道,原始数据和输出数据)绘制四次。在较小的文件(几百kB)上,它运行良好(但它仍然有点慢)。

对此问题有任何建议吗?

编辑:我发现我对Exception in Tkinter callback Traceback (most recent call last): File "C:\Python33\lib\tkinter\__i`enter code here`nit__.py", line 1475, in __call__ return self.func(*args) File "C:\Python33\lib\site-packages\matplotlib\backends\backend_tkagg.py", line 276, in resize self.show() File "C:\Python33\lib\site-packages\matplotlib\backends\backend_tkagg.py", line 348, in draw FigureCanvasAgg.draw(self) File "C:\Python33\lib\site-packages\matplotlib\backends\backend_agg.py", line 451, in draw self.figure.draw(self.renderer) File "C:\Python33\lib\site-packages\matplotlib\artist.py", line 56, in draw_wrapper draw(artist, renderer, *args, **kwargs) File "C:\Python33\lib\site-packages\matplotlib\figure.py", line 1035, in draw func(*args) File "C:\Python33\lib\site-packages\matplotlib\artist.py", line 56, in draw_wrapper draw(artist, renderer, *args, **kwargs) File "C:\Python33\lib\site-packages\matplotlib\axes.py", line 2088, in draw a.draw(renderer) File "C:\Python33\lib\site-packages\matplotlib\artist.py", line 56, in draw_wrapper draw(artist, renderer, *args, **kwargs) File "C:\Python33\lib\site-packages\matplotlib\lines.py", line 563, in draw drawFunc(renderer, gc, tpath, affine.frozen()) File "C:\Python33\lib\site-packages\matplotlib\lines.py", line 939, in _draw_lines self._lineFunc(renderer, gc, path, trans) File "C:\Python33\lib\site-packages\matplotlib\lines.py", line 979, in _draw_solid renderer.draw_path(gc, path, trans) File "C:\Python33\lib\site-packages\matplotlib\backends\backend_agg.py", line 145, in draw_path self._renderer.draw_path(gc, path, transform, rgbFace) OverflowError: Allocated too many blocks 中16位样本的输入数据有错误的解释(我使用字符串struct.pack()代替{{ 1}})并且不知何故我没有10 MB WAV的问题,似乎有一些加速,但是绘制波形仍然比适当的慢得多。 50 MB WAV似乎绘制得很好,但是当我调整窗口大小(因此调整matplotlib画布)时,会发生上述异常,当我尝试缩放到某个区域或调整窗口大小时,重新绘制不再发生以前的尺寸。

这是我用来稍微了解matplotlib的代码(它基于simple matplotlib demo):

EDIT2:我更改了代码,以便它以相同的方式运行,但现在它更加简单,我希望。)

<H

如何解决此问题以及如何处理以合理的性能和内存消耗绘制WAV数据的任何建议(此示例在异常发生之前使用&gt; 800 MB的内存,这意味着我对此问题的解决方法不是擅长)。

1 个答案:

答案 0 :(得分:1)

您可以在交互式提示中运行更简化,但我离题了

import matplotlib
from matplotlib import pyplot as plt
from random import randrange


samples = [randrange(-32768, 32768) for i in range(int(1e7))]
fig, ax = plt.subplots(1, 1)
ax.plot(samples, "r-")

问题是你正在尝试绘制一个比Agg库更能处理的线段(我不确定是什么限制,并且在路径传递给路径之前应该有一些路径简化)因此,它可能不是点数限制。)

在某种程度上这不是一个大问题,你的屏幕只有~1k像素,如果你绘制了所有的点,每个像素会有1e4点,这有点傻,所以你需要下来样品。

你可以通过多种方式做到这一点(哪种方式是正确的取决于为什么你正在绘制这个),包括:盲目下采样(x = x[::1000]),平均部分( x = np.mean(x[::n * (len(x)//n)].reshape(-1, n), axis=1))或做一些异国情调(取fft并过滤它以保持低频率)。

如果您需要能够放大并查看 all 缩放区域中的点,您可能需要做一些更精彩的操作,以便在缩放时用非下采样版本替换数据