Python generates character videos

One, foreword

In the previous article also wrote the generation of character video, but the use of command line window output, the effect is not very good, and there is a situation of lag. So I’m going to just generate an MP4 character video. The general idea is the same as before: Python20 lines of code to char video.

Here’s an example:

Two, OpenCV operation image

Let’s start with some basic operations. First we need to install OpenCV and execute the following statement:

pip install opencv-python
Copy the code

Then it’s ready to use.

2.1. Read and display

Let’s go straight to the code:

import cv2
# fetch image
img = cv2.imread("1.jpg")
# display images
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()
Copy the code

Where waitKey is the function waiting for input, we need to call it because imshow is displayed for an instant. DestroyAllWindows is the release window.

2.2. Gray scale conversion

Grayscale conversion is converting an image to black and white (gray), which makes it easier to manipulate pixels. The code is as follows:

import cv2
img = cv2.imread("1.jpg")
# Grayscale conversion
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
Copy the code

We can also read it directly in greyscale form:

import cv2
# Read in grayscale
img = cv2.imread("1.jpg".0)
Copy the code

2.4. Get the picture size and modify the size

Let’s go straight to the code:

import cv2
img = cv2.imread("1.jpg".0)
Get the height and width of the image
h, w = img.shape
# Zoom in
res = cv2.resize(img, (w//2, h//2))
Copy the code

Since img’s shape property is a tuple, we can unpack it automatically.

The cv2.resize function is then called, passing in the image as the first argument and the modified size as the second.

2.5. Draw text

To draw text we need to call the cv2.putText function as follows:

import cv2
img = cv2.imread('1.jpg')
# draw text
cv2.putText(
    # Back drawing pictures
    img, 
    # The text to draw
    'Hello'.# coordinates in the lower left corner of the text
    (100.500),
    # font
    cv2.FONT_HERSHEY_SIMPLEX,
    # font size scaling
    20.# Text color
    (0.0.0),
    # Text thickness
    10
)
Copy the code

We just need to pay attention to these parameters.

2.6. Read the video

The operation to read the video is generally generic, with the following code:

import cv2
# Read video
cap = cv2.VideoCapture('1.mp4')
Get the frame rate of the video
fps = cap.get(cv2.CAP_PROP_FPS)
Loop through each frame of the image
while True:
    # Read next frame
    ret, frame = cap.read()
    if not ret:
        break
    else:
        pass
cap.release()
Copy the code

The frame of the video we captured above, we need to use when writing the video.

2.7. Write video

Writing to the video is also regular code:

import cv2
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
writer = cv2.VideoWriter('11.mp4', fourcc, fps, (w, h))
# Write video
writer.write(frame)
***
write.release()
Copy the code

Armed with this knowledge, we can proceed to the next step.

3. Pixels are mapped to characters

For an image with only one channel, we can think of it as a rectangle, in units of at least one pixel. The process of characterization is the process of replacing pixels with characters. So we iterate over every pixel of the image, but what character should we replace it with?

We have a reference table for colors, and OpencV cuts this parameter list into 256 pieces, representing different degrees. We can also make a reference table, but the contents of the table are not colors, but characters.

The color table is shown above. We can map the color table to the character table. Suppose the character table looks like this:

mqpka89045321@#$%^&*()_=||||}

Characters in the corresponding character table of the corresponding color can be obtained after transformation:

It doesn’t matter if you don’t understand this formula, you just need to know how to use it. Here is our code for converting pixels to characters:

def pixel2char(pixel) :
    char_list = "@#$%&erytuioplkszxcv=+---. "
    index = int(pixel / 256 * len(char_list))
    return char_list[index]
Copy the code

The character list is self-definable.

Generate character pictures

Now all we need to do is convert each pixel into a character, as follows:

def get_char_img(img, scale=4, font_size=5) :
    # Resize the image
    h, w = img.shape
    re_im = cv2.resize(img, (w//scale, h//scale))
    # Create a picture to fill in the characters
    char_img = np.ones((h//scale*font_size, w//scale*font_size), dtype=np.uint8)*255
    font = cv2.FONT_HERSHEY_SIMPLEX
    # Walk through image pixels
    for y in range(0, re_im.shape[0) :for x in range(0, re_im.shape[1]):
            char_pixel = pixel2char(re_im[y][x])
            cv2.putText(char_img, char_pixel, (x*font_size, y*font_size), font, 0.5, (0.0.0))
    return char_img
Copy the code

Here we use a np.ones function, which we understand to generate a black image.

How to multiply the generated size by font_size Scale is the reduction of the original image, because there are many pixels, so we need to reduce the image first. To make our font clearer, we need to enlarge the generated character image.

So it’s important to note that although the image we generated looks flat, when font_size is set to 5, the resulting image is already quite large. So when you make a long video, it takes a little bit more time, and the resulting video is a little bit bigger.

Let’s test the above function:

import cv2
import numpy as np


def pixel2char(pixel) :
    char_list = "@#$%&erytuioplkszxcv=+---. "
    index = int(pixel / 256 * len(char_list))
    return char_list[index]


def get_char_img(img, scale=4, font_size=5) :
    # Resize the image
    h, w = img.shape
    re_im = cv2.resize(img, (w//scale, h//scale))
    # Create a picture to fill in the characters
    char_img = np.ones((h//scale*font_size, w//scale*font_size), dtype=np.uint8)*255
    font = cv2.FONT_HERSHEY_SIMPLEX
    # Walk through image pixels
    for y in range(0, re_im.shape[0) :for x in range(0, re_im.shape[1]):
            char_pixel = pixel2char(re_im[y][x])
            cv2.putText(char_img, char_pixel, (x*font_size, y*font_size), font, 0.5, (0.0.0))
    return char_img


if __name__ == '__main__':
    img = cv2.imread('dl.jpg'.0)
    res = get_char_img(img)
    cv2.imwrite('d.jpg', res)

Copy the code

The effect is as follows:

And you can see it’s still pretty good.

Generate character video

With the above code, we can convert the entire video. The code for converting a video to a character video is as follows:

def generate(input_video, output_video) :
    # 1. Read the video
    cap = cv2.VideoCapture(input_video)

    # 2. Get the video frame rate
    fps = cap.get(cv2.CAP_PROP_FPS)

    # Read the first frame to get the size of the picture converted to characters
    ret, frame = cap.read()
    char_img = get_char_img(cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY), 4)

    Create a VideoWriter to save the video
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    writer = cv2.VideoWriter(output_video, fourcc, fps, (char_img.shape[1], char_img.shape[0]))
    while ret:
        # Read the current frame of the video, if not out of the loop
        ret, frame = cap.read()
        if not ret:
            break
        # Convert the current frame to a character map
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        char_img = get_char_img(gray, 4)

        Convert to BGR mode for easy video writing
        char_img = cv2.cvtColor(char_img, cv2.COLOR_GRAY2BGR)
        writer.write(char_img)
    writer.release()
Copy the code

Here is the character video clip of the classic battle of Kakashi:

The complete code is as follows:

import cv2
import numpy as np


def pixel2char(pixel) :
    char_list = "@#$%&erytuioplkszxcv=+---. "
    index = int(pixel / 256 * len(char_list))
    return char_list[index]


def get_char_img(img, scale=4, font_size=5) :
    # Resize the image
    h, w = img.shape
    re_im = cv2.resize(img, (w//scale, h//scale))
    # Create a picture to fill in the characters
    char_img = np.ones((h//scale*font_size, w//scale*font_size), dtype=np.uint8)*255
    font = cv2.FONT_HERSHEY_SIMPLEX
    # Walk through image pixels
    for y in range(0, re_im.shape[0) :for x in range(0, re_im.shape[1]):
            char_pixel = pixel2char(re_im[y][x])
            cv2.putText(char_img, char_pixel, (x*font_size, y*font_size), font, 0.5, (0.0.0))
    return char_img


def generate(input_video, output_video) :
    # 1. Read the video
    cap = cv2.VideoCapture(input_video)

    # 2. Get the video frame rate
    fps = cap.get(cv2.CAP_PROP_FPS)

    # Read the first frame to get the size of the picture converted to characters
    ret, frame = cap.read()
    char_img = get_char_img(cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY), 4)

    Create a VideoWriter to save the video
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    writer = cv2.VideoWriter(output_video, fourcc, fps, (char_img.shape[1], char_img.shape[0]))
    while ret:
        # Read the current frame of the video, if not out of the loop
        ret, frame = cap.read()
        if not ret:
            break
        # Convert the current frame to a character map
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        char_img = get_char_img(gray, 4)

        Convert to BGR mode for easy video writing
        char_img = cv2.cvtColor(char_img, cv2.COLOR_GRAY2BGR)
        writer.write(char_img)
    writer.release()


if __name__ == '__main__':
    generate('in.mp4'.'out.mp4')

Copy the code

We just need to modify the parameters of generate.