ASCII character brightnessPosted: February 2, 2011
I’m currently developing an Android application called ASCII cam. It allows you to view the world as ASCII art and take pictures of it.
I’ve played around with this technology in the past, and have used rough guesses about which characters should be used for different brightnesses. But this time I thought I’d do it properly, and empirically determine the optimal 16 characters in Android’s default fixed width font.
Calculating the brightness of each character was fairly simple. Draw it into an empty bitmap and count the number of non-zero pixels. The main surprise was that the brightest character – by a long way – was the letter M. I would have guessed @, so it’s a good thing I did this experimentally.
Now, the least bright character is obviously a space, so it gets position 0. The brightest character is M, so it gets position 15. All the other characters are then normalized against the brightness of M and assigned a position between 1 and 14.
Obviously, for a given position there are a few characters to choose from. I wanted characters that take up as much of their bounding box as possible, so I needed some kind to metric to calculate “spread”. This should be maximized when pixels are evenly spread throughout their bounding box.
My first thought was to use variance, the average of the squares of the distances from the mean position. This is easy to calculate and, at first glance, should give decent results. But it’s not perfect. A character with maximum variance would indeed be spread out, but it would have all its pixels clustered in the corners of the bounding box.
The solution I went with was to calculate the equivalent of the gravitational potential between all the pixels. Essentially the average of negative one over the distance between each pair of pixels. On paper it has the right characteristics, and in practice it looks pretty good too.