É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?Réponses:
Java, score 0,57058675
C'est en fait ma première fois que je fais de la manipulation d'images, donc c'est un peu gênant, mais je pense que ça s'est bien passé.
Je n'ai pas pu faire fonctionner dssim sur ma machine, mais j'ai pu créer des images à l'aide de PIL.
Fait intéressant, la police me dit en Java que chacun des caractères que j'utilise est de largeur
6
. Vous pouvez voir que dans mon programmeFontMetrics::charWidth
est6
pour tous les personnages que j'ai utilisés. Le{}
logo semble assez décent dans une police monospace. Mais pour une raison quelconque, les lignes ne s'alignent pas réellement dans le fichier de texte intégral. Je blâme les ligatures. (Et oui, je devrais utiliser la bonne police.)En police à espacement fixe:
Après l'avoir exécuté via l'outil d'image:
Quoi qu'il en soit, voici le code réel.
Compiler:
C:\Program Files\Java\jdk1.8.0_91\bin
)AsciiArt.java
javac AsciiArt.java
jar cvfe WhateverNameYouWant.jar AsciiArt AsciiArt.class
Usage:
java -jar WhateverNameYouWant.jar C:\full\file\path.png
:, imprime sur STDOUTEXIGE le fichier source à enregistrer avec une profondeur de 1 bit et l'échantillon pour un pixel blanc à
1
.Sortie de notation:
la source
-ea
pour activer les assertions. Cela ne changera pas le comportement (sauf peut-être le ralentir un peu) parce que les assertions fonctionnent en échouant le programme lors de leur évaluationfalse
et toutes ces assertions passent.