I was inspired by some horrible copy-pasta ASCII art in Twitch chat the other day to try to create my own image to ASCII art converter. It's day 2 of the project and I'm going go into my process of what I did and whether I'm satisfied with the results or not. The program was built in Unity using C#, hopefully I'll have a distributed version at some point when I'm satisfied with how it's functioning and when I figure out how to add the UI elements necessary (and I'll talk about why I can't right now). The program currently works by reading an image as a Texture2D in unity, converting every pixel to grayscale and translating the grayscale to a corresponding ASCII letter or symbol.
Method 0
So here's "method0" aka I kinda just stole this method. The grayscale pixel conversion applies for all of these methods (this is using Unity's own function for conversion, I may mess with it a bit too for future methods). This method only uses characters M, N, F, V, |, *, :, and . that have all been assigned a grayness value. It then looks at the best/closest match and assigns one of these characters to a pixel. It creates one of the sharpest images, but a lot of the grays get lost due to the limited palette.
Method 1
Method 1 attempts to be a bit more detailed with a list of 71 characters arranged top down of darkest to lightest without values actually given. From there I check where each pixel fits into this list of 71 (white being the 71st, black being the first or element 0). This method gives some more detail, but is inherently imperfect since the values aren't normalized. This tended to lean towards a more middle gray.
Method 2
At this point I wanted values for every ASCII character I was using, and jumped from 71 to 93 characters (which I think is everything on the keyboard). I then ran a program that wrote each character to a sprite then took the average "grayness" of the sprite to assign a value between 0-1 as a percentage of how black the character made the sprite. I then sorted this to get a sorted list of all characters in the array with their corresponding values. (this is also why I can't distribute this now since this functionality is still in. I'd like to settle on some values and hard code them in to a finished product, but if you're curious of the values I can share the results). I then used a similar method to method 0 where I attempted to match a pixel to its closest ASCII character. The result was, well, eh. Things were too dark since I didn't normalize any of the characters and the program interpreted many grays as just pure black.
Method 3
This method was a bit less scientific, but I figured since I repeated method 0 I would try to repeat method 1 with a larger palette from 71-93. The results were pretty good actually, similar from jumping from 0 to 1, it created a lot more grays.
Method 4
Currently the best I've got it so far this method takes the 93 characters and normalizes them assuming the darkest character I have is pure black (the character is '@' and it's about 46% black). This stretches the palette out and more appropriately assigns the values based on the palette I have available. The result is much more detailed than any other method, and a brighter version than method 0. There's more detail I'd like to do and ideally I'd like to get some intelligent compression in (where I assign a character to 4 or 6 pixels), so that's where I'll be taking this next. Till then, thanks for checking this out and I'll keep you posted on the happenings!
Comments
Post a Comment