今天刷抖音,看到了一个《极乐净土》的字符动画,舞蹈看起来妖娆啊,满屏幕的字符勾勒出美女的身影,在配上极乐净土的音乐,简直是程序员们的精神食粮啊!!!!
以前也遇到过这种字符动画,当时简单想了想,大概就是控制台的字符输出刷新,再输出什么的吧,只是觉得所有字符手撸太累了,就没深入思考,今天看到这个《极乐净土》中途压制不住内心的冲动,要自己动手来一个了。
关于原理什么的,这篇文章介绍的比较多,我就不多赘述了,也感谢这位老哥提供思路,不然这么久的python图像处理感觉白玩了
视频转字符动画-Python-60行代码
该教程基于python使用openvc做的,我下面的代码使用skimage实现的:
from skimage import color,transform as trans
import imageio
class Transfer:
# 视频路径
__video_path = ''
# 视频中提取出来的帧图像
__input_imgs = []
# 字符填充 从左到右辨识度增加
__pixels = " .,-'`:!1+*abcdefghijklmnopqrstuvwxyz<>()\/{}[]?234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ%&@#$"
# 输出的字符'图像'
__output_imgs = []
# 填充字符长度
__pixels_length = 0
def run(self):
self.__pixels_lenth = len(self.__pixels)
self.__readVideo()
self.__transImgsIntoChars()
print(len(self.__output_imgs))
self.__play()
# echo 0
# 设置视频路径
def setVideo(self, video_path):
self.__video_path = video_path
return self
# 读取视频的每一帧图像转化为灰度图,输出图像列表
def __readVideo(self):
imgs = imageio.get_reader(self.__video_path,'ffmpeg')
for num,img in enumerate(imgs):
print(img.shape)
a = color.rgb2gray(img)
# 根据你控制台的尺寸自己定义resize后的尺寸
b = trans.resize(a, (64, 64),1,None,0,True,True,None,None)
self.__input_imgs.append(b)
# 灰度图像转化为字符图像
def __transImgsIntoChars(self):
for input in self.__input_imgs:
item = []
(h,w) = input.shape
for row in range(h):
row_chars = ''
for col in range(w):
index = int(input[row][col] * (self.__pixels_lenth -1))
row_chars += self.__pixels[index]
item.append(row_chars)
self.__output_imgs.append(item)
# 播放
def __play(self):
import time
import curses
width, height = len(self.__output_imgs[0][0]), len(self.__output_imgs[0])
stdscr = curses.initscr()
curses.start_color()
try:
# 调整窗口大小,宽度最好略大于字符画宽度。另外注意curses的height和width的顺序
stdscr.resize(height, width * 2)
for pic_i in range(len(self.__output_imgs)):
# 显示 pic_i,即第i帧字符画
for line_i in range(height):
# 将pic_i的第i行写入第i列。(line_i, 0)表示从第i行的开头开始写入。最后一个参数设置字符为白色
stdscr.addstr(line_i, 0, self.__output_imgs[pic_i][line_i], curses.COLOR_WHITE)
stdscr.refresh() # 写入后需要refresh才会立即更新界面
time.sleep(1 / 24) # 粗略地控制播放速度。更精确的方式是使用游戏编程里,精灵的概念
finally:
# curses 使用前要初始化,用完后无论有没有异常,都要关闭
curses.endwin()
# print(1)
video_path = './1532448544946410.mp4'
a = Transfer()
a.setVideo(video_path).run()
上面的代码直接粘贴,视频可以用自己的,但是要注意调整尺寸,手机录的分辨率太高,控制台驾驭不了
b = trans.resize(a, (64, 64),1,None,0,True,True,None,None)
这行代码里面的(64,64)就是resize后的尺寸
执行的话最好在控制台操作,不要直接在IDE里面运行
下图所示分别为原视频截图和字符动画截图
很晚了,要猝死了,今天先到这,后续再研究其他的吧