Hilbertify uma imagem

28

Eu gosto da curva de Hilbert .


Sua tarefa para esse desafio é capturar uma imagem (estritamente uma imagem quadrada, onde todos os lados têm uma potência de dois pixels de largura) e desvendá-la linha por linha em zigue-zague e percorrê-la novamente em uma curva pseudo-Hilbert .

Desenrolar

Para desvendar, você começará com o pixel no canto superior esquerdo e viajará para a direita até chegar à borda da imagem. Depois de atingir a borda da imagem, você irá para a próxima linha e começará a viajar para a esquerda até atingir a borda novamente. Você continuará desvendando linha por linha, alternando a direção a cada vez, para obter uma curva contínua. Deve parecer um jogo de cobra bem jogado

O resultado do desembaraço deve ser uma ordem de pixels que inclua todos os pixels exatamente uma vez

Reraveling

Depois de fazer o pedido dos pixels, você os reorganizará em uma nova tela de tamanho igual, seguindo o caminho de uma curva pseudo-Hilbert. Para uma 2**nimagem quadrada de tamanho, você deve usar a enésima iteração da curva pseudo-hilbert. Cada pixel será colocado exatamente em um ponto na nova tela. Você deve desviar a imagem para que o ponto originalmente no canto superior esquerdo (o início da nossa curva de cobra) permaneça lá e aponte no canto inferior direito (o final de nossa curva de cobra) seja colocado no canto superior direito.

I / O

Seu programa ou função deve capturar uma imagem de restrições especificadas por métodos padrão e produzir outra imagem por métodos padrão.

Pontuação

Este é programa de com o menor número de bytes ganhos.

Exemplos

Entrada

Mondrian

Saída

Saída 1


Entrada

Rothko

Saída

Saída 2


Entrada

Mexidos

Saída

Leão


Também recomendo testar uma imagem em branco ou em cores sólidas em branco para garantir que você não perca nenhum pixel.

Sinta-se à vontade para incluir seus próprios resultados em suas respostas!

Assistente de Trigo
fonte
Tudo bem usar uma entrada de valores RGB em vez de uma imagem como entrada? E quanto à saída?
JungHwan Min
@JHM Não, você não pode. Você pode escolher o formato de imagem que desejar, portanto, se seu idioma não possuir suporte de imagem interno, você poderá usar um arquivo .ppm descompactado, que é muito semelhante a uma matriz de valores RGB.
Wheat Wizard

Respostas:

8

Mathematica, 286 273 bytes

Image[Array[1,{l=Length@#,l}]~ReplacePart~Thread[#&@@@Split[#&@@@FoldList[Switch[#2,"-",#{1,I},"+",#/{1,I},"F",#+{ReIm@Last@#,0},_,#]&,{{1,1},I},Characters@Nest[StringReplace@{"L"->"+RF-LFL-FR+","R"->"-LF+RFR+FL-"},"L",Log2@l]]]->Join@@MapAt[Reverse,#,2;;;;2]]]&@*ImageData

Ufa! Desafiador, mas divertido!

Explicação

ImageData

Converta um Imageem uma matriz de valores RGB.

Array[1,{l=Length@#,l}]

Gerar um lpor lmatriz com cabeça 1, onde o lcomprimento da entrada (ou seja, a largura da imagem) é.

Isso gera {{1[1, 1], 1[1, 2], ..., 1[1, L]}, {1[2, 1], ..., 1[2, L]}, ..., {1[L, 1], ..., 1[L, L]}}( lescrito em maiúsculas para reduzir a confusão)

StringReplace@{"L"->"+RF-LFL-FR+","R"->"-LF+RFR+FL-"}

Uma StringReplacefunção que substitui todos "L"com "+RF-LFL-FR+"e "R"com"-LF+RFR+FL-"

Nest[ ... ,"L",Log2@l]

Aplique a StringReplacefunção para as String "L", Log2[l]vezes.

Characters

Converta o resultado Stringem um Listde caracteres.

Switch[#2,"-",#{1,I},"+",#/{1,I},"F",#+{ReIm@Last@#,0},_,#]&

Uma função sem nome que:

  • Se a segunda entrada for "-", multiplique o segundo elemento da primeira entrada por I.
  • Se a segunda entrada for "+", divida o segundo elemento da primeira entrada por I.
  • Se a segunda entrada for "F", aumente a primeira entrada pelo ReIm(separa a parte real e imaginária da entrada) da segunda entrada.
Lista de dobras [..., {{1,1}, I}, ...]

Começando com {{1,1},I}, aplique cumulativamente a função sem nome acima, usando cada elemento Listdos caracteres como a segunda entrada. Este código produz as saídas de todas as iterações.

#&@@@Split[#&@@@ ... ]

Livre-se dos segundos elementos de cada um Liste exclua duplicatas. (Os passos até este ponto geram uma Listdas coordenadas da curva de Hilbert)

Join@@MapAt[Reverse,#,2;;;;2]

Desvendar a matriz RGB de entrada (inverte todas as outras linhas e nivela).

Thread[ ... -> ... ]

Crie Ruleobjetos, de modo que o primeiro elemento da primeira entrada (as coordenadas da curva de Hilbert) seja emparelhado com o primeiro elemento da segunda entrada (a imagem desfeita), o segundo elemento com a segunda entrada e assim por diante.

... ~ReplacePart~ ...

Aplique esses substitutos Ruleno Arrayda segunda etapa.

Image

Converta para a matriz de valores RGB em um Image.

Amostra in / out

Entrada:

Caso de teste 1

Saída:

saída


Entrada:

Edward e Alphonse Elric do Fullmetal Alchemist

Saída:

wat

Função inversa ( 266 253 bytes)

Image[MapAt[Reverse,Extract[#,#&@@@Split[#&@@@FoldList[Switch[#2,"-",#{1,I},"+",#/{1,I},"F",#+{ReIm@Last@b,0},_,#]&,{{1,1},I},Characters@Nest[StringReplace@{"L"->"+RF-LFL-FR+","R"->"-LF+RFR+FL-"},"L",Log2[l=Length@#]]]]]~Partition~l,2;;;;2]]&@*ImageData
JungHwan Min
fonte
5

Octave 234 bytes

I=imread(input(''));w=rows(I);X=[0,3;1,2];for k=2:log2(w);n=numel(X);X=[X',rot90(X',2)+3*n;X+n,X+2*n];end;for k = 1:3;I(2:2:end,:,k)=fliplr(I(2:2:end,:,k));end[~,S]=sort(X(:));I(S+(0:w^2:2*w^2))=permute(I,[2 1 3]);imwrite(I,input(''))

Os nomes de arquivo das imagens de entrada e saída devem ser fornecidos na entrada padrão. o tamanho do código sem entrada / saída é 194 bytes .
Explicação:

O padrão base dos índices é:

X =
  0 3
  1 2

Em cada iteração, 4 cópias do resultado da iteração anterior feita e alguma transformação aplicada a cada cópia, em seguida, todos os blocos são concatenados para formar o resultado atual.

X =[0,3;1,2];
for k = 2:log2(s)
    n=numel(X);
    X = [X',rot90(X',2)+3*n;X+n,X+2*n];
end

então nós temos:

block(1,1): X' 
block(1,2): rot90(X',2)+3*n 
block(2,1): X+n
block(2,2): X+2*n

0    1  | 14   15
3    2  | 13   12
--------|--------
4    7  |  8   11
5    6  |  9   10

Os índices de Hilbert classificados e os índices dos elementos classificados retornados:

[~,S]=sort(X(:));

Desvendando o lançamento de todas as linhas pares:

for k = 1:3
    I(2:2:end,:,k) = fliplr(I(2:2:end,:,k));
end

Reraveling aplicado:
-S repetido para cada canal
-permutação aplicada, já que nos dados do Oitava, dispostos em colunas

I(S+(0:w^2:2*w^2))=permute(I,[2 1 3]);

Imagens de exemplo:

insira a descrição da imagem aqui

insira a descrição da imagem aqui

insira a descrição da imagem aqui

insira a descrição da imagem aqui

rahnema1
fonte
Você pode optar por ter seu programa funcionando como uma função se desejar evitar o uso de E / S.
Wheat Wizard
As palavras-chave function + end consomem mais bytes!
usar o seguinte comando