Dada una imagen en blanco y negro en cualquier formato razonable sin pérdidas como entrada, envíe el arte ASCII que esté lo más cerca posible de la imagen de entrada.
Reglas
- Solo se pueden utilizar avances de línea y bytes ASCII 32-127.
- La imagen de entrada se recortará para que no haya espacios en blanco extraños que rodeen la imagen.
- Las presentaciones deben poder completar todo el corpus de puntuación en menos de 5 minutos.
- Solo se acepta texto sin formato; No hay formatos de texto enriquecido.
- La fuente utilizada en la puntuación es Linux Libertine de 20 puntos .
- El archivo de texto de salida, cuando se convierte en una imagen como se describe a continuación, debe tener las mismas dimensiones que la imagen de entrada, dentro de 30 píxeles en cualquier dimensión.
Puntuación
Estas imágenes se utilizarán para puntuar:
Puede descargar un archivo zip de las imágenes aquí .
Las presentaciones no deben optimizarse para este corpus; más bien, deberían funcionar para 8 imágenes en blanco y negro de dimensiones similares. Me reservo el derecho de cambiar las imágenes en el corpus si sospecho que las presentaciones se están optimizando para estas imágenes específicas.
La puntuación se realizará a través de este 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)))
El proceso de puntuación:
- Ejecute el envío para cada imagen de corpus, enviando los resultados a
.txt
archivos con la misma raíz que el archivo de corpus (hecho manualmente). - Convierta cada archivo de texto en una imagen PNG, utilizando una fuente de 20 puntos, recortando espacios en blanco.
- Cambie el tamaño de la imagen resultante a las dimensiones de la imagen original utilizando el remuestreo de Lanczos.
- Compare cada imagen de texto con la imagen original usando
dssim
. - Salida de la puntuación dssim para cada archivo de texto.
- Salida del puntaje promedio.
La similitud estructural (la métrica por la cual se dssim
calculan los puntajes) es una métrica basada en la visión humana y la identificación de objetos en imágenes. Para decirlo claramente: si dos imágenes se parecen a las de los humanos, probablemente tendrán una puntuación baja dssim
.
La presentación ganadora será la presentación con el puntaje promedio más bajo.
.txt
archivos"? ¿Debería el programa generar texto que se canalizará a un archivo o deberíamos generar un archivo directamente?