Aplikacja do tworzenia obrazkowych mozaik

9

Czysto z nudów i ciekawości napisałem aplikację, która komponuje obrazek z... innych obrazków.

Może najlepiej będzie to widać na przykładzie:
Wejście:
cat.jpg
Wyjście:
cat_rendered.jpg
Aby to uzyskać, potrzebowałem rzecz jasna listy plików będących tymi mniejszymi obrazkami - do tego celu wykorzystałem mój katalog z memami, który zbieram od roku (~100MB, nieco ponad tysiąc różnych obrazków), sprawił się prawie idealnie :D

Aplikacja jest napisana przede wszystkim z nudy, lecz posiada kilka imho 'ciekawych' cech:

  • wielowątkowe wczytywanie obrazków (domyślnie na czterech wątkach, jako że mam czterordzeniowy Core i3)
  • pamięć podręczna; wczytane obrazki są pomniejszane (domyślnie do rozmiaru 10x10) i zapisywane do katalogu cache na późniejszy użytek (podczas następnego uruchomienia), dla mojego tysiąca obrazów daje to zaledwie 430 KB zajętego miejsca, a wczytywanie jest ośmiokrotnie krótsze
  • możliwość dostosowania wymiaru obrazków, liczby wątków czy cache z linii komend

Zasada działania jest, w drobnym uproszczeniu, następująca:

  1. małe obrazki zostają wielowątkowo wczytane z katalogu imgs i na bieżąco pomniejszane do wymiarów 10x10
  2. liczona jest średnia barwa każdego z nich (R, G, B każdego piksela zostaje dodane i podzielone przez ich liczbę), kolor ten zostaje potem zamieniony na przestrzeń barw Lab i zapamiętany
  3. wczytywany jest główny obrazek, na podstawie którego stworzona zostanie mozaika
  4. brany jest pierwszy/następny fragment tego obrazka po 10x10 pikseli, liczona jest jego średnia i znów zamieniana na Lab
  5. porównywane są kolory Lab aktualnie sprawdzanego sektora i każdego z obrazków; wybierany jest ten, który daje najmniejszą różnicę
  6. powrót do kroku czwartego, aż do końca

Skomplikowane to niby nie jest, ale ~15h pisania było - choć to pewnie kwestia tego, że to moje pierwsze podejście do robienia czegoś z grafiką :D

W załączniku znajduje się apka wraz z moim katalogiem cache (czyli gotowa do użycia - Windows x86), kod źródłowy (Lazarus, niecały tysiąc linii) i plik Readme, także tutaj więcej nie mam zbytnio co opisywać ;)

Zachęcam do zabawy i oceny ;)

1

Super motyw! Myślałeś może o doczepieniu do tego możliwości rozszerzenia obrazka jak np w reklamach kiedyś? tzn plik do zrenderowania ma np. 1920x1080, renderujesz go Twoją techniką, ale składasz go z obrazków o różnym stopniu pomniejszenia. Hmm... Ok głupio brzmi poprzednie zdanie, ale chodzi o mniej więcej to że z obrazka 1920x1080 robisz Twoją techniką z użyciem odpowiednio wiekszych obrazków kolejne wielkości poczynając od 1920x1080 do 192000x108000 (ale to by musiało być renderowane fragmentami chyba) a skoro z memów to pewnie maks do osiągnięcia byłby 19200x10800 ;)

1

Aktualnie można to osiągnąć najłatwiej w drugą stronę: od największego do coraz mniejszych, dzięki temu efektywniej byłoby wykorzystywane cache (nie trzeba by tworzyć za każdym razem całego od nowa), można by się pokusić o napisanie batcha wykonującego to.
Niemniej jednak, to stosunkowo proste zadanie - pomyślę, jak dodam renderowanie wielowątkowe (czyli gdy znowu będę miał wolną chwilę) ;)

1

Okej, na pokładzie wersja 0.2.

Changelog:

  • zmniejszony czas ładowania danych z pamięci podręcznej. 1091 obrazków poniżej sekundy. Stworzenie cache zajęło niecałe dwadzieścia dwie.
  • wielordzeniowe renderowanie. To dało około trzykrotne przyśpieszenie.
  • zmieniona nazwa opcji; z -workers na -threads.
  • dodana przełączka -reuse (do poczytania w Readme).
  • rozmiar wyjściowego obrazka (mozaiki) jest od teraz dopasowywany do rozmiarów małych obrazków częściowych.

Oczywiście wrzucam także obrazki:
cat_hq_rendered.jpg
2560x1600 - czas renderowania: ~1600ms.

img_rendered.jpg
A to jest pokój, w którym mieszkam na wakacje (zdjęcie machnięte miesiąc temu; 3264x2448, 4.3s renderowania, ponieważ musiałem przełączyć na jeden rdzeń (teraz dopiero zauważyłem, że z jakiegoś powodu to zdjęcie crashuje mi program na >1); aktualnie mam nieco inne ustawienie i odłożyłem drugi monitor na bok).
Całkiem nieźle, imho :D

W następnej wersji zajmę się tym, o czym wspomniał @Johnny_Bit ;)

0

Dobre! Muszę coś takiego też napisać w ramach ćwiczeń, ale to jak skończe obecnie otwarte projekty ;)

0

Pomysł na nudę fajny, ale zabawię się w hejtera.
Cały cymes w budowaniu takiego coulage jest taki, by było widać co jest na małych obrazkach inaczej nie ma to sensu.
Małe obrazki rozdzielczości 10x10 nie dają przydanego efektu.
Rozumiem, że użycie większych obrazków wymagałoby po prostu użycia znacznie bardziej skomplikowanego algorytmu.

0
MarekR22 napisał(a)

Rozumiem, że użycie większych obrazków wymagałoby po prostu użycia znacznie bardziej skomplikowanego algorytmu.

Poniekąd tak - do głowy przychodzi mi taki pomysł, aby liczyć średni kolor pojedynczych obszarów pod-obrazków (np.mając mem o wymiarach 100x100 pikseli, liczymy średnią bloków ((0,0), (50,50)), ((50,0), (100,50)) (...) i potem wykorzystujemy te dane przy szukaniu odpowiedniego pod-obrazka). Ale to jest już byłoby trochę bardziej czasochłonne i prawdę mówiąc nie zagłębiałem się jeszcze dokładniej w to.


Aktualnie dorabiam do programu GUI i naprawiam błędy związane z wielowątkowością przy renderowaniu większych obrazów, potem renderowanie animacji i w sumie to będzie chyba koniec życia tego małego eksperymentu. Chyba że będzie mi się chciało implementować to bardziej zaawansowane szukanie; Ale w zamian mam już pomysł na następny programik-gierkę, który jest nawet ciekawszy od tego - lecz, aby nie zepsuć zabawy, nie powiem nic poza to, że będzie korzystać z OpenCL ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1