Video to ASCII Art

In this post we will discuss how to convert live video broadcast to ascii art using python

Installing Required Packages

pip install opencv-python
pip install pillow
pip install numpy

Code Explanation

import cv2
from PIL import Image,ImageDraw, ImageFont
import math
import numpy

Lets import the required packages packages first

chars = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. "[::-1]

video_capture = cv2.VideoCapture(0)

charArray = list(chars)
charLength = len(charArray)
interval = charLength/256

scaleFactor = 0.09

oneCharWidth = 10
oneCharHeight = 18

chars variable is the string having all the ascii characters, video_capture will capture video stream from webcam you can also take input from various other sources (like mobile phone, wireless arduino camera), charArray will convert string with all ascii character to a list, charlength is the length of all the characters list, oneCharHeight & oneCharwidth is the height and width of one pixel

fnt = ImageFont.truetype('C:\\Windows\\Fonts\\lucon.ttf', 15)

fnt will be font of characters on our ascii art

while True:
    _,im = video_capture.read()
    im= cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
    color_coverted = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
    im = Image.fromarray(color_coverted)
    width, height = im.size
    im = im.resize((int(scaleFactor*width), int(scaleFactor*height(oneCharWidth/oneCharHeight))), Image.NEAREST)
    width, height = im.size
    pix = im.load()

Inside an infinite we will read our incoming video and store it in im variable , for better feature recognition we will convert our rgb image to black and white, by using fromarray we will convert array to image for pillow image manipulation , resize function will resize the image according to our parameters, pix will be the variable that loads or image

    outputImage = Image.new('RGB', (oneCharWidth * width, oneCharHeight * height), color = (0, 0, 0))
    d = ImageDraw.Draw(outputImage)

    for i in range(height):
        for j in range(width):
            r, g, b = pix[j, i]
            h = int(r/3 + g/3 + b/3)
            pix[j, i] = (h, h, h)
            d.text((j*oneCharWidth, i*oneCharHeight), getChar(h), font = fnt, fill = (r, g, b))

outputImage will create a new blank image that we will use to write our ascii characters on, d is class instance we will use to draw ascii characters, after that we will create two while loop for both row and column to access each pixel , r,g & b are variables that will store red green and blue values of each pixel after that we will select ascii characters for each of theses ascii bundles and write on blank image

    outputImage = numpy.array(outputImage)
    outputImage = outputImage[:, :, ::-1].copy() 
    cv2.imshow("attendence system",outputImage)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

video_capture.release()
cv2.destroyAllWindows()

final task is to display the output to the user and close all windows

watch this tutorial for more detailed explanation

Complete Code

import cv2
from PIL import Image,ImageDraw, ImageFont
import math
import numpy

chars = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. "[::-1]

video_capture = cv2.VideoCapture(0)

charArray = list(chars)
charLength = len(charArray)
interval = charLength/256

scaleFactor = 0.09

oneCharWidth = 10
oneCharHeight = 18

def getChar(inputInt):
    return charArray[math.floor(inputInt*interval)]

fnt = ImageFont.truetype('C:\\Windows\\Fonts\\lucon.ttf', 15)

while True:
    _,im = video_capture.read()
    im= cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
    color_coverted = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
    im = Image.fromarray(color_coverted)
    width, height = im.size
    im = im.resize((int(scaleFactor*width), int(scaleFactor*height*(oneCharWidth/oneCharHeight))), Image.NEAREST)
    width, height = im.size
    pix = im.load()

    outputImage = Image.new('RGB', (oneCharWidth * width, oneCharHeight * height), color = (0, 0, 0))
    d = ImageDraw.Draw(outputImage)

    for i in range(height):
        for j in range(width):
            r, g, b = pix[j, i]
            h = int(r/3 + g/3 + b/3)
            pix[j, i] = (h, h, h)
            d.text((j*oneCharWidth, i*oneCharHeight), getChar(h), font = fnt, fill = (r, g, b))
    outputImage = numpy.array(outputImage)
    outputImage = outputImage[:, :, ::-1].copy() 
    cv2.imshow("attendence system",outputImage)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

video_capture.release()
cv2.destroyAllWindows()

About the author

Harshit

Hey, I'am Harshit Roy, a programmer with an obsession of learning new things, this blog is dedicated to helping people to learn programming fun way by creating projects

View all posts