OpenCV3+python3实现视频转字符动画
2020-01-13 04:11
344 查看
import sys import os import time import threading import cv2 import pyprind # 图片转字符画的原理:首先将图片转为灰度图,每个像素都只有亮度信息(用 0~255 表示)。 # 然后我们构建一个有限字符集合,其中的每一个字符都与一段亮度范围对应, # 我们便可以根据此对应关系以及像素的亮度信息把每一个像素用对应的字符表示,这样字符画就形成了。 # luminance 亮度 class CharFrame: ascii_char = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. " # 像素映射到字符 def pixelToChar(self, luminance): return self.ascii_char[int(luminance/256*len(self.ascii_char))] # 将普通帧转为 ASCII 字符帧 def convert(self, img, limitSize=-1, fill=False, wrap=False): if limitSize != -1 and (img.shape[0] > limitSize[1] or img.shape[1] > limitSize[0]): img = cv2.resize(img, limitSize, interpolation=cv2.INTER_AREA) ascii_frame = '' blank = '' if fill: blank += ' '*(limitSize[0]-img.shape[1]) if wrap: blank += '\n' for i in range(img.shape[0]): for j in range(img.shape[1]): ascii_frame += self.pixelToChar(img[i,j]) ascii_frame += blank return ascii_frame class I2Char(CharFrame): result = None def __init__(self, path, limitSize=-1, fill=False, wrap=False): self.genCharImage(path, limitSize, fill, wrap) def genCharImage(self, path, limitSize=-1, fill=False, wrap=False): img = cv2.imread(path, cv2.IMREAD_GRAYSCALE) if img is None: return self.result = self.convert(img, limitSize, fill, wrap) def show(self, stream = 2): if self.result is None: return if stream == 1 and os.isatty(sys.stdout.fileno()): self.streamOut = sys.stdout.write self.streamFlush = sys.stdout.flush elif stream == 2 and os.isatty(sys.stderr.fileno()): self.streamOut = sys.stderr.write self.streamFlush = sys.stderr.flush elif hasattr(stream, 'write'): self.streamOut = stream.write self.streamFlush = stream.flush self.streamOut(self.result) self.streamFlush() self.streamOut('\n') class V2Char(CharFrame): charVideo = [] timeInterval = 0.033 def __init__(self, path): if path.endswith('txt'): self.load(path) else: self.genCharVideo(path) def genCharVideo(self, filepath): self.charVideo = [] cap = cv2.VideoCapture(filepath) self.timeInterval = round(1/cap.get(5), 3) nf = int(cap.get(7)) print('Generate char video, please wait...') for i in pyprind.prog_bar(range(nf)): rawFrame = cv2.cvtColor(cap.read()[1], cv2.COLOR_BGR2GRAY) frame = self.convert(rawFrame, os.get_terminal_size(), fill=True) self.charVideo.append(frame) cap.release() def export(self, filepath): if not self.charVideo: return with open(filepath,'w') as f: for frame in self.charVideo: # 加一个换行符用以分隔每一帧 f.write(frame + '\n') def load(self, filepath): self.charVideo = [] # 一行即为一帧 for i in open(filepath): self.charVideo.append(i[:-1]) def play(self, stream = 1): # Bug: # 光标定位转义编码不兼容 Windows if not self.charVideo: return if stream == 1 and os.isatty(sys.stdout.fileno()): self.streamOut = sys.stdout.write self.streamFlush = sys.stdout.flush elif stream == 2 and os.isatty(sys.stderr.fileno()): self.streamOut = sys.stderr.write self.streamFlush = sys.stderr.flush elif hasattr(stream, 'write'): self.streamOut = stream.write self.streamFlush = stream.flush breakflag = False def getChar(): nonlocal breakflag try: # 若系统为 windows 则直接调用 msvcrt.getch() import msvcrt except ImportError: import termios, tty # 获得标准输入的文件描述符 fd = sys.stdin.fileno() # 保存标准输入的属性 old_settings = termios.tcgetattr(fd) try: # 设置标准输入为原始模式 tty.setraw(sys.stdin.fileno()) # 读取一个字符 ch = sys.stdin.read(1) finally: # 恢复标准输入为原来的属性 termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) if ch: breakflag = True else: if msvcrt.getch(): breakflag = True # 创建线程 getchar = threading.Thread(target=getChar) # 设置为守护线程 getchar.daemon = True # 启动守护线程 getchar.start() # 输出的字符画行数 rows = len(self.charVideo[0])//os.get_terminal_size()[0] for frame in self.charVideo: # 接收到输入则退出循环 if breakflag: break self.streamOut(frame) self.streamFlush() time.sleep(self.timeInterval) # 共 rows 行,光标上移 rows-1 行回到开始处 self.streamOut('\033[{}A\r'.format(rows-1)) # 光标下移 rows-1 行到最后一行,清空最后一行 self.streamOut('\033[{}B\033[K'.format(rows-1)) # 清空最后一帧的所有行(从倒数第二行起) for i in range(rows-1): # 光标上移一行 self.streamOut('\033[1A') # 清空光标所在行 self.streamOut('\r\033[K') if breakflag: self.streamOut('User interrupt!\n') else: self.streamOut('Finished!\n') if __name__ == '__main__': import argparse # 设置命令行参数 parser = argparse.ArgumentParser() parser.add_argument('file', help='Video file or charvideo file') parser.add_argument('-e', '--export', nargs = '?', const = 'charvideo.txt', help='Export charvideo file') # 获取参数 args = parser.parse_args() v2char = V2Char(args.file) if args.export: v2char.export(args.export) v2char.play()
·命令行用法:
如果没有转换过
python3 main.py video.mp4 -e
如果已经转换过,下次播放可以直接
python3 main.py charvideo.txt
- 点赞
- 收藏
- 分享
- 文章举报
相关文章推荐
- Python3 & OpenCV 视频转字符动画
- 用 Python3 & OpenCV 将视频转成字符动画
- 使用opencv3+python实现视频运动目标检测
- Python opencv:实现与自己同框对话的视频特效
- Python基于OpenCV实现视频的人脸检测
- OpenCV + python 实现人脸检测(基于照片和视频进行检测)
- 【python下使用OpenCV实现计算机视觉读书笔记4】保存摄像头视频
- python+opencv打开摄像头,保存视频、拍照功能的实现方法
- Python OpenCV实现视频分帧
- 初学者学习 python实现字符动画
- 【python下使用OpenCV实现计算机视觉读书笔记4】保存摄像头视频
- OpenCV+python实现实时目标检测并保存视频
- 使用Python opencv实现视频与图片的相互转换
- OpenCV - 图像及视频读写(Python实现)
- python游戏开发之视频转彩色字符动画
- 【图像识别】 Python+Opencv调用摄像头实现人脸识别并保存视频
- python+opencv打开摄像头,保存视频、拍照功能的实现
- 【python下使用OpenCV实现计算机视觉读书笔记3】读写视频文件
- Python基于OpenCV实现视频的人脸检测
- Python+OpenCV实现车牌字符分割和识别