Compilei um mosaico de 2025 fotos na cabeça dos avatares dos principais usuários do Stack Overflow .
(Clique na imagem para vê-la em tamanho real.)
Sua tarefa é escrever um algoritmo que crie um fotomosaico preciso de outra imagem usando os avatares de 48 × 48 pixels dessa grade de 45 × 45 deles.
Imagens de teste
Aqui estão as imagens de teste. O primeiro é, obviamente, uma lâmpada!
(Eles não são em tamanho normal aqui. Clique em uma imagem para vê-la em tamanho normal. As versões em tamanho real estão disponíveis para The Kiss , A Sunday Afternoon ... , Steve Jobs e as esferas .)
Obrigado à Wikipedia por todas, exceto as esferas traçadas por raios.
Em tamanho real, essas imagens têm todas as dimensões divisíveis por 48. As maiores tinham que ser JPEGs para que pudessem ser compactadas o suficiente para serem carregadas.
Pontuação
Este é um concurso de popularidade. A submissão com mosaicos que descrevam com mais precisão as imagens originais deve ser votada. Aceitarei a resposta mais votada em uma semana ou duas.
Regras
Seu fotomosaico deve ser inteiramente composto por avatares inalterados de 48 × 48 pixels, retirados do mosaico acima, dispostos em uma grade.
Você pode reutilizar um avatar em um mosaico. (Na verdade, para as imagens de teste maiores, você precisará.)
Mostre sua saída, mas lembre-se de que as imagens de teste são muito grandes e o StackExchange permite apenas a publicação de imagens de até 2 MB . Comprima suas imagens ou hospede-as em outro lugar e coloque versões menores aqui.
Para ser confirmado o vencedor, você deve fornecer versões PNG dos mosaicos de lâmpadas ou esferas. Isso é para que eu possa validá-los (veja abaixo) para garantir que você não esteja adicionando cores extras aos avatares para melhorar a aparência dos mosaicos.
Validador
Esse script Python pode ser usado para verificar se um mosaico completo realmente usa avatares inalterados. Basta definir toValidate
e allTiles
. É improvável que funcione para JPEGs ou outros formatos com perdas, pois compara as coisas exatamente, pixel por 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))
Boa sorte a todos! Mal posso esperar para ver os resultados.
Nota: Eu sei que é fácil encontrar algoritmos fotomosaicos on-line, mas ainda não estão neste site. Eu realmente espero que vejamos algo mais interessante do que o algoritmo usual "média de cada bloco e cada espaço da grade e combiná-los" .
fonte
Respostas:
Java, distância média
O algoritmo realiza uma pesquisa em todos os blocos de avatar para cada espaço da grade separadamente. Devido aos pequenos tamanhos, não implementei nenhuma estrutura sofisticada de dados ou algoritmos de pesquisa, mas simplesmente forço brutal de todo o espaço.
Este código não faz nenhuma modificação nos ladrilhos (por exemplo, nenhuma adaptação às cores de destino).
Resultados
Clique para ampliar a imagem.
Efeito do raio
Usando
radius
você pode reduzir a repetitividade dos blocos no resultado. Definirradius=0
não há efeito. Por exemplo,radius=3
suprime o mesmo bloco em um raio de 3 blocos.raio = 0
raio = 3
Efeito do fator de escala
Usando o
scaling
fator, podemos determinar como o bloco correspondente é pesquisado.scaling=1
significa procurar uma correspondência perfeita em pixels, enquantoscaling=48
faz uma pesquisa de blocos médios.escala = 48
escala = 16
escala = 4
escala = 1
fonte
Mathematica, com controle de granularidade
Isso usa as fotos de 48 x 48 pixels, conforme necessário. Por padrão, ele trocará esses pixels por um quadrado de 48x48 pixels correspondente da imagem a ser aproximada.
No entanto, o tamanho dos quadrados de destino pode ser menor que 48 x 48, permitindo maior fidelidade aos detalhes. (veja os exemplos abaixo).
Pré-processando a Paleta
collage
é a imagem que contém as fotos para servir como paleta.picsColors
é uma lista de fotos individuais combinadas com os valores médios de vermelho, verde e azul.Exemplo
Vamos encontrar a foto que melhor combina com RGBColor [0.640, 0.134, 0.249]:
photoMosaic
`photoMosaic toma como entrada a imagem crua da qual criaremos um mosaico de fotos.
targetPic
removerá um quarto parâmetro (de PNGs e alguns JPGs), deixando apenas R, G, B.dims
são as dimensões detargetPic
.tiles
são os pequenos quadrados que juntos compõem a imagem alvo.targetSwathSize is the granularity parameter; it defaults at 48 (x48).
tileReplacements
são as fotos que correspondem a cada bloco, na ordem correta.gallery
é o conjunto de substituições de blocos (fotos) com a dimensionalidade adequada (ou seja, o número de linhas e colunas que correspondem aos blocos).ImageAssembly
une o mosaico em uma imagem de saída contínua.Exemplos
Isso substitui cada quadrado de 12x12 da imagem, domingo, por uma fotografia correspondente de 48 x 48 pixels que melhor corresponde à cor média.
Domingo (detalhe)
Detalhe, stevejobs.
Detalhe do beijo:
fonte
JS
Igual ao golfe anterior: http://jsfiddle.net/eithe/J7jEk/ : D
(desta vez chamado com
unique: false, {pixel_2: {width: 48, height: 48}, pixel_1: {width: 48, height: 48}}
) (não trate a paleta para usar um pixel uma vez, os pixels da paleta são amostras de 48x48, os pixels de forma são amostras de 48x48).Atualmente, ele pesquisa na lista de avatares para encontrar a correspondência mais próxima em peso do algoritmo selecionado, no entanto, não realiza nenhuma correspondência de uniformidade de cores (algo que eu preciso dar uma olhada.
Infelizmente, não consigo brincar com imagens maiores, porque minha RAM acaba: D Se possível, eu apreciaria imagens de saída menores. Se você usar 1/2 do tamanho da imagem fornecido, aqui está a tarde de domingo:
fonte
GLSL
A diferença entre esse desafio e o do American Gothic na paleta da Mona Lisa: reorganize os pixels que me interessam, porque os mosaicos podem ser reutilizados, enquanto os pixels não. Isso significa que é possível paralelizar facilmente o algoritmo, então decidi tentar uma versão massivamente paralela. Por "massivamente", quero dizer usando os 1344 núcleos de shader no GTX670 da minha área de trabalho simultaneamente, via GLSL.
Método
A correspondência real de blocos é simples: calculo a distância RGB entre cada pixel em uma área de destino e a área de mosaicos e escolho o bloco com a menor diferença (ponderada pelos valores de brilho). O índice do bloco é gravado nos atributos de vermelho e verde do fragmento, depois que todos os fragmentos foram renderizados, li os valores novamente no buffer de estrutura e construí a imagem de saída desses índices. A implementação real é um hack; em vez de criar um FBO, apenas abri uma janela e renderizei nela, mas o GLFW não pode abrir janelas em resoluções arbitrariamente pequenas; portanto, crio a janela maior que o necessário e, em seguida, desenhe um pequeno retângulo com o tamanho correto para que um fragmento por bloco que é mapeado para a imagem de origem. Toda a solução MSVC2013 está disponível emhttps://bitbucket.org/Gibgezr/mosaicmaker É necessário que o GLFW / FreeImage / GLEW / GLM seja compilado, e que o OpenGL 3.3 ou melhor driver / placa de vídeo seja executado.
Fonte do Shader do Fragmento
Resultados
As imagens são renderizadas quase instantaneamente, então a paralelização foi um sucesso. A desvantagem é que eu não posso fazer com que os fragmentos individuais dependam da saída de outros fragmentos, então não há como obter o aumento significativo da qualidade que você pode obter ao não escolher o mesmo bloco duas vezes dentro de um determinado intervalo. Resultados rápidos, mas com qualidade limitada devido a repetições massivas de peças. Ao todo, foi divertido. http://imgur.com/a/M0Db0 para versões em tamanho real.
fonte
Python
Aqui vai a primeira solução Python, usando uma abordagem média. Nós podemos evoluir a partir daqui. O resto das imagens está aqui .
fonte
Outra solução Python - com base na média (RGB vs L a b *)
Resultados (existem algumas diferenças)
Bulb - RGB
Vista completa
Bulb - Lab
Vista completa
Steve - RGB
Vista completa
Steve - Laboratório
Vista completa
Esferas - RGB
Vista completa
Esferas - Laboratório
Vista completa
Domingo - RGB
Vista completa
Domingo - Laboratório
Vista completa
Kiss - RGB
Vista completa
Kiss - Lab
Vista completa
Código
requer python-colormath para Lab
fonte