源码地址
原教程在这里
演示效果:(有点虚)
利用Python程序生成字符画 让男大学生们洗脑的挖呀挖呀挖
使用教程(源码在文章最后)
- 打开pyhton编译器安装opencv和Pillow库
- 把要进行字符串化的视频命名为input.mp4(或者在代码里修改进行字符串化的视频从input.mp4改为你的视频名)
- 运行代码,此时会有进度提示
- 找自己这个pyhton文件的位置会有一个video文件夹生成
- 完了,记得帮我点个赞或者收藏一下😳😳😳
你可能需要安装opencv和Pillow。如果没有这两个库,通常情况下本脚本会自动帮你安装。如果自动安装失败,请在cmd分别运行。
pip3 install opencv-python-headlesspip3 install Pillow
源代码
import sys
import os
import time
import shutil
from multiprocessing import Process
try:
from PIL import Image, ImageFont, ImageDraw
except ImportError:
os.system('pip3 install Pillow -i https://mirrors.aliyun.com/pypi/simple/')
from PIL import Image, ImageFont, ImageDraw
try:
import cv2
from cv2 import VideoWriter, VideoWriter_fourcc, imread, resize
except ImportError:
os.system('pip3 install opencv-python-headless -i https://mirrors.aliyun.com/pypi/simple/')
import cv2
from cv2 import VideoWriter, VideoWriter_fourcc, imread, resize
# =========================
# coding:UTF-8
# 视频转字符画含音频version-2.1
# 参考1:https://blog.csdn.net/mp624183768/article/details/81161260
# 参考2:https://blog.csdn.net/qq_42820064/article/details/90958577
# 参考3:https://blog.csdn.net/zj360202/article/details/79026891
# =========================
def get_char(r, g, b, alpha=256):
ascii_char = list("#RMNHQODBWGPZ*@$C&98?32I1>!:-;. ")
# ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:oa+>!:+. ")
if alpha == 0:
return ''
length = len(ascii_char)
gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
unit = (256.0 + 1) / len(ascii_char)
return ascii_char[int(gray / unit)]
# 将视频转换为图片 并进行计数,返回总共生成了多少张图片!
def video_to_pic(vp):
print('正在对视频进行逐帧切片,请稍候...')
# vp = cv2.VideoCapture(video_path)
number = 0
if vp.isOpened():
r, frame = vp.read()
if not os.path.exists(sys.path[0] + '/cache_pic'):
os.mkdir(sys.path[0] + '/cache_pic')
os.chdir(sys.path[0] + '/cache_pic')
else:
r = False
while r:
number += 1
cv2.imwrite(sys.path[0] + '/cache_pic/' + str(number) + '.jpg', frame)
r, frame = vp.read()
print('由视频一共生成了{}张图片!'.format(number))
os.chdir(sys.path[0])
# os.chdir("../../../Downloads")
return number
def img_to_char(image_path, raw_width, raw_height, task):
width = int(raw_width / 6)
height = int(raw_height / 15)
os.chdir(sys.path[0])
im = Image.open(image_path).convert('RGB') # 必须以RGB模式打开
im = im.resize((width, height), Image.NEAREST)
txt = ''
color = []
for i in range(height):
for j in range(width):
pixel = im.getpixel((j, i))
color.append((pixel[0], pixel[1], pixel[2])) # 将颜色加入进行索引
if len(pixel) == 4:
txt += get_char(pixel[0], pixel[1], pixel[2], pixel[3])
else:
txt += get_char(pixel[0], pixel[1], pixel[2])
txt += '\n'
color.append((255, 255, 255))
im_txt = Image.new("RGB", (raw_width, raw_height), (255, 255, 255))
dr = ImageDraw.Draw(im_txt)
# font = ImageFont.truetype('consola.ttf', 10, encoding='unic') #改为这个字体会让图片比例改变
font = ImageFont.load_default().font
x, y = 0, 0
font_w, font_h = font.getsize(txt[1])
font_h *= 1.37 # 调整字体大小
for i in range(len(txt)):
if (txt[i] == '\n'):
x += font_h
y = -font_w
dr.text((y, x), txt[i], fill=color[i])
y += font_w
os.chdir(sys.path[0])
# os.chdir('cache_char')
im_txt.save(sys.path[0] + '/cache_char/' + str(task) + '.jpg')
os.chdir(sys.path[0])
# os.chdir("../../../Downloads")
return 0
# 使用多进程进行图片转字符画,number是cahce_pic中图片总数,start_number是该进程从第几副图开始做,end_number是该进程到第几副图结束。
class StarToCharMultiProcess(Process):
def __init__(self, threadID, number, save_pic_path, start_number, end_number):
super().__init__()
self.threadID = threadID
self.number = number
self.save_pic_path = save_pic_path
self.start_number = start_number
self.end_number = end_number
def run(self):
print("开始进程:" + self.name)
star_to_char2(self.number, self.save_pic_path, self.start_number, self.end_number)
print(self.name + ":处理完成")
print("退出进程:" + self.name)
def star_to_char(number, save_pic_path):
if not os.path.exists('cache_char'):
os.mkdir('cache_char')
img_path_list = [save_pic_path + r'/{}.jpg'.format(i) for i in range(1, number + 1)] # 生成目标图片文件的路径列表
task = 0
for image_path in img_path_list:
img_width, img_height = Image.open(image_path).size # 获取图片的分辨率
task += 1
img_to_char(image_path, img_width, img_height, task)
print('{}/{} is finished.'.format(task, number))
print('=======================')
print('All images were finished!')
print('=======================')
return 0
def star_to_char2(number, save_pic_path, start_number, end_number):
os.chdir(sys.path[0])
if not os.path.exists('cache_char'):
try:
os.mkdir('cache_char')
except:
pass
img_path_list = [save_pic_path + r'/{}.jpg'.format(i) for i in range(start_number, end_number + 1)] # 生成目标图片文件的路径列表
task = start_number - 1
for image_path in img_path_list:
img_width, img_height = Image.open(image_path).size # 获取图片的分辨率
task += 1
img_to_char(image_path, img_width, img_height, task)
# print('{}/{} is finished.'.format(task, number))
# print('=======================')
# print('Finished!')
# print('=======================')
return 0
def star_to_char_multi_process(number, save_pic_path, process_number):
print("\n正在把图片转字符画,请稍候...")
print("启动多进程处理:")
processes = []
for count in range(1, process_number + 1):
if count == 1:
start_number = 1
end_number = start_number + number // process_number
elif count == process_number:
start_number = end_number + 1
end_number = number
else:
start_number = end_number + 1
end_number = start_number + number // process_number
process = StarToCharMultiProcess(count, number, save_pic_path, start_number, end_number)
process.start()
processes.append(process)
time.sleep(1)
return processes
def process_bar(percent, start_str='', end_str='', total_length=0):
# 进度条
bar = ''.join("■ " * int(percent * total_length)) + ''
bar = '\r' + start_str + bar.ljust(total_length) + ' {:0>4.1f}%|'.format(percent * 100) + end_str
print(bar, end='', flush=True)
def jpg_to_video(char_image_path, FPS):
print("\n开始合成视频")
video_fourcc = VideoWriter_fourcc(*"MP42") # 设置视频编码器,这里使用使用MP42编码器,可以生成更小的视频文件
char_img_path_list = [char_image_path + r'/{}.jpg'.format(i) for i in range(1, number + 1)] # 生成目标字符图片文件的路径列表
char_img_test = Image.open(char_img_path_list[1]).size # 获取图片的分辨率
os.chdir(sys.path[0])
if not os.path.exists('video'):
os.mkdir('video')
video_writter = VideoWriter('video/new_char_video.avi', video_fourcc, FPS, char_img_test)
sum = len(char_img_path_list)
count = 0
for image_path in char_img_path_list:
img = cv2.imread(image_path)
video_writter.write(img)
end_str = '100%'
count = count + 1
process_bar(count / sum, start_str='', end_str=end_str, total_length=15)
video_writter.release()
print('\n')
print('=======================')
print('The video is finished!')
print('=======================')
def write_audio(video_path):
# 加入音频
cmd = 'ffmpeg -i ' + sys.path[
0] + '/video/new_char_video.avi' + ' -i ' + video_path + ' -c copy -map 0 -map 1:1 -y -shortest ' + sys.path[
0] + '/video/videoWithAudio.avi' + ' -y'
os.system(cmd)
# 压制成H.264 mp4格式
cmd2 = 'ffmpeg -i ' + sys.path[0] + '/video/videoWithAudio.avi' + ' -c:v libx264 -strict -2 ' + sys.path[
0] + '/video/finalOutput_VideoWithAudio.mp4' + ' -y'
os.system(cmd2)
def delete(path):
try:
shutil.rmtree(path)
print('已删除:' + path)
return 0
except:
print('删除' + path + '失败,可能是权限不足或目录不存在')
return -1
def input_process(default_video_path):
video_path = default_video_path
while not os.path.exists(video_path):
if len(sys.argv) == 2:
video_path = sys.argv[1]
elif len(sys.argv) == 1 and not os.path.exists(video_path):
video_path = input('请输入要处理的视频名称:')
video_path = sys.path[0] + '/' + video_path
return video_path
if __name__ == '__main__':
# 各种参数
video_path = sys.path[0] + '/input.mp4' # 把input.mp4改成你的视频名字,注意前面的斜杠要保留
save_pic_path = sys.path[0] + '/cache_pic' # 别动
save_charpic_path = sys.path[0] + '/cache_char' # 别动
processes_number = 8 # 使用多少个进程同时处理图片,通常不超过CPU线程数,可以自行设置
video_path = input_process(video_path)
# 处理
vp = cv2.VideoCapture(video_path)
number = video_to_pic(vp)
FPS = vp.get(cv2.CAP_PROP_FPS)
threads = star_to_char_multi_process(number, save_pic_path, processes_number)
for thread in threads:
thread.join()
vp.release()
jpg_to_video(save_charpic_path, FPS)
delete(save_pic_path)
delete(save_charpic_path)
write_audio(video_path) # 把原视频的音频复制到新视频中。需要安装ffmpeg,否则报错。没有ffmpeg请注释掉这行代码。
为什么报错?
你可能需要安装opencv和Pillow。如果没有这两个库,通常情况下本脚本会自动帮你安装。如果自动安装失败,请在cmd分别运行。
注意的事及其使用方法
你可能需要安装opencv和Pillow。如果没有这两个库,通常情况下本脚本会自动帮你安装。如果自动安装失败,请在cmd分别运行、。
pip3 install opencv-python-headlesspip3 install Pillow
支持常见的mp4、flv等格式。
需要在main函数中修改你的视频文件路径,默认视频文件名称为input.mp4,放在与本py文件相同的目录里。如果没有找到input.mp4,会自动询问你视频名称。
最简单的方法:将视频放置在py文件的文件夹下,并修改 video_path后的参数为你的视频名字即可运行。
此外还可以设置多进程处理图片,可自行修改进程数量。
if __name__ == '__main__':
video_path = sys.path[0] + '/input.mp4' # 把input.mp4改成你的视频名字,注意前面的斜杠要保留
save_pic_path = sys.path[0] + '/cache_pic' # 别动
save_charpic_path = sys.path[0] + '/cache_char' # 别动
processes_number = 8 # 使用多少个进程同时处理图片,通常不超过CPU线程数,可以自行设置
为生成的视频添加原视频音轨并且压制为mp4需要预先安装好ffmpeg,如果没有安装ffmpeg,请注释掉或者删掉最后一行
write_audio(video_path)
最后附送一段舞蹈😍
利用Python程序生成字符画 跳舞
文章出处登录后可见!
已经登录?立即刷新