社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

用Python将抖音视频转换为字符视频

Python中文社区 • 5 年前 • 754 次点击  

数据科学俱乐部

中国数据科学家社区

介绍

字符视频就是画面全部由字符组成的,那就先来看看效果:

原视频如下:

那么用代码怎么实现的呢?下面用python实现,话不多说,直接上干货。

代码实现详解

其实总体思路分为3个步骤:

1.将原视频分割成若干个图片以及分离出音频

2.将每张图片转为字符画图片(重点部分)

3.将若干个字符画图片和音频合并成新的视频(字符视频)

  • 将原视频分割成若干个图片以及分离出音频

这个过程我们可以用python调用ffmpeg工具进行切割,ffmpeg是专门处理音视频的工具库。可以在ffmpeg官网下载可执行文件放在程序的当前目录

分离音频命令为:

ffmpeg.exe -i filename -vn temp


    
.mp3
    #分离音频
    slice_audio_cmd = 'ffmpeg.exe -i {0} -vn temp.mp3'.format(src_file)
    os.system(slice_audio_cmd)

分割视频成若干图片的命令为:

ffmpeg.exe -i filename -r 24 temp_pic/%06d.jpeg
    #切割成图片
    slice_pic_cmd = 'ffmpeg.exe -i {0} -r 24 temp_pic/%06d.jpeg'.format(src_file)
    os.system(slice_pic_cmd)

将分割出来的图片和音频临时存储起来,为了后面若干图片转字符图片效率及速度有所提高,还需将分割后的图片转为缩略图,就是改变图片的尺寸

这里使用python的PIL图形处理库来进行缩略图转化,同样将缩略图临时存储起来

def create_thumbnail(src_dir, dst_dir):
    picts_list = sorted(os.listdir(src_dir))

    for picture in picts_list:
        base_name = os.path.basename(picture)
        img = Image.open(os.path.join(src_dir, picture))
        size = 200200
        img.thumbnail(size, Image.ANTIALIAS)
        img.save(os.path.join(dst_dir, base_name))
  • 将每张图片转为字符画图片

如何将一张图片转为字符形式呢?其实很简单,分3步:

1.将图片转为灰度图

2.将灰度图的每个像素点替换为相应的字符

3.将所有替换后的字符画成一张字符图片

1.将图片转为灰度图

灰度图,Gray Scale Image 或是Grey Scale Image,又称灰阶图。把白色与黑色之间按对数关系分为若干等级,称为灰度。灰度分为256阶

公式为:Gray = R0.299 + G0.587 + B*0.114

同样在python中可以用PIL库直接转灰度:

def load_picture(filename):

    # Gray = R*0.299 + G*0.587 + B*0.114
    img = Image.open(filename).convert('L')
    (x, y) = img.size

    pixels = list(img.getdata())
    img.close()
    return (pixels, x, y)

2.将灰度图的每个像素点替换为相应的字符

这里如何替换呢?可以根据灰阶值来替换为我们自己设定的字符,例如:

symbols = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")

从上面列表可以看到:越靠前的越密集,越往后越稀疏,于是我们根据灰阶值的大小按比例取列表中的字符,灰阶值越大,取越靠后的字符,这样图片轮廓才能更好的清晰显示

为了是转化后的字符图片看起来不密集以及提高转化时间,我这里将每间隔1个像素来替换字符,初始还要指定图片的边框及尺寸,这些参数可以自行调整,具体展示如下代码:




    
def create_ascii_picture(pixels, symbols, dest_name, x_size, y_size):
    scale 
4    # 长宽扩大倍数
    border = 1  # 边框宽度

    interval_pixel = 2     #原图片间隔多少个像素点来填充

    img = Image.new('L',
                    (x_size*scale + 2*border,
                     y_size*scale + 2*border),
                    255)
    fnt = ImageFont.truetype('DejaVuSansMono.ttf'int(scale*3))
    t = ImageDraw.Draw(img)

    x = border
    y = border
    for j in range(0, y_size, interval_pixel):
        for i in range(0, x_size, interval_pixel):
            t.text( (x, y),
                    symbols[int(pixels[j*x_size + i]/256 * len(symbols))],
                    font
=fnt,
                    fill=0
                    )
            x += scale * interval_pixel
        x = border
        y += scale * interval_pixel

    img.save(dest_name, "JPEG")

3.将所有替换后的字符画成一张字符图片

这步只需调用PIL库的save方法,如上面代码最后一行。

同样,我们将转化后的字符图片临时保存起来。

至此第2大步完成,即:将一张图片转为字符图片完成

  • 将若干个字符画图片和音频合并成新的视频(字符视频)

这里也是使用ffmpeg工具进行合成,命令为:

ffmpeg -threads 2 -start_number 000001 -r 24 -i 路径名/%06d.jpeg -i temp.mp3 -vcodec mpeg4 生成的文件名
    merge_ascii_video_cmd = 'ffmpeg -threads 2 -start_number 000001 -r 24 -i {0}/%06d.jpeg -i temp.mp3 -vcodec mpeg4 {1}'.format('temp_ascii', dst_name)
    os.system(merge_ascii_video_cmd)

这一步完成后,字符视频已经生成了。最后还需删除一些临时的文件及文件夹。

完整代码展示

from PIL import Image, ImageDraw, ImageFont
import os, sys
import shutil

symbols = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")

def ascii_art_convert(src_dir, dest_dir):
    print('开始生成...')
    picts_list = sorted(os.listdir(src_dir))
    len_picts = len(picts_list)

    i = 0

    for picture in picts_list:
        (pixels, x_size, y_size) = load_picture(os.path.join(src_dir, picture))

        #生成字符画图片
        create_ascii_picture(pixels, symbols, os.path.join(dest_dir, picture), x_size, y_size)

        print('正在生成中... {0}/{1}'.format(i, len_picts))
        i += 1

def create_thumbnail(src_dir, dst_dir):
    picts_list = sorted(os.listdir(src_dir))

    for picture in picts_list:
        base_name = os.path.basename(picture)
        img = Image.open(os.path.join(src_dir, picture))
        size = 200200
        img.thumbnail(size, Image.ANTIALIAS)
        img.save(os.path.join(dst_dir, base_name))


def load_picture(filename):

    # Gray = R*0.299 + G*0.587  + B*0.114
    img = Image.open(filename).convert('L')
    (x, y) = img.size

    pixels = list(img.getdata())
    img.close()
    return (pixels, x, y)


def create_ascii_picture(pixels, symbols, dest_name, x_size, y_size):
    scale = 4    # 长宽扩大倍数
    border = 1  # 边框宽度

    interval_pixel = 2     #原图片间隔多少个像素点来填充

    img = Image.new('L',
                    (x_size*scale + 2*border,
                     y_size*scale + 2*border),
                    255)
    fnt = ImageFont.truetype('DejaVuSansMono.ttf', int(scale*3))
    t = ImageDraw.Draw(img)

    x = border
    y = border
    for j in range(0, y_size, interval_pixel):
        for i in range(0, x_size, interval_pixel):
            t.text( (x, y),
                    symbols[int(pixels[j*x_size + i]/256 * len(symbols))],
                    font=fnt,
                    fill=0
                    )
            x += scale * interval_pixel
        x = border
        y += scale * interval_pixel

    img.save(dest_name, "JPEG")


def start_convert(src_file):

    if not os.path.exists('temp_pic'):
        os.mkdir('temp_pic')

    if not os.path.exists('temp_thum'):
        os.mkdir('temp_thum')

    if not os.path.exists('temp_ascii'):
        os.mkdir('temp_ascii')


    #分离音频
    slice_audio_cmd = 'ffmpeg.exe -i {0} -vn temp.mp3'.format(src_file)
    os.system(slice_audio_cmd)


    #切割成图片
    slice_pic_cmd = 'ffmpeg.exe -i {0} -r 24 temp_pic/%06d.jpeg'.format(src_file)
    os.system(slice_pic_cmd)

    #生成缩略图
    create_thumbnail('temp_pic''temp_thum')

    #生成字符画
    ascii_art_convert('temp_thum''temp_ascii')


    #合成字符视频
    dst_name = os.path.join(os.path.dirname(src_file), 'ascii_' + os.path.basename(src_file))
    merge_ascii_video_cmd = 'ffmpeg -threads 2 -start_number 000001 -r 24 -i {0}/%06d.jpeg -i temp.mp3 -vcodec mpeg4 {1}'.format('temp_ascii', dst_name)
    os.system(merge_ascii_video_cmd)

    print('生成完成!')


    if os.path.exists('temp_pic'):
        shutil.rmtree('temp_pic')

    if os.path.exists('temp_thum'):
        shutil.rmtree('temp_thum')

    if  os.path.exists('temp_ascii'):
        shutil.rmtree('temp_ascii')

    if os.path.exists('temp.mp3'):
        os.remove('temp.mp3')


if __name__ == '__main__':

    src_file = sys.argv[1]
    start_convert(src_file)


点击这里参与Python编程学习

本文作者

zarten,互联网一线工作者。

地址:zhihu.com/people/zarten


投稿邮箱:pythonpost@163.com

欢迎点击申请 Python中文社区新专栏作者计划


Python中文社区作为一个去中心化的全球技术社区,以成为全球20万Python中文开发者的精神部落为愿景,目前覆盖各大主流媒体和协作平台,与阿里、腾讯、百度、微软、亚马逊、开源中国、CSDN等业界知名公司和技术社区建立了广泛的联系,拥有来自十多个国家和地区数万名登记会员,会员来自以公安部、工信部、清华大学、北京大学、北京邮电大学、中国人民银行、中科院、中金、华为、BAT、谷歌、微软等为代表的政府机关、科研单位、金融机构以及海内外知名公司,全平台近20万开发者关注。

▼ 点击下方阅读原文免费成为社区会员


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/qSOuCQl4fq
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/24562
 
754 次点击