OpenCV-Python cv2 读取 + 显示图像 / 视频完整详解

区分两大场景:

  1. 静态图片cv2.imread() 读取 + cv2.imshow() 显示
  2. 视频 / USB 摄像头cv2.VideoCapture 流式读取 + cv2.imshow() 实时预览

核心前提:

① OpenCV 图像存储格式:BGR 通道序,shape = (height, width, channel)

② Linux(RDK X5)桌面 / VNC 环境才能正常使用 imshow;后台无桌面推理服务直接移除所有 imshow/waitKey

③ USB 相机采集必须指定后端 cv2.CAP_V4L2

一、静态图片:读取 + 显示 全套 API 与流程

1. 核心 API

(1)图像读取

python

运行

cv2.imread(filename, flags=cv2.IMREAD_COLOR)

flags 选项:

  • cv2.IMREAD_COLOR:默认,3 通道 BGR,丢弃透明通道
  • cv2.IMREAD_GRAYSCALE:单通道灰度图
  • cv2.IMREAD_UNCHANGED:保留原始通道(支持 PNG Alpha 四通道)

返回:np.ndarray;文件损坏 / 路径错误返回 None

(2)窗口创建(可选)

python

运行

cv2.namedWindow(winname, flags)

常用 flags:

  • cv2.WINDOW_NORMAL:窗口可拖动、自由缩放
  • cv2.WINDOW_AUTOSIZE:自适应图像尺寸(默认,不可缩放)

(3)图像渲染显示

python

运行

cv2.imshow(winname, mat)
  • winname:窗口名称,同一个名字复用窗口
  • mat:BGR 格式图像数组

⚠️关键规则:

     imshow 必须配合 cv2.waitKey () 才会刷新画面!

     缺少 waitKey 窗口卡住、黑屏

(4)按键阻塞等待

python

运行

cv2.waitKey(delay)
  • delay = 0:无限阻塞,等待任意按键
  • delay > 0:等待毫秒数;超时返回 - 1
  • 返回值:按键 ASCII 码(需 & 0xFF 过滤高位)

(5)销毁窗口

python

运行

cv2.destroyAllWindows()       # 销毁全部窗口
cv2.destroyWindow(winname)    # 销毁指定窗口

2. 完整执行流程

plaintext

1. cv2.imread() 解码图片得到BGR数组
2. cv2.namedWindow() 创建窗口(可选)
3. cv2.imshow(窗口名, 图像数组) 送入图像缓存
4. cv2.waitKey() 刷新窗口、监听按键
5. cv2.destroyAllWindows() 释放GUI资源

3. 静态图片完整示例

python

运行

import cv2

# 1. 读取图像
img = cv2.imread("test.jpg", cv2.IMREAD_COLOR)
if img is None:
    print("图片读取失败,请检查路径")
else:
    # 2. 创建可缩放窗口
    cv2.namedWindow("Image", cv2.WINDOW_NORMAL)
    # 3. 显示图像
    cv2.imshow("Image", img)
    # 4. 等待按键,0代表无限等待
    cv2.waitKey(0)
# 5. 销毁窗口
cv2.destroyAllWindows()

二、视频 / USB 摄像头:流式读取 + 实时显示

2.1 核心对象:cv2.VideoCapture

python

运行

# 方式1:创建同时打开设备
cap = cv2.VideoCapture("/dev/video0", cv2.CAP_V4L2)

# 方式2:空对象延迟打开(推荐,便于断线重连)
cap = cv2.VideoCapture()
cap.open("/dev/video0", cv2.CAP_V4L2)

source 支持:本地视频文件、/dev/videoX、RTSP 网络流

2.2 VideoCapture 核心采集 API(采集链路)

  1. cap.isOpened():判断资源是否打开(句柄有效≠能读到图像)
  2. cap.set():设置分辨率、帧率、缓冲区大小
  3. cap.get():读取实际生效参数
  4. cap.read()grab() + retrieve(),返回 (ret, frame)
    • ret:是否成功读取帧
    • frame:BGR 图像数组,失败为 None
  5. cap.release():释放摄像头 / 视频资源(必须调用)

2.3 实时显示整套调用时序

plaintext

1. 初始化 cap = cv2.VideoCapture()
2. cap.open() 打开相机/视频
3. 参数配置 cap.set() → cap.get()校验
4. 循环:
    ├─ ret, frame = cap.read()
    ├─ 判断ret,失败则退出循环
    ├─ cv2.imshow("Camera", frame) 渲染当前帧
    ├─ key = cv2.waitKey(1) & 0xFF   # 延时1ms,刷新画面
    └─ 判断按键,例如按q退出
5. cap.release() 释放采集设备
6. cv2.destroyAllWindows() 销毁显示窗口

2.4 完整可运行示例(RDK X5 USB 摄像头)

python

运行

import cv2

def camera_show_demo(dev_path="/dev/video0"):
    cap = cv2.VideoCapture()
    # RDK平台强制指定V4L2后端
    if not cap.open(dev_path, cv2.CAP_V4L2):
        print("摄像头打开失败!")
        return

    # 设置分辨率、减小缓冲区降低延迟
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
    cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)

    # 校验真实分辨率
    w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    print(f"生效分辨率:{w} × {h}")

    cv2.namedWindow("USB Camera", cv2.WINDOW_NORMAL)
    try:
        while True:
            ret, frame = cap.read()
            if not ret:
                print("图像读取中断,流断开")
                break
            
            # 实时渲染图像
            cv2.imshow("USB Camera", frame)
            
            # waitKey 必须存在,毫秒延时,同时刷新窗口
            key = cv2.waitKey(1) & 0xFF
            if key == ord("q"):
                print("退出预览")
                break
    finally:
        # 资源强制释放
        cap.release()
        cv2.destroyAllWindows()

if __name__ == "__main__":
    camera_show_demo()

三、关键底层原理(读取 + 显示链路)

1)USB 摄像头完整数据流(RDK)

plaintext

USB相机 → USB总线 → Linux内核uvcvideo → V4L2子系统 → /dev/video0
→ OpenCV V4L2后端 read() 获取原始数据
→ YUYV/MJPG解码、色彩转换 → BGR numpy数组(frame)
→ cv2.imshow 将图像送入GUI渲染管线
→ cv2.waitKey() 触发窗口刷新

2)imshow + waitKey 工作原理

cv2.imshow 仅把图像存入 OpenCV 内部 GUI 缓冲区;画面真正刷新由 waitKey 触发

  • waitKey (n):阻塞 n 毫秒;期间处理窗口重绘、事件、按键检测
  • 视频循环一般使用 waitKey(1),兼顾流畅性与 CPU 占用

四、两种采集模式(多路相机场景)

模式 1:read () 单路首选

python

运行

ret, frame = cap.read()

模式 2:grab ()+retrieve () 多路同步采集

python

运行

# 先统一抓取底层原始数据(不解码),数据存储在cap对象中
ok1 = cap1.grab()
ok2 = cap2.grab()

# 再分别解码渲染,渲染比较耗时
if ok1:
    _, frame1 = cap1.retrieve()
    cv2.imshow("cam1", frame1)
if ok2:
    _, frame2 = cap2.retrieve()
    cv2.imshow("cam2", frame2)
cv2.waitKey(1)

五、高频问题与限制

  1. VNC 远程桌面 imshow 黑屏 / 无法打开窗口 解决方案:设置环境变量 export QT_QPA_PLATFORM=xcb;后台推理程序直接删除所有显示相关代码。

  2. 忘记写 waitKey → 窗口黑屏、无画面 硬性规则:只要使用 imshow,循环内必须搭配 waitKey

  3. 程序异常退出,没有执行 cap.release()/dev/videoX 被占用,下次无法打开相机;规范写法使用 try...finally

  4. 窗口名称重复、多窗口错乱 不同窗口使用不同 winname

  5. OpenCV 图像是 BGR 如果用 matplotlib 展示,需要手动转换: img_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

  6. cap.set() 设置分辨率不一定生效 摄像头硬件不支持时自动降级;set 之后务必用cap.get()校验。

六、静态图片 vs 视频采集 核心对比

表格

项目cv2.imread + imshowcv2.VideoCapture + imshow
数据源本地静态图片文件视频文件 / USB 相机 / RTSP 流
读取方式一次性解码加载循环持续流式读取
资源释放无需额外释放图像数组必须 cap.release()
waitKey建议使用 waitKey (0)循环内使用 waitKey (1)
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐