This is a short project made during a computer vision class I am taking in GWU. To try out this program, clone this repository and in the file directory, run:
$ python main.py <your-file-path>
where <your-file-path>
is the file path of your image.
I was curious on how to develop a system that transform visual images into ASCII art, a form of text-based imagery where the pixels of an image are replaced with characters, and compare the difference in "quality" between them. This project might strike an interest for artists, developers, and enthusiasts interested in digital art, retro computing. Example inputs include photographs, illustrations, and digital art, while outputs are ASCII conversions that maintain recognizable features and artistic integrity of the original images.
This project involves two major parts, converting the image into a greyscale version of itself, and mapping the intensity of those greyscale pixels to their corresponding ASCII characters, which vary in visual density.
The way to convert the image into greyscale is quite diverse:
-
average: averaging the values,
-
luminosity: taking a weighted average of the values,
-
lightness: min-maxing the values, etc
(lots more details here).
The two main ways I convert the image into greyscale is:
-
using the build-in greyscale convertor from Pillow,
-
and using an all-averaged approach by utilising the formula: (r + g + b) / 3.
You can change different greyscale convertor by setting the use_custom_grayscale
boolean and this section:
# Custom formula for grayscale conversion
gray = int((r + g + b) / 3)
grayscale_image.putpixel((x, y), gray)
There are different brightness scale of ASCII characters. I used the brightness scale posted here by chungaloider.
You can change the brightness scale by changing the scale.txt file found within the repository.
During this project, I noticed that the image printed is "squished", as it was slimmed down. This is due to the representation of character being rectangular as opposed to the square shape of pixels.
An easy fix is to double or triple each character every time it was printed.
One aspect of this project I found surprising tough is the limitation of printing characters in the terminal, as there is limit on how much characters can be printed out on a single line before it will overflow towards the next line.
One ways to overcome this issue is making a max limit on the height and width. If the width exceeds the set limit, resize the image using Pillow's in-build resize function. Same goes for height. You can change the max_width
and max_height
found within the code.
One additional thing:
You can change the printing output to a txt file instead of printing them on the terminal by simply changing the boolean
file_print
. This way, you can share the txt file instead of screenshotting the final image.
One aspect I tested is the difference between various greyscale convertions:
The first image uses the built-in Pillow function while the second image uses the all-averaged approach. There is only minute changes to the shading of the person's face, while the background is slightly altered. I think this is due to the very slight differences between the built-in Pillow function; which uses the formula: 0.299 * r + 0.587 * g + 0.114 * b; compared to the above formula. This formula is weighted towards green, making it particularly sensitive to the green hues dominant in the image:
The first image uses the built-in Pillow function while the second image uses the all-averaged approach. As you can see, the first image is a highly detailed ASCII representation where the different shades and textures of the leaf are distinctly visible, capturing nuances in a way that closely mirrors the original's visual depth; while the second image "smooth out" some of the details, appears less textured and detailed compared to the first image, especially in areas with subtle color differences.
This is further amplified by this example:
Original image
Built-in function by Pillow
All-averaged approach
When compared to the original images, the ASCII art produced by our model retains a high level of visual integrity.
Nevertheless, there are drawbacks, like the loss of detail in extremely complicated images, which could be fixed by improving the model's sensitivity to subtle tonal changes, adding colour in future iterations, or even improving pixel detection, for instance: putting a '/' at edges instead of using a '*'.
Even though this project successfully shows that automated ASCII art generation is feasible for many applications, more work is required to produce outputs that are professional-grade, especially in areas of better quality and faster computation.
The project was developed in Python, utilizing libraries such as Pillow for image processing. Data was sourced from googling different images, mainly for testing purposes.