Imagine um caminho bidimensional contínuo que só pode virar à esquerda, direita ou seguir em frente, não pode se cruzar e deve preencher uma grade retangular, como a grade de pixels em uma imagem. Vamos chamar esse tipo de caminho de cobra .
Este exemplo ampliado mostra um caminho de cobra em uma grade 10 × 4 que começa em vermelho e aumenta em matiz em cerca de 2% a cada passo até ficar roxo. (As linhas pretas servem apenas para enfatizar a direção que toma.)
Objetivo
O objetivo deste concurso de popularidade é escrever um algoritmo que tente recriar uma determinada imagem usando uma única cobra cuja cor muda continuamente em pequenas quantidades.
Seu programa deve ter uma imagem em cores reais de qualquer tamanho, bem como um valor de ponto flutuante entre 0 e 1, inclusive a tolerância .
A tolerância define a quantidade máxima que a cor da cobra pode mudar em cada etapa do tamanho de pixel. Definiremos a distância entre duas cores RGB como a distância euclidiana entre os dois pontos RGB quando organizados em um cubo de cores RGB . A distância será então normalizada, de modo que a distância máxima seja 1 e a distância mínima seja 0.
Pseudocódigo da distância da cor: (assume que todos os valores de entrada são números inteiros no intervalo [0, 255]
; a saída é normalizada).
function ColorDistance(r1, g1, b1, r2, g2, b2)
d = sqrt((r2 - r1)^2 + (g2 - g1)^2 + (b2 - b1)^2)
return d / (255 * sqrt(3))
Se o resultado de chamar essa função na cor atual da cobra e outra cor for maior que a tolerância fornecida, a cobra não poderá mudar para essa outra cor.
Se preferir, você pode usar uma função de distância de cor diferente. Deve ser algo preciso e bem documentado, como os listados em http://en.wikipedia.org/wiki/Color_difference . Você também deve normalizá-lo para estar dentro [0, 1]
, ou seja, a distância máxima possível deve ser 1 e a mínima deve ser 0. Informe-nos em sua resposta se você usar uma métrica de distância diferente.
Imagens de teste
Obviamente, você deve postar suas imagens de saída (e até animações da cobra crescendo, se quiser). Sugiro postar uma variedade dessas imagens usando diferentes tolerâncias baixas (talvez em torno de 0,005 a 0,03).
Critérios de vitória
Como afirmado, este é um concurso de popularidade. A resposta mais votada ganhará. As respostas que fornecem a representação "caminho da cobra" mais precisa e esteticamente agradável das imagens de entrada devem ser votadas para cima.
Qualquer usuário que esteja enviando imagens maliciosamente que não são cobras reais será desqualificado para sempre.
Notas
- Apenas um caminho de cobra pode ser usado e ele deve preencher completamente a imagem sem tocar no mesmo pixel duas vezes.
- A cobra pode começar e terminar em qualquer lugar da imagem.
- A cobra pode começar como qualquer cor.
- A cobra deve permanecer nos limites da imagem. Os limites não são cíclicos.
- A cobra não pode se mover na diagonal ou mais de um pixel de cada vez.
fonte
Respostas:
Python
Eu gero um caminho dinâmico para minimizar as mudanças de cor à medida que a cobra viaja. Aqui estão algumas imagens:
tolerância = 0,01
Caminhos de cores cíclicas para as imagens acima (azul para vermelho, ficando mais verde à medida que se repete):
O caminho é gerado iniciando com algum caminho inicial e adicionando loops 2x2 até a imagem ser preenchida. A vantagem desse método é que os loops podem ser adicionados em qualquer lugar do caminho, para que você não possa se pintar em um canto e tenha mais liberdade para criar o caminho que deseja. Acompanho os possíveis loops adjacentes ao caminho atual e os armazeno em uma pilha, ponderada pela mudança de cor ao longo do loop. Então, saio do loop com o mínimo de mudança de cor, adiciono-o ao caminho e repito até que a imagem seja preenchida.
Na verdade, eu acompanho os loops sozinhos ('DetourBlock' no código) e depois reconstruo o caminho; isso foi um erro, pois existem alguns casos especiais para largura / altura ímpar e passei várias horas depurando o método de reconstrução. Ah bem.
A métrica de geração de caminho precisa ser ajustada e eu também tenho uma idéia para uma melhor coloração, mas achei que seria o primeiro, pois funciona muito bem. Exceto por este, que parece melhor em alguns dos caminhos fixos:
Aqui está o código Python, com desculpas pelos meus hábitos de codificação atrozes:
E mais algumas imagens com uma tolerância muito baixa de 0,001 :
E também o ótimo caminho das ondas, porque é elegante:
EDITAR
A geração do caminho parece melhor ao minimizar a distância das cores entre as cores médias dos blocos adjacentes, em vez de minimizar a soma das distâncias das cores entre os pixels adjacentes. Além disso, verifica-se que você pode calcular a média das cores de quaisquer dois caminhos de cobra compatíveis com tolerância e terminar com outro caminho de cobra compatível com tolerância. Então, eu atravesso o caminho nos dois sentidos e os medio, o que suaviza muitos artefatos. Zombie Lena e Scary Hands Mona parecem muito melhores. Versões finais:
Tolerância 0,01 :
Tolerância 0.001 :
fonte
Java
Meu programa gera um caminho de cobra para uma determinada largura e altura, usando um algoritmo semelhante ao que gera a curva de Hilbert.
(joguinho: na foto acima, a cobra começa no canto superior esquerdo. Você consegue encontrar onde ele termina? Boa sorte :)
Aqui estão os resultados para vários valores de tolerância:
Tolerância = 0,01
Tolerância = 0,05
Tolerância = 0,1
Tolerância = 0,01
Com blocos de pixel 4x4 e o caminho visível
Computando o caminho da cobra
Um caminho de cobra é armazenado em uma matriz inteira de dupla dimensão. A cobra sempre entra na grade pelo canto superior esquerdo. Existem 4 operações básicas que meu programa pode executar em um determinado caminho de cobra:
crie um novo caminho de cobra para uma grade de largura 1 ou altura 1. O caminho é apenas uma linha simples que vai da esquerda para a direita ou para cima e para baixo, dependendo do caso.
aumente a altura da grade, adicionando no topo um caminho de cobra da esquerda para a direita e espelhando a grade (a cobra deve sempre entrar na grade pelo canto superior esquerdo)
aumente a largura da grade, adicionando à esquerda um caminho de cobra de cima para baixo e invertendo a grade (a cobra deve sempre entrar na grade pelo canto superior esquerdo)
dobrar a dimensão da grade usando o algoritmo "estilo Hilbert" (veja a descrição abaixo)
Usando uma série dessas operações atômicas, o programa é capaz de gerar um caminho de cobra de qualquer tamanho.
O código abaixo calcula (em ordem inversa) quais operações serão necessárias para obter uma determinada largura e altura. Uma vez calculadas, as ações são executadas uma a uma até obtermos um caminho de cobra do tamanho esperado.
Dobrar o tamanho do caminho da cobra:
O algoritmo que dobra o tamanho funciona da seguinte maneira:
Considere este nó que está vinculado a RIGHT e BOTTOM. Eu quero dobrar de tamanho.
Existem duas maneiras de dobrar de tamanho e manter as mesmas saídas (direita e inferior):
ou
Para determinar qual escolher, eu preciso manipular para cada direção do nó um valor "shift", indicando se a porta de saída é deslocada para a esquerda / direita ou para cima / para baixo. Sigo o caminho como a cobra faria e atualizo o valor do turno ao longo do caminho. O valor do turno determina exclusivamente qual bloco expandido eu preciso usar para a próxima etapa.
fonte
Python
Aqui está um algoritmo muito simples para começar. Ele começa no canto superior esquerdo da imagem e espirala no sentido horário para dentro, tornando a cor o mais próximo possível da cor do próximo pixel, mantendo-se dentro da tolerância.
Demora um ou dois minutos para executar as imagens maiores, embora eu tenha certeza de que a lógica em espiral poderia ser amplamente otimizada.
Resultados
Eles são interessantes, mas não lindos. Surpreendentemente, uma tolerância acima de 0,1 produz resultados de aparência bastante precisos.
A Grande Onda com tolerância de 0,03:
Mona Lisa com tolerância de 0,02:
Lena com tolerância de 0,03, 0,01, 0,005 e 0,003:
Coisas diversas com tolerância de 0,1, 0,07, 0,04 e 0,01:
fonte
Cobra
Preenche a imagem com uma cobra como:
Isso permite um ajuste de cor muito mais rápido do que apenas linhas em direções alternadas, mas não se torna tão irregular quanto uma versão em três larguras.
Mesmo com tolerâncias muito baixas, as bordas de uma imagem ainda são visíveis (embora com a perda de detalhes em resoluções menores).
0,01
0,1
0,01
0,01
0,1
0,03
0,005
fonte
C #
O Snake começa no pixel superior esquerdo com a cor branca e alterna da esquerda para a direita e depois da direita para a esquerda na imagem.
Tolerância da imagem resultante = 0,1
fonte