python視頻轉化字節問題的完整實現

廢話不多說,直接開幹!

抖音字符視頻在今年火過一段時間。

反正我是始終忘不瞭那段劉耕宏老師本草綱目的音樂…

這一次自己也來實現一波,做一個字符視頻出來

百度好多都是顯示模塊,這個完整實現效果

步驟

將視頻轉化為一幀一幀的圖片

把圖片轉化為字符畫

按順序播放字符畫

1、準備

安裝 Python-OpenCV 庫

安裝 Numpy 科學計算庫

用到模塊庫

import time

import cv2
import os
from PIL import Image, ImageDraw, ImageFont
import numpy as np
import os

然後新建python代碼文檔,在開頭添加上下面的導入語句

2. 材料

材料來個視頻文件瞭,我這裡用的是zimeng.mp4,下載下來和代碼放到同一目錄下

你也可以換成自己的,建議是學習時盡量選個短一點的視頻,十幾秒十秒就行瞭,方便調試用

此外,要選擇對比度高的視頻。否則的話,就需要彩色字符才能有足夠好的表現,有時間我試試。

3、按幀讀取視頻

現在繼續添加代碼,實現第一步:按幀讀取視頻。

下面這個函數,接受視頻路徑和字符視頻的尺寸信息,返回一個img列表,其中的img是尺寸都為指定大小的灰度圖。

第一步截取圖片

def video_img(file='zimeng.mp4'):
    # 在當前目錄下新建文件夾
    folder_path = "img_bear/"
    if folder_path:
        pass
    else:
        os.makedirs(folder_path)
    # 進行視頻的載入
    vc = cv2.VideoCapture(file)
    # 判斷載入的視頻是否可以打開
    ret = vc.isOpened()
    # 循環讀取視頻幀
    num = 0
    while ret:
        num = num + 1
        # 進行單張圖片的讀取,ret的值為True或者Flase,frame表示讀入的圖片
        ret, frame = vc.read()
        if ret:
            # 存儲為圖像
            cv2.imwrite('img_bear/' + str(num) + '.jpg', frame)
            # 輸出圖像名稱
            print('img_bear/' + str(num) + '.jpg')
            # 在一個給定的時間內(單位ms)等待用戶按鍵觸發,1ms
            cv2.waitKey(1)
        else:
            break
    # 視頻釋放
    vc.release()
    time.sleep(0.5)
    video_image(num)

如果運行沒報錯,就沒問題

代碼裡的註釋應該寫得很清晰瞭,繼續下一步

第二步對圖片做灰度處理

視頻轉換成瞭圖像,這一步便是把圖像轉換成字符畫

上面這個函數,一個img對象為參數,前往對應的字符畫

def video_image(num=''):
    # 創建字符圖片文件夾
    folder_path = "bear/"
    if folder_path:
        pass
    else:
        os.makedirs(folder_path)
    for i in range(1, num):
        filename = 'img_bear/' + str(i) + '.jpg'
        im = Image.open(filename)  # 返回一個Image對象
        width = im.size[0]
        heigth = im.size[1]
        print('寬:%d,高:%d' % (im.size[0], im.size[1]))
        # 字符列表
        ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~            <>i!lI;:,\"^`'. ")
        # 判斷圖片是否存在
        if os.path.exists(filename):
            # 將圖片轉化為灰度圖像,並重設大小
            img_array = np.array(Image.open(filename).resize((160, 160), Image.ANTIALIAS).convert('L'))
            # 創建新的圖片對象
            img = Image.new('L', (width, heigth), 255)
            draw_object = ImageDraw.Draw(img)
            # 設置字體
            font = ImageFont.truetype('consola.ttf', 10, encoding='unic')
            # 根據灰度值添加對應的字符
            for j in range(160):
                for k in range(160):
                    x, y = k * 8, j * 8
                    index = int(img_array[j][k] / 4)
                    draw_object.text((x, y), ascii_char[index], font=font, fill=0)
            name = 'bear/' + str(i) + '.jpg'
            print(name)
            # 保存字符圖片
            img.save(name, 'JPEG')
    time.sleep(0.5)
    video(num)

第三步字符轉視頻

寫瞭這麼多代碼,如今終於要出效果瞭。如今就是最激動人心的一步:播放字符畫瞭。

異樣的,我把它封裝成瞭一個函數。上面這個函數承受一個字符畫的列表並播放。

def video(num):
    filename = 'img_bear/' + str(1) + '.jpg'
    im = Image.open(filename)  # 返回一個Image對象
    width = im.size[0]
    heigth = im.size[1]
    # 設置視頻編碼器,這裡使用使用MJPG編碼器
    fourcc = cv2.VideoWriter_fourcc(*'MJPG')
    # 輸出視頻參數設置,包含視頻文件名、編碼器、幀率、視頻寬高(此處參數需和字符圖片大小一致)
    videoWriter = cv2.VideoWriter('bear_character.avi', fourcc, 20.0, (width, heigth))

    for i in range(1, num):
        filename = 'bear/'+str(i)+'.jpg'
        # 判斷圖片是否存在
        if os.path.exists(filename):
            img = cv2.imread(filename=filename)
            # 在一個給定的時間內(單位ms)等待用戶按鍵觸發,100ms
            cv2.waitKey(100)
            # 將圖片寫入視頻中
            videoWriter.write(img)
            print(str(i) + '.jpg' + ' done!')
    # 視頻釋放
    videoWriter.release()
    time.sleep(1)
    # 刪除圖片
    remove_img()
    remove_img_bear()

下面完整代碼

可能要等很久。我使用示例視頻大概需要 500 秒左右。

ctrl+f10執行對應的文件

完整代碼裡面加瞭

執行生成圖片,生成灰度圖片,最後通過灰度生成字節視頻刪除多餘文件

說瞭那太多廢話就是:最後還需刪除一些臨時的文件及文件夾。

import time

import cv2
import os
from PIL import Image, ImageDraw, ImageFont
import numpy as np
import os

# 第一步截取圖片
def video_img(file='zimeng.mp4'):
    # 在當前目錄下新建文件夾
    folder_path = "img_bear/"
    if folder_path:
        pass
    else:
        os.makedirs(folder_path)
    # 進行視頻的載入
    vc = cv2.VideoCapture(file)
    # 判斷載入的視頻是否可以打開
    ret = vc.isOpened()
    # 循環讀取視頻幀
    num = 0
    while ret:
        num = num + 1
        # 進行單張圖片的讀取,ret的值為True或者Flase,frame表示讀入的圖片
        ret, frame = vc.read()
        if ret:
            # 存儲為圖像
            cv2.imwrite('img_bear/' + str(num) + '.jpg', frame)
            # 輸出圖像名稱
            print('img_bear/' + str(num) + '.jpg')
            # 在一個給定的時間內(單位ms)等待用戶按鍵觸發,1ms
            cv2.waitKey(1)
        else:
            break
    # 視頻釋放
    vc.release()
    time.sleep(0.5)
    video_image(num)
# 第二步對圖片做灰度處理
def video_image(num=''):
    # 創建字符圖片文件夾
    folder_path = "bear/"
    if folder_path:
        pass
    else:
        os.makedirs(folder_path)
    for i in range(1, num):
        filename = 'img_bear/' + str(i) + '.jpg'
        im = Image.open(filename)  # 返回一個Image對象
        width = im.size[0]
        heigth = im.size[1]
        print('寬:%d,高:%d' % (im.size[0], im.size[1]))
        # 此字符表用於生字符幀,對應256個像素,字符越多且不同樣式,字符幀越精細
        ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~            <>i!lI;:,\"^`'. ")
        # 判斷圖片是否存在
        if os.path.exists(filename):
            # 將圖片轉化為灰度圖像,並重設大小
            img_array = np.array(Image.open(filename).resize((160, 160), Image.ANTIALIAS).convert('L'))
            # 創建新的圖片對象
            img = Image.new('L', (width, heigth), 255)
            draw_object = ImageDraw.Draw(img)
            # 設置字體
            font = ImageFont.truetype('consola.ttf', 10, encoding='unic')
            # 根據灰度值添加對應的字符
            for j in range(160):
                for k in range(160):
                    x, y = k * 8, j * 8
                    index = int(img_array[j][k] / 4)
                    draw_object.text((x, y), ascii_char[index], font=font, fill=0)
            name = 'bear/' + str(i) + '.jpg'
            print(name)
            # 保存字符圖片
            img.save(name, 'JPEG')
    time.sleep(0.5)
    video(num)
# 第三步字符轉視頻

def video(num):
    filename = 'img_bear/' + str(1) + '.jpg'
    im = Image.open(filename)  # 返回一個Image對象
    width = im.size[0]
    heigth = im.size[1]
    # 設置視頻編碼器,這裡使用使用MJPG編碼器
    fourcc = cv2.VideoWriter_fourcc(*'MJPG')
    # 輸出視頻參數設置,包含視頻文件名、編碼器、幀率、視頻寬高(此處參數需和字符圖片大小一致)
    videoWriter = cv2.VideoWriter('bear_character.avi', fourcc, 20.0, (width, heigth))

    for i in range(1, num):
        filename = 'bear/'+str(i)+'.jpg'
        # 判斷圖片是否存在
        if os.path.exists(filename):
            img = cv2.imread(filename=filename)
            # 在一個給定的時間內(單位ms)等待用戶按鍵觸發,100ms
            cv2.waitKey(100)
            # 將圖片寫入視頻中
            videoWriter.write(img)
            print(str(i) + '.jpg' + ' done!')
    # 視頻釋放
    videoWriter.release()
    time.sleep(1)
    # 刪除圖片
    remove_img()
    remove_img_bear()
# 原圖片刪除
def remove_img():
    files = os.getcwd()  # files中保存的是當前的執行目錄
    file_name = files + "/img_bear"
    del_list = os.listdir(file_name)
    for f in del_list:
        file_path = os.path.join(file_name, f)
        print(file_path)
        if os.path.isfile(file_path):
            os.remove(file_path)
            print('成功刪除文件:')
        else:
            print('未找到此文件:')
# 灰度圖片刪除
def remove_img_bear():
    files = os.getcwd()  # files中保存的是當前的執行目錄
    file_name = files + "/bear"
    del_list = os.listdir(file_name)
    for f in del_list:
        file_path = os.path.join(file_name, f)
        print(file_path)
        if os.path.isfile(file_path):
            os.remove(file_path)
            print('成功刪除文件:')
        else:
            print('未找到此文件:')
def main():
    video_img('video.mp4')


if __name__ == "__main__":
    main()

進一步優化

到瞭這裡,核心功能基本都完成瞭。

不過仔細想想,其實還有很多可以做的:

什麼是指定要轉換的區間、幀率?

每次轉換都要很久的時間,能不能邊轉換邊播放?或者轉換後把數據保存起來,下次播放時,就直接讀緩存

看下效果圖

總結

到此這篇關於python視頻轉化字節問題的文章就介紹到這瞭,更多相關python視頻轉化字節內容請搜索LevelAH以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持LevelAH!

推薦閱讀: