?Python?代碼制作動(dòng)態(tài)鞭炮
前言:
放鞭炮賀新春,在我國有兩千多年歷史。關(guān)于鞭炮的起源,有個(gè)有趣的傳說。
西方山中有焉,長尺余,一足,性不畏人。犯之令人寒熱,名曰年驚憚,后人遂象其形,以火藥為之。——《神異經(jīng)》
當(dāng)初人們?nèi)贾穸?,是為了?qū)嚇危害人們的山魈。據(jù)說山魈最怕火光和響聲,所以每到除夕,人們便“燃竹而爆”,把山魈嚇跑。這樣年復(fù)一年,便形成了過年放鞭炮、點(diǎn)紅燭、敲鑼打鼓歡慶新春的年俗。
新年新氣象,今天就用代碼來制作一個(gè) 動(dòng)態(tài)鞭炮 ,
效果如下所示:
動(dòng)態(tài)鞭炮的基本原理是:將一個(gè)錄制好的鞭炮視頻以字符畫的形式復(fù)現(xiàn),基本步驟是幀采樣 → 逐幀轉(zhuǎn)換為字符畫 → 字符畫合成視頻。下面開始吧!
1 視頻幀采樣
函數(shù)如下所示,主要功能是將視頻的圖像流逐幀保存到特定的緩存文件夾中(若該文件夾不存在會(huì)自動(dòng)創(chuàng)建)。函數(shù)輸入vp是openCV
視頻句柄,輸出number
是轉(zhuǎn)換的圖片數(shù)。
def video2Pic(vp): ? ? number = 0 ? ? if vp.isOpened(): ? ? ? ? r,frame = vp.read() ? ? ? ? if not os.path.exists('cachePic'): ? ? ? ? ? ? os.mkdir('cachePic') ? ? ? ? os.chdir('cachePic') ? ? else: ? ? ? ? r = False ? ? while r: ? ? ? ? number += 1 ? ? ? ? cv2.imwrite(str(number)+'.jpg',frame) ? ? ? ? r,frame = vp.read() ? ? os.chdir("..") ? ? return number
2 將圖片轉(zhuǎn)為字符畫
2.1 創(chuàng)建像素-字符索引
函數(shù)輸入像素RGBA
值,輸出對(duì)應(yīng)的字符碼。其原理是將字符均勻地分布在整個(gè)灰度范圍內(nèi),像素灰度值落在哪個(gè)區(qū)間就對(duì)應(yīng)哪個(gè)字符碼。字符碼可以參考 ASCII碼
ASCII 碼使用指定的7 位或8 位二進(jìn)制數(shù)組合來表示128 或256 種可能的字符。標(biāo)準(zhǔn)ASCII 碼也叫基礎(chǔ)ASCII碼,使用7 位二進(jìn)制數(shù)(剩下的1位二進(jìn)制為0)來表示所有的大寫和小寫字母,數(shù)字0 到9、標(biāo)點(diǎn)符號(hào),以及在美式英語中使用的特殊控制字符。其中:0~31及127(共33個(gè))是控制字符或通信專用字符(其余為可顯示字符),如控制符:LF(換行)、CR(回車)、FF(換頁)、DEL(刪除)、BS(退格)、BEL(響鈴)等;通信專用字符:SOH(文頭)、EOT(文尾)、ACK(確認(rèn))等;ASCII值為8、9、10 和13 分別轉(zhuǎn)換為退格、制表、換行和回車字符。它們并沒有特定的圖形顯示,但會(huì)依不同的應(yīng)用程序,而對(duì)文本顯示有不同的影響。
RGBA
是代表Red(紅色)、Green(綠色)、Blue(藍(lán)色)和Alpha的色彩空間,Alpha通道一般用作不透明度參數(shù)。如果一個(gè)像素的alpha通道數(shù)值為0%,那它就是完全透明的,而數(shù)值為100%則意味著一個(gè)完全不透明的像素(傳統(tǒng)的數(shù)字圖像)。gray=0.2126 * r + 0.7152 * g + 0.0722 * b是RGB轉(zhuǎn)為灰度值的經(jīng)驗(yàn)公式,人眼對(duì)綠色更敏感。
def color2Char(r,g,b,alpha = 256): ? ? imgChar= list("#RMNHQODBWGPZ*@$C&98?32I1>!:-;. ") ? ? if alpha: ? ? ? gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b) ? ? ? unit = 256 / len(imgChar) ? ? ? return imgChar[int(gray / unit)] ? ? else: ? ? ? return ''
2.2 將圖片逐像素轉(zhuǎn)換為字符
核心代碼如下,遍歷圖片的每個(gè)像素
? ? img = Image.open(imagePath).convert('RGB').resize((imgWidth, imgHeight),Image.NEAREST) ? ? for i in range(imgHeight): ? ? ? ? for j in range(imgWidth): ? ? ? ? ? ? pixel = img.getpixel((j, i)) ? ? ? ? ? ? color.append((pixel[0],pixel[1],pixel[2])) ? ? ? ? ? ? txt = txt + color2Char(pixel[0], pixel[1], pixel[2], pixel[3]) if len(pixel) == 4 else \ ? ? ? ? ? ? ? ? ? txt + color2Char(pixel[0], pixel[1], pixel[2])? ? ? ? ? txt += '\n' ? ? ? ? color.append((255,255,255))
3 將字符圖像合成視頻
輸入?yún)?shù)vp是openCV
視頻句柄,number
是幀數(shù),savePath是視頻保存路徑,函數(shù)中 MP42 是可以生成較小并且較小的視頻文件的編碼方式,其他類似的還有isom、mp41、avc1、qt等,表示“最好”基于哪種格式來解析當(dāng)前的文件。
def img2Video(vp, number, savePath): ? ? videoFourcc = VideoWriter_fourcc(*"MP42") ?# 設(shè)置視頻編碼器 ? ? asciiImgPathList = ['cacheChar' + r'/{}.jpg'.format(i) for i in range(1, number + 1)] ? ? asciiImgTemp = Image.open(asciiImgPathList[1]).size ? ? videoWritter= VideoWriter(savePath, videoFourcc, vp.get(cv2.CAP_PROP_FPS), asciiImgTemp) ? ? for imagePath in asciiImgPathList: ? ? ? ? videoWritter.write(cv2.imread(imagePath)) ? ? videoWritter.release()
4 完整代碼
import cv2? from PIL import Image,ImageFont,ImageDraw import os from cv2 import VideoWriter, VideoWriter_fourcc ''' * @breif: 將像素顏色轉(zhuǎn)換為ASCII字符 * @param[in]: 像素RGBA值 * @retval: 字符 ''' def color2Char(r,g,b,alpha = 256): ? ? imgChar = list("#RMNHQODBWGPZ*@$C&98?32I1>!:-;. ") ? ? if alpha: ? ? ? gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b) ? ? ? unit = 256 / len(imgChar) ? ? ? return imgChar[int(gray / unit)] ? ? else: ? ? ? return '' ? ''' * @breif: 將視頻逐幀轉(zhuǎn)換為圖片 * @param[in]: vp -> openCV視頻句柄 * @retval: number -> 轉(zhuǎn)換的圖片數(shù) ''' def video2Pic(vp): ? ? number = 0 ? ? if vp.isOpened(): ? ? ? ? r,frame = vp.read() ? ? ? ? if not os.path.exists('cachePic'): ? ? ? ? ? ? os.mkdir('cachePic') ? ? ? ? os.chdir('cachePic') ? ? else: ? ? ? ? r = False ? ? while r: ? ? ? ? number += 1 ? ? ? ? cv2.imwrite(str(number)+'.jpg',frame) ? ? ? ? r,frame = vp.read() ? ? os.chdir("..") ? ? return number ? ''' * @breif: 將圖片逐像素轉(zhuǎn)換為ASCII字符 * @param[in]: imagePath -> 圖片路徑 * @param[in]: index -> 圖片索引 * @retval: None ''' def img2Char(imagePath, index): ? ? # 初始化 ? ? txt, color, font = '', [], ImageFont.load_default().font ? ? imgWidth, imgHeight = Image.open(imagePath).size ? ? asciiImg = Image.new("RGB",(imgWidth, imgHeight), (255,255,255)) ? ? drawPtr = ImageDraw.Draw(asciiImg) ? ? imgWidth, imgHeight = int(imgWidth / 6), int(imgHeight / 15) ? ? # 對(duì)圖像幀逐像素轉(zhuǎn)化為ASCII字符并記錄RGB值 ? ? img = Image.open(imagePath).convert('RGB').resize((imgWidth, imgHeight),Image.NEAREST) ? ? for i in range(imgHeight): ? ? ? ? for j in range(imgWidth): ? ? ? ? ? ? pixel = img.getpixel((j, i)) ? ? ? ? ? ? color.append((pixel[0],pixel[1],pixel[2])) ? ? ? ? ? ? txt = txt + color2Char(pixel[0], pixel[1], pixel[2], pixel[3]) if len(pixel) == 4 else \ ? ? ? ? ? ? ? ? ? txt + color2Char(pixel[0], pixel[1], pixel[2])? ? ? ? ? txt += '\n' ? ? ? ? color.append((255,255,255)) ? ?? ? ? # 繪制ASCII字符畫并保存 ? ? x, y = 0,0 ? ? fontW, fontH = font.getsize(txt[1]) ? ? fontH *= 1.37 ? ? for i in range(len(txt)): ? ? ? ? if(txt[i]=='\n'): ? ? ? ? ? ? x += fontH ? ? ? ? ? ? y = -fontW ? ? ? ? drawPtr.text((y,x), txt[i], fill=color[i]) ? ? ? ? y += fontW ? ? os.chdir('cacheChar') ? ? asciiImg.save(str(index)+'.jpg') ? ? os.chdir("..") ''' * @breif: 將視頻轉(zhuǎn)換為ASCII圖像集 * @param[in]: number -> 幀數(shù) * @retval: None '''? def video2Char(number): ? ? if not os.path.exists('cacheChar'): ? ? ? ? os.mkdir('cacheChar') ? ? img_path_list = ['cachePic' + r'/{}.jpg'.format(i) for i in range(1, number + 1)]? ? ? task = 0 ? ? for imagePath in img_path_list: ? ? ? ? task += 1 ? ? ? ? img2Char(imagePath, task) ''' * @breif: 將圖像合成視頻 * @param[in]: vp -> openCV視頻句柄 * @param[in]: number -> 幀數(shù) * @param[in]: savePath -> 視頻保存路徑 * @retval: None ''' ? def img2Video(vp, number, savePath): ? ? videoFourcc = VideoWriter_fourcc(*"MP42") ?# 設(shè)置視頻編碼器 ? ? asciiImgPathList = ['cacheChar' + r'/{}.jpg'.format(i) for i in range(1, number + 1)] ? ? asciiImgTemp = Image.open(asciiImgPathList[1]).size ? ? videoWritter= VideoWriter(savePath, videoFourcc, vp.get(cv2.CAP_PROP_FPS), asciiImgTemp) ? ? for imagePath in asciiImgPathList: ? ? ? ? videoWritter.write(cv2.imread(imagePath)) ? ? videoWritter.release() ? ?? if __name__ == '__main__':? ? videoPath = 'test.mp4' ? savePath = 'new.avi' ? vp = cv2.VideoCapture(videoPath) ? number = video2Pic(vp) ? video2Char(number) ? img2Video(vp, number, savePath) ? vp.release()
到此這篇關(guān)于 Python 代碼制作動(dòng)態(tài)鞭炮的文章就介紹到這了,更多相關(guān) Python 制作動(dòng)態(tài)鞭炮內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
5 參考
[1] B站《大二AE結(jié)課作業(yè) 《過 年》(已擺爛)》
[2] https://hongcyu.cn/posts/opencv-pictovideo.html
相關(guān)文章
Pycharm Terminal 與Project interpreter 安裝
本文主要介紹了Pycharm Terminal 與Project interpreter 安裝包不同步問題解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02python操作excel文件并輸出txt文件的實(shí)例
今天小編就為大家分享一篇python操作excel文件并輸出txt文件的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-07-07Python搭建代理IP池實(shí)現(xiàn)接口設(shè)置與整體調(diào)度
這篇文章主要介紹了Python搭建代理IP池實(shí)現(xiàn)接口設(shè)置與整體調(diào)度,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10Python實(shí)現(xiàn)爬蟲爬取NBA數(shù)據(jù)功能示例
這篇文章主要介紹了Python實(shí)現(xiàn)爬蟲爬取NBA數(shù)據(jù)功能,涉及Python針對(duì)URL模塊、字符串、列表遍歷、Excel寫入等相關(guān)操作技巧,需要的朋友可以參考下2018-05-05在pycharm中使用git版本管理以及同步github的方法
今天小編就為大家分享一篇在pycharm中使用git版本管理以及同步github的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-01-01python操作MySQL數(shù)據(jù)庫的方法分享
堅(jiān)持每天學(xué)一點(diǎn),每天積累一點(diǎn)點(diǎn),作為自己每天的業(yè)余收獲,這個(gè)文章是我在吃飯的期間寫的,利用自己零散的時(shí)間學(xué)了一下python操作MYSQL,所以整理一下2012-05-05使用Python實(shí)現(xiàn)with結(jié)構(gòu)的@contextmanager方法詳解
這篇文章主要介紹了使用Python實(shí)現(xiàn)with結(jié)構(gòu)的@contextmanager方法詳解,這個(gè)結(jié)構(gòu)的好處,一個(gè)是簡潔,一個(gè)是當(dāng)我們對(duì)文件操作的邏輯很長的時(shí)候,不會(huì)因?yàn)橥岁P(guān)閉文件而造成不必要的錯(cuò)誤,需要的朋友可以參考下2023-07-07Python format補(bǔ)0的實(shí)現(xiàn)方法
對(duì)于一些數(shù)字的處理,我們可能需要讓它們滿足一定格式的要求,本文主要介紹了Python format補(bǔ)0的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07