春节到,用 Python 代码制作动态鞭炮

312 阅读3分钟

我正在参加「兔了个兔」创意投稿大赛,详情请看:「兔了个兔」创意投稿大赛

前言 放鞭炮贺新春,在我国已经有有几千多年历史。关于鞭炮的起源,我们还有有个有趣的传说。听我说来。

相传在远古时代,有一种凶猛的怪兽叫“年”,一年四季都在深海里,但逢新旧岁之交,便出来糟踏壮稼,伤害人畜,百姓叫苦连天。有一次它又跑到村庄里为非作歹,被一家门口晾的大红衣服吓跑了。到了另一处,又被灯光吓得抱头鼠窜。于是人们掌握了“年”怕声音、怕红色、怕火光的弱点。每至年末岁首,人们就在家门口贴红联、放鞭炮、挂红灯,院子里烧柴禾、拢旺火,用菜刀剁菜肉,发出声音。所以过年大家都要放鞭炮。

正文

新年新气象,今天就用代码来制作一个 动态鞭炮

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

1 视频帧采样

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

    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 将图片转为字符画

2.1 创建像素-字符索引

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

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

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

    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 将字符图像合成视频

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

    videoFourcc = VideoWriter_fourcc(*"MP42")  # 设置视频编码器
    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()

效果如下:

2f6611a2bcd7433885a2253e3e86bf2c.gif

新的一年希望大家开开心心,过的愉快。