这篇文章是 视频转字符动画-Python-60行代码 的后续,如果感兴趣,请先看看它。

0. 话说在前头

最新版使用了画布方式实现,和本文相比改动非常大,如果对旧版本的实现没啥兴趣,可以直接移步 video2chars,它的效果动画见 极乐净土。新版本的核心代码不算注释70行不到,功能更强大。

下面的效果动画是使用 html 实现的字符动画效果(上一篇的效果动画是 shell 版的):

本文的优化仍然是针对 shell 版本的,html 版由于缺陷太大就不写文章介绍了。

1. 速度优化

要是每次播放都要等个一分钟,也太痛苦了一点。

所以可以用 pickle 模块把 video_chars 保存下来,下次播放时,如果发现当前目录下有这个保存下来的数据,就跳过转换,直接播放了。这样就快多了。

只需要改一下测试代码,

先在开头添加两个依赖

import os
import pickle

然后在文件结尾添加代码:

def dump(obj, file_name):
"""
将指定对象,以file_nam为名,保存到本地
"""
with open(file_name, 'wb') as f:
pickle.dump(obj, f)
return def load(filename):
"""
从当前文件夹的指定文件中load对象
"""
with open(filename, 'rb') as f:
return pickle.load(f) def get_file_name(file_path):
"""
从文件路径中提取出不带拓展名的文件名
"""
# 从文件路径获取文件名 _name
path, file_name_with_extension = os.path.split(file_path) # 拿到文件名前缀
file_name, file_extension = os.path.splitext(file_name_with_extension) return file_name def has_file(path, file_name):
"""
判断指定目录下,是否存在某文件
"""
return file_name in os.listdir(path) def get_video_chars(video_path, size):
"""
返回视频对应的字符视频
"""
video_dump = get_file_name(video_path) + ".pickle" # 如果 video_dump 已经存在于当前文件夹,就可以直接读取进来了
if has_file(".", video_dump):
print("发现该视频的转换缓存,直接读取")
video_chars = load(video_dump)
else:
print("未发现缓存,开始字符视频转换") print("开始逐帧读取")
# 视频转字符动画
imgs = video2imgs(video_path, size) print("视频已全部转换到图像, 开始逐帧转换为字符画")
video_chars = imgs2chars(imgs) print("转换完成,开始缓存结果")
# 把转换结果保存下来
dump(video_chars, video_dump)
print("缓存完毕") return video_chars if __name__ == "__main__":
# 宽,高
size = (64, 48)
# 视频路径,换成你自己的
video_path = "BadApple.mp4"
video_chars = get_video_chars(video_path, size)
play_video(video_chars)

另一个优化方法就是边转换边播放,就是同时执行上述三个步骤。学会了的话,可以自己实现一下试试。

2. 字符视频和音乐同时播放

没有配乐的动画,虽然做出来了是很有成就感,但是你可能看上两遍就厌倦了。

所以让我们来给它加上配乐。(不要担心,其实就只需要添加几行代码而已)

首先我们需要找个方法来播放视频的配乐,怎么做呢?

先介绍一下一个跨平台视频播放器:mpv,它有很棒的命令行支持,请先安装好它。

要让 mpv 只播放视频的音乐部分,只需要命令:

mpv --no-video video_path

好了,现在有了音乐,可总不能还让人开俩shell,先放音乐,再放字符画吧。

这时候,我们需要的功能是:使用 Python 调用外部应用.

但是 mpv 使用了类似 curses 的功能,标准库的 os.system 不能隐藏掉这个部分,播放效果不尽如人意。

因此我使用了 pyinvoke 模块,只要给它指定参数hide=True,就可以完美隐藏掉被调用程序的输出(指 stdout,其实 subprocess 也可以的)。运行下面代码前,请先用pip安装好 invoke.(能够看到这里的,安装个模块还不是小菜一碟)

好了废话说这么多,上代码:

import invoke

video_path = "BadApple.mp4"
invoke.run(f"mpv --no-video {video_path}", hide=True, warn=True)

运行上面的测试代码,如果听到了音乐,而shell啥都没输出,但是能听到音乐的话,就正常了。我们继续。(这里使用了python3.6的f字符串)

音乐已经有了,那就好办了。

添加一个播放音乐的函数

import invoke
def play_audio(video_path):
invoke.run(f"mpv --no-video {video_path}", hide=True, warn=True)

然后修改main()方法:

def main():
# 宽,高
size = (64, 48)
# 视频路径,换成你自己的
video_path = "BadApple.mp4" # 只转换三十秒,这个属性是才添加的,但是上一篇的代码没有更新。你可能需要先上github看看最新的代码。其实就稍微改了一点。
seconds = 30 # 这里的fps是帧率,也就是每秒钟播放的的字符画数。用于和音乐同步。这个更新也没写进上一篇,请上github看看新代码。
video_chars, fps = get_video_chars(video_path, size, seconds) # 播放音轨
play_audio(video_path) # 播放视频
play_video(video_chars, fps) if __name__ == "__main__":
main()

然后运行。。并不是我坑你,你只听到了声音,却没看到字符画。。原因是: invoke.run()函数是阻塞的,音乐没放完,代码就到不了play_video(video_chars, fps)这一行。

所以 play_audio 还要改一下,改成这样:

import invoke
from threading import Thread def play_audio(video_path):
def call():
invoke.run(f"mpv --no-video {video_path}", hide=True, warn=True) # 这里创建子线程来执行音乐播放指令,因为 invoke.run() 是一个阻塞的方法,要同时播放字符画和音乐的话,就要用多线程/进程。
# P.S. 更新:现在发现可以用 subprocess.Popen 实现异步调用 mpv,不需要开新线程。有兴趣的同学可以自己试试。
p = Thread(target=call)
p.setDaemon(True)
p.start()

这里使用标准库的 threading.Thread 类来创建子线程,让音乐的播放在子线程里执行,然后字符动画还是主线程执行,Ok,这就可以看到最终效果了。实际上只添加了十多行代码而已。

3. 彩色字符动画

  1. html+javascript 方式:核心都是一样的内容,只是需要点 html 和 javascript 的知识。代码见 video2chars-html
  2. 画布方式:直接把画在图片上,然后自动合成为 mp4 文件。这种方式要优于 html 方式,而且有个很方便的库能用,核心代码就 70 行的样子。代码见 video2chars

参考

Python 视频转字符画 - 进阶的更多相关文章

  1. python图像、视频转字符画

    python图像转字符画需要用到matplotlib.pyplot库,视频转字符画需要用到opencv库,这里的代码基于python 3.5 图像转字符画需要先将图像转为灰度图,转灰度图的公式是 gr ...

  2. Python 图片转字符画

    Python 图片转字符画 一.课程介绍 1. 课程来源 原创 2. 内容简介 本课程讲述怎样使用 Python 将图片转为字符画 3. 前置课程 Python编程语言 Linux 基础入门(新版) ...

  3. 使用Python生成ASCII字符画

    使用Python生成ASCII字符画 在很多的网站主页中或者程序的注释中会有一些好看的字符注释画.显得很牛逼的样子 例如: 知乎 _____ _____ _____ _____ /\ \ /\ \ / ...

  4. Python 图片转字符画 学习笔记

    Python 图片转字符画 学习笔记 标签(空格分隔): Python 声明:此文章和所有代码是学习笔记,非原创,原文教程地址:https://www.shiyanlou.com/courses/37 ...

  5. [笔记] Python 图片转字符画

    一.介绍 用Python 代码完成图片转字符画 二.python 环境 Python 3.6.6 pillow 5.1.0  Python 图像处理库, 需要另外安装 三.原理 gray = 0.21 ...

  6. python图片转字符画(转)

    先上代码: from PIL import Image import argparse #命令行输入参数处理 parser = argparse.ArgumentParser() parser.add ...

  7. 福利!Python制作动态字符画(附源码)

    字符画,一种由字母.标点.汉字或其他字符组成的图画.简单的字符画是利用字符的形状代替图画的线条来构成简单的人物.事物等形象,它一般由人工制作而成:复杂的字符画通常利用占用不同数量像素的字符代替图画上不 ...

  8. Python图片转字符画

    PIL安装很麻烦,推荐下载exe直接安装 PIL官网:http://pythonware.com/products/pil/ 但现在里面下载链接访问不了,我把32位和64位版本上传到博客园以供下载 P ...

  9. 视频转字符动画-Python-60行代码

    更新:2018-5-21 注意: 最后一步播放字符动画使用了只支持类 unix 系统的模块 curses, 因此在windows上是播放不了的... 解决方法: 1. 最近好像有一个移植 https: ...

随机推荐

  1. 【.Net架构】BIM软件架构03:Web管控平台MVC架构

    一.前言        上一篇讲述的是将BIM平台后台架构CoreService.sln,该解决方案主要作用是对管控平台的核心业务进行封装,然后让前端的ApiController去调用该解决方案中的对 ...

  2. ubuntu 13.10 install wireshark

    ubuntu 13.10 install wireshark 今天在使用java jsoup操作remote server的是否,在本地执行可以成功返回内容,然后打成jar包,使用shell在 ser ...

  3. mysql distinct field1,field2,field3, .... from table

    mysql distinct field1,field2,field3, .... from table 我们知道 这样的sql可以去掉重复项 (field1的重复项); select distinc ...

  4. JeeSite数据分页与翻页

    本文章介绍的是JeeSite开源项目二次开发时的一些笔记,对于没有使用过JeeSite的可以不用往下看了,因为下面的代码是跟JeeSite二次开发相关的代码,不做JeeSite的二次开发,以下代码对您 ...

  5. 代码生成平台Xxl-Code-Generator

    <代码生成平台Xxl-Code-Generator> 一.简介 1.1 概述 Xxl-Code-Generator 是一个 "controller/service/dao/myb ...

  6. Net Core 生成图形验证码

    1. NetCore ZKweb       在我第一次绘制图形验证码时是采用的ZKweb的绘制库,奉上代码参考      public byte[] GetVerifyCode(out string ...

  7. CSS中的变形、过渡、动画效果

    一.变形 .过渡效果 1:元素平移 x方向 y方向 transform:translate(100px 100px); 2:过渡动画效果 a:什么属性参与过渡效果 b:过渡时间 c:过渡的效果 值包含 ...

  8. django管理数据库之中文字符编码问题

    django中通过models创建数据库字符编码文字mysql数据库中默认的字符编码都为latin1,插入中文时会出现以下的错误类型 1366 - Incorrect string value: '\ ...

  9. linux基础命令用法

    目录管理 ls.cd.pwd.mkdir.rmdir.tree ls(list) 列出,列表 用法: ls -l:长格式 文件类型: -:普通文件 (f) d: 目录文件 b: 块设备文件 (bloc ...

  10. 爬虫-Python爬虫常用库

    一.常用库 1.requests 做请求的时候用到. requests.get("url") 2.selenium 自动化会用到. 3.lxml 4.beautifulsoup 5 ...