我正在开发一个旨在将用户指定的数据隐藏在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的内存,这意味着我对此问题的解决方法不是擅长)。
答案 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 缩放区域中的点,您可能需要做一些更精彩的操作,以便在缩放时用非下采样版本替换数据