Jetson 13 在 Jupyter Lab 中显示实时画面

来自Waveshare Wiki
跳转至: 导航搜索

在 Jupyter Lab 中显示实时视频画面

在上一章中我们使用 Flask 来显示摄像头的实时画面,那个方法需要在浏览器中格外开启一个新标签页或者使用其它设备打开浏览器来访问,在本章教程中我们使用在 Jupyter Lab 中观看实时视频画面的方案。

准备工作

由于产品开机默认会自动运行主程序,主程序会占用摄像头资源,这种情况下是不能使用本教程的,需要结束主程序或禁止主程序自动运行后再重新启动机器人。

这里需要注意的是,由于机器人主程序中使用了多线程且由 crontab 配置开机自动运行,所以常规的 sudo killall python 的方法通常是不起作用的,所以我们这里介绍禁用主程序自动运行的方法。

如果你已经禁用了机器人主程序的开机自动运行,则不需要执行下面的结束主程序章节。

结束主程序

1. 点击上方本页面选项卡旁边的 “+”号,会打开一个新的名为 Launcher 的选项卡。

2. 点击 Other 内的 Terminal,打开终端窗口。

3. 在终端窗口内输入 bash 后按回车。

4. 现在你可以使用 Bash Shell 来控制机器人了。

5. 输入命令: sudo killall -9 python


例程

以下代码块可以直接运行:

1. 选中下面的代码块

2. 按 Shift + Enter 运行代码块

3. 观看实时视频窗口

4. 按 STOP 关闭实时视频,释放摄像头资源

如果运行时不能看到摄像头实时画面

  • 需要点击上方的 Kernel - Shut down all kernels
  • 关闭本章节选项卡,再次打开
  • 点击 STOP 释放摄像头资源后重新运行代码块
  • 重启设备
import cv2  # OpenCV 库,用于读取摄像头
import numpy as np  # 数组处理,用于图像数据
from IPython.display import display, Image  # Jupyter 实时显示图像
import ipywidgets as widgets  # 小组件,用于生成 Stop 按钮
import threading  # 用于启动独立线程运行摄像头循环
import time  # 控制循环延时

# ===============================
# 创建一个 ToggleButton 按钮,用于停止摄像头
# ===============================
stopButton = widgets.ToggleButton(
    value=False,               # 初始状态未按下
    description='Stop',        # 按钮文字
    disabled=False,            # 按钮可用
    button_style='danger',     # 红色按钮
    tooltip='Stop Stream',     # 鼠标悬停提示
    icon='stop'                # 图标
)

# 显示停止按钮(这是 Jupyter 才能看到的)
display(stopButton)


# ===============================
# 摄像头显示函数(会在一个线程中运行)
# ===============================
def view(button):

    # 打开 USB 摄像头(一般是 0)
    # 如果你是 Jetson CSI 摄像头,需要替换成 GStreamer 管道
    camera = cv2.VideoCapture(0)

    # 设置摄像头分辨率
    camera.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
    camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

    # 创建显示句柄,用于在 Jupyter 动态更新图像
    display_handle = display(None, display_id=True)

    # ===============================
    # 摄像头实时读取循环
    # ===============================
    while True:

        # 如果按下 Stop 按钮 → 退出循环
        if button.value:
            camera.release()  # 释放摄像头
            display_handle.update(Image(data=b""))  # 清空显示
            break  # 跳出循环,结束线程

        # 读取一帧图像
        ret, frame = camera.read()
        if not ret:
            continue  # 读取失败就跳过本次循环

        # 将图像编码为 JPEG,才能在 Jupyter 中显示
        _, jpeg = cv2.imencode('.jpg', frame)

        # 更新 Jupyter 显示的内容
        display_handle.update(Image(data=jpeg.tobytes()))

        # 暂停 30ms,避免 CPU 占用过高
        time.sleep(0.03)


# ===============================
# 启动摄像头线程
# ===============================
thread = threading.Thread(target=view, args=(stopButton,))
thread.daemon = True  # 设为守护线程,在 Notebook 关闭时自动退出
thread.start()        # 启动线程