Ich habe ein Mosaik von 2025 Headshots aus den Avataren der Top-Stack Overflow-Benutzer zusammengestellt .
(Klicken Sie auf das Bild, um es in voller Größe anzuzeigen.)
Ihre Aufgabe ist es, einen Algorithmus zu schreiben, der aus den 48 × 48 Pixel-Avataren dieses 45 × 45-Rasters ein genaues Fotomosaik eines anderen Bildes erstellt.
Bilder testen
Hier sind die Testbilder. Das erste ist natürlich eine Glühbirne!
(Sie sind hier nicht in voller Größe. Klicken Sie auf ein Bild, um es in voller Größe anzuzeigen. Für The Kiss , A Sunday Afternoon ... , Steve Jobs und die Sphären sind Versionen in halber Größe verfügbar .)
Vielen Dank an Wikipedia für alle außer den Raytracing-Sphären.
In voller Größe haben diese Bilder alle Abmessungen, die durch 48 teilbar sind. Die größeren Bilder mussten JPEGs sein, damit sie zum Hochladen komprimiert werden konnten.
Wertung
Dies ist ein Beliebtheitswettbewerb. Die Einreichung mit Mosaiken, die die Originalbilder am genauesten wiedergeben, sollte positiv bewertet werden. Ich werde die Antwort mit den meisten Stimmen in ein oder zwei Wochen annehmen.
Regeln
Ihre Fotomosaiken müssen vollständig aus unveränderten 48 × 48-Pixel-Avataren bestehen, die aus dem obigen Mosaik stammen und in einem Raster angeordnet sind.
Sie können einen Avatar in einem Mosaik wiederverwenden. (In der Tat müssen Sie für die größeren Testbilder.)
Zeigen Sie Ihre Ausgabe, aber denken Sie daran, dass die Testbilder sehr groß sind und StackExchange nur das Posten von Bildern mit bis zu 2 MB zulässt . Komprimieren Sie also Ihre Bilder oder hosten Sie sie woanders und fügen Sie hier kleinere Versionen ein.
Um als Gewinner bestätigt zu werden, müssen Sie PNG-Versionen Ihrer Glühbirnen- oder Kugelmosaike bereitstellen. Auf diese Weise kann ich sie überprüfen (siehe unten), um sicherzustellen, dass Sie den Avataren keine zusätzlichen Farben hinzufügen, damit die Mosaike besser aussehen.
Validator
Mit diesem Python-Skript können Sie überprüfen, ob ein fertiges Mosaik wirklich unveränderte Avatare verwendet. Einfach einstellen toValidate
und allTiles
. Es ist unwahrscheinlich, dass es für JPEGs oder andere verlustbehaftete Formate funktioniert, da es die Dinge Pixel für Pixel genau vergleicht.
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))
Viel Glück euch allen! Ich kann es kaum erwarten, die Ergebnisse zu sehen.
Hinweis: Ich weiß, dass Fotomosaik-Algorithmen online leicht zu finden sind, aber noch nicht auf dieser Website. Ich hoffe wirklich, dass wir etwas interessanteres sehen als den üblichen Algorithmus "Durchschnitt für jede Kachel und jeden Rasterplatz und Abgleich" .
quelle
Antworten:
Java, durchschnittliche Entfernung
Der Algorithmus durchsucht alle Avatar-Kacheln für jeden Rasterplatz separat. Aufgrund der geringen Größe habe ich keine ausgeklügelten Datenstrukturen oder Suchalgorithmen implementiert, sondern einfach den gesamten Raum brachialisiert.
Dieser Code nimmt keine Änderungen an den Kacheln vor (z. B. keine Anpassung an die Zielfarben).
Ergebnisse
Klicken Sie hier für ein größeres Bild.
Auswirkung des Radius
Mit können
radius
Sie die Wiederholbarkeit der Kacheln im Ergebnis reduzieren. Die Einstellungradius=0
hat keine Auswirkung. ZBradius=3
unterdrückt das gleiche Plättchen in einem Radius von 3 Plättchen.Radius = 0
Radius = 3
Auswirkung des Skalierungsfaktors
Anhand des
scaling
Faktors können wir bestimmen, wie die passende Kachel gesucht wird.scaling=1
bedeutet, nach einer pixelgenauen Übereinstimmung zu suchen, während eine Suche nachscaling=48
durchschnittlichen Kacheln durchgeführt wird.Skalierung = 48
Skalierung = 16
Skalierung = 4
Skalierung = 1
quelle
Mathematica mit Kontrolle der Granularität
Hierbei werden nach Bedarf die Fotos mit 48 x 48 Pixeln verwendet. Standardmäßig werden diese Pixel gegen ein entsprechendes 48 x 48 Pixel großes Quadrat aus dem zu approximierenden Bild ausgetauscht.
Die Größe der Zielquadrate kann jedoch kleiner als 48 x 48 eingestellt werden, um eine höhere Detailtreue zu ermöglichen. (siehe die Beispiele unten).
Vorverarbeitung der Palette
collage
ist das Bild, das die Fotos enthält, die als Palette dienen sollen.picsColors
ist eine Liste der einzelnen Fotos, gepaart mit ihren Durchschnittswerten für Rot, Grün und Blau.Beispiel
Lassen Sie uns das Foto finden, das am besten zu RGBColor [0.640, 0.134, 0.249] passt:
Fotomosaik
`photoMosaic verwendet als Eingabe das Rohbild, aus dem wir ein Fotomosaik erstellen.
targetPic
entfernt einen vierten Parameter (von PNGs und einigen JPGs) und lässt nur R, G, B.dims
sind die Dimensionen vontargetPic
.tiles
sind die kleinen Quadrate, die zusammen das Zielbild bilden.targetSwathSize is the granularity parameter; it defaults at 48 (x48).
tileReplacements
sind die Fotos, die zu jeder Kachel passen, in der richtigen Reihenfolge.gallery
ist die Menge der Kachelersetzungen (Fotos) mit der richtigen Dimension (dh der Anzahl der Zeilen und Spalten, die mit den Kacheln übereinstimmen).ImageAssembly
Verbindet das Mosaik zu einem fortlaufenden Ausgabebild.Beispiele
Dies ersetzt jedes 12 x 12 Quadrat aus dem Bild am Sonntag durch ein entsprechendes 48 x 48 Pixel großes Foto, das für die durchschnittliche Farbe am besten geeignet ist.
Sonntag (Detail)
Detail, Stevejobs.
Detail des Kusses:
quelle
JS
Gleich wie beim vorherigen Golf: http://jsfiddle.net/eithe/J7jEk/ : D
(Diesmal mit aufgerufen
unique: false, {pixel_2: {width: 48, height: 48}, pixel_1: {width: 48, height: 48}}
) (Behandeln Sie die Palette nicht so, dass nur ein Pixel verwendet wird. Palettenpixel sind 48x48-Farbfelder, Formpixel sind 48x48-Farbfelder.)Derzeit durchsucht es die Avatare-Liste, um die nächstgelegene Übereinstimmung nach Gewicht des ausgewählten Algorithmus zu finden, führt jedoch keine Farbgleichmäßigkeitsanpassung durch (etwas, das ich mir ansehen muss).
Leider kann ich nicht mit größeren Bildern herumspielen, da mir der Arbeitsspeicher ausgeht: D Wenn möglich, würde ich kleinere Ausgabebilder begrüßen. Wenn Sie die Hälfte der angegebenen Bildgröße verwenden, ist hier der Sonntagnachmittag:
quelle
GLSL
Der Unterschied zwischen dieser Herausforderung und der bei American Gothic in der Palette von Mona Lisa: Die Pixel neu anordnen interessiert mich, weil die Mosaikfliesen wiederverwendet werden können, während die Pixel nicht können. Das bedeutet, dass es leicht möglich ist, den Algorithmus zu parallelisieren. Ich habe mich daher für eine massiv parallele Version entschieden. Mit "massiv" meine ich, die 1344-Shader-Kerne auf der GTX670 meines Desktops gleichzeitig über GLSL zu verwenden.
Methode
Die tatsächliche Kachelanpassung ist einfach: Ich berechne den RGB-Abstand zwischen jedem Pixel in einem Zielbereich und dem Mosaikkachelbereich und wähle die Kachel mit der geringsten Differenz (gewichtet mit Helligkeitswerten). Der Kachelindex wird in den roten und grünen Farbattributen des Fragments ausgegeben. Nachdem alle Fragmente gerendert wurden, lese ich die Werte aus dem Framebuffer zurück und erstelle das Ausgabebild aus diesen Indizes. Die tatsächliche Implementierung ist ein ziemlicher Hack. Anstatt ein FBO zu erstellen, habe ich nur ein Fenster geöffnet und darin gerendert, aber GLFW kann keine Fenster mit willkürlich kleinen Auflösungen öffnen. Daher erstelle ich das Fenster größer als erforderlich und zeichne dann ein kleines Rechteck, das die richtige Größe hat Ein Fragment pro Kachel, das dem Quellbild zugeordnet ist. Die gesamte MSVC2013-Lösung ist unter verfügbarhttps://bitbucket.org/Gibgezr/mosaicmaker Zum Kompilieren sind GLFW / FreeImage / GLEW / GLM und OpenGL 3.3 oder bessere Treiber / Grafikkarten erforderlich.
Fragment Shader Source
Ergebnisse
Die Bilder werden fast sofort gerendert, sodass die Parallelisierung ein Erfolg war. Der Nachteil ist, dass ich die einzelnen Fragmente nicht von der Ausgabe anderer Fragmente abhängig machen kann. Daher gibt es keine Möglichkeit, die signifikante Qualitätssteigerung zu erzielen, die Sie erzielen, wenn Sie nicht zweimal innerhalb eines bestimmten Bereichs dasselbe Plättchen auswählen. Schnelle Ergebnisse, aber eingeschränkte Qualität aufgrund massiver Fliesenwiederholungen. Alles in allem hat es Spaß gemacht. http://imgur.com/a/M0Db0 für Vollversionen.
quelle
Python
Hier geht es um die erste Python-Lösung, die einen mittleren Ansatz verwendet. Wir können uns von hier aus weiterentwickeln. Der Rest der Bilder ist hier .
quelle
Noch eine andere Python-Lösung - auf Durchschnittsbasis (RGB vs L a b *)
Ergebnisse (Es gibt einige geringfügige Unterschiede)
Birne - RGB
Vollansicht
Bulb - Lab
Vollansicht
Steve - RGB
Vollansicht
Steve - Lab
Vollansicht
Kugeln - RGB
Vollansicht
Kugeln - Lab
Vollansicht
Sonntag - RGB
Vollansicht
Sonntag - Labor
Vollansicht
Kuss - RGB
Vollansicht
Kiss-Lab
Vollansicht
Code
benötigt python-colormath für Lab
quelle