字符画-Python

视频转字符动画-Python

# bad apple

步骤
将视频转化为一帧一帧的图片
把图片转化为字符画
按顺序播放字符画

一、准备

  1. 模块
    opencv-python # 用来读取视频和图片
    numpy # opencv-python 依赖于它

首先安装依赖:
pip3 install numpy opencv-python

然后新建python代码文档,在开头添加上下面的导入语句
import numpy as np

  1. 材料文件
    材料就是视频文件了,我这里用的是在百度网盘提取的BadApple.mp4,
    记得下载下来和python代码放到同一目录下

二、按帧读取视频

现在继续添加代码,实现第一步:按帧读取视频。
下面这个函数,接受视频路径和字符视频的尺寸信息,返回一个img列表,其中的img是尺寸都为指定大小的灰度图。
#导入 opencv

import cv2
def video2imgs(video_name, size):

img_list = []

# 从指定文件创建一个VideoCapture对象
cap = cv2.VideoCapture(video_name)

# 如果cap对象已经初始化完成了,就返回true,换句话说这是一个 while true 循环
while cap.isOpened():
    # cap.read() 返回值介绍:
    #   ret 表示是否读取到图像
    #   frame 为图像矩阵,类型为 numpy.ndarry.
    ret, frame = cap.read()
    if ret:
        # 转换成灰度图,也可不做这一步,转换成彩色字符视频。
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        # resize 图片,保证图片转换成字符画后,能完整地在命令行中显示。
        img = cv2.resize(gray, size, interpolation=cv2.INTER_AREA)

        # 分帧保存转换结果
        img_list.append(img)
    else:
        break

# 结束时要释放空间
cap.release()

return img_list

三、图像转化为字符画

视频转换成了图像,这一步便是把图像转换成字符画
下面这个函数,接受一个img对象为参数,返回对应的字符画。

用于生成字符画的像素,越往后视觉上越明显。。这是我自己按感觉排的,你可以随意调整。
pixels = " .,-'`:!1+*abcdefghijklmnopqrstuvwxyz<>()\/{}[]?234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ%&@#$"

def img2chars(img):
res = []
"""

:param img: numpy.ndarray, 图像矩阵
:return: 字符串的列表:图像对应的字符画,其每一行对应图像的一行像素
"""

# 要注意这里的顺序和 之前的 size 刚好相反
height, width = img.shape
for row in range(height):
    line = ""
    for col in range(width):
        # 灰度是用8位表示的,最大值为255。
        # 这里将灰度转换到0-1之间
        percent = img[row][col] / 255
        
        # 将灰度值进一步转换到 0 到 (len(pixels) - 1) 之间,这样就和 pixels 里的字符对应起来了
        index = int(percent * (len(pixels) - 1))

        # 添加字符像素(最后面加一个空格,是因为命令行有行距却没几乎有字符间距,用空格当间距)
        line += pixels[index] + " "
    res.append(line)

return res

上面的函数只接受一帧为参数,一次只转换一帧,可我们需要的是转换所有的帧,所以就再把它包装一下:

def imgs2chars(imgs):
    video_chars = []
    for img in imgs:
        video_chars.append(img2chars(img))

    return video_chars

四、播放字符视频

把它封装成了一个函数。下面这个函数接受一个字符画的列表并播放。
import time
import subprocess

def play_video(video_chars):
    """
    播放字符视频
    :param video_chars: 字符画的列表,每个元素为一帧
    :return: None
    """
    # 获取字符画的尺寸
    width, height = len(video_chars[0][0]), len(video_chars[0])

for pic_i in range(len(video_chars)):
    # 显示 pic_i,即第i帧字符画
    for line_i in range(height):
        # 将pic_i的第i行写入第i列。
        print(video_chars[pic_i][line_i])
    time.sleep(1 / 24)  # 粗略地控制播放速度。

    subprocess.call("clear")  # 调用shell命令清屏

写完后,开个shell,最大化窗口,然后找到代码文件(文件名换成你的)
python3 fx.py
可能要等很久。我使用1080p视频大概需要2分钟左右。
看到提示的时候,按回车,开始播放!

完整代码如下

import numpy as np

import cv2

def video2imgs(video_name, size):

img_list = []

cap = cv2.VideoCapture(video_name)

while cap.isOpened():

    ret, frame = cap.read()
    if ret:
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        img = cv2.resize(gray, size, interpolation=cv2.INTER_AREA)
        img_list.append(img)
    else:
        break
cap.release()
return img_list

pixels = " .,-'`:!1+*abcdefghijklmnopqrstuvwxyz<>()\/{}[]?234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ%&@#$"


def img2chars(img):
    res = []
    height, width = img.shape
    for row in range(height):
        line = ""
        for col in range(width):
            percent = img[row][col] / 255
            index = int(percent * (len(pixels) - 1))
            line += pixels[index] + " "
        res.append(line)
    return res

def imgs2chars(imgs):
    video_chars = []
    for img in imgs:
        video_chars.append(img2chars(img))

    return video_chars

import time
import subprocess

def play_video(video_chars):

    width, height = len(video_chars[0][0]), len(video_chars[0])
    for pic_i in range(len(video_chars)):
        for line_i in range(height):
            print(video_chars[pic_i][line_i])
        time.sleep(1 / 24)
        subprocess.call("clear") 

if __name__ == "__main__":
    imgs = video2imgs("Bad Apple.mp4", (64, 48))
    video_chars = imgs2chars(imgs)
    input("`转换完成!按enter键开始播放")
    play_video(video_chars)

注意在shell窗口运行

字符画-Python_第1张图片

你可能感兴趣的:(will)