字符动画从零制作

先展示一下效果吧


badapple


对动画有了解的人应该知道,动画看起来是流畅的动作,但其实是连续快速播放一张张图片,欺骗眼睛达到的效果,字符动画也是这样的原理,所以要想制作字符动画,要先获取视频中逐帧的图片。

视频的获取

哔哩哔哩视频下载 我下载的是哔哩哔哩的badapple视频,这个视频制作出来的字符动画效果非常好

视频按帧数截取

import cv2
import os
#要提取视频的文件名,隐藏后缀
sourceFileName='badapple'
#在这里把后缀接上
video_path = os.path.join("", "", sourceFileName+'.mp4')
times=0
a=100
#提取视频的频率,每10帧提取一个
frameFrequency=10
#输出图片到当前目录vedio文件夹下
outPutDirName='tupian/'
if not os.path.exists(outPutDirName):
    #如果文件目录不存在则创建目录
    os.makedirs(outPutDirName) 
camera = cv2.VideoCapture(video_path)
while True:
    times+=1
    res, image = camera.read()
    if not res:
        print('not res , not image')
        break
    if times%frameFrequency==0:
        cv2.imwrite(outPutDirName + str(a)+'.jpg', image)
        print(outPutDirName + str(a)+'.jpg')
        a+=1
print('图片提取结束')
camera.release()
注意

这里可能仔细的人会发现,我定义a=100,图片命名是从100开始的,后面会提到原因。

图片转为字符图片

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

def ascii_art(file,i):
    im=Image.open(file)
    # 增强亮度的值,制作彩色字符效果不好时使用
    # brightness = 2  # 增强亮度的值
    # enh_bri = ImageEnhance.Brightness(im)
    # im = enh_bri.enhance(brightness)

    sample_rate=0.15
    font=ImageFont.truetype('SourceCodePro-Regular.ttf')
    aspect_ratio=font.getsize('x')[0]/font.getsize('x')[1]
    new_im_size=np.array([im.size[0]*sample_rate,im.size[1]*sample_rate*aspect_ratio]).astype(int)
    im=im.resize(new_im_size)
    im_color=np.array(im)
    im=im.convert('L')
    im=np.array(im)
    symbols=np.array(list(' .vM'))
    im=(im-im.min())/(im.max()-im.min())*(symbols.size-1)
    ascii=symbols[im.astype(int)]

    #输出单张图片的字符,使用时注释该函数内全部下文
    # lines='\n'.join((''.join(r)for r in ascii))
    # print(lines)

    # 创建一个jpg图片
    letter_size=font.getsize('x')
    im_out_size=new_im_size*letter_size
    bg_color='black'
    im_out=Image.new('RGB',tuple(im_out_size),bg_color)
    draw=ImageDraw.Draw(im_out)
    y=0
    #绘制黑白
    for line in ascii:
        for j,ch in enumerate(line):
            color=(255,255,255)
            draw.text((letter_size[0]*j,y),ch,fill=color,font=font)
        y+=letter_size[1]

    #绘制彩色
    # for a,line in enumerate(ascii):
    #     for j,ch in enumerate(line):
    #         color=tuple(im_color[a,j])
    #         draw.text((letter_size[0]*j,y),ch,fill=color,font=font)
    #     y+=letter_size[1]
    
    print(file+' to '+str(i)+'.jpg\n')
    im_out.save('zifu/'+str(i)+'.jpg')


if __name__=='__main__':
    #单张图片
    # file='any.jpg'
    # ascii_art(file, 1)

    #文件夹中所有的图片
    path='tupian'
    filelist=os.listdir(path)
    a=100
    for i in filelist:
        ascii_art('tupian/'+i,a)
        a+=1
    print('finish !')

这里就是我命名从100开始的原因,在使用os.listdir()返回文件名的列表时,文件原本1 2 3…9 10 11…的顺序就被变成了1 10 11 12…18 19 100 101…这样的顺序被存入列表,遍历时也是用这样错误的顺序遍历,导致看到的动画顺序错乱。只要图片数量小于900张都可以这样命名,小于9000张就从1000开始命名,以此类推。
最开始观看动画时发现这个问题并想到这个解决方法时还是挺高兴的,屏幕前的你有没有想到这个或者更好的解决方法呢 ^ ^

常见报错

1.cannot open resource

python gif 字符动画 python制作字符动画_动画

产生原因:

文件SourceCodePro-Regular.ttf缺失

解决方法:

1.下载地址 2.联系作者获取该文件2.index-2147483648 is out of bounds for axis 0 with size 4

python gif 字符动画 python制作字符动画_python_02

产生原因:

文件夹中含有纯白或纯黑色图片

解决方法:

命令行中会提示运行中断到哪张图片,删除该图片即可

顺便附上文件批量重命名代码

import os
path="shipin"	# 这里填文件夹路径
filelist = os.listdir(path) #该文件夹下所有文件
a=100
for file in filelist:
    os.rename('shipin/'+file,'shipin/'+str(a)+'.jpg')
    a+=1

播放图片

import matplotlib.pyplot as plt
import os
path='zifu'
filelist = os.listdir(path)
plt.ion()
for file in filelist:
    im = plt.imread('zifu/'+file)
    plt.figure('badapple')
    plt.axis('off')
    plt.imshow(im)
    plt.show()
    plt.pause(0.1)
    plt.clf()

做好以上内容就完成了字符动画的制作!

以前的存货应该还够写个两三篇博客,等我回想以前写过的代码,慢慢更新。