使用PIL将浮点数数组渲染为24位RGB图像(例如)

6

x 是一个 numpy.float32 数组,值从 -2000。这些是 dB(分贝)值。

当我执行(如此处建议here):

Image.fromarray(x, mode='F')

我得到一张灰度图或者几乎是黑色的图像。
如何将一个范围在[-200,0]之间的浮点数映射到一个24位RGB字节数组(使用颜色映射),该数组可以通过Python模块PIL读取,并使用Image.fromarray(x, mode='RGB')函数进行处理?

编辑:

所需的 .wav 音频文件在这里,我们想要绘制频谱图

以下是一些测试代码:

import scipy, numpy as np
import scipy.io.wavfile as wavfile
import numpy as np
from PIL import Image

def stft(x, fftsize=1024, overlap=4): 
    hop = fftsize / overlap
    w = scipy.hanning(fftsize+1)[:-1]
    return np.array([np.fft.rfft(w*x[i:i+fftsize]) for i in range(0, len(x)-fftsize, hop)])
    
def dB(ratio):
    return 20 * np.log10(ratio+1e-10)

def magnitudedB(frame, fftsize=1024):
    w = scipy.hanning(fftsize+1)[:-1]
    ref = np.sum(w) / 2
    return dB(np.abs(frame) / ref)

sr, x = wavfile.read('test.wav')

x = np.float32(x) / 2**15

s = magnitudedB(stft(x)).astype(np.float32).transpose()[::-1,]
print "Max %.1f dB, Min %.1f dB" % (np.max(s), np.min(s))

im = Image.fromarray(s+200, mode='F')
im.show()

注:

  • 颜色映射为灰度,如何获取其他的颜色映射?例如这个

  • 我的唯一要求是输出的图像可以读入Tkinter框架/画布(使用PIL的im = Image.fromarray(...)然后ImageTk.PhotoImage(image=im)很好用)或wxPython框架/画布。

enter image description here


你为什么不使用 matplotlib.pyplot.imshow(X) 呢? - Nikolas Rieble
@Basj 你有任何数据可以玩吗?我想试一试。 - BPL
@BPL 我添加了代码和 test.wav 的链接。有了这两个东西,你就可以绘制图像并查看发生了什么。如果你有想法,在此先感谢你! - Basj
@Basj 看起来有点像 这个页面 上的“等离子”或“岩浆”。 - chthonicdaemon
你能给我们提供一些示例数据吗? - J Richard Snape
显示剩余5条评论
3个回答

6

根据这里的回答,你可以在将numpy数组转换为图像之前使用matplotlib色图来转换它。

#im = Image.fromarray(s+200, mode='F')
from matplotlib import cm
s = (s + 200)/200.0 # input data should range from 0-1
im = Image.fromarray(cm.jet(s, bytes=True))
im.show()

根据您的最小/最大值,您应该适当地设置比例。

样本输出:

样本输出


3

如果想使用颜色映射绘制图像,我建议您使用matplotlib.pyplot.imshow

使用您的test.wav文件进行操作的结果将如下所示:

enter image description here

如果您想了解有关使用Python创建音频频谱图的更详细信息,可以在此处阅读更多内容。


谢谢@BPL,但我已经知道如何使用Python创建频谱图,并使用matplotlib显示它们。这个问题的要求是有一个图像输出(使用PIL或其他)可以在Tkinter或wxPython用户界面中加载(例如使用画布小部件)。我正在编写一个音频编辑器,需要在tkinter或wxPython中完成UI,就像这里:http://stackoverflow.com/a/41504376/1422096。您认为能否在类似于[这里](http://stackoverflow.com/a/41504376/1422096)的tkinter UI中使用您的解决方案? - Basj

1
我在文档中找不到mode='F'的详细信息,但是我希望它能够采取像0.0-1.0这样的像素值范围。你的值完全低于该范围,因此出现了黑色图像;你需要对它们进行转换。
获得一个彩色映射图像(而不是灰度)需要使用mode ='P',这将要求您将数据转换为字节数组。

我考虑使用 mode='P',但最多只有256种颜色,这不太好(8位)...也许我需要使用 mode='RGB' 并进行转换 [-200, 0] => 24位整数,可以被 RGB 模式读取。但是如何做到这一点呢... - Basj
我在文档中看到了 mode='F' : [modes] (http://pillow.readthedocs.io/en/3.1.x/handbook/concepts.html#concept-modes)。我是不是看错了文档? - fedepad
这些文档只是说模式“F”使用浮点数;它没有提到这些浮点数意味着什么,我很难想象负数被赋予有用的含义。您正在使用numpy;您可以轻松地执行诸如加上200然后除以200之类的操作,将值转换为可能可用的不同范围内的值。 - jasonharper
@jasonharper 抱歉,我把你的“我在文档中找不到mode ='F'的任何细节”理解成了“我在文档中没有找到...”,这不是你的意思;) - fedepad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接