赞
踩
把大象关进冰箱需要三步
本项目主要利用视频处理库 moviepy 来读取处理视频,利用图片处理库 PIL 来处理图片(视频的每一帧)
pip install moivepy
# 也可利用万能安装模板来加速
pip --default-timeout=100 install moviepy -i https://pypi.tuna.tsinghua.edu.cn/simple
关于库的使用,可以参考这篇文章:moviepy 中文文档 和 PIL 图像基本处理,本文也会将涉及到的用法讲解出来。
利用类对该方法进行包装
# -*- coding: utf-8 -*- import os import os.path as osp import argparse import numpy as np from moviepy.editor import * from PIL import Image, ImageFont, ImageDraw class Converter: def __init__(self, video_input_path, video_output_path, chars_width, fps, isGray, time_start=0, time_end=None): self.video_path = video_input_path self.video_name = osp.basename(video_input_path).split('.')[0] self.output_path = video_output_path if video_output_path else osp.dirname(video_input_path) self.output_path = osp.join(self.output_path, self.video_name + "_char2.mp4") self.isGray = isGray self.vfc = VideoFileClip(self.video_path).subclip(time_start, time_end) self.fps = fps self.chars_width = chars_width self.chars_height = int(self.chars_width / self.vfc.aspect_ratio) self.vfc = self.vfc.resize((self.chars_width, self.chars_height)) font_fp = "DroidSansMono.ttf" self.font = ImageFont.truetype(font_fp, size=14) self.font_width = sum(self.font.getsize('a')) // 2 self.video_size = int(self.chars_width * self.font_width), int(self.chars_height * self.font_width) # 值越大,映射的字母越靠后,表示像素更"白" self.pixels = \ "$#@&%ZYXWVUTSRQPONMLKJIHGFEDCBA098765432?][}{/)(><zyxwvutsrqponmlkjihgfedcba*+1-." # "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. " def gray2char(self, gray): """通过灰度值获取当前像素的字符""" percent = float(gray) / 255 index = int(percent * (len(self.pixels) - 1)) return self.pixels[index] def frame2char(self, t): """ 将每一帧的图片转化为字符 本函数作为 moviepy.editor.VideoClip 特效功能的入口参数 相当于对时间 t 内的视频做转为字符的特效处理 :return: numpy.array 类型字符列表 """ img_np = self.vfc.get_frame(t) img = Image.fromarray(img_np, 'RGB') img_gary = img.convert(mode='L') img_char = Image.new('RGB', self.video_size, color='white') brush = ImageDraw.Draw(img_char) white = (255, 255, 255) black = (0, 0, 0) for y in range(self.chars_height): for x in range(self.chars_width): r, g, b = img_np[y][x] if not self.isGray else black gray = img_gary.getpixel((x, y)) char = self.gray2char(gray) position = x * self.font_width, y * self.font_width brush.text(position, char, fill=(r, g, b), font=self.font) # img_char = img_char if not self.isGray else img_char.convert(mode='L') return np.array(img_char) def generate(self): """生成字符对象""" clip = VideoClip(self.frame2char, duration=self.vfc.duration) clip = clip.set_fps(self.vfc.fps).set_audio(self.vfc.audio) clip.write_videofile(self.output_path) def main(): parser = argparse.ArgumentParser(description='Convert video to char-based video.') parser.add_argument('-i', type=str, help='the input path of source video, such as xx/xx/xx.mp4') parser.add_argument('-o', type=str, default=None, help='the output path of char-based video, default is input path') parser.add_argument('-fps', type=int, default=10, help='the frame per second of output video, default is 8') parser.add_argument('-cw', type=int, default=200, help='the chars width of chars in video, default is 80') parser.add_argument('-g', action='store_true', default=False, help='output the gray video, default is False') args = parser.parse_args() # args.g = True converter = Converter(args.i, args.o, args.cw, args.fps, args.g) converter.generate() if __name__ == '__main__': main()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。