美文网首页Python新世界python热爱者
python有趣的项目那么多,这个GIF转字符动画竟然没上榜!

python有趣的项目那么多,这个GIF转字符动画竟然没上榜!

作者: 48e0a32026ae | 来源:发表于2018-12-10 15:06 被阅读2次

    大概没有什么比解决现实世界里的问题更令一个创造者着迷的了

    趣学Python系列是用python实现一系列小K觉得有意思的功能,灵感来自于网络或自己的生活,实现都比较简单,不涉及复杂的技巧,适合新手入门,希望做到有趣又有用^_^。

    学习Python中有不明白推荐加入交流群

                    号:960410445

                    群里有志同道合的小伙伴,互帮互助,

                    群里有不错的视频学习教程和PDF!

    话不多说,下面进入正题:用Python制作字符动画

    不知道大家有没有见过这种动图:

    第一次在网上见到这种字符动画,内容有点不可描述,咳咳。总之就是惊为天人的感觉吧,第一反应就是:卧槽,还能这么玩?!后来琢磨了一下,做起来应该没啥难度,正好在学Python,顺手实现一个。

    0x00 环境

    系统:Ubuntu Mate

    Python版本:3.7,2.x太古老了,入手Python还是直接上3.x吧

    用到的库:

    pillow:著名的图片处理库

    imageio:从库的名字上就可以看出它的功能,主要是图像读写,用户最后将多张PNG合成

    GIF

    argparser:用于提供良好的cli

    0x01 思路

    将GIF图片拆分成多张图片,可以通过pillow的Image模块实现

    将每一张图片处理为字符画:

    将图片划分成小块,作为后续处理的最小单元,每个单元的颜色近似为其左上角的RGB数值

    计算每个单元的灰度值,灰度值计算公式为:0.2126 * r + 0.7152 * g + 0.0722 * b

    根据灰度值将ASCII字符串映射到对应的单元,同时记录每个单元原来的RGB

    创建创建字符画对象,将ASCII写入到对应单元,并用记录的RGB数值填充

    将生成的字符画合成GIF动图

    0x02 具体实现

    1. 拆分 GIF

    1def gif2png(fileName, asciiChar, font, isgray, scale):

    2 ''' 将GIF拆分,并将每一帧处理成字符画

    3 fileName: GIF文件

    4 asciiChar: 灰度值对应的字符串

    5 font: ImageFont对象

    6 isgray: 是否生成黑白动图

    7 scale: 缩放比例

    8 '''

    9 im = Image.open(fileName) # GIF文件打开为一个序列

    10 path = os.getcwd()

    11 # Cache文件用以保存拆分后的图片和生成的字符画

    12 if(not os.path.exists(path+"/Cache")):

    13 os.mkdir(path+"/Cache")

    14 os.chdir(path+"/Cache")

    15 # 清空Cache文件夹下的内容,防止多次运行时被之前的文件影响

    16 for f in os.listdir(path+"/Cache"):

    17 os.remove(f)

    18 # GIF打开后的序列通过tell返回每一帧的索引,超出索引范围后抛出异常

    19 try:

    20 while 1:

    21 current = im.tell()

    22 name = fileName.split('.')[0]+'-'+str(current)+'.png'

    23 im.save(name) # 保存每一帧图片

    24 # 将每一帧处理为字符画

    25 img2ascii(name, asciiChar, font, isgray, scale)

    26 im.seek(current+1) # 继续处理下一帧

    27 except:

    28 os.chdir(path)

    2. 将每一帧图片转换为字符画

    首先需要将图片转换为RGB模式,并根据图片大小设定转换后的图片尺寸

    1im = Image.open(img).convert('RGB') # 注意,此处需要先将图片转换为RGB模式

    2# 设定处理后的字符画大小,需要为整型

    3raw_width = int(im.width * scale)

    4raw_height = int(im.height * scale)

    然后根据设定的字体大小和缩放倍数确定单元尺寸

    1# 获取设定的字体的尺寸,ImageFont默认的尺寸大小为6x11,其他字体会有所不同

    2# 此处使用的字体为truetype字体,大小为10px

    3font_x, font_y = font.getsize(' ')

    4# 确定单元的大小

    5block_x = int(font_x * scale)

    6block_y = int(font_y * scale)

    之后将图片进行缩放,每一个单元对应缩放后的一个像素点

    1# 确定长宽各有几个单元

    2w = int(raw_width/block_x)

    3h = int(raw_height/block_y)

    4# 将每个单元缩小为一个像素

    5im = im.resize((w, h), Image.NEAREST)

    对缩放后图片的每个像素点进行遍历,记录对应的字符和RGB数值,分别保存在txts和colors中。getpixel返回的是一个包含RGB值的元组,前三项分别为R、G、B的值。

    1# txts和colors分别存储对应块的ASCII字符和RGB值

    2txts = []

    3colors = []

    4for i in range(h):

    5 line = ''

    6 lineColor = []

    7 for j in range(w):

    8 pixel = im.getpixel((j, i))

    9 lineColor.append((pixel[0], pixel[1], pixel[2]))

    10 line += get_char(asciiChar, pixel[0], pixel[1], pixel[2])

    11txts.append(line)

    12colors.append(lineColor)

    遍历txts和colors,写入到新的画布上,生成字符画

    1# 创建新画布

    2im_txt = Image.new("RGB", (raw_width, raw_height), (255, 255, 255))

    3# 创建ImageDraw对象以写入ASCII

    4draw_handle = ImageDraw.Draw(im_txt)

    5for j in range(len(txts)):

    6 for i in range(len(txts[0])):

    7 if isgray:

    8 draw_handle.text((i*block_x, j*block_y), txts[j][i], (50, 50, 50))

    9 else:

    10 draw_handle.text((i*block_x, j*block_y), txts[j][i], colors[j][i])

    11im_txt.save(img)

    3. 将多张图片合成为GIF

    主要通过imageio库来实现GIF图片的合成,其中duration为每一帧图像的持续时间,默认为0.2秒。

    1# 读取Cache文件夹下的文件,合成GIF动画

    2def png2gif(dir_name, duration):

    3 path = os.getcwd()

    4 os.chdir(dir_name)

    5 dirs = os.listdir()

    6 images = []

    7 num = 0

    8 for d in dirs:

    9 images.append(imageio.imread(d))

    10 num += 1

    11 os.chdir(path)

    12 imageio.mimsave(d.split('-')[0]+'-ascii.gif',images,duration = duration)

    0x03 注意事项

    传入参数的类型,如Image.new、Image.resize中的尺寸均需转换为整型

    处理拆分后的图像时需要转换为RGB模式

    遍历图像时注意外层循环为高度,内层循环为宽度

    相关文章

      网友评论

        本文标题:python有趣的项目那么多,这个GIF转字符动画竟然没上榜!

        本文链接:https://www.haomeiwen.com/subject/xdorhqtx.html