ピクセル単位の正確なサイズのFigureの指定と保存


152

たとえば、サイズが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他の画像保存ライブラリではなく、でこれを行う方法を探しています。


matplotlibでは、Figureサイズを直接インチ単位で設定することはできません。
tiago

回答:


175

Matplotlibはピクセルを直接処理しませんが、物理的なサイズとDPIを処理します。特定のピクセルサイズでFigureを表示する場合は、モニターのDPIを知る必要があります。たとえば、このリンクはそれを検出します。

3841x7195ピクセルの画像がある場合、モニターがそれほど大きくなる可能性は低いため、そのサイズの図を表示することはできません(サイズを要求する場合、matplotlibは画面に収まるように図を表示する必要があります大きすぎると画面サイズに縮小します)。例として800x800ピクセルの画像が必要だとします。モニターに800x800ピクセルの画像を表示する方法は次のとおりです(my_dpi=96):

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

したがって、基本的には、寸法をインチ単位でDPIで割ります。

特定のサイズのFigureを保存する場合は、別の問題です。画面のDPIはそれほど重要ではありません(画面に収まらない図を要求しない限り)。800x800ピクセルの図の同じ例を使用すると、のdpiキーワードを使用して、異なる解像度で保存できますsavefig。画面と同じ解像度で保存するには、同じ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とサイズを変更すると、フォントサイズなどにも影響します。DPIが大きいほど、フォントと要素の相対的なサイズは同じになりますが、大きな図に小さいフォントが必要な場合は、DPIではなく物理サイズを大きくする必要があります。

例に戻りますが、3841 x 7195ピクセルの画像を保存する場合は、次のようにします。

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

ほとんどの画面に収まるように100の図dpiを使用しdpi=1000ましたが、必要な解像度を実現するために保存したことに注意してください。私のシステムでは、これは3840x7190ピクセルのpngを生成します-保存されたDPIは常に選択された値より0.02ピクセル/インチ小さいため、大きな画像サイズでは(小さな)効果があるようです。これについては、ここでさらに説明します


5
モニターのサイズ(および標準のブラウザーとUIウィンドウのサイズ)は通常96 dpi(96の倍数)で表されることを覚えておくと便利です。このように考えると、1440ピクセルのような突然の数字は意味があります(15インチ)。
ダニーステープル2014年

これをに渡しfigsizeて動作させることができませんでしたplt.figure。解決策は、他の回答が示唆するようにして、なし figsizeで電話をかけた後、電話をかけることですfig.set_size_inches(w,h)
Trinidad

figureおよびのドキュメントsavefig
ハンドル

リンクにApple Thunderbolt Displayの正しい値が表示されない。
ドミトリー

この解決策は好きですが、警告が1つあります。テキストサイズは 720dpiに反比例します。(私のシステムはMacBook Pro、OS Xです)、インタラクティブな印刷では、dpiを大きく(10 * my_dpiのように)すると、テキストがほとんど見えなくなります。
Huster教授、2017年

16

これはあなたのコードに基づいて私のために働き、色ノイズと望ましい寸法を含む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バージョンを使用しています。

お役に立てば幸いです。


4
非常に低いdpiを設定すると、非常に大きなフォントサイズを明示的に使用しない限り、フォントがほとんど見えなくなります。
tiago

1
おそらくより高いdpiを設定し、インチサイズ(とにかく任意です)をそのdpiで除算することをお勧めします。それ以外では、セットアップはピクセル再現のための正確なピクセルを生成します、ありがとう!
FrenchKheldar 2014年

プロット要素(円、線など)を含む画像を保存する前に、これを使用しようとしています。これは線幅を乱すので、要素はほとんど見えません。
Gauthier

5

ティアゴによって受け入れられた応答に基づいて、以下は、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()

ティアゴによる以前の回答で述べたように、画面DPIは最初に見つける必要があります。たとえば、ここで行うことができます:http : //dpi.lv

resize_factたとえば、画像を元の解像度の50%(0.5)にエクスポートできる追加の引数を関数に追加しました。


-1

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)

設定しているパラメーターと元の投稿のユースケースの推奨値を正確に示すサンプルコードを追加してください。
サラメッサー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.