用Python字符画出了一个谷爱凌

 更新时间:2022年02月16日 10:58:46   作者:算法码上来  
之前经常在网上看到那种由一个个字符构成的视频,非常炫酷。本文也将利用Python字符画一个最近的冬奥冠军谷爱凌,感兴趣的小伙伴可以学习一下

之前经常在网上看到那种由一个个字符构成的视频,非常炫酷。一直不懂是怎么做的,这两天研究了一下,发现并不难。

先来看一个最终效果(如果模糊的话,点击下方链接看高清版):

https://pan.baidu.com/s/1DvedXlDZ4dgHKLogdULogg 提取码:1234

怎么实现的?

简单来说,要将一个彩色的视频变成字符画出来的黑白视频,用下面几步就能搞定:

  1. 对原视频进行抽帧,对每一帧黑白化,并将像素点用对应的字符表示。
  2. 将表示出来的字符串再重新组合成字符图像。
  3. 将所有的字符图像再组合成字符视频。
  4. 将原视频的音频导入到新的字符视频中。

运行方法

完整的代码我放在文章末尾了,直接运行python3 video2char.py即可。程序会要求你输入视频的本地路径和转变后的清晰度(0最模糊,1最清晰。当然越清晰,转变越慢)。

运行代码的话需要用到tqdm、opencv_python、moviepy等几个库,首先得pip3 install确保它们都有了。

原理分析

这里面最关键的步骤就是如何将一帧彩色图像转变为黑白的字符图像,如下图所示:

从青蛙公主视频抽帧出来的

用字符画出来的

而转变的原理其实很简单。首先因为一个字符画在图像里会占据很大一个像素块,所以必须先对彩色图像进行压缩,连续的一个像素块可以合并,这个压缩过程就是opencv的resize操作。

然后将压缩后的像素点转变为黑白像素点,并转变为对应的字符。字符的话我这里采用的是下面的字符串,从黑到白,经过我的实践这一组是效果最好的:

"#8XOHLTI)i=+;:,. "

接着就需要将转变后的字符画到新的画布上去,需要注意的点是排布得均匀紧凑了,画布四周最好不要有太多多余的空白。

最后把所有的字符图像合并成视频就行了,但是合并后是没有声音的,需要用moviepy库把原视频的声音导入过来。

完整代码

import os
import re
import shutil
from tqdm import trange, tqdm
import cv2
from PIL import Image, ImageFont, ImageDraw
from moviepy.editor import VideoFileClip
 
 
class V2Char:
    font_path = "Arial.ttf"
    ascii_char = "#8XOHLTI)i=+;:,. "
 
    def __init__(self, video_path, clarity):
        self.video_path = video_path
        self.clarity = clarity
 
    def video2str(self):
        def convert(img):
            if img.shape[0] > self.text_size[1] or img.shape[1] > self.text_size[0]:
                img = cv2.resize(img, self.text_size, interpolation=cv2.INTER_NEAREST)
            ascii_frame = ""
            for i in range(img.shape[0]):
                for j in range(img.shape[1]):
                    ascii_frame += self.ascii_char[
                        int(img[i, j] / 256 * len(self.ascii_char))
                    ]
            return ascii_frame
 
        print("正在将原视频转为字符...")
        self.char_video = []
        cap = cv2.VideoCapture(self.video_path)
        self.fps = cap.get(cv2.CAP_PROP_FPS)
        self.nframe = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        self.raw_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        self.raw_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
        font_size = int(25 - 20 * max(min(float(self.clarity), 1), 0))
        self.font = ImageFont.truetype(self.font_path, font_size)
        self.char_width, self.char_height = max(
            [self.font.getsize(c) for c in self.ascii_char]
        )
        self.text_size = (
            int(self.raw_width / self.char_width),
            int(self.raw_height / self.char_height),
        )
        for _ in trange(self.nframe):
            raw_frame = cv2.cvtColor(cap.read()[1], cv2.COLOR_BGR2GRAY)
            frame = convert(raw_frame)
            self.char_video.append(frame)
        cap.release()
 
    def str2fig(self):
        print("正在生成字符图像...")
        col, row = self.text_size
        catalog = self.video_path.split(".")[0]
        if not os.path.exists(catalog):
            os.makedirs(catalog)
        blank_width = int((self.raw_width - self.text_size[0] * self.char_width) / 2)
        blank_height = int((self.raw_height - self.text_size[1] * self.char_height) / 2)
        for p_id in trange(len(self.char_video)):
            strs = [self.char_video[p_id][i * col : (i + 1) * col] for i in range(row)]
            im = Image.new("RGB", (self.raw_width, self.raw_height), (255, 255, 255))
            dr = ImageDraw.Draw(im)
            for i, str in enumerate(strs):
                for j in range(len(str)):
                    dr.text(
                        (
                            blank_width + j * self.char_width,
                            blank_height + i * self.char_height,
                        ),
                        str[j],
                        font=self.font,
                        fill="#000000",
                    )
            im.save(catalog + r"/pic_{}.jpg".format(p_id))
 
    def jpg2video(self):
        print("正在将字符图像合成字符视频...")
        catalog = self.video_path.split(".")[0]
        images = os.listdir(catalog)
        images.sort(key=lambda x: int(re.findall(r"\d+", x)[0]))
        im = Image.open(catalog + "/" + images[0])
        fourcc = cv2.VideoWriter_fourcc("m", "p", "4", "v")
        savedname = catalog.split("/")[-1]
        vw = cv2.VideoWriter(savedname + "_tmp.mp4", fourcc, self.fps, im.size)
        for image in tqdm(images):
            frame = cv2.imread(catalog + "/" + image)
            vw.write(frame)
        vw.release()
        shutil.rmtree(catalog)
 
    def merge_audio(self):
        print("正在将音频合成到字符视频中...")
        raw_video = VideoFileClip(self.video_path)
        char_video = VideoFileClip(self.video_path.split(".")[0] + "_tmp.mp4")
        audio = raw_video.audio
        video = char_video.set_audio(audio)
        video.write_videofile(
            self.video_path.split(".")[0] + f"_{self.clarity}.mp4",
            codec="libx264",
            audio_codec="aac",
        )
        os.remove(self.video_path.split(".")[0] + "_tmp.mp4")
 
    def gen_video(self):
        self.video2str()
        self.str2fig()
        self.jpg2video()
        self.merge_audio()
 
 
if __name__ == "__main__":
    video_path = input("输入视频文件路径:\n")
    clarity = input("输入清晰度(0~1, 直接回车使用默认值0):\n") or 0
    v2char = V2Char(video_path, clarity)
    v2char.gen_video()

以上就是用Python字符画出了一个谷爱凌的详细内容,更多关于Python字符画的资料请关注脚本之家其它相关文章!

相关文章

  • Python Flask入门之模板

    Python Flask入门之模板

    今天小编就为大家分享一篇Python Flask模板的入门教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-11-11
  • Python中横向或纵向拼接两个表方法实例

    Python中横向或纵向拼接两个表方法实例

    最近要将两个表格合并,Python处理起来很简单,所以这篇文章主要给大家介绍了关于Python中横向或纵向拼接两个表的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • Python操作串口的方法

    Python操作串口的方法

    这篇文章主要介绍了Python操作串口的方法,以一个简单实例分析了Python操作串口echo输出的方法,需要的朋友可以参考下
    2015-06-06
  • Python模块文件结构代码详解

    Python模块文件结构代码详解

    这篇文章主要介绍了Python模块文件结构代码详解,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
    2018-02-02
  • Tensorflow Summary用法学习笔记

    Tensorflow Summary用法学习笔记

    这篇文章主要介绍了Tensorflow Summary用法学习笔记,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • Python----数据预处理代码实例

    Python----数据预处理代码实例

    这篇文章主要介绍了Python数据预处理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • python实现简单石头剪刀布游戏

    python实现简单石头剪刀布游戏

    这篇文章主要介绍了python实现简单石头剪刀布游戏,相信大家在童年或者生活中都玩过石头剪刀布这个游戏,这个游戏需要两个及以上的人。而今天,网上也实现了石头剪刀布的游戏。通过初步学习python,也学会了如何编写这个游戏。下面一起来看看详细内容吧
    2021-10-10
  • python中文件的创建与写入实战代码

    python中文件的创建与写入实战代码

    这篇文章主要给大家介绍了关于python中文件的创建与写入的相关资料,在Python中文件写入提供了不同的模式和方法来满足不同的需求,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-10-10
  • python异常处理try的实例小结

    python异常处理try的实例小结

    python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误。你可以使用该功能来调试python程序。今天通过本文给大家介绍python异常处理try的实例详解,感兴趣的朋友一起看看吧
    2021-10-10
  • python GUI库图形界面开发之PyQt5布局控件QVBoxLayout详细使用方法与实例

    python GUI库图形界面开发之PyQt5布局控件QVBoxLayout详细使用方法与实例

    这篇文章主要介绍了python GUI库图形界面开发之PyQt5布局控件QVBoxLayout详细使用方法与实例,需要的朋友可以参考下
    2020-03-03

最新评论