Dada uma imagem em preto e branco em qualquer formato razoável sem perdas como entrada, produza arte ASCII o mais próximo possível da imagem de entrada.
Regras
- Somente alimentações de linha e bytes ASCII 32-127 podem ser usados.
- A imagem de entrada será cortada para que não haja espaços em branco estranhos ao redor da imagem.
- As submissões devem poder concluir o corpus de pontuação inteiro em menos de 5 minutos.
- Somente texto bruto é aceitável; sem formatos de texto rico.
- A fonte usada na pontuação é o Linux Libertine de 20 pontos .
- O arquivo de texto de saída, quando convertido em uma imagem como descrito abaixo, deve ter as mesmas dimensões que a imagem de entrada, dentro de 30 pixels em qualquer dimensão.
Pontuação
Essas imagens serão usadas para pontuação:
Você pode baixar um arquivo zip das imagens aqui .
As submissões não devem ser otimizadas para este corpus; em vez disso, eles devem funcionar para quaisquer 8 imagens em preto e branco de dimensões semelhantes. Reservo-me o direito de alterar as imagens no corpus se suspeitar que os envios estão sendo otimizados para essas imagens específicas.
A pontuação será realizada através deste script:
#!/usr/bin/env python
from __future__ import print_function
from __future__ import division
# modified from http://stackoverflow.com/a/29775654/2508324
# requires Linux Libertine fonts - get them at https://sourceforge.net/projects/linuxlibertine/files/linuxlibertine/5.3.0/
# requires dssim - get it at https://github.com/pornel/dssim
import PIL
import PIL.Image
import PIL.ImageFont
import PIL.ImageOps
import PIL.ImageDraw
import pathlib
import os
import subprocess
import sys
PIXEL_ON = 0 # PIL color to use for "on"
PIXEL_OFF = 255 # PIL color to use for "off"
def dssim_score(src_path, image_path):
out = subprocess.check_output(['dssim', src_path, image_path])
return float(out.split()[0])
def text_image(text_path):
"""Convert text file to a grayscale image with black characters on a white background.
arguments:
text_path - the content of this file will be converted to an image
"""
grayscale = 'L'
# parse the file into lines
with open(str(text_path)) as text_file: # can throw FileNotFoundError
lines = tuple(l.rstrip() for l in text_file.readlines())
# choose a font (you can see more detail in my library on github)
large_font = 20 # get better resolution with larger size
if os.name == 'posix':
font_path = '/usr/share/fonts/linux-libertine/LinLibertineO.otf'
else:
font_path = 'LinLibertine_DRah.ttf'
try:
font = PIL.ImageFont.truetype(font_path, size=large_font)
except IOError:
print('Could not use Libertine font, exiting...')
exit()
# make the background image based on the combination of font and lines
pt2px = lambda pt: int(round(pt * 96.0 / 72)) # convert points to pixels
max_width_line = max(lines, key=lambda s: font.getsize(s)[0])
# max height is adjusted down because it's too large visually for spacing
test_string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
max_height = pt2px(font.getsize(test_string)[1])
max_width = pt2px(font.getsize(max_width_line)[0])
height = max_height * len(lines) # perfect or a little oversized
width = int(round(max_width + 40)) # a little oversized
image = PIL.Image.new(grayscale, (width, height), color=PIXEL_OFF)
draw = PIL.ImageDraw.Draw(image)
# draw each line of text
vertical_position = 5
horizontal_position = 5
line_spacing = int(round(max_height * 0.8)) # reduced spacing seems better
for line in lines:
draw.text((horizontal_position, vertical_position),
line, fill=PIXEL_ON, font=font)
vertical_position += line_spacing
# crop the text
c_box = PIL.ImageOps.invert(image).getbbox()
image = image.crop(c_box)
return image
if __name__ == '__main__':
compare_dir = pathlib.PurePath(sys.argv[1])
corpus_dir = pathlib.PurePath(sys.argv[2])
images = []
scores = []
for txtfile in os.listdir(str(compare_dir)):
fname = pathlib.PurePath(sys.argv[1]).joinpath(txtfile)
if fname.suffix != '.txt':
continue
imgpath = fname.with_suffix('.png')
corpname = corpus_dir.joinpath(imgpath.name)
img = text_image(str(fname))
corpimg = PIL.Image.open(str(corpname))
img = img.resize(corpimg.size, PIL.Image.LANCZOS)
corpimg.close()
img.save(str(imgpath), 'png')
img.close()
images.append(str(imgpath))
score = dssim_score(str(corpname), str(imgpath))
print('{}: {}'.format(corpname, score))
scores.append(score)
print('Score: {}'.format(sum(scores)/len(scores)))
O processo de pontuação:
- Execute o envio para cada imagem de corpus, produzindo os resultados em
.txt
arquivos com a mesma raiz que o arquivo de corpus (feito manualmente). - Converta cada arquivo de texto em uma imagem PNG, usando uma fonte de 20 pontos, cortando o espaço em branco.
- Redimensione a imagem resultante para as dimensões da imagem original usando a reamostragem de Lanczos.
- Compare cada imagem de texto com a imagem original usando
dssim
. - Saída da pontuação dssim para cada arquivo de texto.
- Saída a pontuação média.
A similaridade estrutural (a métrica pela qual dssim
calcula as pontuações) é uma métrica baseada na visão humana e na identificação de objetos nas imagens. Em outras palavras: se duas imagens se parecem com seres humanos, elas provavelmente terão uma pontuação baixa dssim
.
O envio vencedor será o envio com a menor pontuação média.
.txt
arquivos"? O programa deve produzir texto que será canalizado para um arquivo ou devemos produzir um arquivo diretamente?Respostas:
Java, pontuação 0.57058675
Esta é realmente a minha primeira vez fazendo manipulação de imagens, por isso é meio estranho, mas acho que ficou bom.
Não consegui que o dssim funcionasse na minha máquina, mas consegui fazer imagens usando o PIL.
Curiosamente, a fonte me diz em Java que cada um dos caracteres que estou usando tem largura
6
. Você pode ver que no meu programaFontMetrics::charWidth
é6
para todos os caracteres que eu usei. O{}
logotipo parece bastante decente em uma fonte monoespaçada. Mas, por algum motivo, as linhas não se alinham no arquivo de texto completo. Eu culpo as ligaduras. (E sim, eu deveria estar usando a fonte correta.)Em fonte monoespaçada:
Depois de executá-lo através da ferramenta de imagem:
Enfim, aqui está o código real.
Compilar:
C:\Program Files\Java\jdk1.8.0_91\bin
)AsciiArt.java
javac AsciiArt.java
jar cvfe WhateverNameYouWant.jar AsciiArt AsciiArt.class
Uso
java -jar WhateverNameYouWant.jar C:\full\file\path.png
:, imprime em STDOUTSOLICITA que o arquivo de origem seja salvo com profundidade de 1 bit e a amostra de um pixel branco
1
.Pontuação de saída:
fonte
-ea
para ativar asserções. Isso não mudará o comportamento (exceto, talvez, desacelerar uma pequena quantia) porque as asserções funcionam com falha no programa quando avaliamfalse
e todas essas asserções passam.