Eu tenho brincado fazendo mosaicos de imagens. Meu script captura um grande número de imagens, reduz ao tamanho das miniaturas e as usa como blocos para aproximar uma imagem de destino.
A abordagem é realmente bastante agradável:
Calculo o erro quadrático médio para cada polegar em cada posição do bloco.
No começo, acabei de usar um posicionamento ganancioso: coloque o polegar com o menor erro no ladrilho que melhor se encaixa e depois no próximo e assim por diante.
O problema com o ganancioso é que, eventualmente, você coloca os polegares mais diferentes nos ladrilhos menos populares, combinando-os de perto ou não. Eu mostro exemplos aqui: http://williamedwardscoder.tumblr.com/post/84505278488/making-image-mosaics
Então, faço trocas aleatórias até que o script seja interrompido. Os resultados são bastante bons.
Uma troca aleatória de dois blocos nem sempre é uma melhoria, mas às vezes uma rotação de três ou mais blocos resulta em uma melhoria global, ou seja, A <-> B
pode não melhorar, mas A -> B -> C -> A
1
pode ..
Por esse motivo, depois de escolher duas peças aleatórias e descobrir que elas não melhoram, eu escolho várias peças para avaliar se elas podem ser a terceira peça dessa rotação. Não exploro se qualquer conjunto de quatro peças pode ser rotacionado com lucro, e assim por diante; isso seria super caro em breve.
Mas isso leva tempo .. Muito tempo!
Existe uma abordagem melhor e mais rápida?
Atualização de recompensa
Testei várias implementações e ligações do Python do método húngaro .
De longe o mais rápido foi o https://github.com/xtof-durr/makeSimple/blob/master/Munkres/kuhnMunkres.py
Meu palpite é que isso se aproxima da resposta ideal; quando executadas em uma imagem de teste, todas as outras bibliotecas concordaram com o resultado, mas esse kuhnMunkres.py, apesar de ter ordens de magnitude mais rápidas, ficou muito, muito, muito próximo da pontuação que as outras implementações concordaram.
A velocidade depende muito dos dados; Mona Lisa correu pelo kuhnMunkres.py em 13 minutos, mas o Periquito-de-peito-escarlate levou 16 minutos.
Os resultados foram os mesmos que os swaps e rotações aleatórias para o periquito:
(kuhnMunkres.py à esquerda, trocas aleatórias à direita; imagem original para comparação )
No entanto, para a imagem da Mona Lisa com a qual eu testei, os resultados foram visivelmente aprimorados e ela realmente teve seu 'sorriso' definido brilhando:
(kuhnMunkres.py à esquerda, trocas aleatórias à direita)
fonte
Respostas:
Sim, existem duas abordagens melhores e mais rápidas.
Em seguida, você pode ajustar seus custos substituindo o MSE por uma distância visualmente mais precisa, sem alterar o algoritmo subjacente.
fonte
Estou razoavelmente certo de que é um problema difícil de NP. Para encontrar uma solução 'perfeita', você deve tentar todas as possibilidades exaustivamente, e isso é exponencial.
Uma abordagem seria usar o ajuste ganancioso e tentar melhorá-lo. Isso pode ser feito com uma imagem mal posicionada (uma das últimas) e encontrando outro lugar para colocá-la, depois pegando essa imagem e movendo-a e assim por diante. Você termina quando (a) fica sem tempo (b) o ajuste é 'bom o suficiente'.
Se você introduzir um elemento probabilístico, ele poderá render uma abordagem simulada de recozimento ou um algoritmo genético. Talvez tudo o que você está tentando alcançar seja espalhar os erros uniformemente. Eu suspeito que isso esteja se aproximando do que você já está fazendo, então a resposta é: com o algoritmo certo, você pode obter um resultado melhor mais rapidamente, mas não há atalho mágico para o Nirvana.
Sim, isso é semelhante ao que você já está fazendo. O objetivo é esquecer uma resposta mágica e pensar em termos de 2 algoritmos: primeiro preencha e depois otimize.
O preenchimento pode ser: aleatório, melhor disponível, primeiro melhor, bom o suficiente, algum tipo de hot spot.
A otimização pode ser aleatória, corrigir o pior ou (como sugeri) o recozimento simulado ou o algoritmo genético.
Você precisa de uma métrica de 'bondade' e de uma quantidade de tempo que esteja preparado para gastar nela e apenas experimentar. Ou encontre alguém que realmente tenha feito isso.
fonte
Se os últimos blocos forem o seu problema, tente colocá-los desde o início, de alguma forma;)
Uma abordagem seria olhar para o bloco que está mais distante do x% superior de suas correspondências (intuitivamente, eu usaria 33%) e colocá-lo na sua melhor correspondência. Essa é a melhor combinação possível de qualquer maneira.
Além disso, você pode optar por não usar a melhor correspondência para o pior bloco, mas aquele que introduz o menor erro em comparação com a melhor correspondência para esse espaço, para que você não jogue completamente fora suas melhores correspondências por causa de " controle de dano".
Outra coisa a ter em mente é que, no final, você está produzindo uma imagem a ser processada pelo olho. Então, o que você realmente deseja é usar alguma detecção de borda para determinar quais posições na sua imagem são mais importantes. Da mesma forma, o que acontece na periferia da imagem tem pouco valor para a qualidade do efeito. Sobreponha esses dois pesos e inclua-os no cálculo da distância. Qualquer tremulação que você receber deve, portanto, gravitar em direção à borda e afastá-la, perturbando muito menos.
Além disso, com a detecção de arestas no lugar, convém colocar os primeiros y% avidamente (talvez até cair abaixo de um certo limite de "nervosismo" nos ladrilhos restantes), para que os "pontos quentes" sejam tratados muito bem, e depois mude para "controle de danos" nos demais.
fonte