ASCII Art with Python

Have you ever wanted to convert an icon or photo to ASCII art? Fortunately there are lots of tools to do this out there. I looked around for one that works with Python 3+ and found a succinct, modular script that can output ASCII art from image files like the following:


The script is from Paul Bourke. There is very clear commenting on each step. Essentially, an image loaded from the "--file" argument is divided into a grid and each position of the grid is assigned certain ASCII character whose gray scale level most closely matches the average for that area of the image. I simply modified line 146 and 150 to demonstrate on console vs. the outfile.txt default.

Save the following as ascii.py:
 #Python code to convert an image to ASCII image.  
 import sys, random, argparse  
 import numpy as np  
 import math  
 from PIL import Image  
 # gray scale level values from:  
 # http://paulbourke.net/dataformats/asciiart/  
 # 70 levels of gray  
 gscale1 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "   
 # 10 levels of gray  
 gscale2 = '@%#*+=-:. '   
 def getAverageL(image):  
      # get image as numpy array  
      im = np.array(image)  
      # get shape  
      w,h = im.shape  
      # get average  
      return np.average(im.reshape(w*h))  
 def covertImageToAscii(fileName, cols, scale, moreLevels):  
      # declare globals  
      global gscale1, gscale2  
      # open image and convert to grayscale  
      image = Image.open(fileName).convert('L')  
      # store dimensions  
      W, H = image.size[0], image.size[1]  
      print("input image dims: %d x %d" % (W, H))  
      # compute width of tile  
      w = W/cols  
      # compute tile height based on aspect ratio and scale  
      h = w/scale  
      # compute number of rows  
      rows = int(H/h)  
      print("cols: %d, rows: %d" % (cols, rows))  
      print("tile dims: %d x %d" % (w, h))  
      # check if image size is too small  
      if cols > W or rows > H:  
           print("Image too small for specified cols!")  
           exit(0)  
      # ascii image is a list of character strings  
      aimg = []  
      # generate list of dimensions  
      for j in range(rows):  
           y1 = int(j*h)  
           y2 = int((j+1)*h)  
           # correct last tile  
           if j == rows-1:  
                y2 = H  
           # append an empty string  
           aimg.append("")  
           for i in range(cols):  
                # crop image to tile  
                x1 = int(i*w)  
                x2 = int((i+1)*w)  
                # correct last tile  
                if i == cols-1:  
                     x2 = W  
                # crop image to extract tile  
                img = image.crop((x1, y1, x2, y2))  
                # get average luminance  
                avg = int(getAverageL(img))  
                # look up ascii char  
                if moreLevels:  
                     gsval = gscale1[int((avg*69)/255)]  
                else:  
                     gsval = gscale2[int((avg*9)/255)]  
                # append ascii char to string  
                aimg[j] += gsval  
      # return txt image  
      return aimg  
 # main() function  
 def main():  
      # create parser  
      descStr = "This program converts an image into ASCII art."   
      parser = argparse.ArgumentParser(description=descStr)  
      # add expected arguments  
      parser.add_argument('--file', dest='imgFile', required=True)  
      parser.add_argument('--scale', dest='scale', required=False)  
      parser.add_argument('--out', dest='outFile', required=False)  
      parser.add_argument('--cols', dest='cols', required=False)  
      parser.add_argument('--morelevels',dest='moreLevels',action='store_true')  
      # parse args  
      args = parser.parse_args()  
      imgFile = args.imgFile  
      # set output file  
      outFile = 'out.txt'   
      if args.outFile:  
           outFile = args.outFile  
      # set scale default as 0.43 which suits  
      # a Courier font  
      scale = 0.43   
      if args.scale:  
           scale = float(args.scale)  
      # set cols  
      cols = 80   
      if args.cols:  
           cols = int(args.cols)  
      print('generating ASCII art...')  
      # convert image to ascii txt  
      aimg = covertImageToAscii(imgFile, cols, scale, args.moreLevels)  
      # open file  
      f = open(outFile, 'w')  
      # write to <console or> file ..f.write(row + '\n')  
      for row in aimg:  
           print(row + '\n')   
      # cleanup  
      f.close()  
      print("ASCII art written to console...") # %s" % outFile)  
 # call main  
 if __name__ == '__main__':  
      main()  


Using Windows CMD, navigate to the directory where your ascii.py script is located. Then execute the following:

ascii.py --file C:\somedir\logo.jpg --cols 150


Referencehttp://paulbourke.net/dataformats/asciiart/

No comments: