__author__ = '先知-6047-@bilibili'
import sys, os, time, threading
import cv2, pyprind
class CharFrame:
ascii_char = ' .`\'^",:;Il!i<>~+_-?[]{}1()|\/*tjfrxnuvczXYUJCLOQ0Zqpbdkhaomw$&8MW%B#@'
def pixel2Char(self, luminance):
return self.ascii_char[luminance * len(self.ascii_char) >> 8]
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)
blank = ''
if fill:
blank += ' ' * (limitSize[0] - img.shape[1])
if wrap:
blank += '\n'
return blank.join(
''.join(
self.pixel2Char(img[i,j]) for j in range(img.shape[1])
) for i in range(img.shape[0])
)
class V2Char(CharFrame):
charVideo = []
timeInterval = 0.033
def __init__(self, path):
if path.endswith('.txt'):
self.load(path)
else:
self.build(path)
self.save(path.rsplit('.', 1)[0] + '.txt')
def build(self, path):
self.charVideo = []
cap = cv2.VideoCapture(path)
self.timeInterval = round(1 / cap.get(5), 3)
nf = int(cap.get(7))
print('Generating char video...')
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 save(self, path):
if not self.charVideo:
return
with open(path, 'w') as f:
f.write('\n'.join(self.charVideo) + '\n')
def load(self, path):
self.charVideo = [frame[:-1] for frame in open(path)]
def play(self):
if not self.charVideo:
return
interrupt = False
def getChar():
nonlocal interrupt
try:
import msvcrt
if msvcrt.getch():
interrupt = True
except ImportError:
import termios, tty
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
if ch:
interrupt = True
getchar = threading.Thread(target=getChar, daemon=True)
getchar.start()
for frame in self.charVideo:
if interrupt:
break
print(frame, end='', flush=True)
time.sleep(self.timeInterval)
print('\033[0;0H', end='')
rows = len(self.charVideo[0]) // os.get_terminal_size()[0]
print('\033[%d;0H' % rows)
if interrupt:
print('KeyboardInterrupt')
else:
print('Press any key to exit', end='', flush=True)
getchar.join()
print('')
if __name__ == '__main__':
if len(sys.argv) == 1:
print('usage: %s <file>' % sys.argv[0])
else:
v2char = V2Char(sys.argv[1])
v2char.play()