Game Barcode: A Study of Colours in Games

This tutorial shows how to download videos from YouTube and to process their frames with Python; I have used this technique to create game barcode, an image created by sorting the colours in each frame of a particular video. You can see some of most intriguing here:

This tutorial is divided in four parts:

Introduction

The idea for this tutorial came to me after reading a post on Reddit titled The average color of every frame of a given movie. I immediately wanted to apply this technique to games. The main reason is that games, compared to movie, have much smoother transitions. This allows to see how colours change very clearly. On top of that, I wanted to explore this concept further, by applying the techniques I’ve discussed in The Incredibly Challenging Task of Sorting Colours. I tested my hypothesis on a short clip from a game I am working on, and the result was quite stunning.

colours_StillTime_600

Another important reason why I wanted to use games rather than movies, is that working with the latter brings you dangerously close to the neutral zone of piracy and copyright infringement. Switching to games, however, you are forced to used a particular Let’s Play video. All the game barcodes in this post have been generated from Let’s Plays I have found on YouTube. I have no affiliation with their respective creators. You can see all the game barcodes here.

Step 1. Processing a video

Let’s start with a top-down approach. Each movie is processed by the process_video function. Frames are extracted using the library OpenCV, then passed through process_frame which returns the list of sorted colours within that frame.

import cv2

def process_video (input_movie, size=(2000,100)):
    colours = []

    # Takes the frames of the video
    cap = cv2.VideoCapture(input_movie)
    while cap.isOpened():
        flag, frame = cap.read()
        if not flag:
            continue

        # Processes the frame
        colours_frame = process_frame(frame, size[1])
        colours.append(colours_frame)
    
    # Generates the final picture
    generate_pic(colours, size)

Finally, all the sorted colours are given to generate_pic which joints them together to create the final picture.

📰 Ad Break

Step 2. Processing a frame

Processing a frame is relatively straightforward. First, the frame is reduced in size to save time and memory. Then, is it reshaped into an array and sorted. For this process I have chosen to sort the colours in the HSV space, since it is more consistent across different frames. In the last step, the sorted array is converted back into an image and interpolated to the requested size using cv2.resize.

import numpy as np
import colorsys

def process_frame (frame, height=100):
    # Resize and put in a single line
    image = resize_image(frame)
    image = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
    image = image.reshape((image.shape[0] * image.shape[1], 1, 3))
    
    # Sort the pixels
    sorted_idx = np.lexsort(    (image[:,0,2], image[:,0,1], image[:,0,0]  )   )
    image = image[sorted_idx]

    # Resize into a column
    image_column = cv2.resize(image, (1, height), interpolation=cv2.INTER_AREA)
    return image_column

The function to resize the original frame is this one:

def resize_image (image, size=100):
    # Resize it
    h, w, _ = image.shape
    w_new = int(size * w / max(w, h) )
    h_new = int(size * h / max(w, h) )
     
    image = cv2.resize(image, (w_new, h_new));
    return image

Step 3. Creating the barcode

The final step to create the image is to join all the sorted columns together. We also convert the image back to RGB.

def generate_pic (colours, size):
    # Generates the picture
    height = size[1]
    img = np.zeros((height,len(colours),3), np.uint8)

    # Puts the colours in the image
    for x in range(0, len(colours)):
        for y in range(0, height):
            img[y,x,:] = colours[x][y,0]

    # Converts back to RGB
    img = cv2.cvtColor(img, cv2.COLOR_HSV2RGB)
    cv2.imwrite("barcode_full.png", img)

If you want to resize the image to a more manageable size, you can use this code:

image_1 = cv2.resize(img, size, interpolation=cv2.INTER_AREA)
cv2.imwrite("barcode_%d.png" % size[0], image_1)

Step 4. Downloading from YouTube

Since many Let’s Play are on YouTube, it makes sense to invest some time to download them directly. I have used pafy, a Python library which allows to query YouTube.

# Download the video
video = pafy.new('https://www.youtube.com/watch?v=Re5NFApk9dQ')
resolution = video.getbestvideo(preftype="mp4")
input_movie = resolution.download(quiet=False)

# Process it
process_video(input_movie)
os.remove(input_movie)

If you work is derivative (i.e.: if you are using someone else video), don’t forget to credit them.

Conclusion

If you are curious to see this technique applied to movies, there is a nice selection here.

Other resources

Comments

2 responses to “Game Barcode: A Study of Colours in Games”

  1. […] Zucconi shares his colour study techniques in Game Barcode: A Study of Colours in Games. Using Python, Zucconi shows how to output a colour script from a play through video. This is a […]

  2. […] all colors into each slice. It sounds complicated, but it's really not. In fact, Zucconi has a tutorial on his website so you can create your own […]

Leave a Reply

Your email address will not be published. Required fields are marked *