python視頻轉(zhuǎn)化字節(jié)問題的完整實(shí)現(xiàn)
廢話不多說,直接開干!
抖音字符視頻在今年火過一段時(shí)間。
反正我是始終忘不了那段劉耕宏老師本草綱目的音樂…
這一次自己也來實(shí)現(xiàn)一波,做一個(gè)字符視頻出來
百度好多都是顯示模塊,這個(gè)完整實(shí)現(xiàn)效果
步驟
將視頻轉(zhuǎn)化為一幀一幀的圖片
把圖片轉(zhuǎn)化為字符畫
按順序播放字符畫
1、準(zhǔn)備
安裝 Python-OpenCV 庫
安裝 Numpy 科學(xué)計(jì)算庫
用到模塊庫
import time import cv2 import os from PIL import Image, ImageDraw, ImageFont import numpy as np import os
然后新建python代碼文檔,在開頭添加上下面的導(dǎo)入語句
2. 材料
材料來個(gè)視頻文件了,我這里用的是zimeng.mp4,下載下來和代碼放到同一目錄下
你也可以換成自己的,建議是學(xué)習(xí)時(shí)盡量選個(gè)短一點(diǎn)的視頻,十幾秒十秒就行了,方便調(diào)試用
此外,要選擇對比度高的視頻。否則的話,就需要彩色字符才能有足夠好的表現(xiàn),有時(shí)間我試試。
3、按幀讀取視頻
現(xiàn)在繼續(xù)添加代碼,實(shí)現(xiàn)第一步:按幀讀取視頻。
下面這個(gè)函數(shù),接受視頻路徑和字符視頻的尺寸信息,返回一個(gè)img列表,其中的img是尺寸都為指定大小的灰度圖。
第一步截取圖片
def video_img(file='zimeng.mp4'): # 在當(dāng)前目錄下新建文件夾 folder_path = "img_bear/" if folder_path: pass else: os.makedirs(folder_path) # 進(jìn)行視頻的載入 vc = cv2.VideoCapture(file) # 判斷載入的視頻是否可以打開 ret = vc.isOpened() # 循環(huán)讀取視頻幀 num = 0 while ret: num = num + 1 # 進(jìn)行單張圖片的讀取,ret的值為True或者Flase,frame表示讀入的圖片 ret, frame = vc.read() if ret: # 存儲(chǔ)為圖像 cv2.imwrite('img_bear/' + str(num) + '.jpg', frame) # 輸出圖像名稱 print('img_bear/' + str(num) + '.jpg') # 在一個(gè)給定的時(shí)間內(nèi)(單位ms)等待用戶按鍵觸發(fā),1ms cv2.waitKey(1) else: break # 視頻釋放 vc.release() time.sleep(0.5) video_image(num)
如果運(yùn)行沒報(bào)錯(cuò),就沒問題
代碼里的注釋應(yīng)該寫得很清晰了,繼續(xù)下一步
第二步對圖片做灰度處理
視頻轉(zhuǎn)換成了圖像,這一步便是把圖像轉(zhuǎn)換成字符畫
上面這個(gè)函數(shù),一個(gè)img對象為參數(shù),前往對應(yīng)的字符畫
def video_image(num=''): # 創(chuàng)建字符圖片文件夾 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) # 返回一個(gè)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): # 將圖片轉(zhuǎn)化為灰度圖像,并重設(shè)大小 img_array = np.array(Image.open(filename).resize((160, 160), Image.ANTIALIAS).convert('L')) # 創(chuàng)建新的圖片對象 img = Image.new('L', (width, heigth), 255) draw_object = ImageDraw.Draw(img) # 設(shè)置字體 font = ImageFont.truetype('consola.ttf', 10, encoding='unic') # 根據(jù)灰度值添加對應(yīng)的字符 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)
第三步字符轉(zhuǎn)視頻
寫了這么多代碼,如今終于要出效果了。如今就是最激動(dòng)人心的一步:播放字符畫了。
異樣的,我把它封裝成了一個(gè)函數(shù)。上面這個(gè)函數(shù)承受一個(gè)字符畫的列表并播放。
def video(num): filename = 'img_bear/' + str(1) + '.jpg' im = Image.open(filename) # 返回一個(gè)Image對象 width = im.size[0] heigth = im.size[1] # 設(shè)置視頻編碼器,這里使用使用MJPG編碼器 fourcc = cv2.VideoWriter_fourcc(*'MJPG') # 輸出視頻參數(shù)設(shè)置,包含視頻文件名、編碼器、幀率、視頻寬高(此處參數(shù)需和字符圖片大小一致) 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) # 在一個(gè)給定的時(shí)間內(nèi)(單位ms)等待用戶按鍵觸發(fā),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執(zhí)行對應(yīng)的文件
完整代碼里面加了
執(zhí)行生成圖片,生成灰度圖片,最后通過灰度生成字節(jié)視頻刪除多余文件
說了那太多廢話就是:最后還需刪除一些臨時(shí)的文件及文件夾。
import time import cv2 import os from PIL import Image, ImageDraw, ImageFont import numpy as np import os # 第一步截取圖片 def video_img(file='zimeng.mp4'): # 在當(dāng)前目錄下新建文件夾 folder_path = "img_bear/" if folder_path: pass else: os.makedirs(folder_path) # 進(jìn)行視頻的載入 vc = cv2.VideoCapture(file) # 判斷載入的視頻是否可以打開 ret = vc.isOpened() # 循環(huán)讀取視頻幀 num = 0 while ret: num = num + 1 # 進(jìn)行單張圖片的讀取,ret的值為True或者Flase,frame表示讀入的圖片 ret, frame = vc.read() if ret: # 存儲(chǔ)為圖像 cv2.imwrite('img_bear/' + str(num) + '.jpg', frame) # 輸出圖像名稱 print('img_bear/' + str(num) + '.jpg') # 在一個(gè)給定的時(shí)間內(nèi)(單位ms)等待用戶按鍵觸發(fā),1ms cv2.waitKey(1) else: break # 視頻釋放 vc.release() time.sleep(0.5) video_image(num) # 第二步對圖片做灰度處理 def video_image(num=''): # 創(chuàng)建字符圖片文件夾 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) # 返回一個(gè)Image對象 width = im.size[0] heigth = im.size[1] print('寬:%d,高:%d' % (im.size[0], im.size[1])) # 此字符表用于生字符幀,對應(yīng)256個(gè)像素,字符越多且不同樣式,字符幀越精細(xì) ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~ <>i!lI;:,\"^`'. ") # 判斷圖片是否存在 if os.path.exists(filename): # 將圖片轉(zhuǎn)化為灰度圖像,并重設(shè)大小 img_array = np.array(Image.open(filename).resize((160, 160), Image.ANTIALIAS).convert('L')) # 創(chuàng)建新的圖片對象 img = Image.new('L', (width, heigth), 255) draw_object = ImageDraw.Draw(img) # 設(shè)置字體 font = ImageFont.truetype('consola.ttf', 10, encoding='unic') # 根據(jù)灰度值添加對應(yīng)的字符 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) # 第三步字符轉(zhuǎn)視頻 def video(num): filename = 'img_bear/' + str(1) + '.jpg' im = Image.open(filename) # 返回一個(gè)Image對象 width = im.size[0] heigth = im.size[1] # 設(shè)置視頻編碼器,這里使用使用MJPG編碼器 fourcc = cv2.VideoWriter_fourcc(*'MJPG') # 輸出視頻參數(shù)設(shè)置,包含視頻文件名、編碼器、幀率、視頻寬高(此處參數(shù)需和字符圖片大小一致) 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) # 在一個(gè)給定的時(shí)間內(nèi)(單位ms)等待用戶按鍵觸發(fā),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中保存的是當(dāng)前的執(zhí)行目錄 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中保存的是當(dāng)前的執(zhí)行目錄 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()
進(jìn)一步優(yōu)化
到了這里,核心功能基本都完成了。
不過仔細(xì)想想,其實(shí)還有很多可以做的:
什么是指定要轉(zhuǎn)換的區(qū)間、幀率?
每次轉(zhuǎn)換都要很久的時(shí)間,能不能邊轉(zhuǎn)換邊播放?或者轉(zhuǎn)換后把數(shù)據(jù)保存起來,下次播放時(shí),就直接讀緩存
看下效果圖
總結(jié)
到此這篇關(guān)于python視頻轉(zhuǎn)化字節(jié)問題的文章就介紹到這了,更多相關(guān)python視頻轉(zhuǎn)化字節(jié)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python實(shí)現(xiàn)手寫一個(gè)類似django的web框架示例
這篇文章主要介紹了Python實(shí)現(xiàn)手寫一個(gè)類似django的web框架,結(jié)合具體實(shí)例形式分析了Python自定義簡單控制器、URL路由、視圖模型等功能,實(shí)現(xiàn)類似Django框架的web應(yīng)用相關(guān)操作技巧,需要的朋友可以參考下2018-07-07Python3+SQLAlchemy+Sqlite3實(shí)現(xiàn)ORM教程
這篇文章主要介紹了Python3+SQLAlchemy+Sqlite3實(shí)現(xiàn)ORM教程,需要的朋友可以參考下2021-02-02利用Python實(shí)現(xiàn)原創(chuàng)工具的Logo與Help
這篇文章主要給大家介紹了關(guān)于如何利用Python實(shí)現(xiàn)原創(chuàng)工具的Logo與Help的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考借鑒,下面來一起看看吧2018-12-12使用Python實(shí)現(xiàn)一鍵往Word文檔的表格中填寫數(shù)據(jù)
在工作中,我們經(jīng)常遇到將Excel表中的部分信息填寫到Word文檔的對應(yīng)表格中,以生成報(bào)告,方便打印,所以本文小編就給大家介紹了如何使用Python實(shí)現(xiàn)一鍵往Word文檔的表格中填寫數(shù)據(jù),文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下2023-12-12Python設(shè)計(jì)模式之抽象工廠模式原理與用法詳解
這篇文章主要介紹了Python設(shè)計(jì)模式之抽象工廠模式,簡單講述了抽象工廠模式的概念、原理并結(jié)合實(shí)例形式分析了Python實(shí)現(xiàn)與使用抽象工廠模式的相關(guān)操作技巧,需要的朋友可以參考下2019-01-01django遷移數(shù)據(jù)庫錯(cuò)誤問題解決
這篇文章主要介紹了django遷移數(shù)據(jù)庫錯(cuò)誤問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07