정확한 크기의 그림을 픽셀 단위로 지정하고 저장


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그림 크기를 inchesand에 지정해야 dpi하지만 그림이 디스크에서 차지하는 픽셀 에만 관심이 있습니다. 어떻게해야합니까?

명확히하기 위해 : matplotlib다른 이미지 저장 라이브러리가 아닌 으로이 작업을 수행하는 방법을 찾고 있습니다.


matplotlib를 사용하면 그림 크기를 인치 단위로 직접 설정할 수 없습니다.
tiago December

답변:


175

Matplotlib은 픽셀과 직접 작동하지 않지만 실제 크기와 DPI에서 작동합니다. 특정 픽셀 크기의 그림을 표시하려면 모니터의 DPI를 알아야합니다. 예를 들어이 링크 는이를 감지합니다.

3841x7195 픽셀의 이미지가있는 경우 모니터 할 정도로 크지 않을 수 있으므로 해당 크기의 그림을 표시 할 수 없습니다 (matplotlib은 그림을 요구할 경우 화면에 맞게 그림을 요구합니다) 너무 크면 화면 크기가 줄어 듭니다.) 예를 들어 800x800 픽셀 이미지를 원한다고 가정 해 봅시다. 내 모니터 ( my_dpi=96) 에 800x800 픽셀 이미지를 표시하는 방법은 다음과 같습니다 .

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 픽셀 이미지로 저장하려면 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)

필자는 대부분의 화면에 맞도록 그림 dpi를 100으로 사용했지만 dpi=1000필요한 해상도를 달성하기 위해 저장했습니다 . 내 시스템에서 이것은 3840x7190 픽셀의 png를 생성합니다. 저장된 DPI는 선택한 값보다 항상 0.02 픽셀 / 인치 작으므로 큰 이미지 크기에 (작은) 영향을 미칩니다. 이것에 대한 더 많은 토론은 여기에 있습니다 .


5
모니터 크기 (따라서 표준 브라우저 및 ui 창 크기)는 일반적으로 96dpi-96의 배수로 표시됩니다. 1440 픽셀과 같은 숫자는 이와 같이 생각할 때 의미가 있습니다 (15 인치).
Danny Staple

지나가는 일이를 가져올 수 없습니다 figsizeplt.figure. 해결책은 다른 답변이 제안한대로하고 , 없이 figsize 전화 한 다음 전화하십시오.fig.set_size_inches(w,h)
Trinidad

에 대한 문서 figuresavefig.
처리

링크에 Apple Thunderbolt 디스플레이에 대한 올바른 값이 표시되지 않습니다.
Dmitry

이 솔루션이 마음에 들지만 경고가 하나 있습니다. 텍스트 크기는 dpi의 반비례 확장 할 수 있습니다. (시스템은 MacBook Pro, OS X입니다.) 대화 형 인쇄의 경우 dpi를 크게 (10 * my_dpi와 같이) 크게하면 텍스트가 거의 보이지 않게 줄어 듭니다.
교수 Huster

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 December

1
더 높은 dpi를 설정하고 인치 크기 (어쨌든 임의 임)를 해당 dpi로 나누는 것이 좋습니다. 그 이외의 설정은 픽셀 재생을위한 정확한 픽셀을 생성합니다. 감사합니다!
FrenchKheldar

플롯 요소가있는 그림을 저장하기 전에 이것을 사용하려고합니다 (원, 선 등 ...). 이것은 선폭을 방해하여 요소가 거의 보이지 않게합니다.
Gauthier

5

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)로 내보낼 수있는 함수에 추가 인수 를 추가했습니다 .


2

OP는 1 : 1 픽셀 데이터를 유지하려고합니다. 과학 이미지로 작업하는 천문학 자로서, 알 수없고 예측할 수없는 노이즈 나 오류가 발생할 수 있으므로 이미지 데이터의 보간을 허용 할 수 없습니다. 예를 들어, 다음은 pyplot.savefig ()를 통해 저장된 480x480 이미지의 스 니펫입니다. matplotlib가 대략 2x2로 리샘플링했지만 1x2 픽셀의 열을 확인한 픽셀의 세부 사항

대부분의 픽셀은 단순히 두 배가되었으므로 (1x1 픽셀은 2x2가 됨) 일부 열과 행은 픽셀 당 1x2 또는 2x1이되었으므로 원래 과학 데이터가 변경되었음을 의미합니다.

Alka가 암시 한 것처럼 plt.imsave ()는 OP가 요구하는 것을 달성합니다. 이미지 배열 이미지에 이미지 데이터가 저장되어 있다고 가정하면 다음과 같은 작업을 수행 할 수 있습니다

plt.imsave(fname='my_image.png', arr=im, cmap='gray_r', format='png')

이 예제에서 파일 이름의 확장자는 "png"입니다 (그러나 어쨌든 format = 'png'로 형식을 지정해야 함). 이미지 배열은 arr이며 반전 된 회색조 "gray_r"을 선택했습니다. 컬러 맵으로. 일반적으로 동적 범위를 지정하기 위해 vmin 및 vmax를 추가하지만 선택 사항입니다.

최종 결과는 im 배열과 정확히 같은 픽셀 크기의 png 파일입니다.

참고 : OP는이 솔루션이 정확히 수행하는 축 등을 지정하지 않았습니다. 축, 눈금 등을 추가하려는 경우 선호하는 방법은 transparent = True (PNG 또는 PDF)로 저장하고 이미지에 오버레이를 오버레이하는 별도의 플롯에서 수행하는 것입니다. 이렇게하면 원본 픽셀을 그대로 유지할 수 있습니다.


감사. 이 Q에 질문한지 몇 년이 지났지 만 답에서 기억하고 보는 것에서, 데이터 배열을 이미지로 저장하려고 할 때 잘 작동하지만 저장하려는 경우 실제는 무엇입니까? 그림 (관계없이 콘텐츠) 자체를 제어 여전히 정확하게 생성 된 이미지 파일의 픽셀 크기?
Amelio Vazquez-Reina

-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)

설정중인 매개 변수와 원래 게시물의 사용 사례에 대한 권장 값을 정확하게 보여주는 샘플 코드를 추가하십시오.
Sarah Messer
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.