0.我想做什么?
想做这样一个功能的原型:用网络摄像头做一个尺寸测量的仪器,好吧,就称它为一键测量仪远古版。
原型开发,目的是验证可行性。所以准备不用工业相机和镜头,而是选择便宜的网络摄像头;开发工具使用OpenCV,当然是python版。
1.打开摄像头并预览
本文完成第一步,打开摄像头并预览。
先介绍OpenCV中两个重要的方法: VideoCapture和waitKey。
1.1 VideoCapture
cv2.VideoCapture是OpenCV中处理视频输入的核心类,负责从摄像头、视频文件或网络流中捕获帧数据。
capture = cv2.VideoCapture(source, apiPreference=None)
参数说明:
- source:
0
:默认摄像头(通常为内置摄像头)1, 2, 3...
:USB外接摄像头(按连接顺序递增)"video.mp4"
:视频文件路径(支持MP4/AVI/MOV等)"rtsp://192.168.1.1:554/stream"
:RTSP网络视频流"http://ip:port/video"
:HTTP视频流
- apiPreference(可选):
指定底层视频捕获API,常用选项:
cv2.CAP_ANY# 自动选择(默认)
cv2.CAP_DSHOW# DirectShow(Windows)
cv2.CAP_V4L2# Video4Linux2(Linux)
cv2.CAP_FFMPEG# FFmpeg解码
示例:cv2.VideoCapture(0, cv2.CAP_DSHOW)
还记得在写播放器那篇文章,传入的是视频文件路径。
常用方法
1. 设备状态检查:isOpened()
if not capture.isOpened():
print("错误:无法打开视频源")
exit()
- 返回值:布尔值
- 必须调用:在访问帧数据前验证连接状态
2. 帧捕获:read()
ret, frame = capture.read()
- 返回值:
ret
:布尔值,帧是否成功读取frame
:NumPy数组(三维BGR格式)- 特性:
- 阻塞调用:等待下一帧可用
- 自动解码:处理压缩视频流
3. 属性访问:get(propId)
获取视频流的元数据和设备参数:
width = capture.get(cv2.CAP_PROP_FRAME_WIDTH)
height = capture.get(cv2.CAP_PROP_FRAME_HEIGHT)
fps = capture.get(cv2.CAP_PROP_FPS)
常用属性ID:
属性ID | 说明 | 值类型 |
---|---|---|
cv2.CAP_PROP_FRAME_WIDTH |
帧宽度 | float |
cv2.CAP_PROP_FRAME_HEIGHT |
帧高度 | float |
cv2.CAP_PROP_FPS |
帧率(视频文件) | float |
cv2.CAP_PROP_POS_MSEC |
当前位置(毫秒) | float |
cv2.CAP_PROP_FRAME_COUNT |
总帧数(视频文件) | float |
cv2.CAP_PROP_AUTOFOCUS |
自动对焦状态 | 0/1 |
cv2.CAP_PROP_EXPOSURE |
曝光值 | float |
4. 参数设置:set(propId, value)
# 设置分辨率
capture.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
# 关闭自动对焦
capture.set(cv2.CAP_PROP_AUTOFOCUS, 0)
# 设置曝光(-1到1之间)
capture.set(cv2.CAP_PROP_EXPOSURE, -0.5)
重要注意事项:
- 分辨率设置需设备支持
- 设置后需验证是否成功:
if capture.get(cv2.CAP_PROP_FRAME_WIDTH) != 1280:
print("不支持该分辨率")
5. 资源释放:release()
capture.release()
- 必须调用:释放硬件/网络资源
- 未释放后果:
- 摄像头锁定(其他程序无法访问)
- 内存泄漏
- 网络连接残留
1.2 waitKey
waitKey()
是OpenCV HighGUI库中的工具包,它在OpenCV窗口显示期间负责刷新图像帧并监听键盘事件。
retval = cv2.waitKey([delay]) # → 返回整数 (ASCII 键值)
参数delay
取值 | 行为 | 典型场景 |
---|---|---|
delay > 0 |
等待指定毫秒(如waitKey(30) 表示每帧显示30ms) |
视频播放控制(控制帧率) |
delay = 0 |
无限等待按键,阻塞后续代码执行 | 静态图像显示(按任意键继续) |
delay < 0 |
默认行为,等价于delay=0 (无限等待) |
需主动按键退出的场景 |
返回值
有按键触发,返回值就是按键的ASCII码;没有按键触发,就等待超时吧。
简单的ASCII码有:
按键 | ASCII 值 | 按键 | ASCII 值 |
---|---|---|---|
ESC | 27 | 回车 (Enter) | 13 |
空格 | 32 | 方向键↑ | 38 |
字母 A | 65 | 字母 a | 97 |
数字 0 | 48 | 功能键 F1 | 112 |
2.编写代码
有了上面两个重要的知识点,结合我们的需求,就可以写代码了。
很简单,找到我的USB网络摄像头,用VideoCapture(1)即可。
不断的读取摄像头的帧,read方法即可。
不断的显示出来,用imshow即可。
完整代码很少,如下:
import cv2
def camera_video():
capture = cv2.VideoCapture(1) # 0为电脑内置摄像头
if not capture.isOpened():
return
while True:
ret, frame = capture.read()
cv2.imshow("video", frame)
c = cv2.waitKey(10)
if c == 27:
break
if c == 13: # 回车,处理图像
cv2.imwrite("test.png", frame)
camera_video()
cv2.destroyAllWindows()
至此,借着这个机会梳理了VideoCapture和waitKey两个重要接口,坚持、积累,我们下期再见!