Python 视频转字符画 - 进阶

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

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)

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

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

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

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

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

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

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

mpv --no-video video_path

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

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

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

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

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

import invoke

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

运行上面的测试代码,如果听到了音乐,而shell啥都没输出的话,就正常了。我们继续。

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

添加一个播放音乐的函数

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 = Thread(target=call)
    p.setDaemon(True)
    p.start()

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

代码:

video2chars 里面有个 Pipfile,是因为我使用了 pipenv 来管理依赖的缘故。不清楚的话忽略它就行。

原文地址:https://www.cnblogs.com/kirito-c/p/9089873.html

时间: 2024-10-10 21:27:31

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

Python图片转字符画

目的:将一张图片转换成字符画,采用灰度值与字符对应的算法实现像素与字符之间的转化,另外通过 argparse实现命令行参数管理,argparse其作用是为文件添加命令行参数并获取,用于程序运行输入 关键算法: # 将256灰度映射到70个字符上def get_char(r, b, g, alpha=256): if alpha == 0: return ' ' length = len(ascii_char) gray = int(0.2126 * r + 0.7152 * g + 0.0722

python 图片转字符画

整代码: 将以下代码保存为py文件 from PIL import Image import argparse #命令行输入参数处理 parser = argparse.ArgumentParser() parser.add_argument('file') #输入文件 parser.add_argument('-o', '--output') #输出文件 parser.add_argument('--width', type = int, default = 80) #输出字符画宽 parse

python如何根据图片生成字符画 实例教程

教大家如何用python生成字符画,看起来很炫酷. 思路:原图->灰度->根据像素亮度-映射到指定的字符序列中->输出.字符越多,字符变化稠密.效果会更好.如果根据灰度图的像素亮度范围制作字符画,效果会更好.如果再使用调色板,对字符进行改色,就更像原图了.代码: import Image chars =" ...',;:clodxkLO0DGEKNWMM" fn=r'c:\users\liabc\desktop\jianbing.png' f1=lambda F:''

python学习 —— 字符画

代码: import os from PIL import Image WIDTH = int(250) HEIGHT = int(250/2) ascii_char = list('[email protected]%8&WM#*/\|()1{}[.?-_+~<>i!lI;:,"^`\' ') # 将256灰度映射到70个字符上 def rgb2char(r,g,b,alpha = 256): if alpha == 0: return ' ' length = len(a

python学习---50行代码实现图片转字符画1

转自:https://blog.csdn.net/mm1030533738/article/details/78447714 项目链接: https://www.shiyanlou.com/courses/370/labs/1191/document from PIL import Image #从PIL模块中引入Image这个类import argparse  #引入argparse这个模块(argparse库是用来管理命令行参数输入的) parser = argparse.ArgumentP

Python3:图片转字符画

防伪码:没有相当程度的孤独是不可能有内心的平和. 1.环境准备 主机名 IP 系统 Python版本 Python-01 192.168.10.9 CentOS release 6.9 (Final) 3.5.4 参考:https://www.shiyanlou.com/courses/370/labs/1191/document 2.原理 字符画是一系列字符的组合,可以把字符看作是比较大块的像素,一个字符能表现一种颜色(暂且这么理解吧),字符的种类越多,可以表现的颜色也越多,图片也会更有层次感

Python基础day-5[字符编码,文件处理,函数]

字符编码: 为什么要有字符编码?字符编码是为了让计算机能识别我们人写的字符,因为计算机只认识高低电平,也就是二进制数"0","1". 字符编码其实就是在完成一件,字符====>数字的翻译过程. ASCII: 最早计算机是美国发明的,所以最早诞生的ASCII码也是基于英文考虑的.ASCII码:一个Bytes代表一个字符,1Bytes=bit.最早的ASCII只用到后七位. 127个数字,已经完全能代表键盘了,后来又把127号之后的空位来表示新的字母.符号,还加入

python视频网址

python3英文视频教程(全87集) http://pan.baidu.com/s/1dDnGBvV python从入门到精通视频(全60集)链接:http://pan.baidu.com/s/1eQw2dd4 密码:9bdl python学习手册视频教程(全44集) http://pan.baidu.com/s/1o64tpf8 零基础入门学习Python(全42集) 链接:http://pan.baidu.com/s/1qWNmdKo 密码:jrjy 中谷python视频教程(全38集) 

pyhon 实现图片转换成字符画

#coding=utf-8from PIL import Imageimport argparse #命令行输入参数处理parser = argparse.ArgumentParser() parser.add_argument('file') #输入文件parser.add_argument('-o', '--output') #输出文件parser.add_argument('--width', type = int, default = 80) #输出字符画宽parser.add_argu