Biblioteka Pillow - otwieranie i edytowanie plików graficznych

Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 8397 razy

Kolejne moduły są związane z biblioteką Pythona o nazwie Pillow, której dokładną dokumentację możecie sobie poczytać na stronie pillow.readthedocs.org. Smutną wiadomością jest to, że nie wszystko z tej biblioteki będzie działało pod Windowsem, ale o tym nieco później. Na Windowsie trzeba tą bibliotekę doinstalować ręcznie wpisując w konsoli następującą instrukcję:

pip install pillow

aby po chwili cała biblioteka została ściągnięta na dysk twardy i zainstalowana do naszej dyspozycji. Nie będę omawiał wszystkich elementów tej biblioteki (odsyłam więc do wcześniej wspomnianej strony), zajmę się jednak tutaj dwoma dość ciekawymi modułami tej biblioteki, które należy zaimportować w następujący sposób:

from PIL import Image, ImageFilter

Wczytywanie i wyświetlanie grafiki

Wczytywanie odbywa się za pomocą metody open, w następujący sposób:

im = Image.open("ścieżka do pliku.jpg")

Nieco gorzej się ma sprawa z wyświetleniem grafiki, ponieważ metoda show działa jedynie pod Linuksem, na Windowsie pokazuje się jakiś nieprzyjemny komunikat, którego przytaczać mi się jakoś szczególnie nie chce. Koniec z końców szczęśliwi posiadacze Linuksa mogą wpisać sobie:

im.show()

by po chwili oczom ich ukazało się okienko wyświetlające ową bitmapę.

Filtry graficzne i zapisywanie pliku

W module ImageFilter znajduje się kilka flag, które należy wykorzystać w metodzie filter, oto przykłady użycia:

im1 = im.filter(ImageFilter.BLUR) # rozmywa obraz im1.save("image1.jpg") im2 = im.filter(ImageFilter.CONTOUR) # tworzy kontur obrazu im2.save("image2.jpg") im3 = im.filter(ImageFilter.DETAIL) # im3.save("image3.jpg") im4 = im.filter(ImageFilter.EDGE_ENHANCE) im4.save("image4.jpg") im5 = im.filter(ImageFilter.EDGE_ENHANCE_MORE) im5.save("image5.jpg") im6 = im.filter(ImageFilter.EMBOSS) im6.save("image6.jpg") im7 = im.filter(ImageFilter.FIND_EDGES) # też znajdowanie krawędzi im7.save("image7.jpg") im8 = im.filter(ImageFilter.SMOOTH) # wygładzanie im8.save("image8.jpg") im9 = im.filter(ImageFilter.SMOOTH_MORE) # mocniejsze wygładzanie im9.save("image9.jpg") im10 = im.filter(ImageFilter.SHARPEN) # wyostrzanie im10.save("image10.jpg")

Oczywistym jest fakt, że funkcja save jest odpowiedzialna za zapisywanie danych do pliku.

a) BLUR

b) CONTOUR

c) DETAIL

d) EDGE_ENHANCE

e) EDGE_ENHANCE_MORE

f) EMBOSS

g) FINDEDGEM

h) SMOOTH

i) SMOOTH_MORE

j) SHARPEN

Rys. 1
Przykłady działania poszczególnych filstrów.
Źródło:
Oryginalny plik został pobrany z strony Wikimedia Commons i jest dostępny w domenie publicznej.

Zmiana rozmiarów grafiki

Pozyskany obiekt im ma pole size, które zawiera krotkę składającą się z dwóch elementów: pierwszego opisującego szerokość bitmapy i drugiego, opisującego wysokość bitmapy. Istnieje też metoda resize, która z kolei umożliwia uzyskanie nowej bitmapy o zmienionych rozmiarach, oto przykładowy kod:

im_resize = im.resize((im.size[0] / 2, im.size[1] / 2)) print("Rozmiar oryginału: {so[0]}; {so[1]}; Rozmiar kopii: {sc[0]}; {sc[1]}".format(so = im.size, sc = im_resize.size)) im.show() im_resize.show()

Jeżeli powyższy skrypt został uruchomiony pod Linuksem to oprócz wyświetlania wymiarów bitmapy oryginalnej i tej o zmienionych wymiarach powinny pokazać się dwa okna z tymi właśnie grafikami.

Obrót grafiki o kąt

Istnieje metoda rotate, która umożliwia obracanie bitmapy o zadany kąt podany w stopniach kątowych. Oto przykładowy kod:

im_rot = im.rotate(30) im_rot.show()

Wynik działania pokazany został na poniższej ilustracji.

a) Przed obrotem

b) Po obrocie

Rys. 2
Przykład działania obracania bitmapy.
Źródło:
Oryginalny plik został pobrany z strony Wikimedia Commons i jest dostępny w domenie publicznej.

Przycinanie grafiki

Do przycinania grafiki służy metoda crop, która przyjmuje jako argument krotkę opisującą pozycję lewego górnego narożnika i prawego dolnego narożnika prostokąta wycinania. Oto przykładowy kod:

im_crop = im.crop((10,10,230,230)) im_crop.show()

Przycięta bitmapa będzie wyglądała jak na poniższym rysunku.

Przycinanie bitmapy w Pythonie
Rys. 3
Przykład przycinania bitmapy.

Operacje na bitach bitmapy za pomocą metody point.

Metoda point daje nam pewną możliwość operowania na poszczególnych bitach bitmapy w następujący przykładowy sposób:

im_roz = im.point(lambda i: i * 2.2) im_roz.show()

Powyższy kod spowoduje, że każda składowa koloru bitmapy zostanie przemnożona przez współczynnik 2.2, spowoduje to nierównomierne rozjaśnienie bitmapy. Co ciekawe użyty zapis lambda i: 1 *2.2 jest funkcją jednoargumentową, która operuje na pewnej wartości i w sposób opisany po dwókropku.

Wynikiem działania powyższego kodu będzie uzyskanie bitmapy z poniższej ilustracji.

Wynik dziłania na pikselach bitmapy w Pythonie
Rys. 4
Efekt działania na poszczególnych bitach bitmapy.

Tworzenie nowej bitmapy o określonych wymiarach

Funkcja new, która przyjmuje kilka argumentów. Oto przykładowy kod pozyskiwania bitmapy o wymiarach 600 na 200:

new_im = Image.new("RGB", (600, 200), (255, 255, 255)) new_im.show()

Pierwszy argument funkcji new to system kolorów (w tym przypadku RGB, drugi argument to wymiary bitmapy w postaci krotki, trzeci to kolor wypełnienia bitmapy również podany jako krotka.

Rysowanie po bitmapie

Istnieje moduł ImageDraw, który udostępnia nowej funkcjonalności i możliwości rysowania po bitmapie. Oto sposób importowania tego modułu:

from PIL import ImageDraw

Czas najwyższy uzyskać kontekst urządzenia, ale zanim trzeba go powiązać z jakąś bitmapą. Ja powiążę go z bitmapą otrzymaną już wcześniej new_im:

dr = ImageDraw.Draw(new_im)

Jak nie trudno się domyślić z kontekstem urządzenia powiązany jest szereg metod umożliwiających rysowanie po bitmapie. Poniżej omówione zostaną niektóre z nich, wszystkie natomiast zostały omówione dokładnie na stronie pillow.readthedocs.org.

Rysowanie linii za pomocą metody line

Oto prosty przykład rysowania linii:

dr.line([10,10,new_im.width - 10, new_im.height - 10], (255, 0, 0))

Jak widać metoda line przyjmuje dwa argumenty, pierwszym jest lista opisująca współrzędne początku i końca linii, drugim jest krotka opisująca kolor rysowanej linii.

Rysowanie elipsy za pomocą metody ellipse

Oto prosty przykład rysowania elipsy:

dr.ellipse([10,10,new_im.width - 10, new_im.height - 10], (255, 0, 0), (0, 255, 0))

Jak widać metoda ellipse przyjmuje trzy argumenty, pierwszym jest lista opisująca współrzędne lewego górnego i prawego dolnego narożnika prostokąta, w który elipsa się wpisuje. Drugim argumentem jest krotka opisująca kolor wypełnienia elipsy (może być pominięty lub ustawiony na None). Trzecim argumentem jest krotka opisująca kolor konturu elipsy (może być pominięty lub ustawiony na None).

Rysowanie prostokąta za pomocą metody rectangle

Oto prosty przykład rysowania prostokąta:

dr.rectangle([10,10,new_im.width - 10, new_im.height - 10], (255, 0, 0), (0, 255, 0))

Jak widać metoda rectangle przyjmuje trzy argumenty, pierwszym jest lista opisująca współrzędne lewego górnego i prawego dolnego narożnika prostokąta. Drugim argumentem jest krotka opisująca kolor wypełnienia prostokąta (może być pominięty lub ustawiony na None). Trzecim argumentem jest krotka opisująca kolor konturu prostokąta (może być pominięty lub ustawiony na None).

Zamykanie bitmapy

Tak jak nieładnie jest zostawiać otwarte drzwi, tak samo nieładnie jest zostawiać otwarte bitmapy, toteż na koniec pracy z bitmapą należy ją zamknąć używając metody close.

Strony powiązane
strony powiązane
  1. pillow.readthedocs.org - dokładna dokumentacja omawianej biblioteki
Propozycje książek