Skip to content

Instantly share code, notes, and snippets.

@salt-die
Last active October 12, 2023 14:59
Show Gist options
  • Save salt-die/576220194d14ea69894cd129a91fba34 to your computer and use it in GitHub Desktop.
Save salt-die/576220194d14ea69894cd129a91fba34 to your computer and use it in GitHub Desktop.
rick rolling in ascii!
import curses
from itertools import product
from time import time, sleep
import cv2
import numpy as np
path = "never_gonna.mp4"
ASCII_MAP = np.array(list(' .,:;<+*LtCa4U80dQM@'))
SCALE = len(ASCII_MAP) / 255
VALUES = [255 // 5 * i for i in range(6)]
COLOR_MAP = np.array([min(range(6), key=lambda index: abs(VALUES[index] - color)) for color in range(256)])
BASE_6 = np.array([36, 6, 1])
def init_curses(screen):
curses.noecho()
curses.cbreak()
screen.nodelay(1)
curses.curs_set(0)
curses.start_color()
for x, y, z in product(range(6), repeat=3):
curses.init_color(x * 6 ** 2 + y * 6 + z + 17, *(round(1000 / 255 * VALUES[i]) for i in (z, y, x)))
for i in range(6 ** 3):
curses.init_pair(i + 1, i + 17, 0)
screen.clear()
def main(screen):
init_curses(screen)
curses_pairs = np.array([curses.color_pair(i) for i in range(1, 6 ** 3 + 1)])
h, w = screen.getmaxyx()
dim = w - 1, h
movie = cv2.VideoCapture(path)
start = time()
while screen.getch() != ord('q'):
read_flag, frame = movie.read()
if not read_flag:
break
color = cv2.resize(frame, dim)
grayscale = ASCII_MAP[ (SCALE * cv2.cvtColor(color, cv2.COLOR_BGR2GRAY)).astype(int) ]
pairs = curses_pairs[(BASE_6 * COLOR_MAP[color]).sum(axis=-1)]
it = np.nditer((grayscale, pairs), ["multi_index"])
for char, pair in it:
y, x = it.multi_index
screen.addstr(y, x, str(char), pair)
delta = movie.get(cv2.CAP_PROP_POS_MSEC) / 1000 - (time() - start)
if delta > 0:
sleep(delta)
screen.refresh()
movie.release()
if __name__ == '__main__':
curses.wrapper(main)
@ethansocal
Copy link

ethansocal commented Jul 3, 2021

you are evil 🤣

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment