字符画的原理就是先将图像转换为灰度图,再将图像每个像素灰度值映射到相应的字符上,当所有灰度值转化完成后就是字符文本了。而要实现字符视频的生成就需要以下步骤,将原视频进行抽帧,对每一帧图像进行转换,将转换后的字符文本转换为图像,最后将字符图像合成视频。
import sys
import cv2
import numpy
from cv2 import VideoCapture
from PIL import Image, ImageFont, ImageDraw
#颜色深度映射字符表
SF2='$@B%8&WM#*oahkbdpqwmLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,"^'
SF3=list(SF2)
#图像处理主函数
def get_tzt(im,num):
# 字符高度和宽度不一致打印到画布上高宽比例不对,需要进行修正
HDxiuzheng = [2.125,3.3]
Width = 300 #字符宽度,对应像素多少
size = im.size #获取图像的像素并储存在size列表中
HWbili=size[1]/size[0]
Height=int(Width*HWbili/HDxiuzheng[1])
if num==1:
print("图像源宽度",size[0],"\t高度",size[1],"\n转换现宽度",Width,"\t高度",Height)
im = im.resize((Width,Height)) #修改图片尺寸
im = im.convert('L') #1获得二值图像 L获取灰度图
txt = "" #建立变量储存字符串
#嵌套for循环将图像中的每一点像素的灰度值转换为相应的字符再存储在txt变量中
for i in range(Height):
for j in range(Width):
txt += SF3[int(im.getpixel((j, i))/4.15)] #getpixel是获取图像中某一点像素的RGB颜色值
txt += '\n'
im1 = Image.new("RGB", (900,680), (255, 255, 255)) #新建空白图像
dr = ImageDraw.Draw(im1) #将图像转换为画布
font = ImageFont.truetype(r"D:\Image\Ziti\宋体.ttf",6) #获取字体文件并设置字体大小
dr.text((0, 0),txt, font=font, fill="#000000") #将文本写到画布上
return cv2.cvtColor(numpy.asarray(im1), cv2.COLOR_RGB2BGR)
#视频抽帧并将图像转为字符画,再将字符图像合成视频
def Pihe():
#待转换视频文件路径
video_path = r"D:\Image\*.mp4"
is_all_frame =False # 是否对视频的所有帧进行转换(true/false)
sta_frame = 1 # 开始帧 自定义
end_frame = 500 # 结束帧 自定义
time_interval = 1 # 时间间隔 抽帧可以不连续 自定义
# 读取视频文件
videoCapture = VideoCapture(video_path)
# 读帧
success, frame = videoCapture.read()
fps = videoCapture.get(cv2.CAP_PROP_FPS)
print('源视频帧率',int(fps))
if success:
print("视频文件加载成功")
else:
print("视频文件加载失败")
sys.exit()
#合成视频的基本参数
fps = 30 #视频每秒24帧
size = (900,680) #需要转为视频的图片的尺寸
#保存视频路径
video = cv2.VideoWriter(r"D:\Image\*.avi", cv2.VideoWriter_fourcc('M', 'P', '4', '2'), fps, size)
i = 0
j = 0
if is_all_frame:
time_interval = 1
while success:
i = i + 1
img = Image.fromarray(frame) # 完成np.array向PIL.Image格式的转换
if (i % time_interval == 0):
if is_all_frame == False:
if i >= sta_frame and i <= end_frame:
j = j + 1
video.write(get_tzt(img,j))
print('当前帧处理进度:', i)
elif i > end_frame:
break
else:
j = j + 1
video.write(get_tzt(img,j))
print('当前帧处理进度:', i)
success, frame = videoCapture.read()
#关闭相关操作
videoCapture.release()
video.release()
cv2.destroyAllWindows()
print('视频转字符进度完成')
Pihe()
效果图