Escreva um programa que obtenha uma imagem RGB colorida I , o número máximo de linhas para desenhar L e o comprimento mínimo e máximo M de cada linha. Saída uma imagem ó que a aparência tanto quanto possível, como I e é desenhado utilizando L ou menos linhas rectas, todos os quais têm comprimento Euclidiana entre m e M .
Cada linha deve ter uma cor sólida, ter os dois pontos de extremidade nos limites de O e ser desenhada usando o algoritmo de linha de Bresenham (o que a maioria das bibliotecas gráficas já fará por você). As linhas individuais podem ter apenas 1 pixel de espessura.
Todas as linhas, mesmo as de comprimento 0, devem ocupar pelo menos um pixel. Linhas podem ser desenhadas umas sobre as outras.
Antes de desenhar qualquer linha, você pode inicializar o fundo de O com qualquer cor sólida (que pode depender de I ).
Detalhes
- O deve ter as mesmas dimensões que eu .
- L sempre será um número inteiro não negativo. Ele pode ser maior do que a área de I .
- m e M são números de ponto flutuante não-negativos com M > = m . A distância entre dois pixels é a distância euclidiana entre seus centros. Se essa distância for menor que m ou maior que M , uma linha entre esses pixels não será permitida.
- As linhas não devem ter antialias.
- Opacidade e alfa não devem ser usados.
- Seu programa não deve demorar mais de uma hora para ser executado em um computador moderno decente em imagens com menos de um milhão de pixels e L inferior a 10.000.
Imagens de teste
Você deve mostrar-nos, naturalmente, as suas imagens de saída precisas ou interessantes a maioria (que eu espero vai ocorrer quando L é entre 5% e 25% do número de pixels em I , e m e M são cerca de um décimo do tamanho diagonal).
Aqui estão algumas imagens de teste (clique para originais). Você também pode postar o seu próprio.
Imagens mais simples:
Este é um concurso de popularidade. A inscrição mais votada vence.
Notas
- Pode ser útil permitir que L seja derivado de uma porcentagem do total de pixels em I , bem como de um valor absoluto. por exemplo,
>>> imageliner I=img.png L=50% m=10 M=20
seria a mesma coisa que>>> imageliner I=img.png L=32 m=10 M=20
seimg.png
fosse uma imagem de 8 por 8 pixels. Algo semelhante poderá ser feito para m e M . Isso não é necessário. - Desde linhas não pode sair dos limites, as linhas mais longas possíveis será o comprimento diagonal de I . Ter M maior que isso não deve quebrar nada.
- Naturalmente, se m for 0 e L for maior ou igual ao número de pixels em I , O poderá ser idêntico a I por ter 0 "linhas" de comprimento em cada localização de pixel. Esse comportamento não é necessário.
- Indiscutivelmente, reproduzir a forma de I é mais importante do que reproduzir a cor. Você pode querer examinar a detecção de borda .
fonte
Respostas:
C ++ - linhas um tanto aleatórias e algumas
Primeiro algumas linhas aleatórias
A primeira etapa do algoritmo gera linhas aleatoriamente, leva para a imagem de destino uma média dos pixels ao longo disso e calcula se o quadrado resumido das distâncias do espaço rgb de todos os pixels seria menor se pintássemos a nova linha (e apenas pinte, se for). A cor das novas linhas para isso é escolhida como a média sábia do canal dos valores rgb, com uma adição aleatória de -15 / + 15.
Coisas que eu notei e influenciei a implementação:
Eu estava experimentando alguns números e escolhi
L=0.3*pixel_count(I)
e saím=10
eM=50
. Ela irá produzir resultados agradáveis a partir de cerca0.25
de0.26
para o número de linhas, mas eu escolhi 0,3 a ter mais espaço para detalhes precisos.Para a imagem em tamanho real do golden gate, isso resultou em 235929 linhas para pintar (pelas quais demoraram 13 segundos aqui). Observe que todas as imagens aqui são exibidas em tamanho reduzido e você precisa abri-las em uma nova guia / fazer o download delas para visualizar a resolução completa.
Apague os indignos
O próximo passo é bastante caro (para as linhas de 235k demorou cerca de uma hora, mas isso deve estar dentro do requisito de tempo "uma hora para 10k linhas em 1 megapixel"), mas também é um pouco surpreendente. Passo por todas as linhas pintadas anteriormente e removo aquelas que não melhoram a imagem. Isso me deixa nesta corrida com apenas 97347 linhas que produzem a seguinte imagem:
Você provavelmente precisará fazer o download e compará-los em um visualizador de imagens apropriado para identificar a maioria das diferenças.
e começar de novo
Agora eu tenho muitas linhas que posso pintar novamente para ter um total de 235929 novamente. Não há muito a dizer, então aqui está a imagem:
breve análise
Todo o procedimento parece funcionar como um filtro de desfoque sensível ao contraste local e ao tamanho dos objetos. Mas também é interessante ver onde as linhas são pintadas; portanto, o programa também as grava (para cada linha, a cor do pixel será tornada um passo mais branca, no final, o contraste é maximizado). Aqui estão os correspondentes aos três coloridos acima.
animações
E como todos nós amamos animações, aqui estão alguns gifs animados de todo o processo para a imagem menor do portão de ouro. Observe que há um pontilhamento significativo devido ao formato gif (e como os criadores de formatos de arquivos de animação em cores verdadeiras e os fabricantes de navegadores estão em guerra por seus egos, não há um formato padrão para animações em cores verdadeiras, caso contrário, eu poderia ter adicionado um .mng ou semelhante )
Um pouco mais
Conforme solicitado, aqui estão alguns resultados das outras imagens (novamente, você pode abri-las em uma nova guia para não reduzi-las)
Pensamentos futuros
Brincar com o código pode dar algumas variações interessantes.
O código
Essas são apenas as duas principais funções úteis, o código inteiro não se encaixa aqui e pode ser encontrado em http://ideone.com/Z2P6Ls
As
bmp
classesraw
e araw_line
função acessam pixels e linhas, respectivamente, em um objeto que pode ser gravado no formato bmp (eram apenas alguns truques e achei que isso tornava isso um pouco independente de qualquer biblioteca).O formato do arquivo de entrada é PPM
fonte
Java - linhas aleatórias
Uma solução muito básica que desenha linhas aleatórias e calcula para elas a cor média da imagem de origem. A cor do plano de fundo é definida como a cor média de origem.
L = 5000, m = 10, M = 50
L = 10000, m = 10, M = 50
EDITAR
Eu adicionei um algoritmo genético que lida com uma população de linhas. A cada geração, mantemos apenas as 50% melhores linhas, descartamos as outras e geramos novas aleatoriamente. Os critérios para manter as linhas são:
Para minha grande decepção, o algoritmo não parece realmente melhorar a qualidade da imagem :-( apenas as linhas estão ficando mais paralelas.
Primeira geração (5000 linhas)
Décima geração (5000 linhas)
Brincando com parâmetros
fonte
C - linhas retas
Uma abordagem básica em C que opera em arquivos ppm. O algoritmo tenta colocar linhas verticais com o comprimento ideal para preencher todos os pixels. A cor do plano de fundo e as cores da linha são calculadas como um valor médio da imagem original (a mediana de cada canal de cores):
L = 5000, m = 10, M = 50
L = 5000, m = 10, M = 50
L = 100000, m = 10, M = 50
fonte
O Python 3 é baseado em "linhas um tanto aleatórias e depois em algumas", além de detecção de borda sobel.
teoricamente, o código pode ser executado para sempre (para que eu possa executá-lo durante a noite por diversão), mas registra seu progresso, para que todas as imagens sejam tiradas da marca de 1 a 10 minutos.
Ele primeiro lê a imagem e, em seguida, usa a detecção de arestas sobel para encontrar o ângulo de todas as arestas, para garantir que as linhas não invadam outra cor. Depois que uma linha do comprimento aleatório dentro (lengthmin, lengthmax) é definida, ela é testada para verificar se contribui com a imagem geral. Enquanto linhas menores são melhores, eu defino o comprimento da linha de 10 a 50.
fonte