Skompilowałem mozaikę 2025 strzałów w głowę z awatarów najlepszych użytkowników Stack Overflow .
(Kliknij obraz, aby wyświetlić go w pełnym rozmiarze).
Twoim zadaniem jest napisanie algorytmu, który utworzy dokładną fotomozaikę innego obrazu przy użyciu awatarów 48 × 48 pikseli z tej siatki 45 × 45.
Testuj obrazy
Oto zdjęcia testowe. Pierwszą jest oczywiście żarówka!
(Nie są tutaj pełnowymiarowe. Kliknij zdjęcie, aby wyświetlić je w pełnym rozmiarze. Połowy wielkości są dostępne dla Pocałunku , Niedzielnego popołudnia ... , Steve'a Jobsa i sfer .)
Dzięki Wikipedii za wszystkie sfery oprócz raytraced.
W pełnym rozmiarze wszystkie te obrazy mają wymiary podzielne przez 48. Większe musiały być plikami JPEG, aby można je było wystarczająco skompresować, aby je załadować.
Punktacja
To konkurs popularności. Zgłoszenie z mozaikami, które najdokładniej przedstawiają oryginalne obrazy, powinno zostać poddane pod głosowanie. Przyjmę najwyższą głosowaną odpowiedź za tydzień lub dwa.
Zasady
Twoja fotomozaika musi w całości składać się z niezmienionych awatarów 48 × 48 pikseli wziętych z powyższej mozaiki, ułożonych w siatkę.
Możesz ponownie użyć awatara w mozaice. (Rzeczywiście, w przypadku większych zdjęć testowych będziesz musiał.)
Pokaż swoje wyniki, ale pamiętaj, że obrazy testowe są bardzo duże, a StackExchange pozwala tylko na publikowanie obrazów do 2 MB . Więc skompresuj swoje zdjęcia lub umieść je gdzie indziej i umieść tutaj mniejsze wersje.
Aby zostać zwycięzcą, musisz dostarczyć wersje PNG mozaiki żarówki lub kulek. Dzięki temu mogę je zweryfikować (patrz poniżej), aby upewnić się, że nie dodajesz dodatkowych kolorów do awatarów, aby mozaiki wyglądały lepiej.
Walidator
Tego skryptu w Pythonie można użyć do sprawdzenia, czy ukończona mozaika rzeczywiście używa niezmienionych awatarów. Po prostu ustaw toValidate
i allTiles
. Jest mało prawdopodobne, aby działał w przypadku plików JPEG lub innych formatów stratnych, ponieważ porównuje dokładnie rzeczy, piksel po pikselu.
from PIL import Image, ImageChops
toValidate = 'test.png' #test.png is the mosaic to validate
allTiles = 'avatars.png' #avatars.png is the grid of 2025 48x48 avatars
def equal(img1, img2):
return ImageChops.difference(img1, img2).getbbox() is None
def getTiles(mosaic, (w, h)):
tiles = {}
for i in range(mosaic.size[0] / w):
for j in range(mosaic.size[1] / h):
x, y = i * w, j * h
tiles[(i, j)] = mosaic.crop((x, y, x + w, y + h))
return tiles
def validateMosaic(mosaic, allTiles, tileSize):
w, h = tileSize
if mosaic.size[0] % w != 0 or mosaic.size[1] % h != 0:
print 'Tiles do not fit mosaic.'
elif allTiles.size[0] % w != 0 or allTiles.size[1] % h != 0:
print 'Tiles do not fit allTiles.'
else:
pool = getTiles(allTiles, tileSize)
tiles = getTiles(mosaic, tileSize)
matches = lambda tile: equal(tiles[pos], tile)
success = True
for pos in tiles:
if not any(map(matches, pool.values())):
print 'Tile in row %s, column %s was not found in allTiles.' % (pos[1] + 1, pos[0] + 1)
success = False
if success:
print 'Mosaic is valid.'
return
print 'MOSAIC IS INVALID!'
validateMosaic(Image.open(toValidate).convert('RGB'), Image.open(allTiles).convert('RGB'), (48, 48))
Powodzenia wszystkim! Nie mogę się doczekać, aby zobaczyć wyniki.
Uwaga: wiem, że algorytmy fotomozaiczne są łatwe do znalezienia w Internecie, ale jeszcze ich nie ma na tej stronie. Naprawdę mam nadzieję, że zobaczymy coś bardziej interesującego niż zwykły algorytm „uśredniania każdego kafelka i każdego pola siatki i dopasowywania ich” .
źródło
Odpowiedzi:
Java, średni dystans
Algorytm przeszukuje wszystkie kafelki awatara dla każdego pola siatki osobno. Ze względu na małe rozmiary nie wdrożyłem żadnych skomplikowanych struktur danych ani algorytmów wyszukiwania, ale po prostu brutalnie wykorzystałem całą przestrzeń.
Ten kod nie wprowadza żadnych modyfikacji kafelków (np. Nie dostosowuje kolorów docelowych).
Wyniki
Kliknij, aby wyświetlić obraz w pełnym rozmiarze.
Wpływ promienia
Używając
radius
możesz zmniejszyć powtarzalność płytek w wyniku. Ustawienieradius=0
nie ma wpływu. Np.radius=3
Tłumi tę samą płytkę w promieniu 3 płytek.promień = 0
promień = 3
Wpływ współczynnika skalowania
Za pomocą tego
scaling
współczynnika możemy ustalić, w jaki sposób zostanie wyszukany pasujący kafelek.scaling=1
oznacza wyszukiwanie dopasowania w pikselach podczasscaling=48
wyszukiwania średniego kafelka.skalowanie = 48
skalowanie = 16
skalowanie = 4
skalowanie = 1
źródło
Matematyka, z kontrolą szczegółowości
W razie potrzeby wykorzystuje zdjęcia 48 x 48 pikseli. Domyślnie zamienia te piksele na odpowiadający im kwadrat 48 x 48 pikseli z obrazu, który ma zostać przybliżony.
Jednak rozmiar kwadratów docelowych można ustawić na mniejszy niż 48 x 48, co pozwala na większą wierność detali. (patrz przykłady poniżej).
Wstępne przetwarzanie palety
collage
to obraz zawierający zdjęcia, które mają służyć jako paleta.picsColors
to lista pojedynczych zdjęć w połączeniu z ich średnią wartością czerwoną, średnią zieloną i średnią niebieską.Przykład
Znajdźmy zdjęcie, które najlepiej pasuje do RGBColor [0.640, 0.134, 0.249]:
photoMosaic
`photoMosaic przyjmuje jako surowe zdjęcie, z którego zrobimy mozaikę fotograficzną.
targetPic
usunie czwarty parametr (PNG i niektórych JPG), pozostawiając tylko R, G, B.dims
są wymiarytargetPic
.tiles
to małe kwadraty, które razem składają się na obraz docelowy.targetSwathSize is the granularity parameter; it defaults at 48 (x48).
tileReplacements
są zdjęcia pasujące do każdego kafelka w odpowiedniej kolejności.gallery
to zestaw zamienników kafelków (zdjęć) o odpowiedniej wymiarowości (tj. liczbie wierszy i kolumn pasujących do kafelków).ImageAssembly
łączy mozaikę w ciągły obraz wyjściowy.Przykłady
To zastępuje każdy kwadrat 12 x 12 z obrazu, w niedzielę, odpowiadającym mu zdjęciem 48 x 48 pikseli, który najlepiej pasuje do przeciętnego koloru.
Niedziela (szczegóły)
Szczegóły, stevejobs.
Szczegół pocałunku:
źródło
JS
Tak jak w poprzednim golfie: http://jsfiddle.net/eithe/J7jEk/ : D
(tym razem nazywane za pomocą
unique: false, {pixel_2: {width: 48, height: 48}, pixel_1: {width: 48, height: 48}}
) (nie traktuj palety, aby użyć jednego piksela raz, piksele palety to próbki 48 x 48, piksele kształtu to próbki 48 x 48).Obecnie przeszukuje listę awatarów, aby znaleźć najbliższe dopasowanie według wagi wybranego algorytmu, jednak nie wykonuje żadnego dopasowania jednorodności kolorów (coś, na co muszę spojrzeć.
Niestety nie jestem w stanie bawić się większymi obrazami, ponieważ kończy się pamięć RAM: D Jeśli to możliwe, doceniłbym mniejsze obrazy wyjściowe. Jeśli używasz 1/2 rozmiaru obrazu, oto niedzielne popołudnie:
źródło
GLSL
Różnica między tym wyzwaniem a wyzwaniem w American Gothic w palecie Mona Lisa: Zmień rozmieszczenie pikseli , ponieważ mozaiki można ponownie użyć, a pikseli nie. Oznacza to, że można łatwo zrównoleglić algorytm, więc postanowiłem spróbować wersji masowo równoległej. Pod pojęciem „masowo” mam na myśli jednoczesne używanie rdzeni cieniujących 1344 na GTX670 mojego komputera stacjonarnego za pośrednictwem GLSL.
metoda
Rzeczywiste dopasowanie kafelków jest proste: obliczam odległość RGB między każdym pikselem w obszarze docelowym a obszarem mozaiki i wybieram kafelek o najniższej różnicy (ważony wartościami jasności). Indeks kafelków jest zapisywany w atrybutach koloru czerwonego i zielonego fragmentu, a następnie po wyrenderowaniu wszystkich fragmentów czytam wartości z bufora ramki i buduję obraz wyjściowy z tych indeksów. Rzeczywista implementacja jest dość hack; zamiast tworzenia FBO właśnie otworzyłem okno i renderowałem je, ale GLFW nie może otwierać okien w dowolnie małych rozdzielczościach, więc tworzę okno większe niż jest to wymagane, a następnie narysuję mały prostokąt o odpowiednim rozmiarze, aby miał jeden fragment na kafelek, który jest odwzorowany na obraz źródłowy. Całe rozwiązanie MSVC2013 jest dostępne pod adresemhttps://bitbucket.org/Gibgezr/mosaicmaker Wymaga GLFW / FreeImage / GLEW / GLM do kompilacji oraz OpenGL 3.3 lub lepszych sterowników / karty graficznej do uruchomienia.
Źródło Shader Fragment
Wyniki
Obrazy renderują się niemal natychmiast, więc równoległość zakończyła się sukcesem. Minusem jest to, że nie mogę sprawić, aby poszczególne fragmenty opierały się na wynikach innych fragmentów, więc nie ma sposobu, aby uzyskać znaczny wzrost jakości, jaki można uzyskać, nie wybierając tej samej płytki dwukrotnie w określonym zakresie. Szybkie wyniki, ale ograniczona jakość z powodu ogromnej liczby powtórzeń płytek. W sumie było fajnie. http://imgur.com/a/M0Db0 dla wersji pełnowymiarowych.
źródło
Pyton
Oto pierwsze rozwiązanie w języku Python, oparte na podejściu. Możemy ewoluować stąd. Reszta zdjęć jest tutaj .
źródło
Jeszcze inne rozwiązanie w języku Python - oparte na średniej (RGB vs L a b *)
Wyniki (istnieją pewne nieznaczne różnice)
Żarówka - RGB
Pełny widok
Żarówka - Lab
Pełny widok
Steve - RGB
Pełny widok
Steve - Lab
Pełny widok
Kule - RGB
Pełny widok
Kule - Lab
Pełny widok
Niedziela - RGB
Pełny widok
Niedziela - Lab
Pełny widok
Pocałunek - RGB
Pełny widok
Kiss - Lab
Pełny widok
Kod
wymaga Python-colormath dla Lab
źródło