Baseado no muito bem-sucedido desafio de codificação de imagem do Twitter no Stack Overflow.
Se uma imagem vale mais que 1000 palavras, quanto da imagem você pode caber em 114,97 bytes?
Desafio você a criar um método de uso geral para compactar imagens em um comentário padrão do Twitter que contenha apenas texto ASCII imprimível .
Regras:
- Você deve escrever um programa que possa capturar uma imagem e gerar o texto codificado.
- O texto criado pelo programa deve ter no máximo 140 caracteres e deve conter apenas caracteres cujos pontos de código estejam no intervalo de 32 a 126, inclusive.
- Você deve escrever um programa (possivelmente o mesmo) que possa pegar o texto codificado e gerar uma versão decodificada da fotografia.
- Seu programa pode usar bibliotecas e arquivos externos, mas não pode exigir conexão à Internet ou conexão com outros computadores.
- O processo de decodificação não pode acessar ou conter as imagens originais de forma alguma.
- Seu programa deve aceitar imagens em pelo menos um desses formatos (não necessariamente mais): Bitmap, JPEG, GIF, TIFF, PNG. Se algumas ou todas as imagens de amostra não estiverem no formato correto, você poderá convertê-las antes da compactação pelo seu programa.
A julgar:
Este é um desafio um tanto subjetivo, de modo que o vencedor (eventualmente) será julgado por mim. Vou concentrar meu julgamento em alguns fatores importantes, listados abaixo em importância decrescente:
- Capacidade de realizar um trabalho razoável de compactação de uma ampla variedade de imagens, incluindo aquelas não listadas como imagem de amostra
- Capacidade de preservar os contornos dos principais elementos de uma imagem
- Capacidade de compactar as cores dos principais elementos de uma imagem
- Capacidade de preservar contornos e cores dos pequenos detalhes em uma imagem
- Tempo de compressão. Embora não seja tão importante quanto a compactação de uma imagem, programas mais rápidos são melhores que programas mais lentos que fazem a mesma coisa.
Seu envio deve incluir as imagens resultantes após a descompressão, junto com o comentário do Twitter gerado. Se possível, você também pode fornecer um link para o código-fonte.
Respostas:
Eu melhorei meu método adicionando compactação real. Agora ele opera iterativamente, fazendo o seguinte:
Diminua o tamanho da imagem, preservando a proporção (se a imagem for colorida, o croma será amostrado em 1/3 da largura e altura da luminância)
Reduza a profundidade de bits para 4 bits por amostra
Aplique previsão mediana à imagem, tornando a distribuição da amostra mais uniforme
Aplique compressão de faixa adaptável à imagem.
Veja se o tamanho da imagem compactada é <= 112
A maior imagem que se encaixa nos 112 bytes é então usada como imagem final, com os dois bytes restantes usados para armazenar a largura e a altura da imagem compactada, além de um sinalizador indicando se a imagem está em cores. Para decodificação, o processo é revertido e a imagem é ampliada para que a dimensão menor seja 128.
Há algum espaço para aprimoramento, a saber, nem todos os bytes disponíveis são usados normalmente, mas sinto que estou no ponto de retornos significativamente menores para a redução de amostragem + compactação sem perdas.
Fonte C ++ rápida e suja
Windows exe
Mona Lisa (luminosidade 13x20, croma 4x6)
Hindenburg (luminosidade 21x13)
Montanhas (luminância 19x14, 6x4 croma)
Formas 2D (luminância 21x15, croma 7x5)
fonte
Ir
Trabalha dividindo a imagem em regiões recursivamente. Tento dividir regiões com alto conteúdo de informações e escolho a linha divisória para maximizar a diferença de cores entre as duas regiões.
Cada divisão é codificada usando alguns bits para codificar a linha divisória. Cada região da folha é codificada como uma única cor.
A foto de Hindenburg parece bem ruim, mas as outras que eu gosto.
fonte
Pitão
A codificação requer numpy , SciPy e scikit-image .
A decodificação requer apenas PIL .
Este é um método baseado na interpolação de superpixel. Para começar, cada imagem é dividida em 70 regiões de tamanhos semelhantes e cores semelhantes. Por exemplo, a imagem da paisagem é dividida da seguinte maneira:
O centróide de cada região está localizado (até o ponto de varredura mais próximo em uma grade que não contém mais de 402 pontos), assim como a cor média (de uma paleta de cores 216), e cada uma dessas regiões é codificada como um número de 0 a 86832 , capaz de ser armazenado em 2,5 caracteres ascii imprimíveis (na verdade , 2.497 , deixando espaço suficiente para codificar para um bit na escala de cinza).
Se você estiver atento, poderá ter notado que 140 / 2,5 = 56 regiões, e não 70, como afirmei anteriormente. Observe, no entanto, que cada uma dessas regiões é um objeto único e comparável, que pode ser listado em qualquer ordem. Por esse motivo, podemos usar a permutação das 56 primeiras regiões para codificar para as outras 14 , além de ter alguns bits restantes para armazenar a proporção.
Mais especificamente, cada uma das 14 regiões adicionais é convertida em um número e, em seguida, cada um desses números concatenados juntos (multiplicando o valor atual por 86832 e adicionando a próxima). Esse número (gigantesco) é então convertido em uma permutação em 56 objetos.
Por exemplo:
irá produzir:
A permutação resultante é então aplicada às 56 regiões originais . O número original (e, portanto, as 14 regiões adicionais ) também pode ser extraído convertendo a permutação das 56 regiões codificadas em sua representação numérica.
Quando a
--greyscale
opção é usada com o codificador, 94 regiões são usadas (separadas 70 , 24 ), com 558 pontos raster e 16 tons de cinza.Ao decodificar, cada uma dessas regiões é tratada como um cone 3D estendido até o infinito, com seu vértice no centróide da região, como visto de cima (também conhecido como Diagrama de Voronoi). As bordas são então combinadas para criar o produto final.
Melhorias futuras
As dimensões da Mona Lisa são um pouco diferentes, devido ao modo como estou armazenando a proporção. Vou precisar usar um sistema diferente.Corrigido, assumindo que a proporção original está entre 1:21 e 21: 1, o que eu acho que é uma suposição razoável.O Hindenburg poderia ser melhorado muito. A paleta de cores que estou usando tem apenas 6 tons de cinza. Se eu introduzisse um modo somente em escala de cinza, poderia usar as informações extras para aumentar a profundidade da cor, o número de regiões, o número de pontos de varredura ou qualquer combinação dos três.Eu adicionei uma--greyscale
opção ao codificador, que faz todos os três.2d Shapes provavelmente ficaria melhor com a mistura desativada. Eu provavelmente adicionarei uma bandeira para isso.Adicionada uma opção de codificador para controlar a taxa de segmentação e uma opção de decodificador para desativar a mistura.e
O segundo codificado com a
--greyscale
opçãoCodificado com a
--greyscale
opçãoCodificado com
--ratio 60
e decodificado com--no-blending
opções.encoder.py
decoder.py
my_geom.py
fonte
PHP
OK, demorei um pouco, mas aqui está. Todas as imagens em escala de cinza. As cores levaram muitos bits para codificar para o meu método: P
Mona Lisa:
47 cores Monocromático, sequência de
101 bytes.
Formas 2D
36 Cores Monocromático Cadeia de
105 bytes.
Hindenburg
62 cores monocromático
112 caracteres.
Montanhas
63 cores monocromático
122 caracteres.
Meu método
Eu codifico meu fluxo de bits com um tipo de codificação base64. Antes de ser codificado em texto legível, eis o que acontece.
Carrego a imagem de origem e redimensiono-a para uma altura ou largura máxima (dependendo da orientação, retrato / paisagem) de 20 pixels.
Em seguida, recolorir cada pixel da nova imagem para a correspondência mais próxima em uma paleta de 6 cores em escala de cinza.
Depois disso, crio uma string com cada cor de pixel representada pelas letras [AF].
Em seguida, calculo a distribuição das 6 letras diferentes na sequência e seleciono a árvore binária mais otimizada para codificação com base nas frequências das letras. Existem 15 árvores binárias possíveis.
Inicio meu fluxo de bits com um único bit,
[1|0]
dependendo da imagem ser alta ou larga. Em seguida, uso os próximos 4 bits no fluxo para informar ao decodificador qual árvore binária deve ser usada para decodificar a imagem.O que se segue é o fluxo de bits que representa a imagem. Cada pixel e sua cor são representados por 2 ou 3 bits. Isso permite armazenar pelo menos 2 e até 3 pixels de informações para cada caractere ASCII impresso. Aqui está uma amostra da árvore binária
1110
, usada pela Mona Lisa:As letras E
00
e F10
são as cores mais comuns na Mona Lisa. A010
, B011
, C110
e D111
são os menos frequentes.As árvores binárias funcionam assim: Ir de bit em bit,
0
significa ir para a esquerda,1
significa ir para a direita. Continue indo até bater em uma folha na árvore ou em um beco sem saída. A folha em que você termina é o personagem que você deseja.De qualquer forma, eu codifico a picada binária em caracteres base64. Ao decodificar a sequência, o processo é feito ao contrário, atribuindo todos os pixels à cor apropriada e, em seguida, a imagem é dimensionada duas vezes o tamanho codificado (máximo de 40 pixels, X ou Y, o que for maior) e, em seguida, uma matriz de convolução aplicado a tudo para suavizar as cores.
De qualquer forma, aqui está o código atual: " link pastebin "
É feio, mas se você encontrar algum espaço para melhorias, me avise. Eu o cortei juntos como eu quero. APRENDI MUITO DESTE DESAFIO. Obrigado OP por publicá-lo!
fonte
Minha primeira tentativa. Isso tem espaço para melhorias. Eu acho que o formato em si realmente funciona, o problema está no codificador. Isso, e estou perdendo bits individuais da minha saída ... meu arquivo (de qualidade um pouco mais alta do que aqui) terminou em 144 caracteres, quando deveria ter sobrado algum. (e eu realmente gostaria que houvesse - as diferenças entre essas e aquelas são visíveis). Aprendi, porém, nunca superestime o tamanho de 140 caracteres ...
Eu a reduzi para uma versão modificada da paleta RISC-OS - basicamente, porque eu precisava de uma paleta de 32 cores e isso parecia um bom lugar para começar. Isso também pode mudar algumas coisas, eu acho.
Eu a divido nas seguintes formas: e divido a imagem em blocos de paleta (neste caso, 2x2 pixels) de uma cor frontal e traseira.
Resultados:
A seguir estão os tweets, os originais e como o tweet é decodificado
Sei que as cores estão erradas, mas na verdade gosto da Monalisa. Se eu removesse o desfoque (o que não seria muito difícil), é uma impressão cubista razoável: p
Eu preciso trabalhar
Darei mais trabalho posteriormente para tentar corrigi-los e aprimorei o codificador. Esses 20 ou mais personagens extras fazem uma enorme diferença. Eu gostaria deles de volta.
A fonte C # e a paleta de cores estão em https://dl.dropboxusercontent.com/u/46145976/Base96.zip - embora, em retrospectiva, possam não funcionar perfeitamente quando executadas separadamente (pois os espaços nos argumentos dos programas não funcionam assim) bem).
O codificador leva menos de alguns segundos na minha máquina razoavelmente média.
fonte
Desisti de tentar manter a cor e fiquei em preto e branco, pois tudo o que tentava com a cor era irreconhecível.
Basicamente, tudo o que faz é dividir os pixels em três partes aproximadamente iguais: preto, cinza e branco. Também não mantém o tamanho.
Hindenburg
Monalisa
Montanhas
Formas
Aqui está o programa.
python compress.py -c img.png
comprimeimg.png
e imprime o tweet.python compress.py -d img.png
pega o tweet de stdin e salva a imagem emimg.png
.fonte
Minha modesta contribuição em R:
A idéia é simplesmente reduzir a varredura (o arquivo deve estar em png) para uma matriz cujo número de células é menor que 140; os tweets são uma série de cores (em 64 cores), precedidas por dois caracteres, indicando o número de linhas. e colunas da varredura.
fonte
Não é uma solução completa, basta colocar o método lá fora. (Matlab)
Usei uma paleta de 16 cores e uma posição 40 para criar um diagrama de voronoi ponderado . Utilizou algoritmo genético e algoritmo simples de escalada para se ajustar à imagem.
Álbum com imagem original e também tenho uma versão de 16 bytes com 4 cores e posições fixas. :)
(Posso redimensionar a imagem aqui?)
fonte
C #
Atualização - Versão 2
Fiz outra tentativa, agora usando o MagickImage.NET ( https://magick.codeplex.com/ ) para codificar os dados JPEG, também escrevi um código básico para processar melhor os dados do cabeçalho JPEG (como sugerido pelo primo), também GuassianBlur usado na saída, que ajuda a suavizar parte da compactação JPEG. Como a nova versão se pré-forma melhor, atualizei minha postagem para refletir o novo método.
Método
Tentei algo único (espero), em vez de tentar manipular a profundidade de cores ou a identificação das bordas, ou tentar usar maneiras diferentes de reduzir o tamanho das imagens. Utilizei o algoritmo JPEG na compressão máxima em versões reduzidas do as imagens e, ao eliminar tudo, menos o "StartOfScan" ( http://en.wikipedia.org/wiki/JPEG#Syntax_and_structure ) e alguns elementos-chave do cabeçalho, posso reduzir o tamanho a um valor aceitável. Os resultados são realmente impressionantes para 140 caracteres, me dá um novo respeito pelos JPEGs:
Hindenburg
Montanhas
Monalisa
Formas
Código
Versão 2 - http://pastebin.com/Tgr8XZUQ
Estou realmente começando a sentir falta do ReSharper +, tenho muitas coisas para melhorar, ainda há muita codificação em andamento aqui, interessante para se mexer (lembre-se de que você precisa das dll MagickImage para fazer isso funcionar no VS)
Original (descontinuado) - http://pastebin.com/BDPT0BKT
Ainda um pouco de bagunça.
fonte
Python 3
Método
O que o programa faz primeiro é reduzir a imagem, diminuindo bastante seu tamanho.
Segundo, converte os valores rgb em binários e corta os últimos dígitos.
Em seguida, converte os dados da base 2 na base 10, onde adiciona as dimensões da imagem.
Em seguida, ele converte os dados da base 10 para a base 95, usando todos os ascii que pude encontrar. No entanto, não pude usar / x01 e similares por causa de sua capacidade de negar a função que gravou o arquivo de texto.
E (para aumentar a ambiguidade), a função decodificar faz isso ao contrário.
compress.py
decode.py
O grito
Monalisa
Esferas
fonte