用 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 也給出了相應的解決辦法。

對了,最近剛建了個公衆號【寫代碼的海怪】,以爲我寫得不錯就隨緣關注一下嘍~

相關文章
相關標籤/搜索