Biorąc pod uwagę czarno-biały obraz w dowolnym rozsądnym formacie bezstratnym jako dane wejściowe, należy wyprowadzić grafikę ASCII możliwie najbliższą obrazowi wejściowemu.
Zasady
- Można stosować tylko sygnały liniowe i bajty ASCII 32-127.
- Obraz wejściowy zostanie przycięty, aby wokół obrazu nie było żadnych białych znaków.
- Zgłoszenia muszą być w stanie wypełnić cały korpus punktacji w czasie krótszym niż 5 minut.
- Akceptowany jest tylko surowy tekst; brak formatów tekstu sformatowanego.
- Czcionka użyta w punktacji to 20-pkt Linux Libertine .
- Wyjściowy plik tekstowy po przekonwertowaniu na obraz, jak opisano poniżej, musi mieć takie same wymiary jak obraz wejściowy, w granicach 30 pikseli w każdym z wymiarów.
Punktacja
Te obrazy zostaną wykorzystane do oceny:
Możesz pobrać plik zip z obrazkami tutaj .
Zgłoszenia nie powinny być optymalizowane dla tego korpusu; powinny raczej działać na dowolne 8 czarno-białych obrazów o podobnych wymiarach. Zastrzegam sobie prawo do zmiany obrazów w korpusie, jeśli podejrzewam, że zgłoszenia są optymalizowane dla tych konkretnych obrazów.
Punktacja zostanie przeprowadzona za pomocą tego skryptu:
#!/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)))
Proces punktacji:
- Uruchom przesyłanie dla każdego obrazu korpusu, wysyłając wyniki do
.txt
plików o tym samym rdzeniu co plik korpusu (wykonywane ręcznie). - Konwertuj każdy plik tekstowy na obraz PNG, używając 20-punktowej czcionki, usuwając spacje.
- Zmień rozmiar obrazu wynikowego do wymiarów oryginalnego obrazu za pomocą próbkowania Lanczosa.
- Porównaj każdy obraz tekstowy z oryginalnym obrazem, używając
dssim
. - Wyjście wyniku dssim dla każdego pliku tekstowego.
- Podaj średni wynik.
Podobieństwo strukturalne (metryka, za pomocą której dssim
obliczane są wyniki) to metryka oparta na wizji człowieka i identyfikacji obiektu na obrazach. Mówiąc wprost: jeśli dwa obrazy wyglądają podobnie do ludzi, (prawdopodobnie) będą miały niski wynik od dssim
.
Zwycięskie zgłoszenie będzie zgłoszeniem o najniższym średnim wyniku.
.txt
plikach”? Czy program powinien wypisywać tekst, który zostanie przesłany potokiem do pliku, czy też powinniśmy wydrukować plik bezpośrednio?Odpowiedzi:
Java, wynik 0,57058675
To właściwie moja pierwsza operacja na obrazie, więc jest to trochę niezręczne, ale myślę, że wyszło.
Nie mogłem zmusić dssim do pracy na moim komputerze, ale mogłem tworzyć obrazy przy użyciu PIL.
Co ciekawe, czcionka mówi mi w Javie, że każdy ze znaków, których używam, ma szerokość
6
. Widać, że w moim programieFontMetrics::charWidth
jest6
dla wszystkich znaków, których użyłem.{}
Logo wygląda całkiem przyzwoity w czcionce o stałej szerokości. Ale z jakiegoś powodu wiersze tak naprawdę nie pokrywają się w pełnym pliku tekstowym. Obwiniam ligatury. (I tak, powinienem używać poprawnej czcionki.)W czcionce o stałej szerokości:
Po uruchomieniu go za pomocą narzędzia obrazu:
Tak czy inaczej, oto aktualny kod.
Skompilować:
C:\Program Files\Java\jdk1.8.0_91\bin
)AsciiArt.java
javac AsciiArt.java
jar cvfe WhateverNameYouWant.jar AsciiArt AsciiArt.class
Użycie
java -jar WhateverNameYouWant.jar C:\full\file\path.png
:, drukuje do STDOUTWYMAGA pliku źródłowego do zapisania z głębokością 1-bitową i próbki dla białego piksela
1
.Wynik punktacji:
źródło
-ea
aby włączyć asercje. Nie zmieni to zachowania (z wyjątkiem być może spowolnienia go w niewielkim stopniu), ponieważ asercje działają przez to, że zawiodły program, gdy oceniająfalse
i wszystkie te asercje miną.