文章目录
OpenCV的基础应用
一、OpenCV简介:
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库。
OpenCV 由一系列 C 函数和少量 C++ 类构成,同时提供了 Python、Java、MATLAB 等语言的接口。
OpenCV 提供了大量的计算机视觉算法和图像处理工具,广泛应用于图像和视频的处理、分析以及机器学习领域。
OpenCV 的设计目标是提供一套简单易用的计算机视觉基础库,帮助开发人员快速构建复杂的视觉应用。
1.1 OpenCV 优势
**开源免费:**完全开源,可以自由使用,降低开发成本和技术门槛。
**多语言支持:**除C++原生接口外,还支持Java、Python等编程语言。
**跨平台:**支持多种操作系统,Windows、Linux、ios、Android等,方便开发和部署。
**丰富API:**完善的传统计算机视觉算法,涵盖主流的机器学习算法,同时添加了对深度学习的支持。
1.2 OpenCV-Python
- C++ 高性能 + Python 简洁
- 基于Numpy,易于科学计算、与其他库进行集成(Scipy、Matplotlib)
二、环境安装
pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple
2.1 环境导入
import cv2 as cv
三、图像表示
在计算机视觉中,图像是由像素(Pixel)组成的矩阵,每个像素包含了该位置的颜色或灰度信息。
- 像素:图像的最小信息单位,通常用 8 位无符号整数表示,取值范围 0~255
- 位深:常见图像是 8 位图像,即每个像素的每个通道占用 8 位
3.1 颜色空间(Color Space)
颜色空间 是表示颜色的一种方式,决定了像素的含义和颜色的表达方式不同颜色空间适用于不同的图像处理场景。
颜色空间 | 通道含义 | 典型用途 |
---|---|---|
RGB | Red, Green, Blue | 显示、绘图、图像合成 |
BGR | Blue, Green, Red | OpenCV 默认格式 |
HSV | Hue, Saturation, Value | 颜色分割、滤色、目标跟踪 |
GRAY | 灰度 | 边缘检测、特征提取 |
YCrCb | Luma + 色度分量 | 视频压缩,肤色检测 |
LAB | Lightness, a*, b* | 颜色校正,色彩调整 |
3.2 具体说明
RGB(红绿蓝)
- 最常见的颜色空间,图像以 三通道 存储,每通道 0~255
- 适合图像显示、绘制、调色板操作
- 在 OpenCV 中,读取的彩色图像是 BGR 顺序(注意差别)
HSV(色调-饱和度-明度)
- 色调(H):表示颜色种类(0~179)
- 饱和度(S):颜色的纯度(0~255)
- 明度(V):亮度(0~255)
- 适用于颜色分割、物体跟踪,因为颜色分量与光照变化关系较小。
- 颜色转换
BGR
->HSV
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
灰度图(Grayscale)
单通道,0 表示黑色,255 表示白色
用于边缘检测、特征提取、图像二值化
读取灰度图:
gray_img = cv2.imread('path/to/image.jpg', cv2.IMREAD_GRAYSCALE)
3.3 图像在计算机中的表示
- 彩色图像:三维 NumPy 数组,形状
(高度, 宽度, 3)
- 灰度图像:二维 NumPy 数组,形状
(高度, 宽度)
- 数据类型:
unit8
(0-255) - 通道顺序:
- OpenCV 默认 BGR
- 其他库(如 Matplotlib)通常是 RGB
四、基本图像操作
4.1 创建窗口
cv.namedWindow(winname,flags)
在 OpenCV 中,cv.namedWindow()
的 flags
参数用于控制窗口的行为(如是否可缩放、是否保持比例、显示样式等)。以下是常见 flags
的详细作用和使用场景:
1. 核心窗口行为控制
cv.WINDOW_NORMAL
- 作用:允许用户自由调整窗口大小(可拉伸、缩放),窗口尺寸不受图像原始大小限制。
- 场景:需要手动放大 / 缩小窗口查看图像细节时(如医学影像、高分辨率图像)。
cv.WINDOW_AUTOSIZE
(默认值)
- 作用:窗口大小自动适配图像尺寸,用户无法手动调整窗口大小。
- 场景:固定尺寸展示图像,避免误操作改变窗口大小(如批量展示图像预览)。
2. 宽高比控制
cv.WINDOW_KEEPRATIO
作用:调整窗口大小时,强制保持图像的宽高比(图像不会拉伸变形)。
依赖:需与
WINDOW_NORMAL
配合(因为WINDOW_AUTOSIZE
下窗口不可调整)。示例
cv.namedWindow("image", cv.WINDOW_NORMAL | cv.WINDOW_KEEPRATIO)
此时拉伸窗口,图像会按原始比例缩放,避免变形。
cv.WINDOW_FREERATIO
- 作用:允许窗口和图像自由缩放(不保持宽高比),可能导致图像拉伸变形。
- 场景:特殊需求(如强制填充窗口,忽略比例)。
3. 显示模式
cv.WINDOW_FULLSCREEN
- 作用:直接以全屏模式显示窗口(覆盖整个屏幕)。
- 场景:需要最大化展示图像(如演示、大屏展示)。
4. 渲染与 GUI 样式
cv.WINDOW_OPENGL
- 作用:启用 OpenGL 渲染支持,利用 GPU 加速绘制(适合复杂图形渲染,如 3D 可视化结合 OpenCV 窗口)。
cv.WINDOW_GUI_EXPANDED
/ cv.WINDOW_GUI_NORMAL
作用
:控制窗口的 GUI 样式:
WINDOW_GUI_EXPANDED
:显示扩展界面(含工具栏、状态栏,更现代)。WINDOW_GUI_NORMAL
:显示传统简洁界面(无额外控件)。
flags 的组合使用(位运算 |
)
多个 flags
可通过按位或组合,例如:
# 允许自由调整窗口大小 + 保持图像宽高比
cv.namedWindow("image", cv.WINDOW_NORMAL | cv.WINDOW_KEEPRATIO)
总结:如何选择?
需求 | 推荐 flags 组合 | |
---|---|---|
固定尺寸展示 | cv.WINDOW_AUTOSIZE (默认) |
|
可缩放且保持图像比例 | `cv.WINDOW_NORMAL | cv.WINDOW_KEEPRATIO` |
全屏展示 | cv.WINDOW_FULLSCREEN |
|
高性能渲染(如 3D) | cv.WINDOW_OPENGL |
理解这些 flags
后,可更灵活地控制 OpenCV 窗口的交互性和显示效果 ✨。
4.2 读取图像
cv.imread(filename='',flags=cv.IMREAD_COLOR)
参数详解
filename ='xxx'
filename关键字参数为要读取的图片地址,可以使用绝对地址也可以是相对地址。
以下是 cv.imread()
中 flags
参数的核心说明(表格形式,按功能分类):
标志常量 | 核心作用 | 典型场景 & 补充说明 |
---|---|---|
基础色彩模式 | ||
cv.IMREAD_GRAYSCALE |
以 灰度图 读取(单通道,uint8 类型) |
需黑白处理时使用;忽略颜色信息,计算更快。 |
cv.IMREAD_COLOR |
以 彩色图 读取(BGR 三通道,uint8 类型,默认行为) |
忽略 Alpha 通道(透明层);OpenCV 默认存储为 BGR(而非 RGB)。 |
cv.IMREAD_UNCHANGED |
读取 原始图像(保留所有通道,包括 Alpha 通道,如 PNG 透明层) | 处理带透明背景的图像(输出为 4 通道:BGR+Alpha)。 |
深度与格式兼容 | ||
cv.IMREAD_ANYCOLOR |
允许 任意颜色模式 读取(不强制转换为 BGR,保留文件原始色彩格式) | 灵活处理特殊格式图像(如 CMYK 等非 RGB 格式)。 |
cv.IMREAD_ANYDEPTH |
允许读取 高深度图像(如 16 位灰度图,普通图像为 8 位) | 医学影像(CT)、遥感图像等场景;需配合格式支持。 |
降采样(快速预览) | ||
cv.IMREAD_REDUCED_COLOR_2 |
彩色图 + 尺寸缩小为 1/2(降采样,加速加载) | 后缀 _4 (1/4)、_8 (1/8)同理;适合大图像快速预览。 |
cv.IMREAD_REDUCED_GRAYSCALE_2 |
灰度图 + 尺寸缩小为 1/2 | 同上,后缀数字表示缩小倍数(2ⁿ 倍)。 |
特殊处理 | ||
cv.IMREAD_IGNORE_ORIENTATION |
忽略 EXIF 方向信息(如手机拍照的旋转标记,强制原始方向) | 避免自动旋转图像,保持像素原始排列。 |
cv.IMREAD_LOAD_GDAL |
使用 GDAL 库 加载(支持 TIFF、GeoTIFF 等地理 / 遥感图像格式) | 需提前安装 GDAL 库;处理专业地理数据场景。 |
关键补充:
组合使用:多个标志可通过 按位或
|
组合,例如:# 灰度图 + 尺寸缩小1/2 img = cv.imread("img.jpg", cv.IMREAD_GRAYSCALE | cv.IMREAD_REDUCED_2)
默认行为:若不指定
flags
,等价于cv.IMREAD_COLOR
(但建议显式指定,避免版本差异)。返回值:若图像读取失败(路径错误、格式不支持),返回
None
,需提前判断。
通过合理选择 flags
,可灵活控制图像的读取方式(色彩、通道、尺寸、深度等),适配不同业务场景 ✨。
4.3 显示图像
cv.imshow(winname,mat)
参数解释:
winname
:显示图像的窗口名,以字符串类型表示,如果你的窗口之前没有定义会自动创建一个默认的窗口属性(cv.WINDOW_AUTOSIZE)
mat
:为你要显示的图像,也可以是numpy数组。
cv.imshow('win', img)
cv.waitKey(0)
cv.destroyAllWindows()
注意:在调用显示图像的API后,要调用cv2.waitKey(0)给图像绘制留下时间,否则窗口会出现无响应情况,并且图像无法显示出来。
cv.waitKey(0):表示无限期地等待任何键盘按键。这种用法常见于图像显示窗口中,确保图像在窗口中显示直到用户决定关闭它。
cv.waitKey(n):n>0,意味着程序将等待n毫秒。这种方式常用于视频播放或实时摄像头捕获场景,以便控制每一帧停留的时间,同时允许用户通过按键来中断循环或发出命令。
cv.destroyAllWindows([winname])
cv.destroyAllWindows()
:会在当前程序执行到该语句时立即销毁打开的窗口,并释放与这些窗口相关的资源。winname
:窗口名,关闭指定名称的窗口。可省略,销毁所有已打开的窗口。- 使用任意的按键就可以退出程序。
4.4 保存图像
cv.imwrite(cv.imwrite(filename='output.png', img=img1)
参数说明
filename
(必填)- 类型:字符串(
str
) - 作用:指定保存的文件路径和文件名(需包含扩展名,如
.png
、.jpg
、.bmp
等)。 - 示例:
"output.png"
(保存在当前目录)、"./images/result.jpg"
(保存在指定文件夹)。
- 类型:字符串(
img
(必填)- 类型:NumPy 数组(
numpy.ndarray
) - 作用:需要保存的图像数据,必须符合 OpenCV 图像格式要求:
- 维度:2 维(灰度图,
(height, width)
)或 3 维(彩色图,(height, width, 3)
,BGR 通道顺序)。 - 数据类型:通常为
uint8
(像素值范围 0-255)。
- 维度:2 维(灰度图,
- 类型:NumPy 数组(
4.5 创建黑白图像和随机图像
import cv2 as cv
import numpy as np
height = 360
width = 480
channels = 3
# 创建一个全0数组,表示黑色图像
black = np.zeros((360, 480, 3), dtype=np.uint8)
# black = np.zeros((height,width,channels),dtype=np.uint8)
cv.imshow("black", black)
# 使用np.full()创建白色图像
white = np.full((height, width, channels), 255, dtype=np.uint8)
cv.imshow("white", white)
# 使用np.ones()创建白色图像,利用广播机制
white_img = np.ones((512, 512, 3), dtype=np.uint8) * 255
# 索引修改像素值,表示白色图像
black[:, :, :] = 255
# black[:,:] = 255 # 利用广播机制
# black[:] = 255 # 利用广播机制
cv.imshow("trans_black", black)
cv.imshow("trans_white", white_img)
# 使用np.random.randint()创建随机颜色图像 [low,high)
random_color = np.random.randint(0, 256, (height, width, channels), dtype=np.uint8)
cv.imshow("random_color", random_color)
cv.waitKey(0)
cv.destroyAllWindows()
一、创建黑色图像
核心原理:所有像素值为 0(BGR 三通道均为 0)
# 方法:使用np.zeros()初始化全0数组
black = np.zeros((height, width, channels), dtype=np.uint8)
- 适用场景:需要纯黑色背景时
- 特点:直接创建,无需额外计算,效率最高
二、创建白色图像
核心原理:所有像素值为 255(BGR 三通道均为 255)
方法 1:np.full () 直接填充
white = np.full((height, width, channels), 255, dtype=np.uint8)
- 特点:一步到位,直接指定填充值
方法 2:np.ones () + 广播乘法
white_img = np.ones((height, width, channels), dtype=np.uint8) * 255
- 特点:利用广播机制,先创建全 1 数组再放大到 255
方法 3:索引切片修改现有数组
# 先创建黑色图像,再通过切片整体修改 black = np.zeros((height, width, channels), dtype=np.uint8) black[:, :, :] = 255 # 三种等价写法 # black[:,:] = 255 # 利用广播省略最后一维 # black[:] = 255 # 利用广播省略后两维
- 适用场景:需要在已有图像基础上修改时
三、创建随机颜色图像
核心原理:每个像素的 BGR 通道值随机生成(0-255)
# 方法:np.random.randint()生成随机整数
random_color = np.random.randint(0, 256, (height, width, channels), dtype=np.uint8)
- 特点:左闭右开区间 [0,256) 刚好覆盖 0-255 的像素值范围
- 适用场景:测试、随机背景生成等
四、通用注意事项
- 数组形状:必须是
(height, width, channels)
,符合 OpenCV 的图像格式要求 - 数据类型:固定使用
np.uint8
(8 位无符号整数),对应像素值 0-255 的范围 - 通道顺序:OpenCV 默认使用 BGR 格式(蓝、绿、红),与 RGB 不同但不影响纯色图像创建
4.6 图像的裁剪(切片)
Opencv中,图像切片用于从图像中提取一个子区域(矩形区域)。
假设你有一个图像
img
,它的类型是numpy.ndarray
。img[y:y+h,x:x+w]
的含义如下:- x:子区域左上角的x坐标
- y:子区域左上角的y坐标
- w:子区域的宽度
- h:子区域的高度
切片操作
img[y:y+h,x:x+w]
提取的是从(x,y)
开始,高度为h
,宽度为w
的矩形区域
import cv2 as cv
# 读取图像
cat = cv.imread("./images/1.jpg", cv.IMREAD_COLOR)
# 切片 arr[h1:h2, w1:w2] h2 = h1 + h, w2 = w1 + w
# (291,242) (353,288) #shape() 返回的是(h,w,c)
eye = cat[242:288,291:353]
leg = cat[99:341,82:271] #(82,99) (271,341)
# cv.imshow("cat", cat)
cv.imshow("eye", eye)
cv.imshow("leg", leg)
cv.waitKey(0)
cv.destroyAllWindows()
4.7 图像大小的调整(缩放)
import cv2 as cv
import numpy as np
from PIL import Image
# 读取图像
pig = cv.imread('./images/pig.png', cv.IMREAD_COLOR)
print(pig.shape)
cv.imshow("pig", pig)
# 调整图像大小 cv.resize(img, (width, height))
pig2 =cv.resize(pig,(480,520))
print(pig2.shape) #(height, width, channel)
pig3 = np.reshape(pig,(1080,650,3))
print(pig3.shape)
pig.shape = (1080,650,3)
# 显示图像
cv.imshow("pig2", pig2)
cv.imshow("pig3", pig3)
pig4 = Image.open('./images/pig.png')
pig4 = pig4.resize((480,520))
pig4.show()
# 等待按键按下
cv.waitKey(0)
# 释放窗口
cv.destroyAllWindows()
一、三种图像尺寸处理方式对比
方法 | 原理 | 效果 / 特点 | 是否推荐用于图像缩放 |
---|---|---|---|
cv.resize(pig, (480, 520)) |
OpenCV 内置缩放,通过插值算法重新计算像素 | 生成平滑的缩放图像,尺寸为 (520, 480, 3) (高 × 宽 × 通道),显示正常 |
✅ 推荐 |
np.reshape /pig.shape = ... |
仅修改数组维度,不改变像素值和总数 | 若像素总数不匹配则报错;若匹配则像素排列混乱,图像严重撕裂、失真 | ❌ 不推荐 |
PIL.Image.resize((480, 520)) |
PIL 库的缩放,同样通过插值重新计算像素 | 生成平滑的缩放图像,尺寸为 (480, 520) (宽 × 高),显示正常(PIL 默认 RGB 格式,但缩放逻辑正确) |
✅ 推荐 |
二、关键注意点
OpenCV 与 PIL 的坐标顺序差异
- OpenCV 中
cv.resize(img, (width, height))
的尺寸参数是(宽, 高)
,但返回图像的shape
是(高, 宽, 通道)
(如(520, 480, 3)
)。 - PIL 中
Image.resize((width, height))
的尺寸参数同样是(宽, 高)
,且返回图像的尺寸直接是(宽, 高)
(如(480, 520)
),与视觉直观感受一致。
两者的缩放逻辑相同(都是重采样生成新像素),只是返回的尺寸表示方式略有差异(OpenCV 更贴近数组的
(行, 列)
逻辑)。- OpenCV 中
NumPy 维度修改的问题依然存在
代码中的pig3 = np.reshape(pig, (1080, 650, 3))
和pig.shape = (1080, 650, 3)
仍然面临之前的问题:- 若原始图像的总像素数(
高×宽×3
)不等于1080×650×3
,会直接报ValueError
。 - 即使像素总数恰好匹配,图像也会因像素排列混乱而撕裂(例如原本连续的像素被强行拆分到不同行,导致线条断裂、色彩错位)。
- 若原始图像的总像素数(
三、总结
- 图像缩放的正确方式:使用
cv.resize()
(OpenCV)或Image.resize()
(PIL),两者都通过插值算法重新计算像素,保证图像平滑不失真。 - NumPy 维度修改的正确用途:仅用于不改变像素总数的维度重组(例如将
(h, w, 3)
展平为(h×w, 3)
),绝对不能用于改变图像的实际宽高(缩放)。
[!NOTE]
PIL库的Image.resize()方法的参数有哪些?
除了这三种方式,还有哪些方法可以调整图像大小?
如何在保持图像比例的同时调整图像大小?
五、图像绘制
5.1 绘制直线
cv2.line(img, start_point, end_point, color, thickness)
img
:要绘制的图像start_point
,end_point
:起点、终点坐标(x, y)
color
:线条颜色(B, G, R)
thickness
:线宽,像素值
5.2 绘制矩形
cv2.rectangle(img, top_left, bottom_right, color, thickness)
top_left
,bottom_right
:左上角与右下角坐标color
:颜色thickness
:线宽,-1
表示填充
5.3 绘制圆形
cv2.circle(img, center, radius, color, thickness[, lineType])
center
:圆心radius
:半径lineType
:线型(cv2.LINE_AA
抗锯齿,推荐)
5.4 绘制椭圆
cv2.ellipse(img, center, axes, angle, startAngle, endAngle, color, thickness)
axes
:长轴半径,短轴半径(长, 短)
angle
:椭圆旋转角度startAngle
,endAngle
:起始角度,结束角度
5.5 绘制文本
cv2.putText(img, text, org, fontFace, fontScale, color, thickness[, lineType])
org
:文本左下角坐标fontFace
:字体样式(如cv2.FONT_HERSHEY_COMPLEX
)fontScale
:字体大小缩放系数lineType
:cv2.LINE_AA
抗锯齿
5.6 绘制多边形
cv2.polylines(img, [pts], isClosed, color, thickness)
pts
:多边形顶点数组,形状必须是(-1, 1, 2)
isClosed
:是否闭合color
:颜色thickness
:线宽
综合案例:
import cv2 as cv
import numpy as np
cat = cv.imread('./images/1.jpg')
# 绘制直线 cv.line(img,start,end,color,thickness) (w,h)
cv.line(cat,(50,40),(80,40),(188,100,25),2)
#绘制矩形 cv.rectangle(img,start(左上角),end(右下角),color,thickness(等于-1表示填充))
cv.rectangle(cat,(78,106),(237,306),(0,255,0),-1)
#绘制圆形 cv.circle(img,center,radius,color,thickness)
# cv.LINE_AA 反走样技术 抗锯齿技术 平滑 默认使用的是LINE_8
cv.circle(cat,(325,269),30,(0,0,255),-1,cv.LINE_AA)
#绘制椭圆形 cv.ellipse(img,center(中心点),axes(设置宽,高),angle,startAngle,endAngle,color,thickness)
cv.ellipse(cat,(550,550),(100,50),0,0,270,(255,0,0),3)
#绘制文本 cv.putText(img,text,start,font,fontScale,color,thickness)
cv.putText(cat,'hello world',(10,500),cv.FONT_HERSHEY_COMPLEX,1,(255,255,255),2)
#绘制多边形 cv.polylines(img,points,isClosed,color,thickness)
pts = np.array([[10,5],[20,30],[70,20],[50,10]],np.int32)
pts = pts.reshape((-1,1,2))
cv.polylines(cat,[pts],True,(0,255,255),3)
cv.imshow('cat',cat)
cv.waitKey(0)
cv.destroyAllWindows()
难点解析:
在使用 cv.polylines()
时对 pts
进行 reshape((-1, 1, 2))
转换,是为了满足 OpenCV 对多边形顶点数据格式的硬性要求。具体原因如下:
1. cv.polylines()
对顶点格式的要求
cv.polylines()
的 points
参数需要传入一个形状为 (N, 1, 2)
的 NumPy 数组,其中:
N
表示多边形的顶点数量(例如你的例子中有 4 个顶点,N=4
);- 中间的
1
是一个固定的维度(可理解为每个顶点被包裹在一个单元素数组中); - 最后的
2
表示每个顶点的(x, y)
坐标。
这种格式本质上是 “顶点数组的数组”,即把每个顶点作为一个独立的子数组,整体构成一个三维数组。
2. 为什么原始 pts
不符合要求?
你的原始顶点定义是:
pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32)
此时 pts
的形状是 (4, 2)
(二维数组),表示 “4 个顶点,每个顶点有 x、y 两个坐标”。但 OpenCV 不直接接受这种二维格式,必须转换为三维格式 (4, 1, 2)
。
3. reshape((-1, 1, 2))
的作用
-1
表示 “自动计算该维度的大小”(这里会自动计算为顶点数量 4);1
和2
固定,强制将二维数组(4, 2)
转换为三维数组(4, 1, 2)
。
4. 为什么没有返回值?
在 OpenCV 中,绘图函数(如 cv.line
、cv.rectangle
、cv.circle
等)的一个重要特性是:直接在原图上进行修改,不返回新图像。这是 OpenCV 设计上的一个核心特点,具体原因和细节如下:
原地操作(In-place Operation):
OpenCV 的绘图函数会直接修改输入的图像数组(如代码中的cat
),所有绘制的图形(多边形、线条等)都会直接 “画” 在原图上,因此不需要返回新图像。
这种设计的好处是节省内存—— 如果每次绘图都返回新图像,会额外占用一倍的内存空间(尤其对大图像或批量处理不友好)。与 NumPy 数组的特性一致:
图像在 OpenCV 中以 NumPy 数组的形式存储,而 NumPy 数组的很多操作(如切片修改、数值更新)也是原地修改(不返回新数组)。绘图函数遵循这一特性,保持了与数组操作逻辑的一致性。
六、视频读取与捕捉
6.1 cv2.VideoCapture()
方法
用于从摄像头、视频文件或视频流中捕获视频
cap = cv2.VideoCapture(source[, apiPreference])
source
:输入源0
:默认摄像头1
、2
:外接摄像头(编号递增)'video.mp4'
:视频文件路径'rtsp://... '
:RTSP/网络视频流
apiPreference
(可选):指定使用的后端API(通常可省略)cv2.CAP_DSHOW
:Windows DirectShowcv2.CAP_V4L2
:Linux V4L2cv2.CAP_FFMPEG
:使用FFmpeg解码
6.2 捕获摄像头实时视频
cap = cv2.VideoCapture(0) # 打开默认摄像头
while True:
ret, frame = cap.read() # 逐帧读取
if not ret:
break # 读取失败时退出
cv2.imshow('camera', frame)
# 按 q 键退出
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cap.release() # 释放摄像头
cv2.destroyAllWindows() # 关闭窗口
6.3 读取本地视频文件
cap = cv2.VideoCapture('video.mp4') # 替换自己本地的视频文件
while True:
ret, frame = cap.read()
if not ret:
break # 视频结束或读取失败
cv2.imshow('video', frame)
if cv2.waitKey(30) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
6.4 常用属性设置与获取
可以使用 cap.get()
和 cap.set()
方法对视频流参数进行读取与修改
方法 | 说明 |
---|---|
cap.get(cv2.CAP_PROP_FRAME_WIDTH) |
获取帧宽度 |
cap.get(cv2.CAP_PROP_FRAME_HEIGHT) |
获取帧高度 |
cap.get(cv2.CAP_PROP_FPS) |
获取帧率 |
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) |
设置帧宽度 |
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) |
设置帧高度 |
6.5 难点解析
1.为什么在读取视频流的时候不使用cv2.waitKey(0)
?
cv2.waitKey(0)
的作用是无限等待,直到用户按下任意键
如果你写在视频播放循环里,会导致:
- 第一帧暂停等待按键
- 你不按键,程序就卡死在那里
- 按下后,继续下一帧,再次等待,变成每一帧都要你按键
🛑 这显然不符合连续播放视频的逻辑
🎯 小结:
用法 场景 cv2.waitKey(0)
静态图像,等待用户操作 cv2.waitKey(n)
(n > 0)视频播放,循环内控制帧间隔,n越小刷新越快,越流畅
2.为什么在要使用&0XFF
来操作?
cv2.waitKey()
返回的键值,有些系统/后端会返回 32位整数- 其中 低8位 才是实际的按键 ASCII 编码
所以:
if cv2.waitKey(10) & 0xFF == ord('q'):
break
是为了 屏蔽高位影响,确保兼容性
💡 示例说明:
- 假设
cv2.waitKey()
返回了0x00000071
ord('q') = 0x71
(0x00000071) & 0xFF = 0x71
✅ 正常检测
如果不加 & 0xFF
,有的环境判断就会失败,保证键值兼容,避免系统差异