作者 | FrigidWinter

来源 | CSDN博客

放鞭炮贺新春,在我国有两千多年历史。关于鞭炮的起源,有个有趣的传说。

西方山中有焉,长尺余,一足,性不畏人。犯之令人寒热,名曰年惊惮,后人遂象其形,以火药为之。——《神异经》

当初人们燃竹而爆,是为了驱吓危害人们的山魈。据说山魈最怕火光和响声,所以每到除夕,人们便“燃竹而爆”,把山魈吓跑。这样年复一年,便形成了过年放鞭炮、点红烛、敲锣打鼓欢庆新春的年俗。

新年新气象,今天就用代码来制作一个 动态鞭炮 ,效果如下所示。

动态鞭炮的基本原理是:将一个录制好的鞭炮视频以字符画的形式复现,基本步骤是帧采样 → 逐帧转换为字符画 → 字符画合成视频。下面开始吧!

视频帧采样

函数如下所示,主要功能是将视频的图像流逐帧保存到特定的缓存文件夹中(若该文件夹不存在会自动创建)。函数输入vp是openCV视频句柄,输出number是转换的图片数。

def video2Pic(vp):number = 0if vp.isOpened():r,frame = vp.read()if not os.path.exists('cachePic'):os.mkdir('cachePic')os.chdir('cachePic')else:r = Falsewhile r:number += 1cv2.imwrite(str(number)+'.jpg',frame)r,frame = vp.read()os.chdir("..")return number

将图片转为字符画

2.1 创建像素-字符索引

函数输入像素RGBA值,输出对应的字符码。其原理是将字符均匀地分布在整个灰度范围内,像素灰度值落在哪个区间就对应哪个字符码。字符码可以参考 ASCII码。

RGBA是代表Red(红色)、Green(绿色)、Blue(蓝色)和Alpha的色彩空间,Alpha通道一般用作不透明度参数。如果一个像素的alpha通道数值为0%,那它就是完全透明的,而数值为100%则意味着一个完全不透明的像素(传统的数字图像)。gray=0.2126 * r + 0.7152 * g + 0.0722 * b是RGB转为灰度值的经验公式,人眼对绿色更敏感。

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 将图片逐像素转换为字符

核心代码如下,遍历图片的每个像素

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))

将字符图像合成视频

输入参数vp是openCV视频句柄,number是帧数,savePath是视频保存路径,函数中 MP42 是可以生成较小并且较小的视频文件的编码方式,其他类似的还有isom、mp41、avc1、qt等,表示“最好”基于哪种格式来解析当前的文件。

def img2Video(vp, number, savePath):videoFourcc = VideoWriter_fourcc(*"MP42")  # 设置视频编码器asciiImgPathList = ['cacheChar' + r'/{}.jpg'.format(i) for i in range(1, number + 1)]asciiImgTemp = Image.open(asciiImgPathList[1]).sizevideoWritter= VideoWriter(savePath, videoFourcc, vp.get(cv2.CAP_PROP_FPS), asciiImgTemp)for imagePath in asciiImgPathList:videoWritter.write(cv2.imread(imagePath))videoWritter.release()

完整代码

import cv2
from PIL import Image,ImageFont,ImageDraw
import os
from cv2 import VideoWriter, VideoWriter_fourcc'''
* @breif: 将像素颜色转换为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: 将视频逐帧转换为图片
* @param[in]: vp -> openCV视频句柄
* @retval: number -> 转换的图片数
'''
def video2Pic(vp):number = 0if vp.isOpened():r,frame = vp.read()if not os.path.exists('cachePic'):os.mkdir('cachePic')os.chdir('cachePic')else:r = Falsewhile r:number += 1cv2.imwrite(str(number)+'.jpg',frame)r,frame = vp.read()os.chdir("..")return number'''
* @breif: 将图片逐像素转换为ASCII字符
* @param[in]: imagePath -> 图片路径
* @param[in]: index -> 图片索引
* @retval: None
'''
def img2Char(imagePath, index):# 初始化txt, color, font = '', [], ImageFont.load_default().fontimgWidth, imgHeight = Image.open(imagePath).sizeasciiImg = Image.new("RGB",(imgWidth, imgHeight), (255,255,255))drawPtr = ImageDraw.Draw(asciiImg)imgWidth, imgHeight = int(imgWidth / 6), int(imgHeight / 15)# 对图像帧逐像素转化为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,0fontW, fontH = font.getsize(txt[1])fontH *= 1.37for i in range(len(txt)):if(txt[i]=='\n'):x += fontHy = -fontWdrawPtr.text((y,x), txt[i], fill=color[i])y += fontWos.chdir('cacheChar')asciiImg.save(str(index)+'.jpg')os.chdir("..")'''
* @breif: 将视频转换为ASCII图像集
* @param[in]: number -> 帧数
* @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 = 0for imagePath in img_path_list:task += 1img2Char(imagePath, task)'''
* @breif: 将图像合成视频
* @param[in]: vp -> openCV视频句柄
* @param[in]: number -> 帧数
* @param[in]: savePath -> 视频保存路径
* @retval: None
'''
def img2Video(vp, number, savePath):videoFourcc = VideoWriter_fourcc(*"MP42")  # 设置视频编码器asciiImgPathList = ['cacheChar' + r'/{}.jpg'.format(i) for i in range(1, number + 1)]asciiImgTemp = Image.open(asciiImgPathList[1]).sizevideoWritter= 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()

技术

盘一盘程序员们喜欢的数据网站

资讯

算力超越iPhone,芯片堪比Mac

技术

31个好用的Python字符串方法

资讯

游戏圈地震级消息,微软收购动视暴雪

分享

点收藏

点点赞

点在看

新年新气象,100 行 Python 代码制作动态鞭炮相关推荐

  1. 新年新气象,100行 Python 代码制作动态鞭炮

  2. 教你用1行Python代码制作动态二维码

    在GitHub上发现了一个比较有意思的项目,只需要一行Python代码就可以快捷方便生成普通二维码.艺术二维码(黑白/彩色)和动态GIF二维码. GitHub网站参见:https://github.c ...

  3. 超动感,百行Python代码制作动态气泡图

    先上图片: 再上视频: 最后上代码: import numpy as np import pandas as pd from matplotlib import pyplot as plt impor ...

  4. 1行Python代码制作动态二维码

    目录 1.二维码简介 2.普通二维码 3.艺术二维码 4.动态二维码 1.二维码简介 目前流行的二维码(QR code)是1994年由日本Denso-Wave公司发明的.英文字中 QR 所代表的意义是 ...

  5. 100个必会的python脚本-100行Python代码实现自动抢火车票(附源码)

    前言 又要过年了,今年你不妨自己写一段代码来抢回家的火车票,是不是很Cool.下面话不多说了,来一起看看详细的介绍吧. 先准备好: 12306网站用户名和密码 chrome浏览器及下载chromedr ...

  6. c语言微信挑一挑编程,100行python代码实现微信跳一跳辅助程序

    写在前面 分享一下今天下午用python写的"跳一跳"小游戏的辅助程序.之前是准备用树莓派操控一个"机械手指"来代替人的触摸操作,但该方案还在酝酿中,实现了再分 ...

  7. python做出来的小程序、可以在win10上面运行_超详细,手把手教你用20行Python代码制作飞花令小程序!...

    原标题:超详细,手把手教你用20行Python代码制作飞花令小程序! 来源:早起Python 作者:陈熹 飞花令是古时候人们经常玩一种"行酒令"的游戏,是中国古代酒令之一,属雅令. ...

  8. 如何用python破解热点_用30行Python代码制作wifi万能钥匙,邻居家wifi网速好快

    原标题:用30行Python代码制作wifi万能钥匙,邻居家wifi网速好快 当我们拖着疲惫的身体下班回到家,想开开心心的吹着空调风扇吃着西瓜,然后手机连上wifi打一把游戏好好舒服下,然而家里wif ...

  9. 100行python代码做一个程序_100行python代码实现微信跳一跳辅助程序

    写在前面 分享一下今天下午用python写的"跳一跳"小游戏的辅助程序.之前是准备用树莓派操控一个"机械手指"来代替人的触摸操作,但该方案还在酝酿中,实现了再分 ...

最新文章

  1. linux ftp perl上传脚本
  2. vbs删除非空文件夹
  3. vb的VSFlexGrid控件
  4. 核fisher matlab,使用Fisher法matlab结合P值?
  5. LAMP结构-访问日志
  6. uniapp阿里云图标库如何本地引入
  7. ftp文件下载工具,四款超级好用的ftp文件下载工具
  8. acm 程序设计大赛各种输入方式(python版)
  9. 正态总体的样本均值与样本方差的分布定理
  10. 青出于蓝胜于蓝 dfs+树状数组
  11. 光耦w314的各引脚图_a3140光耦用什么代替
  12. 2022-2027年中国开采沙石行业发展监测及投资战略研究报告
  13. 项目经理如何处理中途接手的项目
  14. 大牛博士是如何进行文献检索和阅读的
  15. Json与XML在线互转工具
  16. 17正交矩阵和Gram-Schmidt正交化
  17. 第三届世界5G大会召开之前,我们来复习一下这本6G白皮书
  18. 使用命令行进行替换文件
  19. 外企面试最常见的八大英文问题
  20. 【毕业季·进击的技术er】 什么是微信小程序,带你推开小程序的大门

热门文章

  1. java技术培训之File类中常用的构造方法
  2. 学Python有哪些优势
  3. ASP.NET MVC4中调用WEB API的四个方法
  4. whoosh学习(1)
  5. 最大匹配、最小顶点覆盖、最大独立集、最小路径覆盖(转)
  6. 资质申报 - 系统集成企业资质等级评定条件(2012年修定版)
  7. java百度api人脸识别_百度人脸识别api demo
  8. TFmini传感器使用
  9. cmake, This may result in binaries being created in the wrong place
  10. Git,Github和Gitlab简介和使用方法