以像素为单位指定和保存具有精确大小的图形

2024-10-01 02:21:36 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有一个3841x 7195像素的图像。我想将图中的内容保存到磁盘,从而生成一个以像素为单位指定的精确大小的图像。

没有轴心,没有标题。只是图像。我个人并不关心dpi,因为我只想在磁盘中指定图像在屏幕上的像素大小。

我读过otherthreads,它们似乎都是用英寸进行转换,然后用英寸指定图形的尺寸,并以某种方式调整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要求在inchesdpi中指定图形大小,但我只对图形在磁盘中占用的像素感兴趣。我该怎么做?

要澄清:我正在寻找一种方法来使用matplotlib而不是其他图像保存库来完成此任务。


Tags: 图像图形内容matplotlibfig单位plt像素
3条回答

Matplotlib不直接处理像素,而是处理物理大小和DPI。如果要显示具有特定像素大小的图形,需要知道监视器的DPI。例如,this link将为您检测到这一点。

如果您的图像为3841x7195像素,则监视器不太可能有那么大,因此您将无法显示该大小的图形(matplotlib要求图形适合屏幕,如果您要求的大小太大,则它将缩小到屏幕大小)。假设你想要一个800x800像素的图像作为例子。下面是如何在监视器中显示800x800像素的图像(my_dpi=96):

plt.figure(figsize=(800/my_dpi, 800/my_dpi), dpi=my_dpi)

所以基本上你只需要用DPI除以尺寸(英寸)。

如果你想保存一个特定大小的图形,那就另当别论了。屏幕dpi不再那么重要了(除非你要求一个不适合屏幕的数字)。使用800x800像素图形的相同示例,我们可以使用savefigdpi关键字以不同的分辨率保存它。要以与屏幕相同的分辨率保存,只需使用相同的dpi:

plt.savefig('my_fig.png', dpi=my_dpi)

要将其保存为8000x8000像素图像,请使用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保存以获得所需的分辨率。在我的系统中,这会产生一个3840x7190像素的png——看起来保存的DPI总是比选定的值小0.02像素/英寸,这会对大图像大小产生(小)影响。关于这个here的更多讨论。

这对我很有用,基于你的代码,生成一个93mbpng图像,带有颜色噪声和所需的尺寸:

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)

我正在使用LinuxMint13中Python2.7库的最后一个PIP版本。

希望能有帮助!

基于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)。

相关问题 更多 >