Python Matplotlib画布作为numpy数组人工制品

Python Matplotlib画布作为numpy数组人工制品,python,numpy,matplotlib,Python,Numpy,Matplotlib,我想将matplotlib图形转换为numpy数组。我可以通过直接访问渲染器的内容来实现这一点。然而,当我在numpy数组上调用imshow时,它会沿着原始图形中不存在的边缘显示类似于锯齿的人工制品 我尝试过使用各种参数,但不知道如何修复imshow中的人工制品。如果我将图形保存到图像文件中,图像中的差异仍然存在 请注意,我想要实现的是一种确认数组内容与我之前查看的图相同的方法。我认为这些人工制品可能不在numpy数组中,而是在imshow调用期间创建的。也许适当的imshow配置可以解决这个问

我想将matplotlib图形转换为numpy数组。我可以通过直接访问渲染器的内容来实现这一点。然而,当我在numpy数组上调用imshow时,它会沿着原始图形中不存在的边缘显示类似于锯齿的人工制品

我尝试过使用各种参数,但不知道如何修复imshow中的人工制品。如果我将图形保存到图像文件中,图像中的差异仍然存在

请注意,我想要实现的是一种确认数组内容与我之前查看的图相同的方法。我认为这些人工制品可能不在numpy数组中,而是在imshow调用期间创建的。也许适当的imshow配置可以解决这个问题

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Rectangle
import math

fig = plt.figure(frameon=False)
ax = plt.gca()
ax.add_patch(Rectangle((0,0), 1, 1, angle=45, color="red"))
ax.set_xlim(-2,2)
ax.set_ylim(-2,2)
ax.set_aspect(1)
plt.axis("off")
fig.canvas.draw()
plt.savefig("rec1.png")
plt.show()
X = np.array(fig.canvas.renderer._renderer)

fig = plt.figure(frameon=False)
ax = plt.gca()
plt.axis("off")
plt.imshow(X)
plt.savefig("rec2.png")
plt.show()

感谢那些指出插值是原因的评论。我发现以下代码(适用于Python 3)以我想要的方式显示图像;与第一个图像相同,但通过numpy阵列

import PIL.Image
from io import BytesIO
import IPython.display
import numpy as np
def showarray(a, fmt='png'):
    a = np.uint8(a)
    f = BytesIO()
    PIL.Image.fromarray(a).save(f, fmt)
    IPython.display.display(IPython.display.Image(data=f.getvalue()))

来源:

通过添加填充为-1.08的fig.tight_布局,我能够获得与真实图像一样的精确图像

X = np.array(fig.canvas.renderer._renderer)
fig = plt.figure(frameon=False)
ax = plt.gca()
plt.axis("off")
plt.imshow(X)
fig.tight_layout(pad=-1.08)
plt.savefig("rec2.png")
plt.show()


我希望这能解决你的问题,至少在你找到更好的方法之前。干杯。

我能想到的最好的方法是使用cv2(openCV python)库。我的解决方案确实需要保存图像,对于彩色图像,解码图像的通道将以bgr顺序存储

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Rectangle
import math
import cv2 #import openCV

fig = plt.figure(frameon=False)
ax = plt.gca()
ax.add_patch(Rectangle((0,0), 1, 1, angle=45, color="red"))
ax.set_xlim(-2,2)
ax.set_ylim(-2,2)
ax.set_aspect(1)
plt.axis("off")
fig.canvas.draw()
plt.savefig("rec1.png")
plt.show()`

im = cv2.imread("rec1.png")
print(type(im)) #prints numpy.ndarray

cv2.imshow("pic",im) #creates a window named pic, loads im
cv2.waitKey(0) #has no time limit, window destroyed on any key press
cv2.destroyAllWindows()
最终结果看起来像

因为它是一个numpy数组,所以可以调用它上的方法进行比较

print(im.shape) #prints (288, 432, 3)

这些都是明显的重采样人工制品,可以通过使用将未重采样图像添加到图形中来避免

plt.figimage(X)
plt.show()

请注意,这不适用于Jupyter笔记本电脑中的
%matplotlib inline
,但适用于
%matplotlib笔记本电脑
和GUI后端;原因是第一个完整图形的图像被压缩到一个新创建的更小的轴中——这在不关闭轴的情况下是显而易见的

为了确保第二个图形仅显示图像本身,您可以使用
子图\u adjust
调整边距,使图形边缘和轴之间没有间距

fig = plt.figure(frameon=False)
fig.subplots_adjust(0,0,1,1)
ax = plt.gca()
plt.axis("off")
plt.imshow(X)
这将生成所需的绘图

但是请注意,由于在保存png文件时应用了抗锯齿,因此数组并不完全相同。你可以通过

X = np.array(fig.canvas.renderer._renderer)/255.
Y = plt.imread("rec1.png")
print(np.all(X==Y))  
## This prints False
反过来说,如果希望与保存的图像具有相同的numpy数组,则应确保使用保存的图像本身

plt.savefig("rec1.png")
X = plt.imread("rec1.png")
# use X from here onwards

plt.imshow(X,interpolation='bicubic')
删除了别名,但添加了一个阴影。这可能是您使用的python版本或系统设置的问题吗?如果我只是复制粘贴您的示例代码,那么原始矩形和imshow矩形在默认分辨率下看起来是相同的(没有任何瑕疵),只有当我放大到非常远的地方(矩形的一角占据整个高清屏幕)时才会变得模糊。我使用的是(都是相当旧的)fedora 27,带有
2.7.13 | Anaconda custom(64位)|(默认设置,2016年12月20日,23:09:15)[GCC 4.4.7 20120313(Red Hat 4.4.7-1)]
我本以为最大的区别在于所使用的是后端,而不是matplotlib版本。其他@Paul:你用不同的后端试过吗?我会考虑/调查的其他因素是DPI和图形大小,可能是屏幕分辨率。@JC_CL您可能使用的是旧matplotlib版本。他们在版本2之前的
imshow
中默认使用了
interpolation=“bilinear”
(或者fedora维护人员保留了可追溯性的默认设置,或者您在
matplotlibrc
中有它)。当前默认值(
interpolation=“nearest”
)显示issue@bobrobbob如果您使用
imshow(X[…,:3],interpolation=“双线性”)的话,看起来像阴影的部分实际上可能是alpha合成的一些错误,或者alpha插值的一些错误
如果很快找不到更好的答案(例如使用matplotlib),它将接受此答案