Zadanie - utworzenie kwadratowych miniatur ze zdjęć.
Jestem na etapie tworzenia mini-silnika do własnej galerii i wymyśliłem sobie, że chce mieć w niej miniatury kwadratowe, oczywiście wycięte ładnie ze środka.
Googlając za rozwiązaniem trafiłem na implementacje zarówno z wykorzystaniem ImageMagicka jak i PIL
Oba rozwiązania działają i tworzą to co mają tworzyć, z ciekawości jednak, stworzyłem bliźniacze skrypty i sprawdziłem wydajność obu rozwiązań.
Wynik
80 plików o rozmiarach 750*568
~/temp/misc/ time python generate_thumb_pil.py
python generate_thumb_pil.py 6,02s user 0,09s system 98% cpu 6,175 total
~/temp/misc1_1/ time python generate_thumb_im.py
python generate_thumb_im.py 11,28s user 1,50s system 119% cpu 10,650 total
100 plików o rozmiarach 2560*1920 każdy plik o wadze ok. 1,1MB
~/temp/im/ time python generate_thumb_im.py
python generate_thumb_im.py 58,80s user 9,70s system 116% cpu 58,739 total
~/temp/pil/ time python generate_thumb_pil.py
python generate_thumb_pil.py 60,22s user 1,62s system 98% cpu 1:02,73 total
100 plików o rozmiarach 2560*1920 każdy plik o wadze ok. 3,0MB
~/temp/im2/ time python generate_thumb_im.py
python generate_thumb_im.py 69,18s user 9,69s system 116% cpu 1:07,48 total
~/temp/pil2/ time python generate_thumb_pil.py
python generate_thumb_pil.py 67,58s user 1,42s system 99% cpu 1:09,69 total
AKTUALIZACJA: O ile pierwszy wynik potwierdza test riklaunima, to dwa kolejne (pliki o znacznie większej rozdzielczości) wskazują na delikatną przewagę ImageMagicka
Skrypty
wersja z wykorzystaniem ImageMagick
# -*- coding: utf-8 -*-
#generate thumb im by grizz - Witek Firlej http://grizz.pl
__project__ = "generate thumb im"
__author__ = "Witold Firlej (http://grizz.pl)"
__license__ = "GPL"
__copyright__ = "Witold Firlej"
import glob
import os
THUMB_SIZE = 125
for infile in glob.glob("*.jpg"):
outfile = infile[:-4] + "_thumb.jpg"
cmd = "convert " + infile +" -thumbnail x" + str(THUMB_SIZE*2) + " -resize \'" + str(THUMB_SIZE*2) +"x<\' -resize 50% -gravity center -crop " + str(THUMB_SIZE) + "x" + str(THUMB_SIZE) + "+0+0 +repage -format jpg -quality 91 " + outfile
# print cmd
os.system(cmd)
wersja z wykorzystaniem Python Imaging Library
# -*- coding: utf-8 -*-
#generate thumb pil by grizz - Witek Firlej http://grizz.pl
__project__ = "generate thumb pil"
__author__ = "Witold Firlej (http://grizz.pl)"
__license__ = "GPL"
__copyright__ = "Witold Firlej"
import glob
import Image
THUMB_SIZE = 125, 125
for infile in glob.glob("*.jpg"):
img = Image.open(infile)
width, height = img.size
if width > height:
delta = width - height
left = int(delta/2)
upper = 0
right = height + left
lower = height
else:
delta = height - width
left = 0
upper = int(delta/2)
right = width
lower = width + upper
img = img.crop((left, upper, right, lower))
img.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
outfile = infile[:-4] + "_thumb.jpg"
#print infile + " ==> " + outfile
img.save(outfile, "JPEG")
Dostępne:
git clone git://github.com/grizz-pl/generatesquarethumbs.git
Wersja imagemagick jest w osobnej gałęzi, a więc po ściągnięciu:
cd generatesquarethumbs
git checkout -b imagemagick origin/imagemagick
Podsumowanie
Szybkość, szybkością, ale przejrzystość kodu to dopiero zaleta rozwiązania z użyciem PILa. W tym wypadku,, tak miło się składa, ze zarówno wydajność jak i przejrzystość idą w parze. Oczywiście przy dużych plikach, PIL jest minimalnie mniej wydajny, ale dla celów galerii jaką tworzę (nie będę w niej zamieszczał plików o tak dużej rozdzielczości) jest idealny.
Linki
W powyższych skryptach korzystałem z rozwiązań pochodzących z:

rss

"python generate_thumb_pil.py
"python generate_thumb_pil.py 6,02s" - jest to czas generowania jednej miniaturki?Z jak dużego obrazu robiłeś miniaturkę?
Przeczytaj kod ;)
Przeczytaj kod - to tworzy miniaturki z wszystkich plików w katalogu.
W tym przypadku było to 80 plików o rozmiarach 750*568.
I z ciekawości przeprowadziłem dwa inne testy... co zmieniło wnioski... ehh ;)
Dzięki właśnie tego szukałem
Dzięki właśnie tego szukałem :) Szybkość w obydwu skryptach jest podobna, ale dla mnie przewagą PILa są mniejsze zniekształcenia o których pisał riklaunim na swoje stronie. Nie są to może jakieś duże różnice, ale może stąd PIL jest odrobinę wolniejszy.
Moim zdaniem i tak lepiej
Moim zdaniem i tak lepiej używać PIL'a ze względu na lepszą czytelność kodu. W PIL'u przy rozmiarach 25601920 każdy plik o wadze ok. 1,1MB tracimy ok tylko 2 sekundy zaś 25601920 każdy plik o wadze ok. 3,0MB zyskujemy te 2 sekundy. Zresztą to zależy od programisty w czym chce dokładnie zrobić miniaturki, ale ja bym spokojnie wybrał PIL'a z tych powodów, że użytkownicy często wrzucają zdjęcia, które trochę ważą a tutaj widzę PIL znacznie szybciej działa niż IM:)
Aj... coś źle doczytałeś...
Aj... coś źle doczytałeś... PIL szybszy był jedynie przy miniaturkach 750*568
To chyba nie tak
Hej,
trafiłem przez przypadek, i to jakby ten tego... to chyba nie o to chodzi :-)
Lepsza jest ta implementacja, która jest czytelniejsza, bardziej wspierana, bardziej portowalna, nie wymaga cudów, żeby uruchomić ją na innej platformie i da się automatycznie przetestować testami jednostkowymi.
Benczmarkowanie procedur do własnej galerii jest bez sensu. Nawet, jeżeli system spędzi minutę nad jednym obrazkiem -- to co z tego?
Benczmarkowanie procedur do napędzania flickr czy flaker czy galerii Naszej-Klasy jest... również bez sensu :-) Sens przy takim ruchu ma jedynie napisanie czegoś, co pozwoli w łatwy sposób dzielić pracę - czyli skalować na więcej, niż jednej maszynie. To w Pythonie całkiem przyjemnie się robi (vide: Twisted Python + Perspective Broker).
To, czy ImageMagick skaluje kilka sekund krócej, jest bez znaczenia. W tym zastosowaniu. Jedna i druga implementacja da w miarę zbliżony czas dla w miarę zbliżonych obrazów. Jaja mogą wychodzić dopiero przy bardzo dużych rozmiarach/rozdzielczościach.
Jak chcesz megaszybkiego skalowania do wyświetlenia, to obejrz pygleta, tam jest wsparcie dla OpenGL :-)
Pozdrawiam serdecznie,
m
Dzięki za rozbudowaną
Dzięki za rozbudowaną odpowiedź. Zgadzam się z Tobą całkowicie - dobre jest to rozwiązanie, które jest dla mnie wygodne ;) Od dawna hołduje tej zasadzie - liczy się wygoda, parcie na wydajność jest bez sensu, bo optymalizując tracimy więcej czasu niż na owej optymalizacji zyskujemy, stąd wszelkie benchmarki należy traktować w kategorii ciekawostek i z takim też zamiarem powyższy artykulik był pisany.
A próbowałeś może Ruby?:)
A próbowałeś może Ruby?:)
Nie próbowałem, ale to raczej
Nie próbowałem, ale to raczej nie ma znaczenia, bo to chodzi o konkretne biblioteki, anie język jako taki.
Zapytałem z czystej
Zapytałem z czystej ciekawości, bo mam teraz dylemat czy iść w kierunku Pythona czy Ruby:)
Wszystko jedno ;) Mi
Wszystko jedno ;)
Mi bardziej podoba się składnia pythona, poza tym python ma znacznie większą liczbę bibliotek - zwłaszcza do zastosowań nie-www.
Dodaj nową odpowiedź