Kwadratowe miniatury - python PIL i ImageMagick - wydajność

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

#!/usr/bin/env python
# -*- 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

#!/usr/bin/env python
# -*- 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:

Portret użytkownika Gość

"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ę?

Portret użytkownika grizz

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

Portret użytkownika Gość

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.

Portret użytkownika Gość

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

Portret użytkownika grizz

Aj... coś źle doczytałeś...

Aj... coś źle doczytałeś... PIL szybszy był jedynie przy miniaturkach 750*568

Portret użytkownika Gość

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

Portret użytkownika grizz

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.

Portret użytkownika Gość

A próbowałeś może Ruby?:)

A próbowałeś może Ruby?:)

Portret użytkownika grizz

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.

Portret użytkownika Gość

Zapytałem z czystej

Zapytałem z czystej ciekawości, bo mam teraz dylemat czy iść w kierunku Pythona czy Ruby:)

Portret użytkownika grizz

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ź

Zawartość pola nie będzie udostępniana publicznie. Jeżeli posiadasz konto na serwisie Gravatar, zostanie wyświetlony awatar powiązany z tym e-mailem.
Subskrybuje zawartość