用 Python 把坤坤动起来|Python 主题月

前言

阅读时长 用脑度 前置知识
5min 25% Python

最近看到一个 Up 主 Ele实验室 发布的一个视频:字符化视频是怎么作出来的,感受颇有意思。不如本身也实现一个来玩玩?python

之前也没怎么写过 Python,只用来刷过 LeetCode。正好借这个机会再学一学 Python 吧。git

效果

先来看看实现效果。github

Emmm,有那味了。算法

思路

首先,咱们都知道视频本质上是一张张图片快速展现的效果,因此第一步就是将视频进行 分帧shell

当将视频分红一张张图片后,每张图片里的每一个像素点都是由 红、绿、蓝 三原色混合而成的。而这样的混合机制就是经过数值值来表示的,好比 rgb(255, 255, 255) 就是白色,而 rgb(0, 0, 0) 则表示连个颜色都没有,也就是黑色。数组

拿到三种值后,能够经过必定计算将单像素变成一个值,通常来讲这个过程能够是灰度化。缓存

rgba(255, 255, 255) -> 0
复制代码

拿到灰度后的值,就能够将全部像素映射到 Hash 表上的一个字符,从而造成 字符画markdown

0 -> $
复制代码

将这些字符画都以 txt 文件保存到一个目录,再按顺序打印出来就造成了 字符视频 了。ide

那咱们如今开始实现吧。svn

分帧

分帧这里能够不用咱们实现,直接使用 ffmpeg 就能够了。先用下面命令进行安装:

brew install ffmpeg
复制代码

而后使用这个命令来分帧:

ffmpeg -i res/cxk-video.mov res/image_frames/%d.jpg
复制代码

上面命令很容易理解:res/cxk-video.mov 是原视频,后面的 res/image_frames/%d.jpg 就是存放的路径,%d 表示数字.jpg。

生成字符画

这里要借用到 Pillow 这个库,能够直接获取图片的 rgb 值。

先安装一下这个库:

pip3 install Pillow
复制代码

若是你是 M1 的 Mac 电脑,须要用下面这两个命令来安装。

sudo python3 -m pip install --upgrade pip
sudo python3 -m pip install --upgrade Pillow
复制代码

而后来实现将图片变成字符画:

from os import listdir
from os.path import isfile, join

image_frames_dir = 'res/image_frames'
txt_frames_dir = 'res/txt_frames'

def prepare(width, height):
    for file_name in listdir(image_frames_dir):
        print("正在处理 " + file_name)

        image_path = join(image_frames_dir, file_name) // 获取图片地址
        txt_path = join(txt_frames_dir, file_name.split('.')[0] + '.txt') // 获取 txt 文件地址

        if not isfile(image_path):
            continue

        image = Image.open(image_path) // 获取图片
        image = image.resize((width, height), Image.NEAREST)  # NEAREST 低质量图

        txt = to_string(image, width, height) // 生成字符文本

        with open(txt_path, 'w') as txt_file: // 保存字符文本
            txt_file.write(txt)
复制代码

使用 getpiexel 获取 tuple 而后经过算法生成 gray 值,再映射到定义好的数组上。

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

def get_char(r, g, b, alpha=256):
    if alpha == 0:
        return ' '

    length = len(ascii_char)
    gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b) // 生成灰度值
    unit = (256.0 + 1) / length
    return ascii_char[int(gray / unit)] // 映射到字符


def to_string(image, width, height):
    txt = ""

    for h in range(height):
        for w in range(width):
            txt += get_char(*image.getpixel((w, h)))  # 获取 pixel 的颜色数值
        txt += '\n' # 记得最后要换行

    return txt
复制代码

而后就能够生成不少个 txt 文件了。

字符视频

好了,上面已经能够实现将全部图片转换成字符画了,下面将这些字符画顺序地打印出来就能够了。

import os
from time import sleep

def display(speed):
    def compare_file_name(file_name1, file_name2):
        index1 = int(file_name1.split('.')[0])
        index2 = int(file_name2.split('.')[0])

        return index1 - index2 # 以文件名来做对比
        
    # 获取全部 txt 文件,并排好序
    for file_name in sorted(listdir(txt_frames_dir), key=cmp_to_key(compare_file_name)):
        txt_path = join(txt_frames_dir, file_name)

        os.system('cat ' + txt_path) # cat 出来
        sleep(speed)
复制代码

如今已经能够实现把坤坤打印出来了。

工具函数

虽然功能已经实现好了,可是若是要作出一个别人也能玩得嗨的产品还须要再打磨一下。

首先,能够添加 is_ready 函数来判断是否已经有生成好了的字符画。

from os import listdir

def is_ready():
    return len(listdir(txt_frames_dir)) != 0
复制代码

还能够添加 clear 函数来清楚缓存。

import glob
import os

def clear():
    files = glob.glob(join(txt_frames_dir, '*'))
    for f in files:
        os.remove(f)
复制代码

最后一步,作一个入口文件,添加一些参数来自定义打出字符视频:

#!/usr/local/bin/python3
import argparse
from procedure import prepare, display, is_ready, clear

# 获取参数
def get_args():
    parser = argparse.ArgumentParser()

    parser.add_argument('command', type=str, default='run')
    parser.add_argument('--width', type=int, default=240)
    parser.add_argument('--height', type=int, default=100)
    parser.add_argument('--speed', type=float, default=0.02)

    return parser.parse_args()

if __name__ == '__main__':
    args = get_args()

    # 参数
    command = args.command
    width = args.width
    height = args.height
    speed = args.speed

    if command == 'clear':
        clear()
    if command == 'compile':
        prepare(width, height)
    if command == 'run':
        if not is_ready():
            print('运行 python3 main.py compile 来编译')
        else:
            display(speed) # 输出字符视频
复制代码

用户就能够有多种玩法了:

./main.py run --speed 0.02 # 控制速度,单位为 seconds,这里数值为默认值

./main.py run --width 240 --height 100 # 控制宽高,这里数值为默认值
复制代码

最后

上面全部完整的代码均可以在 Github - cxk-dance 这个仓库 里获取,各位观众老爷自行 clone 来玩吧。

在 M1 的 Mac 上有可能会出现 Pillow 安装不成功的问题,在 README.md 也给出了相应的解决办法。

对了,最近刚建了个公众号【写代码的海怪】,以为我写得不错就随缘关注一下喽~

相关文章
相关标签/搜索