Asciify

Most images nowadays are represented using pixels. They are square, often relatively small and numerous, come in (2^8)^3 different colors and thereby do a good job being the fundamental building block of images. But one can imagine more coarse-grained and differently shaped pixels.
An interesting fact is, that in most monotype fonts two characters placed right next to each other (for example ‘$$’) occupy roughly a square area. So simple ASCII characters can indeed be used to approximately describe any ordinary image.
Asciify does exactly this; it takes in an image and some optional parameters and maps the pixels’ intensity onto a character set. Both the large and small default character sets are taken from a post by Paul Bourke.

Asciified kirby
Kirby grafitti

In conjunction with asciify.py, I wrote index.py, which asciifies a bunch of images and results in their html form; it also creates an index. All images asciified for this post can be viewed through this index.

Converting an image to its asciified form works best when there is a lot of contrast in the image. Because of this, some pre-processing of the image may be required for best results (all images shown where only cropped or rotated). The built-in color functionality also only knows of 8 colors, so bright and different colors look the best, as they interestingly differentiate from one another. The asciified image’s size also plays a role, the larger it is, the better the characters blend into one and appear to be one image.

Asciified cube
AoLong 3^3 cube

Asciify is operated on a command prompt; python asciify.py img.png. To parse arguments, the built-in python module argparse is used. The images are opened and read using the Python Imaging Library module PIL, which needs to be installed for this program to work.
Optional arguments include --size N, where the maximum size can be specified, --invert and --smallcharset, which can sometimes increase the asciified image’s visual appeal and --html, which will output an html file to be viewed in a browser. To see the program’s full potential, simply run python asciify.py --help.
Source code for both asciify.py and index.py can be downloaded, the first is also listed below.

The two examples above use the color mode, though certain images also work in default black and white mode, such as this spider I photographed.

Asciified spider
Spider

Then again, the colored text also has its charm, especially when the source image has bright colors and a lot of contrast.

Asciified boat
Sailboat

# Python 2.7 Code
# Jonathan Frech 3rd, 4th of March 2017
#      rewritten 12th of April 2017
#         edited 13th of April, 13th, 14th, 15th of July 2017

Continue reading

Advertisements

The hundredth Post

The J-Blog has reached its hundredth post, this one. It being the hundredth post, I want to review my previous posts. But rather than going into the context of my previous 99 posts, I decided to write a program to do this for me.

The program goes thru a list fetched from my Table of contents page, looks up the html code, distills the post and counts how many characters of each type there are. It then outputs its results in a nice text-based style (can be seen below).

To further visualize the data, I wrote another program to display it graphically. The results look like this. On the left the characters are sorted alphabetically (ASCII) and on the right they are sorted by occurrence (you may click on the images to view them closely).

The characters sorted by count The characters sorted by ASCII

+------+-------+---------+
| char | count | percent |
+------+-------+---------+
| all  | 33746 | 100.0   |
| '!'  |     8 |   0.023 |
| ' '  |  5693 |  16.870 |
| '%'  |     2 |   0.005 |
| '&'  |     1 |   0.002 |
| ')'  |   109 |   0.323 |
| '('  |   109 |   0.323 |
| '-'  |    45 |   0.133 |
| ','  |   206 |   0.610 |
| '.'  |   364 |   1.078 |
| '1'  |    33 |   0.097 |
| '0'  |    88 |   0.260 |
| '3'  |    12 |   0.035 |
| '2'  |    20 |   0.059 |
| '5'  |    11 |   0.032 |
| '4'  |    21 |   0.062 |
| '7'  |     9 |   0.026 |
| '6'  |    14 |   0.041 |
| '9'  |     1 |   0.002 |
| '8'  |     4 |   0.011 |
| ';'  |     1 |   0.002 |
| ':'  |     9 |   0.026 |
| '='  |     2 |   0.005 |
| '?'  |     2 |   0.005 |
| 'A'  |    40 |   0.118 |
| 'C'  |    58 |   0.171 |
| 'B'  |    32 |   0.094 |
| 'E'  |    10 |   0.029 |
| 'D'  |    15 |   0.044 |
| 'G'  |     8 |   0.023 |
| 'F'  |    17 |   0.050 |
| 'I'  |   151 |   0.447 |
| 'H'  |    13 |   0.038 |
| 'K'  |     1 |   0.002 |
| 'J'  |     9 |   0.026 |
| 'M'  |    20 |   0.059 |
| 'L'  |    27 |   0.080 |
| 'O'  |     6 |   0.017 |
| 'N'  |     5 |   0.014 |
| 'Q'  |     1 |   0.002 |
| 'P'  |    19 |   0.056 |
| 'S'  |    48 |   0.142 |
| 'R'  |    19 |   0.056 |
| 'U'  |    33 |   0.097 |
| 'T'  |   134 |   0.397 |
| 'W'  |    19 |   0.056 |
| 'V'  |     7 |   0.020 |
| 'Y'  |    14 |   0.041 |
| 'X'  |     4 |   0.011 |
| '_'  |     2 |   0.005 |
| 'a'  |  1949 |   5.775 |
| 'c'  |  1035 |   3.067 |
| 'b'  |   287 |   0.850 |
| 'e'  |  3323 |   9.847 |
| 'd'  |   799 |   2.367 |
| 'g'  |   802 |   2.376 |
| 'f'  |   466 |   1.380 |
| 'i'  |  1912 |   5.665 |
| 'h'  |  1165 |   3.452 |
| 'k'  |   215 |   0.637 |
| 'j'  |    17 |   0.050 |
| 'm'  |   714 |   2.115 |
| 'l'  |  1126 |   3.336 |
| 'o'  |  2013 |   5.965 |
| 'n'  |  1839 |   5.449 |
| 'q'  |    24 |   0.071 |
| 'p'  |   656 |   1.943 |
| 's'  |  1782 |   5.280 |
| 'r'  |  1765 |   5.230 |
| 'u'  |   681 |   2.018 |
| 't'  |  2422 |   7.177 |
| 'w'  |   437 |   1.294 |
| 'v'  |   233 |   0.690 |
| 'y'  |   487 |   1.443 |
| 'x'  |    94 |   0.278 |
| 'z'  |    26 |   0.077 |
| '~'  |     1 |   0.002 |
+------+-------+---------+
+------+-------+---------+
| char | count | percent |
+------+-------+---------+
| all  | 33746 | 100.0   |
| ' '  |  5693 |  16.870 |
| 'e'  |  3323 |   9.847 |
| 't'  |  2422 |   7.177 |
| 'o'  |  2013 |   5.965 |
| 'a'  |  1949 |   5.775 |
| 'i'  |  1912 |   5.665 |
| 'n'  |  1839 |   5.449 |
| 's'  |  1782 |   5.280 |
| 'r'  |  1765 |   5.230 |
| 'h'  |  1165 |   3.452 |
| 'l'  |  1126 |   3.336 |
| 'c'  |  1035 |   3.067 |
| 'g'  |   802 |   2.376 |
| 'd'  |   799 |   2.367 |
| 'm'  |   714 |   2.115 |
| 'u'  |   681 |   2.018 |
| 'p'  |   656 |   1.943 |
| 'y'  |   487 |   1.443 |
| 'f'  |   466 |   1.380 |
| 'w'  |   437 |   1.294 |
| '.'  |   364 |   1.078 |
| 'b'  |   287 |   0.850 |
| 'v'  |   233 |   0.690 |
| 'k'  |   215 |   0.637 |
| ','  |   206 |   0.610 |
| 'I'  |   151 |   0.447 |
| 'T'  |   134 |   0.397 |
| '('  |   109 |   0.323 |
| ')'  |   109 |   0.323 |
| 'x'  |    94 |   0.278 |
| '0'  |    88 |   0.260 |
| 'C'  |    58 |   0.171 |
| 'S'  |    48 |   0.142 |
| '-'  |    45 |   0.133 |
| 'A'  |    40 |   0.118 |
| '1'  |    33 |   0.097 |
| 'U'  |    33 |   0.097 |
| 'B'  |    32 |   0.094 |
| 'L'  |    27 |   0.080 |
| 'z'  |    26 |   0.077 |
| 'q'  |    24 |   0.071 |
| '4'  |    21 |   0.062 |
| '2'  |    20 |   0.059 |
| 'M'  |    20 |   0.059 |
| 'P'  |    19 |   0.056 |
| 'R'  |    19 |   0.056 |
| 'W'  |    19 |   0.056 |
| 'F'  |    17 |   0.050 |
| 'j'  |    17 |   0.050 |
| 'D'  |    15 |   0.044 |
| '6'  |    14 |   0.041 |
| 'Y'  |    14 |   0.041 |
| 'H'  |    13 |   0.038 |
| '3'  |    12 |   0.035 |
| '5'  |    11 |   0.032 |
| 'E'  |    10 |   0.029 |
| ':'  |     9 |   0.026 |
| 'J'  |     9 |   0.026 |
| '7'  |     9 |   0.026 |
| '!'  |     8 |   0.023 |
| 'G'  |     8 |   0.023 |
| 'V'  |     7 |   0.020 |
| 'O'  |     6 |   0.017 |
| 'N'  |     5 |   0.014 |
| '8'  |     4 |   0.011 |
| 'X'  |     4 |   0.011 |
| '%'  |     2 |   0.005 |
| '='  |     2 |   0.005 |
| '?'  |     2 |   0.005 |
| '_'  |     2 |   0.005 |
| '&'  |     1 |   0.002 |
| '~'  |     1 |   0.002 |
| '9'  |     1 |   0.002 |
| ';'  |     1 |   0.002 |
| 'K'  |     1 |   0.002 |
| 'Q'  |     1 |   0.002 |
+------+-------+---------+

The main program (shell-based):

# Python 2.7.7 Code
# Jonathan Frech 15th of January, 2016

The visualization program:

# Python 2.7.7 Code
# Pygame 1.9.1 (for Python 2.7.7)
# Jonathan Frech 15th of January, 2016

Continue reading