Étant donné une image en noir et blanc dans n'importe quel format raisonnable sans perte en entrée, affichez une image ASCII aussi proche que possible de l'image en entrée.
Règles
- Seuls les sauts de ligne et les octets ASCII 32-127 peuvent être utilisés.
- L'image d'entrée sera rognée de sorte qu'il n'y ait pas d'espace blanc étranger entourant l'image.
- Les soumissions doivent être en mesure de compléter l'ensemble du corpus de notation en moins de 5 minutes.
- Seul le texte brut est acceptable; aucun format de texte riche.
- La police utilisée dans la notation est Linux Libertine 20 points .
- Le fichier texte de sortie, lorsqu'il est converti en une image comme décrit ci-dessous, doit avoir les mêmes dimensions que l'image d'entrée, dans les 30 pixels dans l'une ou l'autre dimension.
Notation
Ces images seront utilisées pour la notation:
Vous pouvez télécharger un fichier zip des images ici .
Les soumissions ne doivent pas être optimisées pour ce corpus; ils devraient plutôt fonctionner pour 8 images en noir et blanc de dimensions similaires. Je me réserve le droit de modifier les images du corpus si je soupçonne que les soumissions sont optimisées pour ces images spécifiques.
La notation sera effectuée via ce 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)))
Le processus de notation:
- Exécutez la soumission pour chaque image de corpus, en sortant les résultats dans des
.txt
fichiers avec la même racine que le fichier de corpus (fait manuellement). - Convertissez chaque fichier texte en une image PNG, en utilisant une police de 20 points, en coupant les espaces.
- Redimensionnez l'image résultante aux dimensions de l'image d'origine à l'aide du rééchantillonnage Lanczos.
- Comparez chaque image de texte avec l'image d'origine à l'aide de
dssim
. - Générez le score dssim pour chaque fichier texte.
- Afficher le score moyen.
La similitude structurelle (la métrique par laquelle dssim
calcule les scores) est une métrique basée sur la vision humaine et l'identification des objets dans les images. Pour le dire clairement: si deux images ressemblent à des humains, elles auront (probablement) un score faible de dssim
.
La soumission gagnante sera la soumission avec le score moyen le plus bas.
.txt
fichiers»? Le programme devrait-il afficher le texte qui sera acheminé vers un fichier ou devrions-nous produire un fichier directement?