Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
zmx0142857
GitHub Repository: zmx0142857/mini-games
Path: blob/master/py/v2char.py
363 views
1
#!/usr/bin/env python3
2
3
__author__ = '先知-6047-@bilibili'
4
5
# 自带
6
import sys, os, time, threading
7
8
# 需要另外安装. 其中 cv2 的安装方式是 pip3 install opencv-python
9
import cv2, pyprind
10
11
class CharFrame:
12
#ascii_char = '@#B%WM8&$wmoahkbdpqZ0QOLCJUYXzcvunxrjft*/\|()1{}[]?-_+~<>i!lI;:,"^`\'. '
13
ascii_char = ' .`\'^",:;Il!i<>~+_-?[]{}1()|\/*tjfrxnuvczXYUJCLOQ0Zqpbdkhaomw$&8MW%B#@'
14
15
# 像素映射到字符
16
def pixel2Char(self, luminance):
17
return self.ascii_char[luminance * len(self.ascii_char) >> 8]
18
19
# 将普通帧转为 ASCII 字符帧
20
def convert(self, img, limitSize=-1, fill=False, wrap=False):
21
if limitSize != -1 and (img.shape[0] > limitSize[1]
22
or img.shape[1] > limitSize[0]):
23
img = cv2.resize(img, limitSize, interpolation=cv2.INTER_AREA)
24
blank = ''
25
if fill:
26
blank += ' ' * (limitSize[0] - img.shape[1])
27
if wrap:
28
blank += '\n'
29
return blank.join(
30
''.join(
31
self.pixel2Char(img[i,j]) for j in range(img.shape[1])
32
) for i in range(img.shape[0])
33
)
34
35
class V2Char(CharFrame):
36
charVideo = []
37
timeInterval = 0.033
38
39
def __init__(self, path):
40
if path.endswith('.txt'):
41
self.load(path)
42
else:
43
self.build(path)
44
self.save(path.rsplit('.', 1)[0] + '.txt')
45
46
def build(self, path):
47
self.charVideo = []
48
# 用 opencv 读取视频
49
cap = cv2.VideoCapture(path)
50
self.timeInterval = round(1 / cap.get(5), 3)
51
nf = int(cap.get(7))
52
print('Generating char video...')
53
for i in pyprind.prog_bar(range(nf)):
54
# 转换颜色空间
55
rawFrame = cv2.cvtColor(cap.read()[1], cv2.COLOR_BGR2GRAY)
56
frame = self.convert(rawFrame, os.get_terminal_size(), fill=True)
57
self.charVideo.append(frame)
58
cap.release()
59
60
def save(self, path):
61
if not self.charVideo:
62
return
63
with open(path, 'w') as f:
64
f.write('\n'.join(self.charVideo) + '\n')
65
66
def load(self, path):
67
self.charVideo = [frame[:-1] for frame in open(path)]
68
69
def play(self):
70
if not self.charVideo:
71
return
72
interrupt = False
73
def getChar():
74
nonlocal interrupt
75
try:
76
# 若系统为 windows 则直接调用 msvcrt.getch()
77
import msvcrt
78
if msvcrt.getch():
79
interrupt = True
80
except ImportError:
81
import termios, tty
82
fd = sys.stdin.fileno() # 获取文件描述符
83
old_settings = termios.tcgetattr(fd) # 保存旧设置
84
tty.setraw(sys.stdin.fileno()) # 设置输入为原始模式
85
ch = sys.stdin.read(1) # 线程在这里阻塞
86
# 恢复旧设置
87
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
88
if ch:
89
interrupt = True
90
91
# 用后台线程监听按键
92
getchar = threading.Thread(target=getChar, daemon=True)
93
getchar.start()
94
95
for frame in self.charVideo:
96
# 接收到输入则退出循环
97
if interrupt:
98
break
99
print(frame, end='', flush=True)
100
time.sleep(self.timeInterval)
101
print('\033[0;0H', end='') # 光标回到 0,0
102
rows = len(self.charVideo[0]) // os.get_terminal_size()[0]
103
print('\033[%d;0H' % rows) # 光标移到最后一行
104
if interrupt:
105
print('KeyboardInterrupt')
106
else:
107
print('Press any key to exit', end='', flush=True)
108
getchar.join()
109
print('')
110
111
if __name__ == '__main__':
112
if len(sys.argv) == 1:
113
print('usage: %s <file>' % sys.argv[0])
114
else:
115
v2char = V2Char(sys.argv[1])
116
v2char.play()
117
118