序言
参考了博文:https://blog.youkuaiyun.com/qq_39687901/article/details/83347915的思路。参考pygame官方文档:https://www.pygame.org/docs/。和之前的图片转字符画不同,用颜色来区分,所以字符集没有特殊要求。
目标
如题,实现视频转彩色字符动画。
步骤
声明以及初始化
WIN_SIZE = (1280, 720) # 720p
VIDEO_PATH = './video/test02.mp4'
VIDEO_WIDTH = 80
VIDEO_HEIGHT = 45
VIDEO_SIZE = (VIDEO_WIDTH, VIDEO_HEIGHT)
FONT_SIZE = 16
CHARS = 'ERROR'
CHARS_LEN = len(CHARS)
先声明一些需要用到的常量,WIN_SIZE和VIDEO_WIDTH、VIDEO_HEIGHT、FONT_SIZE是乘积的对应关系。
WIN_SIZE = (VIDEO_WIDTH * FONT_SIZE, VIDEO_HEIGHT * FONT_SIZE)
pygame.init() # 初始化模块
win_sur = pygame.display.set_mode(WIN_SIZE) # 创造图形窗口
视频转换成图片
def video2images(video_path, video_size):
imgs = []
video_cap = cv2.VideoCapture(video_path) # 打开视频
while video_cap.isOpened():
ret, frame = video_cap.read() # 按帧读取
if ret:
img = cv2.resize(frame, video_size, interpolation=cv2.INTER_AREA) # 调整尺寸,像素重采样
imgs.append(img)
else:
break
video_cap.release()
return imgs
这里用到cv2模块打开并按帧读取视频,之后将帧存放到数组中。
图片转换成彩色字符
def images2chars(imgs):
sur_list = []
font = pygame.font.SysFont('fangsong', FONT_SIZE) # 从系统字库创建Font对象
font.set_bold(True) # 加粗
for img in imgs:
surface = pygame.Surface(WIN_SIZE) # 创建图像对象
index = 0
x, y = 0, 0
for row in range(VIDEO_HEIGHT):
for col in range(VIDEO_WIDTH):
rgb = img[row][col]
rgb[0], rgb[2] = rgb[2], rgb[0]
text_sur = font.render(CHARS[index], True, rgb)
index = (index + 1) % CHARS_LEN
surface.blit(text_sur, (x, y))
x += FONT_SIZE
x = 0
y += FONT_SIZE
sur_list.append(surface)
return sur_list
对于每一帧逐行扫描,获取对应颜色的字符放到Surface对象中,最后添加到数组。
窗口渲染输出
current_frame = 0
while 1:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
exit()
pygame.time.delay(int(1000 / 24)) # 一秒24帧
win_sur.fill((0, 0, 0)) # 黑色填充
win_sur.blit(sur_list[current_frame], [0, 0])
current_frame = (current_frame + 1) % sur_list_len
pygame.display.flip() # 展示图像
填充背景,渲染图像,读取下一帧。
这里的操作和官网的例子大同小异:
import sys, pygame
pygame.init()
size = width, height = 320, 240
speed = [2, 2]
black = 0, 0, 0
screen = pygame.display.set_mode(size)
ball = pygame.image.load("intro_ball.gif")
ballrect = ball.get_rect()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
ballrect = ballrect.move(speed)
if ballrect.left < 0 or ballrect.right > width:
speed[0] = -speed[0]
if ballrect.top < 0 or ballrect.bottom > height:
speed[1] = -speed[1]
screen.fill(black)
screen.blit(ball, ballrect)
pygame.display.flip()
The last thing we need to do is actually update the visible display. Pygame manages the display with a double buffer. When we are finished drawing we call the pygame.display.flip()Update the full display Surface to the screen method. This makes everything we have drawn on the screen Surface become visible.
结果


源码
import pygame
import cv2
WIN_SIZE = (1280, 720) # 720p
VIDEO_PATH = './video/test02.mp4'
VIDEO_WIDTH = 80
VIDEO_HEIGHT = 45
VIDEO_SIZE = (VIDEO_WIDTH, VIDEO_HEIGHT)
FONT_SIZE = 16
CHARS = 'ERROR'
CHARS_LEN = len(CHARS)
# 视频转图片
def video2images(video_path, video_size):
imgs = []
video_cap = cv2.VideoCapture(video_path) # 打开视频
while video_cap.isOpened():
ret, frame = video_cap.read() # 按帧读取
if ret:
img = cv2.resize(frame, video_size, interpolation=cv2.INTER_AREA) # 调整尺寸,像素重采样
imgs.append(img)
else:
break
video_cap.release()
return imgs
# 图片转字符
def images2chars(imgs):
sur_list = []
font = pygame.font.SysFont('fangsong', FONT_SIZE) # 从系统字库创建Font对象
font.set_bold(True) # 加粗
for img in imgs:
surface = pygame.Surface(WIN_SIZE) # 创建图像对象
index = 0
x, y = 0, 0
for row in range(VIDEO_HEIGHT):
for col in range(VIDEO_WIDTH):
rgb = img[row][col]
rgb[0], rgb[2] = rgb[2], rgb[0]
text_sur = font.render(CHARS[index], True, rgb)
index = (index + 1) % CHARS_LEN
surface.blit(text_sur, (x, y))
x += FONT_SIZE
x = 0
y += FONT_SIZE
sur_list.append(surface)
return sur_list
def main():
pygame.init() # 初始化模块
win_sur = pygame.display.set_mode(WIN_SIZE) # 创造图形窗口
imgs = video2images(VIDEO_PATH, VIDEO_SIZE) # 视频转图集
sur_list = images2chars(imgs) # 图集转字符图集
sur_list_len = len(sur_list)
current_frame = 0
while 1:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
exit()
pygame.time.delay(int(1000 / 24)) # 一秒24帧
win_sur.fill((0, 0, 0)) # 黑色填充
win_sur.blit(sur_list[current_frame], [0, 0])
current_frame = (current_frame + 1) % sur_list_len
pygame.display.flip() # 展示图像
if __name__ == '__main__':
print('开始转换...')
main()
2274



被折叠的 条评论
为什么被折叠?



