3、读取本地摄像头:cv2.VideoCapture的使用、帧率设置、分辨率调整与属性获取

好,咱们进入实战环节。

摄像头数据流接入,说白了就是让电脑认识摄像头。OpenCV 里最核心的工具就是 cv2.VideoCapture。我刚开始接触这个接口时,觉得它就是个简单的摄像头开关。后来踩的坑多了,才发现里面门道不少。

3.1 打开摄像头:cv2.VideoCapture 的基本用法

先看最基础的代码。打开摄像头只需要一行:

import cv2

# 打开默认摄像头(通常是笔记本前置摄像头)
cap = cv2.VideoCapture(0)

# 检查是否成功打开
if not cap.isOpened():
    print("摄像头打开失败,请检查连接")
    exit()

# 读取一帧
ret, frame = cap.read()

# 释放资源
cap.release()

这里 0 代表设备索引。如果你插了多个摄像头,可以试试 12…… 我遇到过一种情况:笔记本自带摄像头是 0,外接 USB 摄像头有时是 1,有时是 2。嗯,这跟驱动加载顺序有关。

注意: 有些摄像头在 Windows 下索引从 0 开始,但在 Linux 下可能从 1 开始。建议写个循环尝试 0~5,哪个能打开就用哪个。

3.2 帧率设置:别被数字骗了

很多人以为设置帧率就是调个参数那么简单。其实不然。

# 尝试设置帧率为 30fps
cap.set(cv2.CAP_PROP_FPS, 30)

# 获取实际帧率
fps = cap.get(cv2.CAP_PROP_FPS)
print(f"实际帧率: {fps}")

你猜怎么着?我曾在项目中设置 60fps,结果实际跑出来只有 15fps。为什么?因为摄像头硬件能力有限,或者 USB 带宽不够。说白了,set() 只是给摄像头发个请求,它不一定听你的。

我的经验: 设置帧率后,一定要用 get() 读回来确认。如果实际帧率远低于设定值,别硬调,考虑降低分辨率或换硬件。

还有一个坑:有些摄像头不支持动态调整帧率。我曾经调试一个工业相机,怎么调帧率都不变,后来发现它只支持 30fps 和 60fps 两档。你想想看,中间值根本没用。

3.3 分辨率调整:别贪心

分辨率设置和帧率类似,也是先 set 再 get 确认。

# 设置分辨率为 1280x720
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

# 获取实际分辨率
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(f"实际分辨率: {width}x{height}")

我个人习惯是:先设一个目标分辨率,然后读回来看看实际是多少。如果差太多,就降一档。比如你想用 1920x1080,但摄像头只支持 1280x720,那就别硬撑。

避坑指南: 我曾经在树莓派上设了 4K 分辨率,结果帧率掉到 5fps,CPU 占用 100%。后来老老实实降到 640x480,流畅多了。记住:高分辨率不等于好效果,够用就行。

3.4 属性获取:知己知彼

除了帧率和分辨率,还有很多属性可以查。我列几个常用的:

属性常量 含义 常见值
CAP_PROP_FRAME_WIDTH 画面宽度 640, 1280, 1920
CAP_PROP_FRAME_HEIGHT 画面高度 480, 720, 1080
CAP_PROP_FPS 帧率 15, 30, 60
CAP_PROP_BRIGHTNESS 亮度 0~255
CAP_PROP_CONTRAST 对比度 0~255
CAP_PROP_SATURATION 饱和度 0~255
CAP_PROP_HUE 色调 0~255
CAP_PROP_GAIN 增益 0~255
CAP_PROP_EXPOSURE 曝光时间 视摄像头而定

获取这些属性的代码很简单:

# 一次性获取多个属性
props = {
    "宽度": cv2.CAP_PROP_FRAME_WIDTH,
    "高度": cv2.CAP_PROP_FRAME_HEIGHT,
    "帧率": cv2.CAP_PROP_FPS,
    "亮度": cv2.CAP_PROP_BRIGHTNESS,
    "对比度": cv2.CAP_PROP_CONTRAST,
}

for name, prop_id in props.items():
    value = cap.get(prop_id)
    print(f"{name}: {value}")

你可能会发现,有些属性返回 0 或者 -1。别慌,这通常意味着摄像头不支持该属性。我遇到过一款廉价 USB 摄像头,亮度、对比度全都不支持,只能调分辨率。嗯,一分钱一分货。

3.5 完整示例:一个实用的摄像头检测脚本

最后,我分享一个自己常用的脚本。它帮你快速了解一个摄像头的底细:

import cv2

def inspect_camera(index=0):
    cap = cv2.VideoCapture(index)
    if not cap.isOpened():
        print(f"摄像头 {index} 无法打开")
        return
    
    print(f"=== 摄像头 {index} 信息 ===")
    
    # 尝试设置常用分辨率
    for w, h in [(640, 480), (1280, 720), (1920, 1080)]:
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, w)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, h)
        actual_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        actual_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
        print(f"设置 {w}x{h} -> 实际 {actual_w}x{actual_h}")
    
    # 获取当前帧率
    fps = cap.get(cv2.CAP_PROP_FPS)
    print(f"当前帧率: {fps}")
    
    cap.release()

# 检查 0 号和 1 号摄像头
inspect_camera(0)
inspect_camera(1)

这个脚本会遍历几个常见分辨率,告诉你摄像头到底支持什么。我每次拿到新摄像头,第一件事就是跑这个脚本。你想想看,连硬件能力都不清楚,后面怎么调参?

小技巧: 如果发现摄像头支持的分辨率很少,别灰心。很多摄像头在 640x480 下能跑到 30fps 甚至 60fps,对于大多数视觉任务来说完全够用。

好了,关于 cv2.VideoCapture 的基本操作就这些。记住三个要点:打开要检查、设置要确认、属性要了解。下一节咱们聊聊如何从摄像头持续读取视频流,以及如何处理实时数据。