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


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

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

에 대한 문서 figure와 savefig.
— 처리

링크에 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.