Задание и сохранение фигуры с точным размером в пикселях


скажем, у меня есть изображение размером 3841 x 7195 пикселей. Я хотел бы сохранить содержимое рисунка на диск, в результате чего изображение точный размер Я указываю в пикселях.

нет оси, нет титулов. Только образ. Я лично не забочусь о DPIs, так как я только хочу указать размер изображения на экране в disk в точках.

Я прочитал другие темы, и все они, похоже, делают преобразования в дюймы, а затем указывают размеры фигуры в дюймах и настроить 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, а не с другими библиотеками сохранения изображений.

3 90

3 ответа:

Matplotlib работает не с пикселями напрямую, а с физическими размерами и DPI. Если вы хотите отобразить фигуру с определенным размером пикселя, вам нужно знать DPI вашего монитора. Например этой ссылке определит, что для вас.

если у вас есть изображение 3841x7195 пикселей, маловероятно, что ваш монитор будет таким большим, поэтому вы не сможете показать фигуру такого размера (matplotlib требует, чтобы фигура помещалась на экране, если вы тоже попросите размер большой он будет сжиматься до размера экрана). Давайте представим, что вам нужно изображение размером 800x800 пикселей только для примера. Вот как показать изображение 800x800 пикселей на моем мониторе (my_dpi=96):

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

таким образом, вы в основном просто делите размеры в дюймах на ваш DPI.

если вы хотите сохранить фигуру определенного размера, то это другое дело. Экранные DPI больше не так важны (если вы не попросите цифру, которая не будет вписываться в экран). Используя тот же пример 800x800 пиксель рисунок, мы можем сохранить его в различных разрешениях с помощью dpi ключевое слово savefig. Чтобы сохранить его в том же разрешении, что и экран, просто используйте тот же dpi:

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

чтобы сохранить его как изображение 8000x8000 пикселей, используйте dpi в 10 раз больше:

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

обратите внимание, что настройка DPI поддерживается не всеми бэкэндами. Здесь используется бэкэнд PNG, но бэкэнды pdf и ps будут реализовывать размер по-разному. Кроме того, изменение точек на дюйм и размеров также повлияет на такие вещи, как размер шрифта. Более крупный DPI сохранит те же относительные размеры шрифтов и элементов, но если вы хотите использовать меньшие шрифты для большей фигуры, вам нужно увеличить физический размер вместо DPI.

возвращаясь к вашему примеру, если вы хотите сохранить изображение с 3841 х 7195 пикселей, вы можете сделать следующее:

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

обратите внимание, что я использовал цифру dpi 100, чтобы вписаться в большинство экранов, но сохранил с dpi=1000 для достижения необходимого разрешения. В моей системе это создает png с 3840x7190 пикселями - кажется, что сохраненный DPI всегда на 0,02 пикселя / дюйм меньше выбранного значения, что будет иметь (небольшой) эффект на большие размеры изображения. Еще немного обсуждения этого здесь.

это сработало для меня, основываясь на вашем коде, генерируя 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)

Я использую последние версии PIP библиотек Python 2.7 в Linux Mint 13.

надеюсь, что это поможет!

основываясь на принятом ответе 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) исходного разрешения, для пример.