问题:指定并保存具有精确大小(以像素为单位)的图形
假设我的图像尺寸为3841 x 7195像素。我想将图形的内容保存到磁盘,以得到我指定的确切大小的图像(以像素为单位)。
没有轴,没有标题。只是图像。我个人并不关心DPI,因为我只想以像素为单位指定图像在屏幕上所占的大小。
我已经阅读了其他 线程,它们似乎都将转换为英寸,然后以英寸为单位指定图形的尺寸,并以某种方式调整dpi。我想避免处理像素到英寸转换可能导致的精度损失。
我尝试过:
w = 7195
h = 3841
fig = plt.figure(frameon=False)
fig.set_size_inches(w,h)
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)
ax.imshow(im_np, aspect='normal')
fig.savefig(some_path, dpi=1)
没有运气(Python抱怨宽度和高度都必须低于32768(?))
从我所看到的一切来看,都matplotlib
需要在inches
和中指定图形大小dpi
,但是我只对图形在磁盘中占据的像素感兴趣。我怎样才能做到这一点?
需要说明的是:我正在寻找一种使用matplotlib
而不是其他图像保存库的方法。
回答 0
Matplotlib不能直接处理像素,而是可以处理物理尺寸和DPI。如果要显示具有特定像素大小的图形,则需要知道显示器的DPI。例如,此链接将为您检测到该链接。
如果您具有3841×7195像素的图像,则监视器不太可能会那么大,因此您将无法显示该尺寸的图形(matplotlib要求该图形适合屏幕尺寸,如果您要求一个尺寸太大会缩小到屏幕尺寸)。让我们想象一下,您仅需要一个800×800像素的图像作为示例。这是在监视器(my_dpi=96
)中显示800×800像素图像的方法:
plt.figure(figsize=(800/my_dpi, 800/my_dpi), dpi=my_dpi)
因此,您基本上只需将尺寸(以英寸为单位)除以DPI。
如果要保存特定大小的图形,则是另一回事。屏幕DPI不再那么重要了(除非您要求提供一个不适合屏幕的数字)。使用相同的800×800像素图形示例,我们可以使用dpi
关键字来将其保存为不同的分辨率savefig
。要将其保存为与屏幕相同的分辨率,只需使用相同的dpi:
plt.savefig('my_fig.png', dpi=my_dpi)
要将其保存为8000×8000像素的图像,请使用10倍大的dpi:
plt.savefig('my_fig.png', dpi=my_dpi * 10)
请注意,并非所有后端都支持DPI的设置。在这里,使用PNG后端,但是pdf和ps后端将以不同的方式实现大小。同样,更改DPI和大小也会影响诸如fontsize之类的内容。较大的DPI将保持相同的字体和元素相对大小,但是如果您希望较小的字体用于较大的图形,则需要增加物理尺寸而不是DPI。
回到您的示例,如果要保存3841 x 7195像素的图像,可以执行以下操作:
plt.figure(figsize=(3.841, 7.195), dpi=100)
( your code ...)
plt.savefig('myfig.png', dpi=1000)
请注意,我使用的数字dpi为100以适合大多数屏幕,但dpi=1000
为了获得所需的分辨率而将其保存下来。在我的系统中,这会生成一个3840×7190像素的png -似乎保存的DPI总是比所选值小0.02像素/英寸,这将对大图像尺寸产生(较小)影响。这里对此进行更多讨论。
回答 1
根据您的代码,这对我有用,生成了一个93Mb png图像,带有彩色噪声和所需的尺寸:
import matplotlib.pyplot as plt
import numpy
w = 7195
h = 3841
im_np = numpy.random.rand(h, w)
fig = plt.figure(frameon=False)
fig.set_size_inches(w,h)
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)
ax.imshow(im_np, aspect='normal')
fig.savefig('figure.png', dpi=1)
我正在使用Linux Mint 13中Python 2.7库的最新PIP版本。
希望有帮助!
回答 2
根据tiago接受的响应,这是一个小型通用函数,该函数将numpy数组导出到与该数组具有相同分辨率的图像:
import matplotlib.pyplot as plt
import numpy as np
def export_figure_matplotlib(arr, f_name, dpi=200, resize_fact=1, plt_show=False):
"""
Export array as figure in original resolution
:param arr: array of image to save in original resolution
:param f_name: name of file where to save figure
:param resize_fact: resize facter wrt shape of arr, in (0, np.infty)
:param dpi: dpi of your screen
:param plt_show: show plot or not
"""
fig = plt.figure(frameon=False)
fig.set_size_inches(arr.shape[1]/dpi, arr.shape[0]/dpi)
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)
ax.imshow(arr)
plt.savefig(f_name, dpi=(dpi * resize_fact))
if plt_show:
plt.show()
else:
plt.close()
如tiago上次答复中所述,需要首先找到屏幕DPI,例如,可以在此处完成:http : //dpi.lv
我resize_fact
在函数中添加了一个附加参数,例如,您可以将图像导出到原始分辨率的50%(0.5)。
回答 3
plt.imsave为我工作。您可以在此处找到文档:https : //matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.imsave.html
#file_path = directory address where the image will be stored along with file name and extension
#array = variable where the image is stored. I think for the original post this variable is im_np
plt.imsave(file_path, array)