一、环境准备
1、需要安装opencv,直接安装 pip install opencv-python
2、需要安装ffmpeg ,直接解压免安装,下载传送门; 将 ffmpeg.exe 的路径复制,替换代码开头的 ffmpeg = r'G:\ffmpeg\bin\ffmpeg.exe‘
3、源码参考自 https://blog.csdn.net/kongfu_cat/article/details/79681719?utm_source=copy ,对其稍微修改了一下,并增加了视频截取和颜色选择的功能,亲测可用。
二、源代码
1 # -*- coding:utf-8 -*- 2 # coding:utf-8 3 import os, cv2, subprocess 4 from cv2 import VideoWriter, VideoWriter_fourcc, imread, resize 5 from PIL import Image, ImageFont, ImageDraw 6 7 ffmpeg = r'G:\ffmpeg\bin\ffmpeg.exe' 8 code_color = (169,169,169) # 颜色RGB 默认灰色 ,'' 则彩色 9 10 # 像素对应ascii码 11 #ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:oa+>!:+. ") 12 #ascii_char = ['.',',',':',';','+','*','?','%','S','#','@'][::-1] 13 #ascii_char = list("MNHQ$OC67+>!:-. ") 14 ascii_char = list("MNHQ$OC67)oa+>!:+. ") 15 16 # 将像素转换为ascii码 17 def get_char(r, g, b, alpha=256): 18 if alpha == 0: 19 return '' 20 length = len(ascii_char) 21 gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b) 22 unit = (256.0 + 1) / length 23 return ascii_char[int(gray / unit)] 24 25 # 将txt转换为图片 26 def txt2image(file_name): 27 im = Image.open(file_name).convert('RGB') 28 # gif拆分后的图像,需要转换,否则报错,由于gif分割后保存的是索引颜色 29 raw_width = im.width 30 raw_height = im.height 31 width = int(raw_width / 6) 32 height = int(raw_height / 15) 33 im = im.resize((width, height), Image.NEAREST) 34 35 txt = "" 36 colors = [] 37 for i in range(height): 38 for j in range(width): 39 pixel = im.getpixel((j, i)) 40 colors.append((pixel[0], pixel[1], pixel[2])) 41 if (len(pixel) == 4): 42 txt += get_char(pixel[0], pixel[1], pixel[2], pixel[3]) 43 else: 44 txt += get_char(pixel[0], pixel[1], pixel[2]) 45 txt += '\n' 46 colors.append((255, 255, 255)) 47 48 im_txt = Image.new("RGB", (raw_width, raw_height), (255, 255, 255)) 49 dr = ImageDraw.Draw(im_txt) 50 # font = ImageFont.truetype(os.path.join("fonts","汉仪楷体简.ttf"),18) 51 font = ImageFont.load_default().font 52 x = y = 0 53 # 获取字体的宽高 54 font_w, font_h = font.getsize(txt[1]) 55 font_h *= 1.37 # 调整后更佳 56 # ImageDraw为每个ascii码进行上色 57 for i in range(len(txt)): 58 if (txt[i] == '\n'): 59 x += font_h 60 y = -font_w 61 # self, xy, text, fill = None, font = None, anchor = None, 62 # *args, ** kwargs 63 if code_color: 64 dr.text((y, x), txt[i], fill=code_color) # fill=colors[i]彩色 65 else: 66 dr.text((y, x), txt[i], fill=colors[i]) # fill=colors[i]彩色 67 # dr.text((y, x), txt[i], font=font, fill=colors[i]) 68 y += font_w 69 70 name = file_name 71 # print(name + ' changed') 72 im_txt.save(name) 73 74 # 将视频拆分成图片 75 def video2txt_jpg(file_name): 76 vc = cv2.VideoCapture(file_name) 77 c = 1 78 if vc.isOpened(): 79 r, frame = vc.read() 80 if not os.path.exists('Cache'): 81 os.mkdir('Cache') 82 os.chdir('Cache') 83 else: 84 r = False 85 while r: 86 cv2.imwrite(str(c) + '.jpg', frame) 87 txt2image(str(c) + '.jpg') # 同时转换为ascii图 88 r, frame = vc.read() 89 c += 1 90 os.chdir('..') 91 return vc 92 93 # 将图片合成视频 94 def jpg2video(outfile_name, fps): 95 fourcc = VideoWriter_fourcc(*"MJPG") 96 images = os.listdir('Cache') 97 im = Image.open('Cache/' + images[0]) 98 vw = cv2.VideoWriter(outfile_name, fourcc, fps, im.size) 99 100 os.chdir('Cache') 101 for image in range(len(images)): 102 # Image.open(str(image)+'.jpg').convert("RGB").save(str(image)+'.jpg') 103 frame = cv2.imread(str(image + 1) + '.jpg') 104 vw.write(frame) 105 # print(str(image + 1) + '.jpg' + ' finished') 106 os.chdir('..') 107 vw.release() 108 109 # 递归删除目录 110 def remove_dir(path): 111 if os.path.exists(path): 112 if os.path.isdir(path): 113 dirs = os.listdir(path) 114 for d in dirs: 115 if os.path.isdir(path + '/' + d): 116 remove_dir(path + '/' + d) 117 elif os.path.isfile(path + '/' + d): 118 os.remove(path + '/' + d) 119 os.rmdir(path) 120 return 121 elif os.path.isfile(path): 122 os.remove(path) 123 return 124 125 # 调用ffmpeg获取mp3音频文件 126 def video2mp3(file_name, outfile_name): 127 cmdstr = " -i {0} -f mp3 {1} -y".format(file_name, outfile_name) 128 cmd(cmdstr) 129 130 # 合成音频和视频文件 131 def video_add_mp3(file_name, mp3_file,outfile_name): 132 cmdstr = " -i {0} -i {1} -strict -2 -f mp4 {2} -y".format(file_name, mp3_file, outfile_name) 133 cmd(cmdstr) 134 135 # 视频截取 136 def vediocut(file_name, outfile_name, start, end): 137 cmdstr = " -i {0} -vcodec copy -acodec copy -ss {1} -to {2} {3} -y".format(file_name,start,end,outfile_name) 138 cmd(cmdstr) 139 140 # 执行脚本命令 141 def cmd(cmdstr): 142 cmdstr = ffmpeg + cmdstr 143 response = subprocess.call(cmdstr, shell=True, creationflags=0x08000000) 144 if response == 1: 145 print("ffmpeg脚本执行失败,请尝试手动执行:{0}".format(cmdstr)) 146 147 # 主函数 148 def main(vedio, save=False, iscut=False, start='00:00:00', end='00:00:14'): 149 """ 150 :param vedio: 原视频文件地址 151 :param save: 是否保存临时文件 默认不保存 152 :param iscut: 是否先对原视频做截取处理 默认不截取 153 :param start: 视频截取开始时间点 仅当iscut=True时有效 154 :param end: 视频截取结束时间点 仅当iscut=True时有效 155 :return: 输出目标视频文件 vedio.split('.')[0] + '-code.mp4' 156 """ 157 file_cut = vedio.split('.')[0] + '_cut.mp4' 158 file_mp3 = vedio.split('.')[0] + '.mp3' 159 file_temp_avi = vedio.split('.')[0] + '_temp.avi' 160 outfile_name = vedio.split('.')[0] + '-code.mp4' 161 print("开始生成...") 162 if iscut: 163 print("正在截取视频...") 164 vediocut(vedio, file_cut, start, end) 165 vedio = file_cut 166 print("正在转换代码图片...") 167 vc = video2txt_jpg(vedio) # 视频转图片,图片转代码图片 168 FPS = vc.get(cv2.CAP_PROP_FPS) # 获取帧率 169 vc.release() 170 print("正在分离音频...") 171 video2mp3(vedio, file_mp3) # 从原视频分离出 音频mp3 172 print("正在转换代码视频...") 173 jpg2video(file_temp_avi, FPS) #代码图片转视频 174 print("正在合成目标视频...") 175 video_add_mp3(file_temp_avi, file_mp3, outfile_name) # 将音频合成到代码视频 176 print("正在移除临时文件...") 177 if (not save): # 移除临时文件 178 remove_dir("Cache") 179 for file in [file_cut, file_mp3, file_temp_avi]: 180 if os.path.exists(file): 181 os.remove(file) 182 print("生成成功:{0}".format(outfile_name)) 183 184 if __name__ == '__main__': 185 vedio = r"H:\Projects\test\抖音.mp4" 186 main(vedio, save=False, iscut=False, start='00:00:00', end='00:00:14')