龙空技术网

在终端中观看网络摄像头流,使用 ascii 字符和 Python

庄志炎 556

前言:

而今姐妹们对“ubuntu下安装cv2”大约比较珍视,各位老铁们都需要知道一些“ubuntu下安装cv2”的相关知识。那么小编也在网络上汇集了一些有关“ubuntu下安装cv2””的相关文章,希望大家能喜欢,同学们一起来学习一下吧!

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

要求

我正在使用 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 osimport sysimport timeimport signalimport cv2 as cvimport numpy as npfrom typing import Listfrom enum import Enum, uniquefrom os import get_terminal_size

网络摄像头流

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

播放模式

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

@uniqueclass 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        )

标签: #ubuntu下安装cv2 #ubuntu终端断开