Powiedzmy, że mam obraz o rozmiarze 3841 x 7195 pikseli. Chciałbym zapisać zawartość figury na dysku, w wyniku czego otrzymuję obraz o dokładnym rozmiarze, który określę w pikselach.
Bez osi, bez tytułów. Tylko obraz. Osobiście nie obchodzą mnie DPI, ponieważ chcę tylko określić rozmiar obrazu na ekranie w pikselach .
Czytałem inne wątki i wydaje się, że wszystkie one przeliczają na cale, a następnie określają wymiary figury w calach i dostosowują w jakiś sposób dpi. Chciałbym uniknąć potencjalnej utraty dokładności, która może wynikać z konwersji pikseli na cale.
Próbowałem z:
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)
bez powodzenia (Python narzeka, że szerokość i wysokość muszą być mniejsze niż 32768 (?))
Ze wszystkiego, co widziałem, matplotlib
wymaga określenia rozmiaru figury w inches
i dpi
, ale interesują mnie tylko piksele, które figura zajmuje na dysku. W jaki sposób mogę to zrobić?
Wyjaśnienie: szukam sposobu, aby to zrobić matplotlib
z innymi bibliotekami do zapisywania obrazów, a nie z nimi.
źródło
Odpowiedzi:
Matplotlib nie działa bezpośrednio z pikselami, ale raczej z fizycznymi rozmiarami i DPI. Jeśli chcesz wyświetlić figurę o określonym rozmiarze piksela, musisz znać DPI swojego monitora. Na przykład ten link wykryje to za Ciebie.
Jeśli masz obraz o wymiarach 3841x7195 pikseli, jest mało prawdopodobne, że monitor będzie tak duży, więc nie będziesz w stanie wyświetlić figury tego rozmiaru (matplotlib wymaga, aby figura zmieściła się na ekranie, jeśli poprosisz o rozmiar za duży, zmniejszy się do rozmiaru ekranu). Wyobraźmy sobie, że jako przykład potrzebujesz obrazu 800x800 pikseli. Oto jak wyświetlić obraz o rozdzielczości 800x800 pikseli na moim monitorze (
my_dpi=96
):Więc po prostu dzielisz wymiary w calach przez swoje DPI.
Jeśli chcesz zapisać figurę o określonym rozmiarze, to inna sprawa. DPI ekranu nie są już tak ważne (chyba że poprosisz o figurę, która nie zmieści się na ekranie). Korzystając z tego samego przykładu piksela 800x800, możemy zapisać go w różnych rozdzielczościach, używając
dpi
słowa kluczowego zsavefig
. Aby zapisać go w tej samej rozdzielczości, co ekran, użyj tej samej rozdzielczości:Aby zapisać go jako obraz o rozdzielczości 8000x8000 pikseli, użyj rozdzielczości 10 razy większej:
Zwróć uwagę, że ustawienie DPI nie jest obsługiwane przez wszystkie backendy. Tutaj używany jest backend PNG, ale backend pdf i ps będą implementować rozmiar inaczej. Ponadto zmiana DPI i rozmiarów wpłynie również na takie rzeczy, jak rozmiar czcionki. Większy DPI zachowa te same względne rozmiary czcionek i elementów, ale jeśli chcesz mieć mniejsze czcionki dla większej figury, musisz zwiększyć rozmiar fizyczny zamiast DPI.
Wracając do przykładu, jeśli chcesz zapisać obraz o rozmiarze 3841 x 7195 pikseli, możesz wykonać następujące czynności:
Zauważ, że użyłem wartości 100 dpi, aby zmieścić się na większości ekranów, ale zapisałem z,
dpi=1000
aby uzyskać wymaganą rozdzielczość. W moim systemie daje to png o rozdzielczości 3840x7190 pikseli - wydaje się, że zapisane DPI jest zawsze o 0,02 piksela / cal mniejsze od wybranej wartości, co będzie miało (mały) wpływ na duże rozmiary obrazu. Więcej dyskusji na ten temat tutaj .źródło
figsize
doplt.figure
. Rozwiązaniem było zrobienie tego, co sugerują inne odpowiedzi i po wywołaniu go bezfigsize
, a następnie zadzwońfig.set_size_inches(w,h)
figure
isavefig
.To zadziałało dla mnie, w oparciu o twój kod, generując obraz PNG o rozmiarze 93 MB z szumem kolorów i pożądanymi wymiarami:
Używam ostatnich wersji PIP bibliotek Python 2.7 w Linux Mint 13.
Mam nadzieję, że to pomoże!
źródło
Na podstawie zaakceptowanej odpowiedzi tiago, oto mała ogólna funkcja, która eksportuje tablicę numpy do obrazu o tej samej rozdzielczości co tablica:
Jak wspomniano w poprzedniej odpowiedzi tiago, najpierw należy znaleźć DPI ekranu, co można zrobić na przykład tutaj: http://dpi.lv
Dodałem dodatkowy argument
resize_fact
w funkcji, dzięki któremu można np. Wyeksportować obraz do 50% (0,5) oryginalnej rozdzielczości.źródło
OP chce zachować dane piksela 1: 1. Jako astronom pracujący z obrazami naukowymi nie mogę pozwolić na jakąkolwiek interpolację danych obrazu, ponieważ wprowadzałaby ona nieznane i nieprzewidywalne szumy lub błędy. Na przykład, oto fragment z obrazu 480x480 zapisanego przez pyplot.savefig (): Szczegóły pikseli, które matplotlib ponownie próbkowały do rozmiaru mniej więcej 2x2, ale zwróć uwagę na kolumnę 1x2 pikseli
Widać, że większość pikseli została po prostu podwojona (więc piksel 1x1 zmienia się na 2x2), ale niektóre kolumny i wiersze zmieniły się na 1x2 lub 2x1 na piksel, co oznacza, że oryginalne dane naukowe zostały zmienione.
Jak zasugerował Alka, plt.imsave (), który osiągnie to, o co prosi PO. Powiedzmy, że masz dane obrazu przechowywane w image array im, wtedy można zrobić coś takiego
gdzie nazwa pliku ma rozszerzenie „png” w tym przykładzie (ale i tak musisz określić format za pomocą format = 'png', o ile wiem), tablica obrazu to arr, a my wybraliśmy odwróconą skalę szarości „gray_r” jako mapa kolorów. Zwykle dodaję vmin i vmax, aby określić zakres dynamiczny, ale są one opcjonalne.
Końcowym wynikiem jest plik png o dokładnie takich samych wymiarach w pikselach jak tablica im.
Uwaga: OP nie określił żadnych osi itp., Co dokładnie robi to rozwiązanie. Jeśli ktoś chce dodać osie, znaczniki, itp., Moim preferowanym podejściem jest zrobienie tego na oddzielnym wykresie, zapisanie z przezroczystym = True (PNG lub PDF), a następnie nałożenie tego ostatniego na obraz. Gwarantuje to, że oryginalne piksele pozostały nienaruszone.
źródło
plt.imsave pracował dla mnie. Dokumentację można znaleźć tutaj: https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.imsave.html
źródło