J'ai compilé une mosaïque de 2025 tirs à la tête à partir des avatars des principaux utilisateurs de Stack Overflow .
(Cliquez sur l'image pour la voir en taille réelle.)
Votre tâche consiste à écrire un algorithme permettant de créer une photomosaïque précise d'une autre image à l'aide des avatars de 48 × 48 pixels de cette grille de 45 × 45.
Images d'essai
Voici les images de test. Le premier est, bien sûr, une ampoule!
(Ils ne sont pas en taille réelle ici. Cliquez sur une image pour la voir en taille réelle. Des versions en taille réduite sont disponibles pour The Kiss , Un dimanche après-midi ... , Steve Jobs et les sphères .)
Merci à Wikipedia pour toutes les sphères sauf les rayons.
A leur taille maximale, ces images ont toutes des dimensions divisibles par 48. Les plus grandes doivent être des images JPEG pour pouvoir être suffisamment comprimées pour être téléchargées.
Notation
C'est un concours de popularité. La soumission avec des mosaïques qui représentent le plus fidèlement les images originales doit être votée. J'accepterai la réponse la plus votée dans une semaine ou deux.
Règles
Vos mosaïques photographiques doivent être entièrement composées d' avatars inaltérés de 48 × 48 pixels extraits de la mosaïque ci-dessus, disposés en grille.
Vous pouvez réutiliser un avatar dans une mosaïque. (En effet, pour les images de test plus grandes, vous devrez le faire.)
Montrez votre sortie, mais gardez à l' esprit que les images de test sont très grandes, et StackExchange permet uniquement l' affichage d'images à 2MB . Alors, compressez vos images ou hébergez-les ailleurs et mettez des versions plus petites ici.
Pour être confirmé gagnant, vous devez fournir les versions PNG de votre mosaïque à ampoule ou sphères. C’est pour que je puisse les valider (voir ci-dessous) afin de vous assurer que vous n’ajoutez pas de couleurs supplémentaires aux avatars pour améliorer l’apparence des mosaïques.
Validateur
Ce script Python peut être utilisé pour vérifier si une mosaïque terminée utilise réellement des avatars non modifiés. Il suffit de mettre toValidate
et allTiles
. Il est peu probable que cela fonctionne avec les formats JPEG ou autres formats avec pertes, car il compare exactement les choses, pixel par pixel.
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))
Bonne chance à tous! J'ai hâte de voir les résultats.
Note: Je sais que les algorithmes de photomosaïque sont faciles à trouver en ligne, mais ils ne sont pas encore sur ce site. J'espère vraiment que nous verrons quelque chose de plus intéressant que l' algorithme habituel "moyenne de chaque tuile et de chaque espace de grille et les faire correspondre" .
la source
Réponses:
Java, distance moyenne
L'algorithme effectue une recherche dans toutes les tuiles d'avatar pour chaque espace de grille séparément. En raison des petites tailles, je n’ai mis en œuvre aucune structure de données sophistiquée ni aucun algorithme de recherche, mais tout simplement une force brute dans tout l’espace.
Ce code ne modifie pas les mosaïques (par exemple, aucune adaptation aux couleurs de destination).
Résultats
Cliquez pour l'image en taille réelle.
Effet du rayon
En utilisant
radius
vous pouvez réduire la répétitivité des carreaux dans le résultat. Définirradius=0
il n'y a pas d'effet. Par exemple,radius=3
supprime le même carreau dans un rayon de 3 carreaux.rayon = 0
rayon = 3
Effet du facteur d'échelle
En utilisant le
scaling
facteur, nous pouvons déterminer comment la mosaïque correspondante est recherchée.scaling=1
signifie rechercher une correspondance parfaite au pixel tout enscaling=48
effectuant une recherche moyenne.mise à l'échelle = 48
mise à l'échelle = 16
mise à l'échelle = 4
mise à l'échelle = 1
la source
Mathematica, avec contrôle de la granularité
Cela utilise les photos 48 x 48 pixels, selon les besoins. Par défaut, ces pixels seront échangés contre un carré correspondant de 48 x 48 pixels de l'image à approximer.
Toutefois, la taille des carrés de destination peut être définie sur une taille inférieure à 48 x 48, ce qui permet une plus grande fidélité des détails. (voir les exemples ci-dessous).
Prétraitement de la palette
collage
est l'image contenant les photos pour servir de palette.picsColors
est une liste de photos individuelles associées à leurs valeurs moyennes rouge, vert moyen et bleu moyen.Exemple
Trouvons la photo qui correspond le mieux à RGBColor [0.640, 0.134, 0.249]:
photoMosaic
`photoMosaic prend en entrée l'image brute dont nous allons faire une mosaïque.
targetPic
supprimera un quatrième paramètre (de PNG et de certains JPG), ne laissant que R, G, B.dims
sont les dimensions detargetPic
.tiles
sont les petits carrés qui composent l’image cible.targetSwathSize is the granularity parameter; it defaults at 48 (x48).
tileReplacements
sont les photos qui correspondent à chaque carreau, dans le bon ordre.gallery
est l'ensemble des remplacements de mosaïque (photos) avec la dimensionnalité appropriée (c'est-à-dire le nombre de lignes et de colonnes correspondant aux mosaïques).ImageAssembly
associe la mosaïque en une image de sortie continue.Exemples
Ceci remplace chaque carré 12x12 de l'image, dimanche, par une photo correspondante de 48 x 48 pixels qui lui correspond le mieux pour une couleur moyenne.
Dimanche (détail)
Détail, stevejobs.
Détail du baiser:
la source
JS
Comme dans le golf précédent: http://jsfiddle.net/eithe/J7jEk/ : D
(cette fois appelée avec
unique: false, {pixel_2: {width: 48, height: 48}, pixel_1: {width: 48, height: 48}}
) (ne traitez pas la palette pour utiliser un pixel une fois, les pixels de la palette sont 48x48 échantillons, les pixels de forme sont des échantillons 48x48).Actuellement, il cherche dans la liste des avatars la correspondance la plus proche en fonction du poids de l'algorithme sélectionné. Toutefois, il ne réalise aucune correspondance d'uniformité des couleurs (ce que je dois examiner.
Malheureusement, je ne suis pas capable de jouer avec des images plus grandes, car ma mémoire RAM est épuisée: D Si possible, j'apprécierais des images de sortie plus petites. Si vous utilisez la moitié de la taille de l'image fournie, le dimanche après-midi:
la source
GLSL
La différence entre ce défi et celui de American Gothic dans la palette de Mona Lisa: Réorganiser les pixels m'intéresse, car les mosaïques peuvent être réutilisées, alors que les pixels ne le peuvent pas. Cela signifie qu'il est possible de paralléliser facilement l'algorithme. J'ai donc décidé d'essayer une version massivement parallèle. Par "massivement", j'entends utiliser les 1344 noyaux de shader sur la GTX670 de mon ordinateur de bureau simultanément, via GLSL.
Méthode
La correspondance de mosaïque réelle est simple: je calcule la distance RVB entre chaque pixel d'une zone cible et la zone de mosaïque, puis je sélectionne la mosaïque présentant la différence la plus faible (pondérée par les valeurs de luminosité). L'index de mosaïque est écrit dans les attributs de couleur rouge et vert du fragment, puis après que tous les fragments aient été restitués, je relis les valeurs hors du framebuffer et construit l'image de sortie à partir de ces index. L'implémentation réelle est un sacré bidouillage; au lieu de créer un FBO, je viens d'ouvrir une fenêtre et de la rendre, mais GLFW ne peut pas ouvrir les fenêtres à des résolutions arbitrairement petites. Je crée donc la fenêtre plus grande que nécessaire, puis dessine un petit rectangle de la taille correcte. un fragment par mosaïque qui correspond à l'image source. L’ensemble de la solution MSVC2013 est disponible à l’adresse suivante:https://bitbucket.org/Gibgezr/mosaicmaker GLFW / FreeImage / GLEW / GLM est nécessaire pour la compilation, et OpenGL 3.3 ou une meilleure carte / carte vidéo pour fonctionner.
Fragment Shader Source
Résultats
Les images sont rendues presque instantanément, la parallélisation a donc été un succès. L'inconvénient est que je ne peux pas faire en sorte que les fragments individuels dépendent de la sortie d'autres fragments. Il est donc impossible d'obtenir une augmentation significative de la qualité en ne sélectionnant pas deux fois la même tuile dans une certaine plage. Donc, des résultats rapides, mais une qualité limitée en raison de répétitions massives de carreaux. Dans l'ensemble, c'était amusant. http://imgur.com/a/M0Db0 pour les versions grandeur nature.
la source
Python
Voici la première solution Python, utilisant une approche moyenne. Nous pouvons évoluer à partir d'ici. Le reste des images sont ici .
la source
Encore une autre solution Python - Moyenne (RVB vs L a b *)
Résultats (il y a quelques légères différences)
Ampoule - RGB
vue complète
Ampoule - Lab
vue complète
Steve - RVB
vue complète
Steve - Lab
vue complète
Sphères - RVB
vue complète
Sphères - Lab
vue complète
Dimanche - RVB
vue complète
Dimanche - Lab
vue complète
Kiss - RGB
vue complète
Kiss - Lab
vue complète
Code
nécessite python-colormath pour le laboratoire
la source