Nichols and Sense

All Things Coding and CyberSecurity

Image to ASCII Converter

I’m going to try something different with this project. When I normally type these up, it is after I have already completed the project and is basically a recounting of the steps I took to complete it. This time however, I want to start from the very beginning. I have done nothing with this project so far other than some brainstorming, so I am going to go through my usual thought process while working on these projects. So let's get started.

Firstly, what is this project even going to be? The idea that I have come up with is to create a script that takes an image as input, then converts and displays that image as ASCII art. What is ASCII art you ask? Well some nerds my age may remember the good old days of the early internet where things like uploading an image could take hours. Some artistic people became very good at drawing images with just text. Here is a really cool example of a picture of George Washington drawn with nothing but characters you can type on a keyboard!

 

processing image

 

So would it even be possible to make a program that can convert an image to ASCII art like above? (Spoiler: it is and many people have done so before). I want to do it myself though and without looking up any help from other projects. I think I have a solid base plan on what I need to do, so I guess let’s start with that, and we can get into the actual coding later.

 

Step 1: Processing the Image


At the risk of jinxing myself, I think this step is going to be the easiest. I need a way to take an image and get the data of all the pixels in the image. Luckily I know there is a python module named OpenCV that does a great job of modifying images. You pass the module an image file, and it stores all the pixel values in an array, letting you reference any pixel in the image and make adjustments. It also lets you easily convert an image to grayscale which is very important, but we’ll come back to that later. Also since I am going to be using an ASCII character to represent each pixel, I will probably need a way to automatically scale down the image to something manageable.


 

Step 2: Converting the Image


This is the part that I believe will be the trickiest. Here is my basic idea on what I should do, but it may change as I am just going off of a hunch. The general idea is that after I have processed the image, I will have a very low resolution grayscale image. This means that I do not need to worry about color, only how bright or dark each pixel is. Each pixel in a grayscale image is given a value between 0 and 255 where 0 is completely black and 255 is completely white. Everything else in between is a gradient shade of gray. So in theory, all I need to do is have a whole bunch of characters, each assigned to a small number range representing a shade of gray. For example, take a look again at the image of George Washington. Dark areas are usually depicted with characters that are very dense, like “W”,“M”, and “N”. On the other hand, areas that are very light are depicted with characters that are very sparse, such as “.” and “:”. What I can do is, starting from the darkest, make a list of characters that represent a shade of gray. I probably don’t need to have a separate character for every single value between 0 and 255 though. If I divide 255 by 15, then I will only need 17 characters to display the whole spectrum. I’m just guessing that will be enough though, and this may need to be revisited. There’s a couple other things I’m already thinking about too. For one, I am going to need a monospaced font for this. Most modern fonts have different spacing between the letters which could cause issues because each “pixel” needs to be evenly distributed. Secondly, the horizontal space between characters is much smaller than the vertical space, so that will have to be accounted for too. 

 

So that’s it. That’s the plan. Let’s get started

Let’s start with the image processing step. Here I am using the sys and OpenCV modules to grab an image file, then read it. OpenCV stores all the pixels of the image in nested arrays, where each row is its own array. Then I convert the image to grayscale so that I can reference each pixel’s brightness with just one value. After that, I resize the image to have a width of 125 pixels while keeping the aspect ratio of the pixel the same.

 

processing image

 

Here is where I actually convert each pixel to a character. I iterate through all the pixels, check its brightness value, then assign it a character accordingly depending on how dense that character is. While iterating over each row of pixels in the image, I add these characters to a blank array and when it is done, the data between the original image and my new array are exactly the same except now each pixel is defined by a character instead of a brightness value.

 

processing image

 

Finally, I write all of these characters to a text file and that’s it! We now have a script that can convert any image to ASCII art!

 

processing image

 

Here are are some results.

Original:

processing image

 

Converted to ASCII:

processing image

 


 

Original:

 

processing image

 

Converted to ASCII:

processing image

Tune in for the next blog post where we expand this to convert entire gifs this way.


Here is the source code if you would like to try it yourself.

Source Code