快捷搜索:  汽车  科技

python调用ascii码:在终端中观看网络摄像头流

python调用ascii码:在终端中观看网络摄像头流现在我将只使用 REALTIME 模式,只是跳过帧以获得更低的 fps,这是降低标准输出负载所必需的。 因此,我们可以以较低的 fps 观看网络摄像头,但分辨率更高而不会出现故障。播放模式# hah looks like foot :) import os import sys import time import signal import cv2 as cv import numpy as np from typing import List from Enum import Enum unique from os import get_terminal_size网络摄像头流创建此代码也是为了将录制的视频转换为 ascii 格式,但在以后的文章中会对此进行更多介绍……

如果您想在没有 x-server、ssh 连接的机器上观看网络摄像头,或者只是自己为 Instagram 拍摄了一张 ASCII 的照片,这可能会有所帮助。

python调用ascii码:在终端中观看网络摄像头流(1)

要求

我正在使用 Ubuntu,所以准备好使用 apt install 命令……我为什么要使用 Konsole? 因为它更快,并且显示所有内容都没有故障 VS ubuntu 终端、xterm 或 tmux。

sudo apt install konsole python3 \ && python3 -m pip install numpy \ && python3 -m pip install opencv-python

import

# hah looks like foot :) import os import sys import time import signal import cv2 as cv import numpy as np from typing import List from Enum import Enum unique from os import get_terminal_size



网络摄像头流

创建此代码也是为了将录制的视频转换为 ascii 格式,但在以后的文章中会对此进行更多介绍……

播放模式

现在我将只使用 REALTIME 模式,只是跳过帧以获得更低的 fps,这是降低标准输出负载所必需的。 因此,我们可以以较低的 fps 观看网络摄像头,但分辨率更高而不会出现故障。

@unique class PlayMode(Enum): # fps-dependent behaviour: VIDEO = 'RESTART_CMD' # sleep until next frame time REALTIME = 'SHUTDOWN_CMD' # skip until nex frame time

清算控制台

我将在 ctrl c 键入(SIGINT)之后、在打印每一帧之前以及在 ok 程序退出之前清除控制台。

clearConsole = lambda: os.system('cls' if os.name in ('nt' 'dos') else 'clear') def on_sigint_clear_console(sig frame): if sig == signal.SIGINT: clearConsole() sys.exit(0)

读取视频流

在这里,我们做所有顶级的事情:

  • 使用 opencv 读取网络摄像头流
  • 转换为灰度帧
  • 调整到终端大小
  • 转换为 ascii 帧
  • 在终端打印它。

同样在这里,我以 2 种不同的方式将 fps 限制设置为 max_fps arg,如上所述……

black2white_chars — 包含将用于替换帧像素的字符。 像素范围是 [0 255] => black...white,所以如果你通过 ['.' ' ' '@'] - 黑色像素将替换为 '.',灰色替换为 ' ' 和带有“@”的白色。 您可以传递更多不同的字符,使图像更时髦。

black2white_ansi_colors — 包含 ansi 转义码,将用于打印特定像素,与其值相关。 它类似于 black2white_chars,但我使用颜色而不是字符,这是 ansi 转义码。

def play_in_terminal( video_path_or_cam_idx : [str int] black2white_chars : List[str] black2white_ansi_colors : List[int] height : int width : int mode : PlayMode max_fps = None): cap = cv.VideoCapture(video_path_or_cam_idx) if not cap.isOpened(): print("Cannot cap") exit() signal.signal(signal.SIGINT on_sigint_clear_console) max_fps = max_fps if max_fps else cap.get(cv.CAP_PROP_FPS) frame_period_ns = 1e9 / max_fps prev_frame_time_ns = time.time_ns() while True: ret frame = cap.read() if not ret: print("Can't receive frame exiting...") break elapsed_time_ns = (time.time_ns() - prev_frame_time_ns) if (elapsed_time_ns < frame_period_ns): if mode == PlayMode.REALTIME: continue elif mode == PlayMode.VIDEO: time.sleep((frame_period_ns-elapsed_time_ns)/1e9) else: assert 0 "Unhandled play mode" prev_frame_time_ns = time.time_ns() frame = cv.cvtColor(frame cv.COLOR_BGR2GRAY) frame = cv.resize(frame (width height) cv.INTER_NEAREST) ascii_frame = frame2ascii(frame black2white_chars black2white_ansi_colors) print_video_frame_ascii(ascii_frame) cap.release() clearConsole()

帧转ASCII

在这里我做两件事:

  • 用 ascii 字符替换像素灰度值,分别对应于 black2white_chars
  • 使用 ansi 转义码对 ascii 字符进行着色,分别对应于 black2white_ansi_colors
  • 使用 np.vectorize() 向量化这个过程,以获得更快的代码。

def frame2ascii(frame: np.ndarray black2white_chars: List[str] black2white_ansi_colors: List[int]): dims = len(frame.shape) assert dims == 2 \ f"Frame shape should be 2d got: <{dims}d>" if dims == 2: return process_gray_frame(frame black2white_chars black2white_ansi_colors) return res def process_gray_frame(frame: np.ndarray black2white_chars: List[str] black2white_ansi_colors: List[int]): return np.vectorize(lambda pix : colorize_text_gray(pix2ascii_gray(pix black2white_chars) pix black2white_ansi_colors))(frame) def colorize_text_gray(text: str gray: int black2white_ansi_colors: List[int]): black2white = black2white_ansi_colors step = 255 / len(black2white) color_idx = min(int(gray / step) len(black2white)-1) color = black2white[color_idx] return f"\033[{color};1m{text}\033[0m" def pix2ascii_gray(pix: int black2white_chars: List[str]): step = 255 / len(black2white_chars) char_idx = min(int(pix/step) len(black2white_chars)-1) return black2white_chars[char_idx]

打印ASCII帧

所以......我只是连接所有 ascii 字符,插入 \n 以形成行,然后清除控制台并使用刷新选项打印它以立即将所有内容放入终端(不允许缓冲它)。

def print_video_frame_ascii(frame: np.ndarray): dims = len(frame.shape) assert dims == 2 f"Frame shape should be 2d got: <{dims}d>" frame_str = '' for row in frame: for pix in row: frame_str = pix frame_str = "\n" clearConsole() print(f"{frame_str}" flush=True)

主要的

有趣的东西从这里开始 :) 我选择了几个调色板用于框架着色和一些漂亮的 ascii 字符集。 让我们都试试!!!

if __name__ == "__main__": term_size = get_terminal_size() h w = term_size.lines term_size.columns print(f"Terminal size (h w): ({h} {w})") black2white_gray = [90 37 97] black2white_green = [90 32 92] black2white_yellow = [33 93] black2white_blue = [34 36 94 96] black2white_rainbow_dark = list(range(30 38)) black2white_rainbow_light = list(range(90 98)) while True: play_in_terminal( video_path_or_cam_idx = 0 black2white_chars = [' ' '`' '.' '~' ' ' '*' 'o' 'O' '0' '#' '@'] black2white_ansi_colors = black2white_green height = h width = w mode = PlayMode.REALTIME max_fps = 30 )

猜您喜欢: