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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13714454/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 09:26:49  来源:igfitidea点击:

Specifying and saving a figure with exact size in pixels

pythonmatplotlibscipy

提问by Amelio Vazquez-Reina

Say I have an image of size 3841 x 7195 pixels. I would like to save the contents of the figure to disk, resulting in an image of the exact sizeI specify in pixels.

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

No axis, no titles. Just the image. I don't personally care about DPIs, as I only want to specify the size the image takes in the screen in disk in pixels.

没有轴,没有标题。只是图像。我个人并不关心 DPI,因为我只想以像素为单位指定图像在屏幕中的屏幕大小。

I have read otherthreads, and they all seem to do conversions to inches and then specify the dimensions of the figure in inches and adjust dpi's in some way. I would like to avoid dealing with the potential loss of accuracy that could result from pixel-to-inches conversions.

我读过其他线程,它们似乎都转换为英寸,然后以英寸为单位指定图形的尺寸并以某种方式调整 dpi。我想避免处理可能因像素到英寸的转换而导致的潜在精度损失。

I have tried with:

我试过:

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)

with no luck (Python complains that width and height must each be below 32768 (?))

没有运气(Python 抱怨宽度和高度都必须低于 32768 (?))

From everything I have seen, matplotlibrequires the figure size to be specified in inchesand dpi, but I am only interested in the pixelsthe figure takes in disk. How can I do this?

从我所看到的一切来看,matplotlib需要在inches和 中指定图形大小dpi,但我只对图形在磁盘中占用的像素感兴趣。我怎样才能做到这一点?

To clarify: I am looking for a way to do this with matplotlib, and not with other image-saving libraries.

澄清一下:我正在寻找一种方法来做到这一点matplotlib,而不是其他图像保存库。

采纳答案by tiago

Matplotlib doesn't work with pixels directly, but rather physical sizes and DPI. If you want to display a figure with a certain pixel size, you need to know the DPI of your monitor. For example this linkwill detect that for you.

Matplotlib 不直接处理像素,而是处理物理尺寸和 DPI。如果要显示具有特定像素大小的图形,则需要知道显示器的 DPI。例如,此链接将为您检测。

If you have an image of 3841x7195 pixels it is unlikely that you monitor will be that large, so you won't be able to show a figure of that size (matplotlib requires the figure to fit in the screen, if you ask for a size too large it will shrink to the screen size). Let's imagine you want an 800x800 pixel image just for an example. Here's how to show an 800x800 pixel image in my monitor (my_dpi=96):

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

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

So you basically just divide the dimensions in inches by your DPI.

所以你基本上只是用你的 DPI 来划分以英寸为单位的尺寸。

If you want to save a figure of a specific size, then it is a different matter. Screen DPIs are not so important anymore (unless you ask for a figure that won't fit in the screen). Using the same example of the 800x800 pixel figure, we can save it in different resolutions using the dpikeyword of savefig. To save it in the same resolution as the screen just use the same dpi:

如果要保存特定大小的图形,则另当别论。屏幕 DPI 不再那么重要(除非您要求的数字不适合屏幕)。使用 800x800 像素图形的相同示例,我们可以使用dpi关键字将其保存为不同的分辨率savefig。要将其保存为与屏幕相同的分辨率,只需使用相同的 dpi:

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

To to save it as an 8000x8000 pixel image, use a dpi 10 times larger:

要将其保存为 8000x8000 像素的图像,请使用 10 倍大的 dpi:

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

Note that the setting of the DPI is not supported by all backends. Here, the PNG backend is used, but the pdf and ps backends will implement the size differently. Also, changing the DPI and sizes will also affect things like fontsize. A larger DPI will keep the same relative sizes of fonts and elements, but if you want smaller fonts for a larger figure you need to increase the physical size instead of the DPI.

请注意,并非所有后端都支持 DPI 的设置。这里使用了 PNG 后端,但 pdf 和 ps 后端将实现不同的大小。此外,更改 DPI 和大小也会影响字体大小等内容。较大的 DPI 将保持相同的字体和元素的相对大小,但如果您希望为较大的图形使用较小的字体,则需要增加物理大小而不是 DPI。

Getting back to your example, if you want to save a image with 3841 x 7195 pixels, you could do the following:

回到您的示例,如果您想保存 3841 x 7195 像素的图像,您可以执行以下操作:

plt.figure(figsize=(3.841, 7.195), dpi=100)
( your code ...)
plt.savefig('myfig.png', dpi=1000)

Note that I used the figure dpi of 100 to fit in most screens, but saved with dpi=1000to achieve the required resolution. In my system this produces a png with 3840x7190 pixels -- it seems that the DPI saved is always 0.02 pixels/inch smaller than the selected value, which will have a (small) effect on large image sizes. Some more discussion of this here.

请注意,我使用 100 的图形 dpi 以适合大多数屏幕,但保存为dpi=1000以实现所需的分辨率。在我的系统中,这会生成一个 3840x7190 像素的 png——似乎保存的 DPI 总是比所选值小 0.02 像素/英寸,这将对大图像尺寸产生(小)影响。这里有更多的讨论。

回答by heltonbiker

This worked for me, based on your code, generating a 93Mb png image with color noise and the desired dimensions:

根据您的代码,这对我有用,生成了一个带有颜色噪声和所需尺寸的 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)

I am using the last PIP versions of the Python 2.7 libraries in Linux Mint 13.

我在 Linux Mint 13 中使用 Python 2.7 库的最新 PIP 版本。

Hope that helps!

希望有帮助!

回答by Cyril

Based on the accepted response by tiago, here is a small generic function that exports a numpy array to an image having the same resolution as the array:

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

As said in the previous reply by tiago, the screen DPI needs to be found first, which can be done here for instance: http://dpi.lv

tiago在之前的回复中说,首先需要找到屏幕DPI,可以在这里完成例如:http: //dpi.lv

I've added an additional argument resize_factin the function which which you can export the image to 50% (0.5) of the original resolution, for instance.

resize_fact在函数中添加了一个额外的参数,例如,您可以将图像导出为原始分辨率的 50% (0.5)。

回答by Alka

plt.imsave worked for me. You can find the documentation here: https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.imsave.html

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)