In [79]:
import cv2

See here, a tiny image of the football. The goal (dohohoho) is to transform this image into ascii art.

Tools used:

OpenCV for image reading, and the built-in numpy array of OpenCV.

Images are typically represented by an array of numbers in the form of [R,G,B]

Example: [0,255,17]

That would be a more or less green pixel.

A football it is ideal for working with grayscale since it is already black and white. A grayscale array of numbers is easier to work with because instead of 3 colors/values, we're working with one value per pixel (essentially saying how dark/light a pixel is going to show).


In [80]:
img = cv2.imread("football-ball.jpg",0)
print img


[[254 254 254 ..., 254 253 252]
 [254 254 254 ..., 254 254 253]
 [254 254 254 ..., 254 253 253]
 ..., 
 [254 254 254 ..., 254 254 254]
 [254 254 254 ..., 254 254 254]
 [254 254 254 ..., 254 254 254]]

In [83]:
img.shape


Out[83]:
(30, 40)

As expected, we have rows and columns of numbers. Exactly 30 rows and 40 columns because our image is 30x40 pixels.

To convert an image into ascii, we need to map/draw a letter or ascii symbol for each number in the image. It is also not displayed the same as an image because we're saving it to a text file or just printing it straight to the console.

Below here I have a mapping set up for these numbers. I chose a very simple scheme to use:

Numbers 0-180 are represented by a 'W'

Numbers 180+ are represented by a '!'

This essentially creates a binary ascii image since there are only two symbols at play in any transformation.


In [81]:
def setupAsciiMapping():
    characterSet = list(('W'*18)+'!!!!!!!!')
    for i in range(26):
        for j in range(10):
            asciiToNum[i*10+j]=characterSet[i]
asciiToNum = {}
setupAsciiMapping()
print asciiToNum


{0: 'W', 1: 'W', 2: 'W', 3: 'W', 4: 'W', 5: 'W', 6: 'W', 7: 'W', 8: 'W', 9: 'W', 10: 'W', 11: 'W', 12: 'W', 13: 'W', 14: 'W', 15: 'W', 16: 'W', 17: 'W', 18: 'W', 19: 'W', 20: 'W', 21: 'W', 22: 'W', 23: 'W', 24: 'W', 25: 'W', 26: 'W', 27: 'W', 28: 'W', 29: 'W', 30: 'W', 31: 'W', 32: 'W', 33: 'W', 34: 'W', 35: 'W', 36: 'W', 37: 'W', 38: 'W', 39: 'W', 40: 'W', 41: 'W', 42: 'W', 43: 'W', 44: 'W', 45: 'W', 46: 'W', 47: 'W', 48: 'W', 49: 'W', 50: 'W', 51: 'W', 52: 'W', 53: 'W', 54: 'W', 55: 'W', 56: 'W', 57: 'W', 58: 'W', 59: 'W', 60: 'W', 61: 'W', 62: 'W', 63: 'W', 64: 'W', 65: 'W', 66: 'W', 67: 'W', 68: 'W', 69: 'W', 70: 'W', 71: 'W', 72: 'W', 73: 'W', 74: 'W', 75: 'W', 76: 'W', 77: 'W', 78: 'W', 79: 'W', 80: 'W', 81: 'W', 82: 'W', 83: 'W', 84: 'W', 85: 'W', 86: 'W', 87: 'W', 88: 'W', 89: 'W', 90: 'W', 91: 'W', 92: 'W', 93: 'W', 94: 'W', 95: 'W', 96: 'W', 97: 'W', 98: 'W', 99: 'W', 100: 'W', 101: 'W', 102: 'W', 103: 'W', 104: 'W', 105: 'W', 106: 'W', 107: 'W', 108: 'W', 109: 'W', 110: 'W', 111: 'W', 112: 'W', 113: 'W', 114: 'W', 115: 'W', 116: 'W', 117: 'W', 118: 'W', 119: 'W', 120: 'W', 121: 'W', 122: 'W', 123: 'W', 124: 'W', 125: 'W', 126: 'W', 127: 'W', 128: 'W', 129: 'W', 130: 'W', 131: 'W', 132: 'W', 133: 'W', 134: 'W', 135: 'W', 136: 'W', 137: 'W', 138: 'W', 139: 'W', 140: 'W', 141: 'W', 142: 'W', 143: 'W', 144: 'W', 145: 'W', 146: 'W', 147: 'W', 148: 'W', 149: 'W', 150: 'W', 151: 'W', 152: 'W', 153: 'W', 154: 'W', 155: 'W', 156: 'W', 157: 'W', 158: 'W', 159: 'W', 160: 'W', 161: 'W', 162: 'W', 163: 'W', 164: 'W', 165: 'W', 166: 'W', 167: 'W', 168: 'W', 169: 'W', 170: 'W', 171: 'W', 172: 'W', 173: 'W', 174: 'W', 175: 'W', 176: 'W', 177: 'W', 178: 'W', 179: 'W', 180: '!', 181: '!', 182: '!', 183: '!', 184: '!', 185: '!', 186: '!', 187: '!', 188: '!', 189: '!', 190: '!', 191: '!', 192: '!', 193: '!', 194: '!', 195: '!', 196: '!', 197: '!', 198: '!', 199: '!', 200: '!', 201: '!', 202: '!', 203: '!', 204: '!', 205: '!', 206: '!', 207: '!', 208: '!', 209: '!', 210: '!', 211: '!', 212: '!', 213: '!', 214: '!', 215: '!', 216: '!', 217: '!', 218: '!', 219: '!', 220: '!', 221: '!', 222: '!', 223: '!', 224: '!', 225: '!', 226: '!', 227: '!', 228: '!', 229: '!', 230: '!', 231: '!', 232: '!', 233: '!', 234: '!', 235: '!', 236: '!', 237: '!', 238: '!', 239: '!', 240: '!', 241: '!', 242: '!', 243: '!', 244: '!', 245: '!', 246: '!', 247: '!', 248: '!', 249: '!', 250: '!', 251: '!', 252: '!', 253: '!', 254: '!', 255: '!', 256: '!', 257: '!', 258: '!', 259: '!'}

Above here I automated the task of creating a dictionary for this mapping.

Now onto the actual transformation...

In the bottom and final block of code, we see here that I am iterating through the image row by row to transform each number into the appropriate symbol of 'W' or '!' and then appending that into a list, which is then added to the list of transformedAscii. The variable transformedAscii is a list of lists, where each list is a row. It is essentially an array of the transformed symbols.

From that list, I join the characters into a long string, and add a new line character at the end of each row to display the string properly.

Pretty picture!


In [82]:
transformedAscii = []

for i in img:
    temp = []
    for j in i:
        temp.append(asciiToNum[j])
    transformedAscii.append(temp)
ascii = ''
for i in transformedAscii:
    ascii+= ' '.join(i)
    ascii+='\n'

print ascii


! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! W ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! W W ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! W W ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! W W ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! W W W ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! W W W W W ! ! ! ! ! ! W W W ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! W W W W W W W ! ! ! ! ! ! W W W ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! W ! ! ! ! W W W W W W W W ! ! ! ! ! ! ! W W ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! W ! ! ! ! W W W W W W W W ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! W W ! ! ! ! W W W W W W W W ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! W W ! ! ! ! W W W W W W W W ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! W ! ! ! ! ! ! W W W W W W ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! W ! ! ! ! ! ! ! W W ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! W ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! W W ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! W W W W W W ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! W W W W W W ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! W W W W W W ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! W W W W W ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! W W W W W W ! ! ! ! ! ! ! W W W W W W ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! W W W W W W W ! ! ! ! ! ! W W W W W ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! W W W W W W W ! ! ! ! ! ! W W W ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! W W W W W W W ! ! W W W W W ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! W W W W W W W W W W W ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! W W W W ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !