有没有一种方法可以将pyplot.imshow()对象转换成numpy数组?

8

我需要可视化一个二维的numpy数组。我会使用pyplot库来完成这个任务。

下面是代码:

import cv2 as cv
import numpy as np
from matplotlib import pyplot

img = pyplot.imshow( radiance_val )
#radiance_val is a 2D numpy array of size = ( 512, 512 ) 
#filled with np.float32 values

pyplot.show()

我得到了预期的输出。
现在我的问题是,是否有一种方法可以将上面代码中的“img”从pyplot类型转换为numpy类型。我需要这样做才能将可视化加载为opencv图像并对其进行进一步处理。我正在使用Python 2.7,32位。
编辑1:在Thorsten Kranz的解决方案之后
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
import PIL
from cStringIO import StringIO

frame1 = plt.gca()
frame1.axes.get_xaxis().set_visible(False)
frame1.axes.get_yaxis().set_visible(False)
plt.imshow(np.random.random((10,10)))

buffer_ = StringIO()
plt.savefig( buffer_, format = "png", bbox_inches = 'tight', pad_inches = 0 )
buffer_.seek(0)

image = PIL.Image.open( buffer_ )

ar = np.asarray(image)
cv.imshow( 'a', ar )
cv.waitKey(0)
cv.destroyAllWindows()

在程序结束后,我从MS VC++运行库得到了一个运行时错误。我的猜测是这可能是由于未关闭"buffer_"引起的。但我已经得到了所需的输出。


编辑2:使用以下方式关闭缓冲区

buffer_.close()

没有解决运行时错误


我按照Thorsten Kranz所说添加了buffer_.close(),但是运行时错误仍然出现。 - Yash
4个回答

12

除非您真的需要标记刻度等内容,

im._rgba_cache

直接访问 MxNx4 的 numpy 数组,这是映射到颜色的数据。

如果您只需要颜色映射的数据,可以完全绕过 imshow 直接对数据进行颜色映射(参见指南以选择您的颜色映射方案)。

my_cm = maplotlib.cm.get_cmap('Reds')
normed_data = (data - np.min(data)) / (np.max(data) - np.min(data))
mapped_data = my_cm(normed_data)

这将为您提供一个在01之间映射的MxNx4数组,

mapped_datau8 = (255 * my_cm(normed_data)).astype('uint8')
或者
mapped_data = my_cm(normed_data, bytes=True)

将其转换为无符号整数,可以使用 matplotlib 中的一系列规范化代码,可在此处查看

有关 get_cmap 的文档,请参阅此处,以及颜色地图库

编辑:修正了在https://stackoverflow.com/a/14880947/380231中指出的疏漏。


哇,你的解决方案保留了原始图像的尺寸,这是我接下来要问的问题。非常感谢你。而且我也没有遇到任何运行时错误。 - Yash
1
如果你想使用不同的颜色映射,例如 get_cmap('jet_r'),你可以通过名称调用它们。这样做会得到相同的结果,因为如果你不传递参数,它会返回默认值(除非你已经更改了它,否则默认值为 'jet')。 - tacaswell
@Yash,你应该开一个新的问题来解决这个问题。 - tacaswell
2
尝试直接使用 im._rgba_cache 访问 numpy 数组会抛出 AttributeError: 'AxesImage' object has no attribute '_rgba_cache'。那么我们第一段代码中的 im 是什么? - FaCoffee
1
正如@FaCoffee所提到的,答案第一行中的im._rgba_cache中的im是什么? - Anirban Chakraborty
显示剩余3条评论

5

你确定你想要转换方法的返回值还是整个图?

如果是后者,你应该尝试:

  • 使用savefig将图保存到StringIO缓冲区图像中
  • 使用PIL或OpenCV从此缓冲区加载图像
  • 将其转换为numpy数组

参见下面的示例:

import numpy as np
import matplotlib.pyplot as plt
import PIL
from cStringIO import StringIO

plt.imshow(np.random.random((20,20)))
buffer_ = StringIO()
plt.savefig(buffer_, format = "png")
buffer_.seek(0)
image = PIL.Image.open(buffer_)
ar = np.asarray(image)
buffer_.close()

请查阅savefig-*args**kwargs以获取更多选项,如dpi、背景颜色、透明度、填充等。

如果您只想要带有彩色编码的图像,没有坐标轴、标签等,我仍然建议相同的操作,只需使用

plt.subplots_adjust(0,0,1,1)

要将轴扩展到整个图形。注意您绘图的 aspect (纵横比),否则 mpl 可能会再次缩小您的轴。


太棒了,这对我有用。非常感谢你。你的解决方案正好提供了我想要的。不过我有一个问题。我把脚本放到一个文件中并执行它。程序终止后,我从Microsoft VC++运行时库收到一个运行时错误(此应用程序已请求运行时以不寻常的方式终止)。我已经编辑了我的帖子,包括代码。你能告诉我如何纠正它吗?我更好的猜测是打开“buffer_”。但在PIL中没有关闭打开文件的选项。 - Yash
1
buffer_是一个StringIO对象,与PIL无关。您可以通过调用 buffer_.close() 释放所有已使用的资源。虽然我不确定这是否会解决您的问题。无论如何,在我们继续搜索之前,请尝试此方法。 - Thorsten Kranz
1
你可以尝试将 from cStringIO import StringIO 替换为 from StringIO import StringIO。这可能会稍微慢一些(在这里不相关),但可以减少对编译的 C 代码的依赖。 - Thorsten Kranz
我必须补充说明的是,如果我将代码逐行输入到Python IDLE中,则不会引发任何错误......只有当我将代码放入.py文件并运行它时才会出现错误。 - Yash
1
如果您不使用matplotlib,只将np.random.random((20,20))放入cv.imshow中,是否也会发生这种情况?也许设置另一个mpl后端可以帮助解决问题,例如在脚本开头添加import matplotlib; matplotlib.use("Agg") - Thorsten Kranz
显示剩余2条评论

1
这里我找到了一个更简单的示例来将数组转换为RGBA, 我想将声谱图转换为使用熔岩颜色映射的RGB图像,这是我的实现方法:
import matplotlib.cm as cm
sm = cm.ScalarMappable(cmap='magma')
sm.set_clim(spect.min(), spect.max())
im = sm.to_rgba(spect)

plt.imshow(im)
plt.title(im.shape)

enter image description here


0

更新的答案灵感来自@Thorsten Kranz

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import io
plt.imshow(np.random.random((20,20)))
with io.BytesIO() as buffer:
    plt.savefig(buffer, format = "png")
    buffer.seek(0)
    image = Image.open(buffer)
    ar = np.asarray(image)
print(ar.shape)

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