Nota : Anders Kaseorg recebeu o prêmio por enquanto, para chamar a atenção para sua grande resposta, mas o desafio nunca acabou! Ainda há uma recompensa de 400 pontos na oferta para quem obtém a pontuação máxima sem usar a compactação incorporada.
Abaixo está uma 386x320
representação png da Noite Estrelada de van Gogh.
Seu objetivo é reproduzir esta imagem o mais próximo possível, em não mais que 1024 bytes de código. Para os propósitos deste desafio, a proximidade das imagens é medida pelas diferenças quadráticas nos valores de pixel RGB, conforme explicado abaixo.
Este é um desafio de código . As pontuações são calculadas usando o script de validação abaixo. A pontuação mais baixa vence.
Seu código deve obedecer às seguintes restrições:
- Deve ser um programa completo
- Ele deve gerar uma imagem em um formato que possa ser lido pelo script de validação abaixo, executando na minha máquina. O script usa a biblioteca PIL do Python, que pode carregar uma ampla variedade de formatos de arquivo , incluindo png, jpg e bmp.
- Ele deve ser completamente independente, sem entrada e sem carregamento de arquivos (exceto a importação de bibliotecas, o que é permitido)
- Se o seu idioma ou biblioteca incluir uma função que produz Starry Night, você não poderá usar essa função.
- Ele deve ser executado deterministicamente, produzindo a mesma saída sempre.
- As dimensões da imagem de saída devem ser
386x320
- Para evitar dúvidas: respostas válidas devem usar linguagens de programação de acordo com as regras usuais do PPCG . Deve ser um programa que produz uma imagem, não apenas um arquivo de imagem.
É provável que alguns envios sejam gerados por código. Se for esse o caso, inclua em sua resposta o código que foi usado para produzir seu envio e explique como ele funciona. As restrições acima se aplicam apenas ao programa de geração de imagens de 1kB enviado por você; eles não se aplicam a nenhum código usado para gerá-lo.
Pontuação
Para calcular sua pontuação, pegue sua imagem de saída e o original acima e converta os valores de pixel RGB em números de ponto flutuante que variam de 0 a 1. A pontuação de um pixel é (orig_r-img_r)^2 +(orig_g-img_g)^2 + (orig_b-img_b)^2
, ou seja, a distância ao quadrado no espaço RGB entre as duas imagens. A pontuação de uma imagem é a soma das pontuações de seus pixels.
Abaixo está um script Python que executa esse cálculo - no caso de qualquer inconsistência ou ambiguidade, a pontuação definitiva é aquela calculada pelo script em execução na minha máquina.
Observe que a pontuação é calculada com base na imagem de saída; portanto, se você usar um formato com perdas que afetará a pontuação.
Quanto menor a pontuação, melhor. A imagem original da Noite Estrelada teria uma pontuação igual a 0. No evento astronomicamente improvável de empate, a resposta com mais votos determinará o vencedor.
Objetivos bônus
Como as respostas foram dominadas por soluções que usam compactação incorporada, concedi uma série de recompensas a respostas que usam outras técnicas. O próximo será uma recompensa de 400 pontos , a ser concedida se e quando uma resposta que não usa compactação incorporada ocupa o primeiro lugar no geral.
As recompensas de bônus concedidas anteriormente foram as seguintes:
Uma recompensa de 100 pontos foi concedida à resposta de nneonneo , por ser a resposta de maior pontuação que não usava a compactação incorporada na época. Tinha 4852,87 pontos no momento em que foi premiado. Menções honrosas vão para o acampamento de 2012, que fez uma tentativa valiosa de vencer o nneonneo usando uma abordagem baseada no mosaico de Voronoi , marcando 5076 pontos, e para Sleafar, cuja resposta estava na liderança até perto do fim, com 5052 pontos, usando um método semelhante ao nneonneo.
Uma recompensa de 200 pontos foi concedida à entrada de Strawdog . Ela foi premiada por ser uma estratégia baseada em otimização que assumiu a liderança entre as respostas não integradas à compactação e a manteve por uma semana. Ele marcou 4749,88 pontos usando um método impressionantemente inteligente.
Script de pontuação / validação
O script Python a seguir deve ser colocado na mesma pasta da imagem acima (que deve ser nomeada ORIGINAL.png
) e executado usando um comando do formulário python validate.py myImage.png
.
from PIL import Image
import sys
orig = Image.open("ORIGINAL.png")
img = Image.open(sys.argv[1])
if img.size != orig.size:
print("NOT VALID: image dimensions do not match the original")
exit()
w, h = img.size
orig = orig.convert("RGB")
img = img.convert("RGB")
orig_pix = orig.load()
img_pix = img.load()
score = 0
for x in range(w):
for y in range(h):
orig_r, orig_g, orig_b = orig_pix[x,y]
img_r, img_g, img_b = img_pix[x,y]
score += (img_r-orig_r)**2
score += (img_g-orig_g)**2
score += (img_b-orig_b)**2
print(score/255.**2)
Nota técnica: Medidas objetivas de similaridade de imagem são complicadas. Nesse caso, optei por um que seja fácil de implementar, com pleno conhecimento de que existem medidas muito melhores.
Entre os melhores
fonte
pip unistall PIL
, entãopip install pillow
) e alterar a primeira linha parafrom PIL import Image
.Respostas:
Pitão (sem compactação integrada), pontuação
4695,074656,034444,82A única funcionalidade relacionada à imagem de Pyth é integrada para gravar uma matriz de triplos RGB como um arquivo de imagem. Portanto, a idéia maluca aqui é treinar uma pequena rede neural profunda na função ( x , y ) ↦ ( r , g , b ) que representa a imagem e executá-la nas coordenadas de cada pixel.
O plano
A rede atual é construída a partir de 45 neurônios sigmóides, com cada neurônio conectado às entradas x , y e a todos os neurônios anteriores, e os três últimos neurônios interpretados como r , g , b . É treinado usando o algoritmo Adam sem lote. Os parâmetros que pesam as conexões 1125 são quantizados para um intervalo de 93 valores possíveis (exceto os termos constantes, que possuem 93 2 valores possíveis) usando uma variante da quantização estocástica , sendo a variação primária que definimos o gradiente para os parâmetros quantizados como zero.
O resultado
O código
1023 bytes, codificados com
xxd
(decodifique comxxd -r
). Eu usei a versão 2016-01-22 do Pyth que estava atual quando este desafio foi lançado. Você pode executar o código diretamente no Pyth, mas o Pyth no PyPy3 (pypy3 pyth starry.pyth
) executa nove vezes mais rápido, em cerca de 3 minutos. A imagem de saída é gravada emo.png
.Como funciona
Treinamento
Durante meu treinamento final, usei um cronograma de quantização muito mais lento e fiz algumas brincadeiras interativas com isso e a taxa de aprendizado, mas o código que usei foi mais ou menos o seguinte.
Visualização
Esta imagem mostra as ativações de todos os 45 neurônios em função das coordenadas x , y . Clique para ampliar.
fonte
Mathematica, pontuação 14125.71333
Salva esta imagem:
para
a.png
.fonte
Java, 7399.80678201
Isso me lembrou um projeto que eu tinha na minha aula de computação numérica alguns semestres atrás, que era desenhar uma silhueta do Monte Everest usando interpolação polinomial. Isso foi feito no MATLAB, mas eu não gosto muito do MATLAB, então decidi trabalhar em Java. A idéia básica por trás disso é que eu escolhi pontos "inteligentes" (lidos aqui como "aleatórios") para a interpolação polinomial. Com os poucos bytes restantes, criei uma maneira de desenhar as estrelas, o que acontece antes do desenho da montanha. Pode ser possível condensar o código e adicionar outro polinômio na parte inferior para ajudar a melhorar a pontuação.
Editar: eu adicionei e alterei alguns dos polinômios e adicionei todas as estrelas. Minha pontuação anterior foi de 9807.7168935, portanto, como você pode ver, é uma grande melhoria. Infelizmente, o código prejudicou sua legibilidade, porque tive que extrair os últimos bytes para obter todas as estrelas e dar-lhes grupos.
Qual o valor do frete para o seu CEP?
fonte
Python3.4 +, 4697.26
Usei o mesmo método da resposta do ImageMagick, mas com os seguintes parâmetros:
Usando esses parâmetros, gerei o seguinte programa Python de 1003 bytes (não encontrei nenhuma melhoria no método de saída do @ kennytm):
Por sua vez, gera esta imagem:
fonte
1
a partir delatin1
e salvar um espaço em branco deimport *
, pelo menos. Mas jogar golfe não era uma prioridade (já que tem menos de 1024 bytes).Python 3, pontuação 5701,31
Basta redimensionar a partir de uma imagem PNG de 18 × 13.
fonte
Java, 8748.95
Outra abordagem:
Criei uma classe que calcula um diagrama de Voronoi a partir de um determinado conjunto de pontos. Este conjunto de pontos é usado como o conjunto de parâmetros que serve como entrada para o Apache BOBYQAOptimizer . A função de avaliação do otimizador pega os pontos e cria um diagrama voronoi a partir deles. As regiões voronoi são coloridas com a cor média da região correspondente da imagem original.
O processo de otimização é mostrado aqui:
A imagem final é esta:
que alcança uma pontuação de 8748,95
(Isso foi medido com minha própria função, mas deve ser o mesmo que com o script de avaliação)
O resultado desse processo é apenas um conjunto de 8 pontos e as cores correspondentes. (Um número maior de pontos causou piores resultados, mas não tentei fazer isso extensivamente).
O código resultante é mostrado aqui (desculpe, eu tive que jogar um pouco para apertar no limite de 1kB):
(Eu sei, existem algumas maneiras fáceis que poderiam ter alcançado melhores resultados, mas ... isso de alguma forma foi divertido ...)
Em resposta ao comentário, sobre o estilo artístico de uma imagem tão voronoi com um número maior de pontos: isso realmente parece interessante, e algumas ferramentas de imagem realmente oferecem isso como um "Filtro Mosaico" - por exemplo, o Filtro Mosaico no GIMP ( embora isso ofereça opções para enfatizar as arestas, etc.).
Aqui está um exemplo da imagem da Noite Estrelada, com 256 pontos. (Eles são selecionados aleatoriamente, mas com um número maior de pontos, a melhoria que poderia ser alcançada por uma otimização desaparecerá).
Isso não faz parte do concurso (pois não cabe em 1kB), apenas para os curiosos:
fonte
import java.util.*;
De fato, altere todas as classes de importação para asteriscos.AutoIt ,
9183.257882.53ATUALIZAR
Portanto, redesenhar a imagem como uma criança (bêbada) é mais eficaz do que armazenar qualquer versão da imagem. (Mais eficaz do que minha solução antiga).
Toda linha que desenha um elemento é crucial para diminuir a pontuação. Suspeito que este programa seja capaz de obter pontuações bem abaixo de 7000, com modificações muito pequenas, porque cada alteração tem efeitos enormes (~ 20 a 100 pontos) na pontuação. O programa usa minha
processing
biblioteca de gráficos que fornece nomes de funções concisos para desenhar usando GDI.Como essa solução envolve aleatoriedade, semeamos o PRNG usando o valor constante
0
usandoSRandom(0)
. Por que 0? Porque é até 50 pontos melhor do que qualquer outro quen<=100
eu tentei.A tela começa como um espaço em branco
#587092
.Gerando o piso
A parte inferior da imagem (que começa com exatamente 233px [novamente, por causa dos pontos]) é preenchida com exatamente
int(1e4*2.9)
elipses. Alterar o fator aqui (ou uma casa decimal do fator) pode diminuir e aumentar a pontuação em centenas de pontos. Eu me conformei com 2,9 depois de algumas tentativas. Naturalmente, isso levará algum tempo (alguns segundos).Uma paleta de cinco cores é fornecida:
Gotas no chão
Quatro elipses são usadas para definir acentos de contraste dentro da área do piso (
$4
é um ponteiro de função paraellipse()
):Gerando acentos no céu
Algumas linhas são desenhadas usando uma caneta mais grossa para representar áreas de cores significativas no céu que são muito esticadas para elipses:
Pesando os pixels
Após o exposto, tudo é enxaguado e repetido até ficar sem bytes. Em seguida, um borrão é aplicado para enganar o método de validação. Pela força bruta, foi determinado que um raio de exatamente 20 fornece o melhor resultado. Isso melhora a pontuação por rodada cerca de 1,5k (!).
Imagem final
Código, 985 bytes
RESPOSTA ANTIGA
Isso armazena 80 valores de cores que compõem uma imagem de 10x8 px. Essa imagem bruta tem uma pontuação de 10291. Como 10x8 é um fator de pixelização de 40px, um desfoque gaussiano é aplicado usando um raio de 40px para diminuir a pontuação. É assim que o script atinge 9183.25.
Estes são os dados armazenados:
O arquivo produzido é True.png:
O programa tem 998 bytes :
fonte
1e4*2.9
igual a29e3
?Arquivo BAT do Windows, pontuação 4458.854
O tamanho do programa é 1024 bytes.
Converte da imagem BPG codificada em base64 para PNG.
Usa o certutil.exe (utilitário padrão do Windows) e o decodificador de imagem bpgdec.exe como bibliotecas.
Compressão:
fonte
C ++ 11,
7441.681261056997.654348335198.16107651Mais atualizações
Gostei tanto das elipses do Perl que tive que experimentá-las no C ++ 11. Eu usei a string bruta para inserir bytes, mas por um tempo eu estava tendo uma pequena discrepância com a pontuação que esperava e o código gerado. Acontece que você realmente não pode colocar um 0x0d bruto (retorno de carro), pois o g ++ o converterá em 0x0a (nova linha). Sinceramente, não tenho certeza de quão legítima essa fonte gerada é, mas ela compila e funciona em algumas das minhas máquinas.
Eu também experimentei outro algoritmo, o Adaptive Dimensional Search, depois que o GA pareceu ter parado, apenas para tentar diminuir o mínimo local e talvez ter sorte e cair em outro poço.
Com isso, o C ++ 11 fornece uma pontuação surpreendentemente competitiva (muito melhor do que eu imaginaria) ... Estou bastante surpreso que ele possa fazer isso com o fstream, como o único incluído.
Texto (sim, as novas linhas estão na fonte real ... suponho que eu possa removê-las):
Hexdump:
Essa resposta combina várias abordagens das respostas anteriores, que explicarei abaixo. Infelizmente, acabei tendo que jogar um pouco no programa para caber nos
944949 caracteres (de acordo comwc -c
), para que ele não se pareça mais com C ++ (desculpas se isso é contra as regras do desafio, vou tentar algumas melhorias em breve). Eu não planejei isso no começo, então ainda não é completamente indecifrável e ainda há muitas frutas baixas.Resultados atualizados
Simplesmente executar o algoritmo genético por mais tempo produziu um resultado um pouco melhor; no entanto, como a convergência diminuiu significativamente, eu diria que esse método em particular provavelmente está começando a se destacar (ou caí em um mínimo local profundo). Joguei o programa final um pouco mais para espremer mais alguns retângulos (o gerador permanece o mesmo, exceto que o tamanho máximo do genoma foi aumentado).
A implementação do cruzamento entre indivíduos ajudará se o problema for um mínimo local profundo, mas, como ele permanece no mesmo intervalo por um tempo, estou começando a pensar que isso é tão bom quanto o número de retângulos.
Versão Voronoi, 7331.92407536, 989 caracteres
Eu costumava Idea Voronoi de Marco13 com o meu código GA. Isso realmente não funcionou tão bem quanto eu esperava. Eu só conseguia espremer mais alguns pontos do que retângulos. Eu acho que a natureza potencialmente disjunta dos retângulos devido à sobreposição ajuda a pontuação um pouco. Independentemente disso, eu realmente gosto da maneira como isso parece significativamente melhor, apesar da pontuação semelhante à minha primeira entrada.
Resultados antigos, 7441.68126105, 944 caracteres
Assim como algumas das outras entradas, o programa desenha retângulos sobrepostos. Ele usa PPM binário, já que o formato é simples (a saída é
a.ppm
, mas eu enviei uma versão png porque o SE não gostou do PPM) e é completamente determinístico.Explicação
A geração do PPM ocupou uma boa parte do código padrão, o que significava que eu não poderia ter muitos retângulos mesmo depois de jogar um pouco de golfe. Provavelmente mais alguns podem ser espremidos aqui para melhorar ainda mais a pontuação.
A verdadeira mágica é a lista de retângulos. Semelhante à resposta de Wolfgang, usei um algoritmo genético para encontrá-los. Na verdade, a implementação é bastante incompleta, uma vez que a recombinação entre os indivíduos ainda não ocorre, mas a mutação ainda acontece e a classificação no estilo de torneio por condicionamento físico mantém os melhores organismos na próxima rodada. O elitismo também é usado, pois uma cópia do melhor indivíduo da última rodada é mantida na próxima rodada, para que o organismo mais apto seja sempre pelo menos tão adequado quanto na rodada anterior.
Eu não olhei muito de perto o código de Wolfgang desde que comecei isso ontem, mas parece que ele permite que a cor também varie, o que pode explicar a diferença de pontuação.
Para manter o espaço de pesquisa menor, olhei apenas para a posição do retângulo; a cor é calculada pela média por canal dos pixels visíveis desse retângulo, já que temos a imagem de origem (acho que não podemos fazer nada melhor do que isso para esse retângulo específico, pois isso minimiza a distância ao quadrado).
Vou colocar um repositório do github nas próximas edições, se continuar trabalhando, mas por enquanto o código (arquivo único) está no pastebin . Compilá-lo no modo C ++ 11, (observação: estou muito envergonhado com o quão confuso é mesmo para um caso único).
Você também precisará de uma imagem P3 PPM da noite estrelada, nomeada
ORIGINAL.ppm
para que isso funcione. Você pode fazer o download do arquivo neste GitHub Gist .fonte
i r,g,b
vez de separadamente, e muitos espaços podem ser descartados). Eu não tinha certeza se o programa deveria gerar o arquivo diretamente ou se a tubulação para stdout / stderr estava correta.#include <fstream>
? Além disso, soltar as novas linhas e colocar tudo em uma linha desde C ++ precisa de ponto e vírgula de qualquer maneiraImageMagick, 4551.71
Usa a linguagem de 'programação' do ImageMagick, usando as seguintes opções (pode ser necessário escapar da
!
):Supondo o seguinte arquivo de origem de 968 bytes (fornecido como hexdump):
Produzindo esta imagem:
Você provavelmente está se perguntando como eu gerei o arquivo de entrada, e a resposta é bastante simples. Redimensione para 48x40 com o filtro Lanczos, use uma paleta indexada de 20 cores e otimize o PNG resultante.
Usa
convert
,pngquant
,optipng
eadvdef
.fonte
=(tail +2 $0)
truque da minha resposta , você pode criar um único script ZSH que contém o script ImageMagick e o arquivo de entrada PNG.Python 2, 4749,88
1018 bytes
Todo mundo provavelmente já esqueceu esse problema até agora, exceto eu ....
Esse problema me interessou demais, principalmente porque rapidamente ficou claro que as abordagens que usam algoritmos de compactação de imagem estavam definitivamente na liderança, mas, de alguma forma, eram insatisfatórias do ponto de vista estético. As abordagens baseadas na otimização de um conjunto de primitivas de desenho foram de alguma forma mais agradáveis do ponto de vista estético do código, mas pareciam bloqueadas logo acima da pontuação de 5.000.
O método de nneonneo que não usou uma compactação de imagem pronta para uso ultrapassa a marca de 5000, mas o faz codificando uma imagem minúscula e aumentando sua escala.
Aqui está um programa que usa apenas primitivas de desenho, é gerado automaticamente por um método de otimização e consegue obter uma pontuação de 4749,88.
que se parece com isso:
e o hexdump do código:
Ele usa vários truques usados anteriormente aqui:
Como primeiro primitivo, coloco uma linha do horizonte, dividindo a imagem em dois blocos coloridos diferentes. Posteriormente, como primitivo básico, usei um círculo arrastado entre dois pontos. Isso parecia vagamente uma pincelada para mim, mas era possível expressar em 7 bytes. Para o processo de pesquisa, usei uma pesquisa guiada de padrões. Ele prossegue adicionando alternadamente um primitivo e otimizando seus parâmetros. A primitiva é adicionada no ponto em que o erro borrado assinado é mais alto. Os parâmetros são otimizados pela otimização exaustiva da linha em um domínio pequeno, um após o outro. Quarenta a cinquenta primitivas são adicionadas e otimizadas individualmente. Em seguida, a lista de primitivas é reduzida ao tamanho máximo, jogando fora as primitivas que ajudam menos a pontuação.
Isso ainda não supera a pontuação de nneonneo. Para atingir essa pontuação, foi necessária uma otimização do segundo estágio, que passa novamente pelo processo de adicionar primitivas em cada um dos vários níveis de filtragem e jogar as primitivas fora para reduzir o tamanho do programa gerado. O que foi realmente interessante para mim foi a ideia de aplicar isso a outras imagens. Apliquei-o a algumas outras imagens e forneço mais detalhes e animação das primitivas sendo desenhadas no meu blog aqui .
Os dois programas usados para gerar isso não cabem no espaço permitido nas postagens do Stack Exchange, mas estão no github: https://github.com/str4w/starrynight/tree/StackExchange
a noite estrelada é executada primeiro, seguida pela stage2optimization. O programa resultante também está lá, no mesmo diretório.
fonte
Matlab, pontuação 5388,3
Sem qualquer compactação embutida. A profundidade da cor é reduzida para que cada pixel possa ser representado por um caractere imprimível. E a resolução é reduzida. Isso é codificado como uma string. O código em si reverte todo o processo. A operação de redimensionamento está usando um kernel de interpolação Lanczos 3.
fonte
zsh + bpgdec, 4159.061760861207
Sim, outra solução BPG. Acho que isso serve basicamente para provar que o BPG é o melhor utilitário de compactação de imagem atualmente disponível. Considere isso uma melhoria em relação à solução BPG original da yallie .
O arquivo tem 1024 bytes, no limite. Consiste na linha
seguido pela produção bruta de BPG de
Em hexadecimal, este é o script:
O arquivo resultante é
out.png
(obpgdec
local padrão), parecido com este:Acho surpreendente que
bpg
, em meros 996 bytes, tenha reconstruído com precisão os contornos agudos da árvore, à esquerda, e as colinas à direita. Ele ainda tem uma aproximação aceitável para a torre da igreja! O nível de detalhe é muito impressionante (para mim) para o tamanho pequeno do arquivo. Obviamente,bpgdec
ele não é um programa pequeno, mas está claro para mim que o BPG é uma ordem de grandeza melhor que o JPEG para a compressão de imagens.Como isso
bpgdec
se aplica, obviamente, essa resposta não é elegível para a recompensa.EDITADO: Adicionado
-n
argumentotail
para torná-lo compatível com o GNUtail
.fonte
tail: cannot open ‘+2’ for reading
. No Ubuntu, ele precisa-n +2
, o que o coloca em 1025 bytes = /-n+2
que o coloca exatamente em 1024 bytes - experimente e deixe-me saber se isso funciona. Vou mudar minha resposta para compatibilidade.C, 6641
999 bytes, usando apenas
stdio.h
emath.h
.Eu
d()
criei uma função de círculo preenchido que desenha círculos coloridos RGB concêntricos sobre os valores de raio r..0. 21 círculos são usados aqui. Eu poderia espremer um pouco mais se removesse mais espaços em branco, mas gosto da legibilidade relativa.Eu descobri o posicionamento do círculo aproximado usando as camadas Gimp no
Difference
modo. Procure os pontos brilhantes, adicione um círculo, repita.Histogram
Ferramenta usada na seleção para determinar as cores iniciais a serem usadas.Eu obtive uma pontuação de cerca de 7700 usando o exposto acima, mas achei que poderia fazer melhor aprimorando os valores de cor e raio, então escrevi um código de andaime para a força bruta otimizar cada valor modificando -10 .. + 10, renderização, executando o validador (que eu reescrevi em C para velocidade) e salvando o valor que produziu a menor pontuação. No final, ele despeja a matriz de valores, que eu colo de volta no código e recompile. Fiz algumas passagens e o placar diminuiu em cerca de 1000. Depois, retirei o código do andaime.
Código,
fonte
((x-xo)*(x-xo) + (y-yo)*(y-yo)) <= (r*r)
) parece que seria mais curta e eliminaria a dependênciamath.h
. Com esse tamanho de imagem, também não acho que algo possa transbordar.Python 3, pontuação 5390.25, 998 bytes
Usei um programa de recozimento simulado para ajustar os retângulos na forma de Noite Estrelada. Em seguida, ele usa um desfoque gaussiano para suavizar as bordas retangulares retas.
Para economizar alguns bytes, eu comprimi os dados do retângulo na base 94.
fonte
Python 2, 5238,59 pontos
Provavelmente é hora de postar minha própria resposta. Aqui está a imagem
O código fica assim
Ou como um dump hexadecimal:
Simplesmente descompacta essa cadeia longa nos parâmetros para desenhar 95 elipses translúcidas.
Como muitas das outras respostas, o código é gerado usando um algoritmo genético. Ele usa um tipo específico de algoritmo genético que eu inventei, que eu chamo de "algoritmo de pool genético", embora seja inteiramente possível que alguém também o tenha inventado e lhe tenha dado um nome diferente. Em vez de ter uma população de indivíduos, temos 95 "conjuntos de genes", um para cada gene. Cada pool genético contém 10.000 versões diferentes do gene. Um gene contém os parâmetros para uma elipse (posição, forma, cor, alfa e seu lugar na ordem z). Em cada iteração, criamos duas imagens selecionando um gene de cada um dos 95 pools, e os genes da imagem de menor pontuação substituem os genes da imagem de pior pontuação, com uma pequena mutação.
Executei-o até a 378000ª iteração, que levou alguns dias. Nesse ponto, a pontuação ainda estava caindo, mas bem devagar, então duvido que fique muito melhor do que isso sem algumas alterações no algoritmo.
Aqui está o código do algoritmo genético:
Finalmente, aqui está uma animação , mostrando o algoritmo em ação. Ele mostra a melhor imagem gerada até agora após cada 1000 iterações. (O arquivo gif era muito grande para ser incorporado nesta postagem.)
Provavelmente, pode ser aprimorado (1) usando o truque de codificação de nneonneo para inserir mais dados na string; (2) adicionando um desfoque gaussiano ao final do código de renderização (mas isso o tornará mais lento) e (3) melhorando ainda mais o algoritmo. No momento, ele atinge uma pontuação decente muito rapidamente, mas depois muda muito lentamente - se eu desacelerar a convergência inicial de alguma forma, poderá encontrar um resultado melhor no final. Talvez eu implemente essas coisas em algum momento.
fonte
Estrelado ,
11428.189450210904.307927710874.1307958Estrelado pode não ser o melhor idioma para fazer isso, mas é certamente o mais adequado.
Você pode experimentá-lo on-line, no entanto, parece que a saída está truncada para que você não obtenha a imagem completa.
Este programa gera arquivos ppm descompactados para a saída padrão.
Aqui está a saída do programa:
Explicação
Para que o programa produza todos os 123.520 pixels necessários, divida a imagem em 8 bandas horizontais e criei 7 loops, os 6 primeiros imprimem uma banda, enquanto o último imprime duas bandas da mesma cor. O código consiste em um cabeçalho, que informa ao arquivo ppm como se formatar e os 7 loops mencionados acima.
fonte
Python 2, 4684.46
1021 bytes.
Isso usa um método de decodificação muito semelhante a algumas outras respostas, mas é no Python 2, portanto, são dados codificados em base64 em vez de base85.
Os dados codificados são uma imagem no formato WebP de 64x48.
Aqui está o código que eu usei para encontrar a melhor configuração de tamanho e qualidade de imagem. Restrinja o espaço de pesquisa para que não demore mais do que alguns minutos para ser executado.
fonte
Python 2,
5098.245080.044869.154852.874755.88589004Nenhuma descompressão interna usada! Apenas o utilitário de redimensionamento do PIL e uma imagem de 16 cores decodificada manualmente. Portanto, deve ser elegível para a recompensa.
O programa contém caracteres não-ASCII incorporados. Ele tem 1024 bytes e fica assim:
e em hexadecimal:
e gera esta imagem:
Este programa abusa do fato de que você pode basicamente inserir bytes não processados no código-fonte Python, desde que você escape de NULs e barras invertidas.
O programa em si consiste em uma paleta de 16 entradas (a
|
sequência separada) e uma imagem de 16 cores 40x41 (codificada com 4 bits por pixel e decodificada por abuso.encode('hex')
). A imagem é redimensionada para o tamanho apropriado com um filtro bicúbico, e é isso.A imagem real foi gerada com o ImageMagick:
e os dados da paleta e da imagem foram extraídos do BMP resultante. (Observe que solicitamos 18 cores do ImageMagick, pois o IM insere automaticamente algumas entradas não utilizadas).
A paleta foi reorganizada levemente para reduzir o número de caracteres de escape nos dados binários, e os dados binários finais foram editados um pouco à mão para fazer com que tudo se encaixasse em 1024 bytes.
EDITADO: Golfou um pouco o código e melhorou a precisão solicitando 17 cores do ImageMagick.
EDITADO: Desativar o pontilhamento produziu uma enorme melhoria na pontuação. Ele agora tem uma pontuação abaixo de 5000 e está se tornando competitivo com algoritmos de compactação prontos para uso!
EDITADO: A adição
-filter Cosine
oferece outra melhoria considerável. O golfe agressivo, graças ao @primo pelo truque da UTF-8 BOM, permitiu-me dar outra linha à imagem, melhorando ainda mais a pontuação.fonte
!
verdade, é flanqueado em ambos os lados por caracteres não imprimíveis. A cor é toda#1d211e
, que é um cinza escuro ligeiramente azulado.#coding:latin
linha pode ser substituída por uma marca de pedido de byte UTF-8:
(0xEF, 0xBB, 0xBF).zsh + FLIF + ImageMagick, 4358,14
Com o BPG roubando os holofotes como um codec com perdas, refinei minha abordagem sofisticada sem perdas para usar FLIF em vez de PNG, usando o truque zsh de @ nneonneo. O ImageMagick é usado apenas aqui como um upscaler.
O hexdump (desta vez com
xxd
, não percebi que nãohexdump
era padrão na minha última resposta):Eu gerei o script usando ... outro script:
fonte
Mathematica, 5076.54
Pesando exatamente 1024 bytes, finalmente consegui bater a pontuação de nneonneo ... até que ele a melhorou uma hora atrás = (
Não usa algoritmos de compactação "prontos para uso".
(Melhor descrição depois)
fonte
HTML / JavaScript,
10855.838000.55 (± ~ 5, com base no navegador)A pontuação pode variar um pouco devido a diferenças no navegador ou na GPU.
Você deve clicar com o botão direito do mouse em> Salvar imagem como para salvar os dados da tela como uma imagem, mas essa é a única interação necessária.
Usei o GIMP para selecionar determinadas áreas e encontrar sua média. Em particular, a ferramenta selecionadora de cores e o recurso "diferença de camada" foram muito úteis.
Tentativa nº 1 (10855,83)
Tentativa nº 2 (8000,55)
fonte
Scala, 6003.56
993 caracteres. Uma importação é a biblioteca de imagens scala . A segunda importação é o codificador base 91 .
Estes são os dados base91:
fonte
Java, pontuação 12251.19
Baseado nesta resposta do Mathematica , mas com mais retângulos. Provavelmente continuarei a modificar isso mais tarde.
Resultados:
Algumas versões anteriores:
fonte
Python 2 (sem compactação interna), pontuação 4497.730
Isso usa a mesma abordagem de imagem de 16 cores decodificada manualmente que a minha resposta anterior , mas desta vez apliquei uma estratégia de otimização de descida de gradiente para melhorar significativamente a pontuação. O envio anterior obteve 4755.886 pontos, enquanto o novo envio obteve mais de 250 pontos, superando muitas abordagens de compactação integradas no processo.
Como antes, o programa final tem exatamente 1024 bytes. De fato, a saída bruta do algoritmo de otimização continha quatro bytes que foram escapados (
\0
) e que eu tive que "manipular" para reduzir a contagem de bytes para 1024 bytes. Sem o fudge, o programa de 1028 bytes pontuaria 4490.685 - 7 pontos melhor.A idéia básica é otimizar a paleta e os dados em conjunto. Em uma única iteração, procuro por todos os ajustes da paleta (basicamente, todas as paletas modificadas que diferem 1 em algum componente de cor) e escolho a paleta modificada que melhor melhora a pontuação. Então, pesquiso todos os ajustes dos dados (toda matriz de índice modificada na qual um pixel é alterado para outra entrada da paleta) e escolho uma modificação que reduz a pontuação (aqui não me interessa mais, porque não deseja pesquisar sem sucesso o espaço completo de mais de 25000 ajustes a cada iteração).
Finalmente, ao gerar a saída final do programa, eu executo outra passagem de otimização que reorganiza a paleta para minimizar o número de barras invertidas necessárias na saída final (por exemplo, para o programa mostrado abaixo, a paleta foi reorganizada usando a tabela hexadecimal "0e3428916b7df5ca").
Essa abordagem gerou uma melhoria numérica e perceptiva significativa em relação à abordagem ingênua anterior do ImageMagick. Saída de envio anterior:
E nova saída de envio:
A nova abordagem baseada em otimização possui significativamente mais detalhes e reprodução precisa das cores.
Aqui está o hexdump do programa final:
Ainda há espaço para melhorar. Por exemplo, um histograma simples mostra que algumas cores são pouco usadas:
Isso sugere que uma paleta reequilibrada pode melhorar a eficiência, talvez o suficiente para pegar a solução de BPG em 5º lugar. No entanto, tenho muita dúvida de que essa abordagem de otimização (ou realmente qualquer coisa que não envolva o extraordinário mecanismo do H.265) possa pegar o primeiro lugar na implementação de BPG.
fonte
Perl,
5955.968781245149.56218378Observando a abordagem "sem sentido imprevisível", decidi que também poderia tentar isso em Perl. Novamente, eu realmente não conheço Perl, então tenho certeza de que isso pode ser melhorado (na verdade, a melhoria mais óbvia, redução para 7 bytes por elipse, omitindo o canal alfa, já foi implementada para a próxima versão, mas eu ' ainda estou trabalhando em outras partes desse código; também estou pensando que todo o negócio do pop / push pode ser mais praticado.
Eu não acho que isso realmente funcione em máquinas Windows (não posso testar), pois não consegui descobrir uma maneira fácil de abrir a seção DATA no modo binário - no entanto, funcionou nas minhas máquinas Linux.
Consegui basicamente continuar usando meu mesmo código GA para criar:
Onde a saída xxd é:
O que gera a imagem:
É interessante que, apesar de ter uma pontuação melhor, a imagem pareça um pouco pior para mim - há muita coisa acontecendo com todas as elipses extras, de alguma forma a imagem mais simples é mais fácil de lidar visualmente.
Resultados antigos
Depois de ver a resposta de jamieguinan , usei elipses como um primitivo de desenho, já que em Perl tenho acesso à biblioteca GD para desenhar. Como não sou especialista em Perl, qualquer sugestão seria útil. Eu usei um algoritmo genético que foi modificado da minha resposta C ++ .
Parece funcionar bem, mas sinceramente estou um pouco decepcionado com o placar. Eu provavelmente poderia deixar isso correr um pouco mais, já que você pode ver facilmente que algumas elipses não estão nas posições ideais. No entanto, mesmo agora, parece mais agradável aos meus olhos em comparação à solução baseada em retângulo.
fonte
Bash + Netpbm,
4558,54394,1UPDATE: Melhorei a pontuação usando SPIHT em vez de FIASCO.
SPIHT é um acrônimo para Conjunto de Particionamento em Árvores Hierárquicas. É um formato de compactação de imagem baseado em wavelet altamente eficiente.
Recuei o PNG original por trimestre, em seguida, convertido em PNM usando
pngtopnm
a partir Netpbm v. 10,68, em seguida, removidos do cabeçalho e converteu os dados não processados para SPIHT comcodecolr in.raw out.spi 80 96 0.95
e tem o ficheiro de imagem 913-byte. Depois converti-o novamente para RAW usandodecdcolr -s out.spi out.raw 0.95
, depois convertido para o formato PNM usandorawtoppm -bgr 96 80
, invertido usandopamflip -tb
, redimensionado para o tamanho original usandopamscale -xsize 386 -ysize 320 -filter sinc
e salvo no arquivo PNM, que é lido pelo PIL. Aqui está o meu script (1 KB):Aqui está o PNG de saída:
Abaixo está a minha resposta mais recente:
FIASCO é um acrônimo para Fractal Image And Sequence COdec, é uma implementação altamente eficiente de compactação fractal com perdas .
I encolheu o PNG original por trimestre, então convertido em PNM usando
pngtopnm
de Netpbm v. 10,68, então convertido em fiasco compnmtofiasco -q=14 -z=3
e tenho o arquivo de imagem de 969 bytes. Depois converti-o novamente para PNM usandofiascotopnm
, redimensionado para o tamanho original usandopamscale -xyfill 386 320
e salvei no arquivo PNM, que é lido pelo PIL. Aqui está o meu script (1 KB):Na verdade, eu fiz isso primeiro no Windows
cmd
, mas o script não se encaixava em 1 KB. Então eu o reescrevibash
. Aqui está o PNG de saída:fonte
Ruby, 7834.38
Isso foi divertido!
Eu usei um programa gerador de ruby para escrever um script ruby da seguinte maneira:
Enquanto o arquivo ruby gerado tiver menos de 1024 bytes:
Observe que meu algoritmo de pontuação seleciona aleatoriamente várias cores e escolhe a que resulta na menor diferença de ORIGINAL.png. Como é probabilístico, executei o script várias vezes e escolhi o resultado com a menor pontuação.
Aqui está o meu melhor roteiro até agora:
Gerou a seguinte imagem, com 7834 pontos:
Para ver como meu algoritmo surgiu, aqui está um GIF animado mostrando como ele divide retângulos:
Meu código está no GitHub em https://github.com/jrotter/starry_night_contest
fonte
Java, 9215.38294502
Lendo a imagem como um GIF com um tamanho de 8x6 pixels (!) A partir de uma String codificada em Base64 (contendo 368 caracteres) e ampliando-a bilinearmente.
EDIT: O resultado, conforme solicitação nos comentários, é mostrado nesta imagem:
fonte
Python 3, 5797.125628604383
O programa de compactação primeiro trunca os bits da imagem e depois converte a base 2 em base 36.
O programa de decodificação faz isso ao contrário e redimensiona a imagem.
fonte