Att generera en ASCII-bild
Nyligen startades en inofficiell programmeringstävling på Sweclockers som går ut på att skriva ett program som genererar ASCII-baserade “bilder” utifrån faktiska bilder. Detta lät givetvis som en trevlig utmaning, och jag hade en idé.
Min idé gick ut på att använda den wavelet-transform som används i JPEG2000-formatet för att frilägga kanterna från bilden. En wavelet-transform ger bland annat skillnaden från pixel till pixel, och kan därmed ge en storlek på förändringen som man sedan kan använda för att förstärka kanterna i den slutgiltiga bilden.
Jag började dock med att skriva en liten bitmapsläsare. Språket jag till slut valde var D, och själva BMP-delen gick relativt snabbt att skriva, mycket tack vare Wikipedias utmärkta information om formatet. Själva koden kan ses här. Den är inte särskilt intressant i sammanhanget men kan vara intressant för den som ska skriva något som läser BMP-filer i D.
Nästa steg var att implementera en wavelet-transform. Jag valde att porta den här koden i stort sett omodifierad, med absolutbelopp på utdatan samt lite andra koefficienter. Dessutom implementerade jag inte inverstransformen då denna är ointressant i den här tillämpningen.
Detta gav mig kanterna i bilden. För att nu få en vettig ASCII-representation behöver man dels kombinera transformbilden med originalbilden (jag fann att 5:7 var en bra ratio) och sedan skriva ut denna med hjälp av någon form av palett. Den palett jag valde består av tecknen .,;^-+?rzXwM$, spridda över hela intervallet från 0 till 255, lite glesare runt 128.
Andra viktiga implementationer är bildskalaren, som är baserad på en Bresenham-algoritm. Mycket av koden utnyttjar fina aspekter av D och det har varit ett väldigt bra tillfälle att lära sig D lite närmre. Själva koden kan ni hitta här (eller här om du vill ha båda filerna i en fin tarball), och lite exempel på vad den åstadkommer finns här.
Jag tvivlar på att jag har en chans att vinna, det var många bra bidrag med i tävlingen, men vi får se helt enkelt. Det är roligt att vara med.
Leave a Reply