2. 使用CUDA加速的相机图像采集与显示

任务目标

在Jetson平台上通过CSI接口采集相机图像,利用CUDA对图像进行灰度化与边缘检测预处理,并将处理结果实时显示。本案例聚焦于采集→GPU预处理→显示的完整闭环,不涉及相机标定或高级视觉算法。

环境依赖

  • 硬件:Jetson Nano/Xavier/Orin系列开发板,CSI相机(如IMX219)
  • 软件:JetPack 4.6+(含CUDA 10.2+)、OpenCV 4.x(预编译版本已支持CUDA)、GStreamer
  • 验证CUDA可用:nvcc --version 及 python3 -c "import cv2; print(cv2.getBuildInformation())" 中应包含CUDA支持

关键完整代码

以下代码使用Python + OpenCV的GStreamer后端从CSI相机采集帧,将帧上传至GPU,在GPU上完成灰度化和Canny边缘检测,然后下载回CPU并显示。核心加速逻辑由 cv2.cuda 模块实现。

import cv2
import numpy as np

# CSI相机GStreamer管道(适用于IMX219,30fps 1280x720)
GST_STR = (
    "nvarguscamerasrc ! "
    "video/x-raw(memory:NVMM), width=1280, height=720, format=NV12, framerate=30/1 ! "
    "nvvidconv flip-method=2 ! "
    "video/x-raw, format=BGRx ! "
    "videoconvert ! video/x-raw, format=BGR ! appsink"
)

def process_frame_gpu(frame_bgr):
    """将BGR帧上传GPU,执行灰度化+Canny,返回处理后的CPU图像"""
    # 上传到GPU
    gpu_frame = cv2.cuda_GpuMat()
    gpu_frame.upload(frame_bgr)

    # 灰度化(GPU)
    gpu_gray = cv2.cuda.cvtColor(gpu_frame, cv2.COLOR_BGR2GRAY)

    # 高斯模糊降噪(GPU)
    gpu_blur = cv2.cuda.GaussianBlur(gpu_gray, (5, 5), 1.0)

    # Canny边缘检测(GPU)
    gpu_edges = cv2.cuda.Canny(gpu_blur, 50, 150)

    # 下载回CPU用于显示
    edges_cpu = gpu_edges.download()
    return edges_cpu

def main():
    cap = cv2.VideoCapture(GST_STR, cv2.CAP_GSTREAMER)
    if not cap.isOpened():
        raise RuntimeError("无法打开CSI相机,请检查GStreamer管道与相机连接")

    # 预热CUDA上下文
    dummy = np.zeros((720, 1280, 3), dtype=np.uint8)
    process_frame_gpu(dummy)

    print("开始实时采集与CUDA加速处理,按 'q' 退出")
    while True:
        ret, frame = cap.read()
        if not ret:
            print("读取帧失败")
            break

        # GPU加速处理
        edges = process_frame_gpu(frame)

        # 拼接原图与边缘图并显示
        combined = np.hstack((frame, cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)))
        cv2.imshow("CSI Camera | CUDA Canny Edge", combined)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

运行方式

python3 csi_cuda_display.py

验证方法与通过条件

  • 功能验证:程序启动后出现实时画面窗口,左侧为原始彩色图像,右侧为边缘检测结果(白线黑底)。移动相机视野中的物体,边缘轮廓应实时跟随变化,无明显延迟感。
  • CUDA加速验证:在 process_frame_gpu 函数内添加计时(time.time()),单帧GPU处理耗时(灰度+模糊+Canny)应小于10ms(Jetson Nano)或5ms(Xavier/Orin)。若耗时异常高,检查是否误用CPU版本函数。
  • 退出机制:按键盘 q 键程序正常退出,无报错。

常见问题

  • 相机无法打开:确认CSI排线连接牢固,执行 ls /dev/video* 查看是否存在video设备;尝试将 flip-method=2 改为0/1/3调整方向。
  • CUDA函数不存在:若提示 cv2.cuda 无Canny属性,说明OpenCV版本CUDA支持不完整,需重新编译OpenCV并开启 WITH_CUDA=ON。
  • 显示延迟高:imshow 本身为CPU操作,若需更低延迟可将显示部分也迁移至GPU(使用OpenGL互操作),但本案例范围不涉及。
预期输出示例:程序运行后窗口标题为 "CSI Camera | CUDA Canny Edge",左侧显示相机实时彩色画面,右侧显示对应的边缘二值图。按q键退出后终端无报错信息。