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

96
和幻想谈恋爱
0.1 2018.10.03 19:29 字数 1800

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


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

我们都知道Python容易学,但是就是不知道如何去学,去哪里找资料,在这里呢,python学习交流qq群233539995,分享我精心准备的Python学习资料,0基础到进阶!希望你们在学习Python道路上少走弯路!加油!

代码实现详解

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

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

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

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

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

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

分离音频命令为:

ffmpeg.exe-ifilename-vntemp.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))

forpictureinpicts_list:

base_name =os.path.basename(picture)

img = Image.open(os.path.join(src_dir, picture))

size =200,200

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库直接转灰度:

defload_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个像素来替换字符,初始还要指定图片的边框及尺寸,这些参数可以自行调整,具体展示如下代码:

defcreate_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

forjinrange(0, y_size, interval_pixel):

foriinrange(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

importos, 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

forpictureinpicts_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))

forpictureinpicts_list:

base_name =os.path.basename(picture)

img = Image.open(os.path.join(src_dir, picture))

size =200,200

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

forjinrange(0, y_size, interval_pixel):

foriinrange(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):

ifnotos.path.exists('temp_pic'):

os.mkdir('temp_pic')

ifnotos.path.exists('temp_thum'):

os.mkdir('temp_thum')

ifnotos.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('生成完成!')

ifos.path.exists('temp_pic'):

shutil.rmtree('temp_pic')

ifos.path.exists('temp_thum'):

shutil.rmtree('temp_thum')

ifos.path.exists('temp_ascii'):

shutil.rmtree('temp_ascii')

ifos.path.exists('temp.mp3'):

os.remove('temp.mp3')

if__name__ =='__main__':

src_file = sys.argv[1]

start_convert(src_file)

我们都知道Python容易学,但是就是不知道如何去学,去哪里找资料,在这里呢,python学习交流qq群233539995,分享我精心准备的Python学习资料,0基础到进阶!希望你们在学习Python道路上少走弯路!加油!

日记本